diff --git a/.editorconfig b/.editorconfig
index 872a068c7c6..a5dfab07a50 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -1,4 +1,5 @@
root = true
+
[*]
charset = utf-8
@@ -12,6 +13,7 @@ tab_width = 4
#end_of_line = crlf
insert_final_newline = true
trim_trailing_whitespace = true
+max_line_length = 120
#### .NET Coding Conventions ####
@@ -277,7 +279,7 @@ dotnet_naming_style.t_upper_camel_case_style.capitalization = pascal_case
dotnet_naming_style.t_upper_camel_case_style.required_prefix = T
dotnet_naming_style.upper_camel_case_style.capitalization = pascal_case
-dotnet_naming_symbols.constants_symbols.applicable_accessibilities = public,internal,protected,protected_internal,private_protected
+dotnet_naming_symbols.constants_symbols.applicable_accessibilities = public, internal, protected, protected_internal, private_protected
dotnet_naming_symbols.constants_symbols.applicable_kinds = field
dotnet_naming_symbols.constants_symbols.required_modifiers = const
@@ -316,27 +318,32 @@ dotnet_naming_symbols.private_static_fields_symbols.required_modifiers = static
dotnet_naming_symbols.private_static_readonly_symbols.applicable_accessibilities = private
dotnet_naming_symbols.private_static_readonly_symbols.applicable_kinds = field
-dotnet_naming_symbols.private_static_readonly_symbols.required_modifiers = static,readonly
+dotnet_naming_symbols.private_static_readonly_symbols.required_modifiers = static, readonly
dotnet_naming_symbols.property_symbols.applicable_accessibilities = *
dotnet_naming_symbols.property_symbols.applicable_kinds = property
-dotnet_naming_symbols.public_fields_symbols.applicable_accessibilities = public,internal,protected,protected_internal,private_protected
+dotnet_naming_symbols.public_fields_symbols.applicable_accessibilities = public, internal, protected, protected_internal, private_protected
dotnet_naming_symbols.public_fields_symbols.applicable_kinds = field
-dotnet_naming_symbols.static_readonly_symbols.applicable_accessibilities = public,internal,protected,protected_internal,private_protected
+dotnet_naming_symbols.static_readonly_symbols.applicable_accessibilities = public, internal, protected, protected_internal, private_protected
dotnet_naming_symbols.static_readonly_symbols.applicable_kinds = field
-dotnet_naming_symbols.static_readonly_symbols.required_modifiers = static,readonly
+dotnet_naming_symbols.static_readonly_symbols.required_modifiers = static, readonly
dotnet_naming_symbols.types_and_namespaces_symbols.applicable_accessibilities = *
-dotnet_naming_symbols.types_and_namespaces_symbols.applicable_kinds = namespace,class,struct,enum,delegate
+dotnet_naming_symbols.types_and_namespaces_symbols.applicable_kinds = namespace, class, struct, enum, delegate
dotnet_naming_symbols.type_parameters_symbols.applicable_accessibilities = *
dotnet_naming_symbols.type_parameters_symbols.applicable_kinds = type_parameter
# ReSharper properties
resharper_braces_for_ifelse = required_for_multiline
+resharper_csharp_wrap_arguments_style = chop_if_long
+resharper_csharp_wrap_parameters_style = chop_if_long
resharper_keep_existing_attribute_arrangement = true
+resharper_wrap_chained_binary_patterns = chop_if_long
+resharper_wrap_chained_method_calls = chop_if_long
+resharper_csharp_trailing_comma_in_multiline_lists = true
[*.{csproj,xml,yml,yaml,dll.config,msbuildproj,targets,props}]
indent_size = 2
diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
index ddb66e8694b..45187260126 100644
--- a/.github/CODEOWNERS
+++ b/.github/CODEOWNERS
@@ -15,6 +15,7 @@
#/Content.*/GameTicking/ @moonheart08 @EmoGarbage404
#/Resources/ServerInfo/ @moonheart08 @Chief-Engineer
#/Resources/ServerInfo/Guidebook/ @moonheart08 @EmoGarbage404
+#/Resources/ServerInfo/Guidebook/ServerRules/ @Chief-Engineer
#/Resources/engineCommandPerms.yml @moonheart08 @Chief-Engineer
#/Resources/clientCommandPerms.yml @moonheart08 @Chief-Engineer
@@ -23,11 +24,12 @@
#/Resources/Prototypes/Body/ @DrSmugleaf # suffering
#/Resources/Prototypes/Entities/Mobs/Player/ @DrSmugleaf
#/Resources/Prototypes/Entities/Mobs/Species/ @DrSmugleaf
+#/Resources/Prototypes/Guidebook/rules.yml @Chief-Engineer
#/Content.*/Body/ @DrSmugleaf
#/Content.YAMLLinter @DrSmugleaf
#/Content.Shared/Damage/ @DrSmugleaf
-#/Content.*/Anomaly/ @EmoGarbage404
+#/Content.*/Anomaly/ @EmoGarbage404 @TheShuEd
#/Content.*/Lathe/ @EmoGarbage404
#/Content.*/Materials/ @EmoGarbage404
#/Content.*/Mech/ @EmoGarbage404
@@ -35,7 +37,7 @@
#/Content.*/Stack/ @EmoGarbage404
#/Content.*/Xenoarchaeology/ @EmoGarbage404
#/Content.*/Zombies/ @EmoGarbage404
-#/Resources/Prototypes/Entities/Structures/Specific/anomalies.yml @EmoGarbage404
+#/Resources/Prototypes/Entities/Structures/Specific/anomalies.yml @EmoGarbage404 @TheShuEd
#/Resources/Prototypes/Research/ @EmoGarbage404
#/Content.*/Forensics/ @ficcialfaint
diff --git a/.github/mapchecker/config.py b/.github/mapchecker/config.py
index 82c3c70ab81..0464da529b9 100644
--- a/.github/mapchecker/config.py
+++ b/.github/mapchecker/config.py
@@ -38,13 +38,16 @@
"Plastitanium", # Plastitanium walls should only be appearing on security ships.
"Kammerer", # Opportunity
"HighSecDoor",
+ "ShuttleGun",
],
"Syndicate": [
"Plastitanium", # And also on blackmarket ships cause syndicate.
- "ButtonFrameCautionSecurity", # Decal.
+ "ButtonFrameCautionSecurity", # Decal.
+ "ShuttleGun",
],
"BlackMarket": [
"Plastitanium", # And also on blackmarket ships cause syndicate.
"ButtonFrameCautionSecurity", # Decal.
+ "ShuttleGun",
]
}
\ No newline at end of file
diff --git a/.github/mapchecker/whitelist.yml b/.github/mapchecker/whitelist.yml
index 074857ab784..226b2e57f7d 100644
--- a/.github/mapchecker/whitelist.yml
+++ b/.github/mapchecker/whitelist.yml
@@ -17,3 +17,7 @@ Trade: true
# the intention for this list to become empty in separate PR's.
#DartX:
# - HighSecDoor
+Rogue:
+ - ShuttleGunFriendship
+Bottleneck:
+ - PosterLegitPDAAd
diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml
index e335f8397af..aa837ab5708 100644
--- a/.github/workflows/publish.yml
+++ b/.github/workflows/publish.yml
@@ -28,7 +28,7 @@ jobs:
chmod 600 ~/.ssh/id_rsa
echo "HOST *" > ~/.ssh/config
echo "StrictHostKeyChecking no" >> ~/.ssh/config
- git -c submodule.Secrets.update=checkout submodule update --init
+ git clone git@github.com:corvax-nexus/secrets.git Secrets
cp -R Secrets/Resources/Prototypes Resources/Prototypes/CorvaxSecrets
cp -R Secrets/Resources/ServerPrototypes Resources/Prototypes/CorvaxSecretsServer
cp -R Secrets/Resources/Locale Resources/Locale/ru-RU/corvax-secrets
diff --git a/.gitignore b/.gitignore
index 2dd5912047c..df4947fd4b4 100644
--- a/.gitignore
+++ b/.gitignore
@@ -10,6 +10,13 @@
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
+# Secret
+Secrets
+Resources/Prototypes/CorvaxSecrets
+Resources/Prototypes/CorvaxSecretsServer
+Resources/Textures/CorvaxSecrets
+Resources/Locale/ru-RU/corvax-secrets
+
# Build results
[Dd]ebug/
[Dd]ebugPublic/
diff --git a/.gitmodules b/.gitmodules
index da4e5bdad10..bda7de5d838 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -2,8 +2,3 @@
path = RobustToolbox
url = https://github.com/space-wizards/RobustToolbox.git
branch = master
-[submodule "Secrets"]
- path = Secrets
- url = git@github.com:corvax-project/secrets.git
- branch = master
- update = none
\ No newline at end of file
diff --git a/Content.Benchmarks/ComponentQueryBenchmark.cs b/Content.Benchmarks/ComponentQueryBenchmark.cs
new file mode 100644
index 00000000000..11c7ab9d5f5
--- /dev/null
+++ b/Content.Benchmarks/ComponentQueryBenchmark.cs
@@ -0,0 +1,273 @@
+#nullable enable
+using System;
+using System.Runtime.CompilerServices;
+using System.Threading.Tasks;
+using BenchmarkDotNet.Attributes;
+using BenchmarkDotNet.Configs;
+using Content.IntegrationTests;
+using Content.IntegrationTests.Pair;
+using Content.Shared.Clothing.Components;
+using Content.Shared.Doors.Components;
+using Content.Shared.Item;
+using Robust.Server.GameObjects;
+using Robust.Shared;
+using Robust.Shared.Analyzers;
+using Robust.Shared.GameObjects;
+using Robust.Shared.Map;
+using Robust.Shared.Map.Components;
+using Robust.Shared.Random;
+
+namespace Content.Benchmarks;
+
+///
+/// Benchmarks for comparing the speed of various component fetching/lookup related methods, including directed event
+/// subscriptions
+///
+[Virtual]
+[GroupBenchmarksBy(BenchmarkLogicalGroupRule.ByCategory)]
+[CategoriesColumn]
+public class ComponentQueryBenchmark
+{
+ public const string Map = "Maps/atlas.yml";
+
+ private TestPair _pair = default!;
+ private IEntityManager _entMan = default!;
+ private MapId _mapId = new(10);
+ private EntityQuery _itemQuery;
+ private EntityQuery _clothingQuery;
+ private EntityQuery _mapQuery;
+ private EntityUid[] _items = default!;
+
+ [GlobalSetup]
+ public void Setup()
+ {
+ ProgramShared.PathOffset = "../../../../";
+ PoolManager.Startup(typeof(QueryBenchSystem).Assembly);
+
+ _pair = PoolManager.GetServerClient().GetAwaiter().GetResult();
+ _entMan = _pair.Server.ResolveDependency();
+
+ _itemQuery = _entMan.GetEntityQuery();
+ _clothingQuery = _entMan.GetEntityQuery();
+ _mapQuery = _entMan.GetEntityQuery();
+
+ _pair.Server.ResolveDependency().SetSeed(42);
+ _pair.Server.WaitPost(() =>
+ {
+ var success = _entMan.System().TryLoad(_mapId, Map, out _);
+ if (!success)
+ throw new Exception("Map load failed");
+ _pair.Server.MapMan.DoMapInitialize(_mapId);
+ }).GetAwaiter().GetResult();
+
+ _items = new EntityUid[_entMan.Count()];
+ var i = 0;
+ var enumerator = _entMan.AllEntityQueryEnumerator();
+ while (enumerator.MoveNext(out var uid, out _))
+ {
+ _items[i++] = uid;
+ }
+ }
+
+ [GlobalCleanup]
+ public async Task Cleanup()
+ {
+ await _pair.DisposeAsync();
+ PoolManager.Shutdown();
+ }
+
+ #region TryComp
+
+ ///
+ /// Baseline TryComp benchmark. When the benchmark was created, around 40% of the items were clothing.
+ ///
+ [Benchmark(Baseline = true)]
+ [BenchmarkCategory("TryComp")]
+ public int TryComp()
+ {
+ var hashCode = 0;
+ foreach (var uid in _items)
+ {
+ if (_clothingQuery.TryGetComponent(uid, out var clothing))
+ hashCode = HashCode.Combine(hashCode, clothing.GetHashCode());
+ }
+ return hashCode;
+ }
+
+ ///
+ /// Variant of that is meant to always fail to get a component.
+ ///
+ [Benchmark]
+ [BenchmarkCategory("TryComp")]
+ public int TryCompFail()
+ {
+ var hashCode = 0;
+ foreach (var uid in _items)
+ {
+ if (_mapQuery.TryGetComponent(uid, out var map))
+ hashCode = HashCode.Combine(hashCode, map.GetHashCode());
+ }
+ return hashCode;
+ }
+
+ ///
+ /// Variant of that is meant to always succeed getting a component.
+ ///
+ [Benchmark]
+ [BenchmarkCategory("TryComp")]
+ public int TryCompSucceed()
+ {
+ var hashCode = 0;
+ foreach (var uid in _items)
+ {
+ if (_itemQuery.TryGetComponent(uid, out var item))
+ hashCode = HashCode.Combine(hashCode, item.GetHashCode());
+ }
+ return hashCode;
+ }
+
+ ///
+ /// Variant of that uses `Resolve()` to try get the component.
+ ///
+ [Benchmark]
+ [BenchmarkCategory("TryComp")]
+ public int Resolve()
+ {
+ var hashCode = 0;
+ foreach (var uid in _items)
+ {
+ DoResolve(uid, ref hashCode);
+ }
+ return hashCode;
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void DoResolve(EntityUid uid, ref int hash, ClothingComponent? clothing = null)
+ {
+ if (_clothingQuery.Resolve(uid, ref clothing, false))
+ hash = HashCode.Combine(hash, clothing.GetHashCode());
+ }
+
+ #endregion
+
+ #region Enumeration
+
+ [Benchmark]
+ [BenchmarkCategory("Item Enumerator")]
+ public int SingleItemEnumerator()
+ {
+ var hashCode = 0;
+ var enumerator = _entMan.AllEntityQueryEnumerator();
+ while (enumerator.MoveNext(out var item))
+ {
+ hashCode = HashCode.Combine(hashCode, item.GetHashCode());
+ }
+
+ return hashCode;
+ }
+
+ [Benchmark]
+ [BenchmarkCategory("Item Enumerator")]
+ public int DoubleItemEnumerator()
+ {
+ var hashCode = 0;
+ var enumerator = _entMan.AllEntityQueryEnumerator();
+ while (enumerator.MoveNext(out _, out var item))
+ {
+ hashCode = HashCode.Combine(hashCode, item.GetHashCode());
+ }
+
+ return hashCode;
+ }
+
+ [Benchmark]
+ [BenchmarkCategory("Item Enumerator")]
+ public int TripleItemEnumerator()
+ {
+ var hashCode = 0;
+ var enumerator = _entMan.AllEntityQueryEnumerator();
+ while (enumerator.MoveNext(out _, out _, out var xform))
+ {
+ hashCode = HashCode.Combine(hashCode, xform.GetHashCode());
+ }
+
+ return hashCode;
+ }
+
+ [Benchmark]
+ [BenchmarkCategory("Airlock Enumerator")]
+ public int SingleAirlockEnumerator()
+ {
+ var hashCode = 0;
+ var enumerator = _entMan.AllEntityQueryEnumerator();
+ while (enumerator.MoveNext(out var airlock))
+ {
+ hashCode = HashCode.Combine(hashCode, airlock.GetHashCode());
+ }
+
+ return hashCode;
+ }
+
+ [Benchmark]
+ [BenchmarkCategory("Airlock Enumerator")]
+ public int DoubleAirlockEnumerator()
+ {
+ var hashCode = 0;
+ var enumerator = _entMan.AllEntityQueryEnumerator();
+ while (enumerator.MoveNext(out _, out var door))
+ {
+ hashCode = HashCode.Combine(hashCode, door.GetHashCode());
+ }
+
+ return hashCode;
+ }
+
+ [Benchmark]
+ [BenchmarkCategory("Airlock Enumerator")]
+ public int TripleAirlockEnumerator()
+ {
+ var hashCode = 0;
+ var enumerator = _entMan.AllEntityQueryEnumerator();
+ while (enumerator.MoveNext(out _, out _, out var xform))
+ {
+ hashCode = HashCode.Combine(hashCode, xform.GetHashCode());
+ }
+
+ return hashCode;
+ }
+
+ #endregion
+
+ [Benchmark(Baseline = true)]
+ [BenchmarkCategory("Events")]
+ public int StructEvents()
+ {
+ var ev = new QueryBenchEvent();
+ foreach (var uid in _items)
+ {
+ _entMan.EventBus.RaiseLocalEvent(uid, ref ev);
+ }
+
+ return ev.HashCode;
+ }
+}
+
+[ByRefEvent]
+public struct QueryBenchEvent
+{
+ public int HashCode;
+}
+
+public sealed class QueryBenchSystem : EntitySystem
+{
+ public override void Initialize()
+ {
+ base.Initialize();
+ SubscribeLocalEvent(OnEvent);
+ }
+
+ private void OnEvent(EntityUid uid, ClothingComponent component, ref QueryBenchEvent args)
+ {
+ args.HashCode = HashCode.Combine(args.HashCode, component.GetHashCode());
+ }
+}
diff --git a/Content.Benchmarks/EntityManagerGetAllComponents.cs b/Content.Benchmarks/EntityManagerGetAllComponents.cs
index 0b9683a4abb..8e02b8d71de 100644
--- a/Content.Benchmarks/EntityManagerGetAllComponents.cs
+++ b/Content.Benchmarks/EntityManagerGetAllComponents.cs
@@ -47,6 +47,7 @@ public void Setup()
var componentFactory = new Mock();
componentFactory.Setup(p => p.GetComponent()).Returns(new DummyComponent());
+ componentFactory.Setup(m => m.GetIndex(typeof(DummyComponent))).Returns(CompIdx.Index());
componentFactory.Setup(p => p.GetRegistration(It.IsAny())).Returns(dummyReg);
componentFactory.Setup(p => p.GetAllRegistrations()).Returns(new[] { dummyReg });
componentFactory.Setup(p => p.GetAllRefTypes()).Returns(new[] { CompIdx.Index() });
diff --git a/Content.Benchmarks/EntityQueryBenchmark.cs b/Content.Benchmarks/EntityQueryBenchmark.cs
deleted file mode 100644
index cef6a5e35c5..00000000000
--- a/Content.Benchmarks/EntityQueryBenchmark.cs
+++ /dev/null
@@ -1,137 +0,0 @@
-#nullable enable
-using System;
-using System.Threading.Tasks;
-using BenchmarkDotNet.Attributes;
-using Content.IntegrationTests;
-using Content.IntegrationTests.Pair;
-using Content.Shared.Clothing.Components;
-using Content.Shared.Item;
-using Robust.Server.GameObjects;
-using Robust.Shared;
-using Robust.Shared.Analyzers;
-using Robust.Shared.GameObjects;
-using Robust.Shared.Map;
-using Robust.Shared.Random;
-
-namespace Content.Benchmarks;
-
-[Virtual]
-public class EntityQueryBenchmark
-{
- public const string Map = "Maps/atlas.yml";
-
- private TestPair _pair = default!;
- private IEntityManager _entMan = default!;
- private MapId _mapId = new MapId(10);
- private EntityQuery _clothingQuery;
-
- [GlobalSetup]
- public void Setup()
- {
- ProgramShared.PathOffset = "../../../../";
- PoolManager.Startup(null);
-
- _pair = PoolManager.GetServerClient().GetAwaiter().GetResult();
- _entMan = _pair.Server.ResolveDependency();
-
- _pair.Server.ResolveDependency().SetSeed(42);
- _pair.Server.WaitPost(() =>
- {
- var success = _entMan.System().TryLoad(_mapId, Map, out _);
- if (!success)
- throw new Exception("Map load failed");
- _pair.Server.MapMan.DoMapInitialize(_mapId);
- }).GetAwaiter().GetResult();
-
- _clothingQuery = _entMan.GetEntityQuery();
-
- // Apparently ~40% of entities are items, and 1 in 6 of those are clothing.
- /*
- var entCount = _entMan.EntityCount;
- var itemCount = _entMan.Count();
- var clothingCount = _entMan.Count();
- var itemRatio = (float) itemCount / entCount;
- var clothingRatio = (float) clothingCount / entCount;
- Console.WriteLine($"Entities: {entCount}. Items: {itemRatio:P2}. Clothing: {clothingRatio:P2}.");
- */
- }
-
- [GlobalCleanup]
- public async Task Cleanup()
- {
- await _pair.DisposeAsync();
- PoolManager.Shutdown();
- }
-
- [Benchmark]
- public int HasComponent()
- {
- var hashCode = 0;
- var enumerator = _entMan.AllEntityQueryEnumerator();
- while (enumerator.MoveNext(out var uid, out var _))
- {
- if (_entMan.HasComponent(uid))
- hashCode = HashCode.Combine(hashCode, uid.Id);
- }
-
- return hashCode;
- }
-
- [Benchmark]
- public int HasComponentQuery()
- {
- var hashCode = 0;
- var enumerator = _entMan.AllEntityQueryEnumerator();
- while (enumerator.MoveNext(out var uid, out var _))
- {
- if (_clothingQuery.HasComponent(uid))
- hashCode = HashCode.Combine(hashCode, uid.Id);
- }
-
- return hashCode;
- }
-
- [Benchmark]
- public int TryGetComponent()
- {
- var hashCode = 0;
- var enumerator = _entMan.AllEntityQueryEnumerator();
- while (enumerator.MoveNext(out var uid, out var _))
- {
- if (_entMan.TryGetComponent(uid, out ClothingComponent? clothing))
- hashCode = HashCode.Combine(hashCode, clothing.GetHashCode());
- }
-
- return hashCode;
- }
-
- [Benchmark]
- public int TryGetComponentQuery()
- {
- var hashCode = 0;
- var enumerator = _entMan.AllEntityQueryEnumerator();
- while (enumerator.MoveNext(out var uid, out var _))
- {
- if (_clothingQuery.TryGetComponent(uid, out var clothing))
- hashCode = HashCode.Combine(hashCode, clothing.GetHashCode());
- }
-
- return hashCode;
- }
-
- ///
- /// Enumerate all entities with both an item and clothing component.
- ///
- [Benchmark]
- public int Enumerator()
- {
- var hashCode = 0;
- var enumerator = _entMan.AllEntityQueryEnumerator();
- while (enumerator.MoveNext(out var _, out var clothing))
- {
- hashCode = HashCode.Combine(hashCode, clothing.GetHashCode());
- }
-
- return hashCode;
- }
-}
diff --git a/Content.Benchmarks/MapLoadBenchmark.cs b/Content.Benchmarks/MapLoadBenchmark.cs
index 261e164f175..a3319e3067f 100644
--- a/Content.Benchmarks/MapLoadBenchmark.cs
+++ b/Content.Benchmarks/MapLoadBenchmark.cs
@@ -26,7 +26,7 @@ public class MapLoadBenchmark
public void Setup()
{
ProgramShared.PathOffset = "../../../../";
- PoolManager.Startup(null);
+ PoolManager.Startup();
_pair = PoolManager.GetServerClient().GetAwaiter().GetResult();
var server = _pair.Server;
diff --git a/Content.Benchmarks/PvsBenchmark.cs b/Content.Benchmarks/PvsBenchmark.cs
index c7f22bdb0cd..fa7f9d45422 100644
--- a/Content.Benchmarks/PvsBenchmark.cs
+++ b/Content.Benchmarks/PvsBenchmark.cs
@@ -1,19 +1,17 @@
#nullable enable
using System;
-using System.Collections.Generic;
using System.Linq;
+using System.Threading.Tasks;
using BenchmarkDotNet.Attributes;
using Content.IntegrationTests;
using Content.IntegrationTests.Pair;
+using Content.Server.Mind;
using Content.Server.Warps;
using Robust.Server.GameObjects;
using Robust.Shared;
using Robust.Shared.Analyzers;
-using Robust.Shared.Enums;
using Robust.Shared.GameObjects;
-using Robust.Shared.GameStates;
using Robust.Shared.Map;
-using Robust.Shared.Network;
using Robust.Shared.Player;
using Robust.Shared.Random;
@@ -49,7 +47,7 @@ public void Setup()
#if !DEBUG
ProgramShared.PathOffset = "../../../../";
#endif
- PoolManager.Startup(null);
+ PoolManager.Startup();
_pair = PoolManager.GetServerClient().GetAwaiter().GetResult();
_entMan = _pair.Server.ResolveDependency();
@@ -58,15 +56,20 @@ public void Setup()
_pair.Server.CfgMan.SetCVar(CVars.NetPvsAsync, false);
_sys = _entMan.System();
+ SetupAsync().Wait();
+ }
+
+ private async Task SetupAsync()
+ {
// Spawn the map
_pair.Server.ResolveDependency().SetSeed(42);
- _pair.Server.WaitPost(() =>
+ await _pair.Server.WaitPost(() =>
{
var success = _entMan.System().TryLoad(_mapId, Map, out _);
if (!success)
throw new Exception("Map load failed");
_pair.Server.MapMan.DoMapInitialize(_mapId);
- }).Wait();
+ });
// Get list of ghost warp positions
_spawns = _entMan.AllComponentsList()
@@ -76,17 +79,19 @@ public void Setup()
Array.Resize(ref _players, PlayerCount);
- // Spawn "Players".
- _pair.Server.WaitPost(() =>
+ // Spawn "Players"
+ _players = await _pair.Server.AddDummySessions(PlayerCount);
+ await _pair.Server.WaitPost(() =>
{
+ var mind = _pair.Server.System();
for (var i = 0; i < PlayerCount; i++)
{
var pos = _spawns[i % _spawns.Length];
var uid =_entMan.SpawnEntity("MobHuman", pos);
_pair.Server.ConsoleHost.ExecuteCommand($"setoutfit {_entMan.GetNetEntity(uid)} CaptainGear");
- _players[i] = new DummySession{AttachedEntity = uid};
+ mind.ControlMob(_players[i].UserId, uid);
}
- }).Wait();
+ });
// Repeatedly move players around so that they "explore" the map and see lots of entities.
// This will populate their PVS data with out-of-view entities.
@@ -168,20 +173,4 @@ public void CycleTick()
}).Wait();
_pair.Server.PvsTick(_players);
}
-
- private sealed class DummySession : ICommonSession
- {
- public SessionStatus Status => SessionStatus.InGame;
- public EntityUid? AttachedEntity {get; set; }
- public NetUserId UserId => default;
- public string Name => string.Empty;
- public short Ping => default;
- public INetChannel Channel { get; set; } = default!;
- public LoginType AuthType => default;
- public HashSet ViewSubscriptions { get; } = new();
- public DateTime ConnectedTime { get; set; }
- public SessionState State => default!;
- public SessionData Data => default!;
- public bool ClientSide { get; set; }
- }
}
diff --git a/Content.Benchmarks/SpawnEquipDeleteBenchmark.cs b/Content.Benchmarks/SpawnEquipDeleteBenchmark.cs
index 8512107b69d..0638d945aa5 100644
--- a/Content.Benchmarks/SpawnEquipDeleteBenchmark.cs
+++ b/Content.Benchmarks/SpawnEquipDeleteBenchmark.cs
@@ -32,7 +32,7 @@ public class SpawnEquipDeleteBenchmark
public async Task SetupAsync()
{
ProgramShared.PathOffset = "../../../../";
- PoolManager.Startup(null);
+ PoolManager.Startup();
_pair = await PoolManager.GetServerClient();
var server = _pair.Server;
diff --git a/Content.Client/Access/UI/AgentIDCardBoundUserInterface.cs b/Content.Client/Access/UI/AgentIDCardBoundUserInterface.cs
index c3fac8cb92a..761f52988a9 100644
--- a/Content.Client/Access/UI/AgentIDCardBoundUserInterface.cs
+++ b/Content.Client/Access/UI/AgentIDCardBoundUserInterface.cs
@@ -1,5 +1,7 @@
using Content.Shared.Access.Systems;
+using Content.Shared.StatusIcon;
using Robust.Client.GameObjects;
+using Robust.Shared.Prototypes;
namespace Content.Client.Access.UI
{
@@ -40,7 +42,7 @@ private void OnJobChanged(string newJob)
SendMessage(new AgentIDCardJobChangedMessage(newJob));
}
- public void OnJobIconChanged(string newJobIconId)
+ public void OnJobIconChanged(ProtoId newJobIconId)
{
SendMessage(new AgentIDCardJobIconChangedMessage(newJobIconId));
}
diff --git a/Content.Client/Access/UI/AgentIDCardWindow.xaml.cs b/Content.Client/Access/UI/AgentIDCardWindow.xaml.cs
index 9a38c0c4853..6d0b2a184f4 100644
--- a/Content.Client/Access/UI/AgentIDCardWindow.xaml.cs
+++ b/Content.Client/Access/UI/AgentIDCardWindow.xaml.cs
@@ -38,7 +38,7 @@ public AgentIDCardWindow(AgentIDCardBoundUserInterface bui)
JobLineEdit.OnFocusExit += e => OnJobChanged?.Invoke(e.Text);
}
- public void SetAllowedIcons(HashSet icons, string currentJobIconId)
+ public void SetAllowedIcons(HashSet> icons, string currentJobIconId)
{
IconGrid.DisposeAllChildren();
@@ -46,10 +46,8 @@ public void SetAllowedIcons(HashSet icons, string currentJobIconId)
var i = 0;
foreach (var jobIconId in icons)
{
- if (!_prototypeManager.TryIndex(jobIconId, out var jobIcon))
- {
+ if (!_prototypeManager.TryIndex(jobIconId, out var jobIcon))
continue;
- }
String styleBase = StyleBase.ButtonOpenBoth;
var modulo = i % JobIconColumnCount;
@@ -77,7 +75,7 @@ public void SetAllowedIcons(HashSet icons, string currentJobIconId)
};
jobIconButton.AddChild(jobIconTexture);
- jobIconButton.OnPressed += _ => _bui.OnJobIconChanged(jobIcon.ID);
+ jobIconButton.OnPressed += _ => _bui.OnJobIconChanged(jobIconId);
IconGrid.AddChild(jobIconButton);
if (jobIconId.Equals(currentJobIconId))
diff --git a/Content.Client/Access/UI/IdCardConsoleBoundUserInterface.cs b/Content.Client/Access/UI/IdCardConsoleBoundUserInterface.cs
index 46b6834b56d..e635478cc70 100644
--- a/Content.Client/Access/UI/IdCardConsoleBoundUserInterface.cs
+++ b/Content.Client/Access/UI/IdCardConsoleBoundUserInterface.cs
@@ -1,7 +1,6 @@
using System.Linq;
using Content.Shared.Access;
using Content.Shared.Access.Components;
-using Content.Shared.Access;
using Content.Shared.Access.Systems;
using Content.Shared.Containers.ItemSlots;
using Content.Shared.CrewManifest;
diff --git a/Content.Client/Access/UI/IdCardConsoleWindow.xaml.cs b/Content.Client/Access/UI/IdCardConsoleWindow.xaml.cs
index b7adb7d348b..3825b06cea8 100644
--- a/Content.Client/Access/UI/IdCardConsoleWindow.xaml.cs
+++ b/Content.Client/Access/UI/IdCardConsoleWindow.xaml.cs
@@ -31,6 +31,9 @@ public sealed partial class IdCardConsoleWindow : DefaultWindow
private string? _lastJobProto;
private bool _interfaceEnabled = false;
+ // The job that will be picked if the ID doesn't have a job on the station.
+ private static ProtoId _defaultJob = "Contractor"; // Frontier: Passenger> accessLevels)
{
@@ -78,7 +81,6 @@ public IdCardConsoleWindow(IdCardConsoleBoundUserInterface owner, IPrototypeMana
}
JobPresetOptionButton.OnItemSelected += SelectJobPreset;
-
_accessButtons.Populate(accessLevels, prototypeManager);
AccessLevelControlContainer.AddChild(_accessButtons);
@@ -208,11 +210,15 @@ public void UpdateState(IdCardConsoleBoundUserInterfaceState state)
new List>());
var jobIndex = _jobPrototypeIds.IndexOf(state.TargetIdJobPrototype);
- if (jobIndex >= 0)
+ // If the job index is < 0 that means they don't have a job registered in the station records.
+ // For example, a new ID from a box would have no job index.
+ if (jobIndex < 0)
{
- JobPresetOptionButton.SelectId(jobIndex);
+ jobIndex = _jobPrototypeIds.IndexOf(_defaultJob);
}
+ JobPresetOptionButton.SelectId(jobIndex);
+
_lastFullName = state.TargetIdFullName;
_lastJobTitle = state.TargetIdJobTitle;
_lastJobProto = state.TargetIdJobPrototype;
diff --git a/Content.Client/Actions/ActionsSystem.cs b/Content.Client/Actions/ActionsSystem.cs
index 5ff003452ab..aff6c1ff7be 100644
--- a/Content.Client/Actions/ActionsSystem.cs
+++ b/Content.Client/Actions/ActionsSystem.cs
@@ -247,7 +247,10 @@ public void TriggerAction(EntityUid actionId, BaseActionComponent action)
if (action.ClientExclusive)
{
if (instantAction.Event != null)
+ {
instantAction.Event.Performer = user;
+ instantAction.Event.Action = actionId;
+ }
PerformAction(user, actions, actionId, instantAction, instantAction.Event, GameTiming.CurTime);
}
diff --git a/Content.Client/Administration/Systems/AdminFrozenSystem.cs b/Content.Client/Administration/Systems/AdminFrozenSystem.cs
new file mode 100644
index 00000000000..885585f985c
--- /dev/null
+++ b/Content.Client/Administration/Systems/AdminFrozenSystem.cs
@@ -0,0 +1,7 @@
+using Content.Shared.Administration;
+
+namespace Content.Client.Administration.Systems;
+
+public sealed class AdminFrozenSystem : SharedAdminFrozenSystem
+{
+}
diff --git a/Content.Client/Administration/UI/AdminMenuWindow.xaml b/Content.Client/Administration/UI/AdminMenuWindow.xaml
index 311d67b826c..d3d3df02d93 100644
--- a/Content.Client/Administration/UI/AdminMenuWindow.xaml
+++ b/Content.Client/Administration/UI/AdminMenuWindow.xaml
@@ -6,7 +6,8 @@
xmlns:tabs="clr-namespace:Content.Client.Administration.UI.Tabs"
xmlns:playerTab="clr-namespace:Content.Client.Administration.UI.Tabs.PlayerTab"
xmlns:objectsTab="clr-namespace:Content.Client.Administration.UI.Tabs.ObjectsTab"
- xmlns:panic="clr-namespace:Content.Client.Administration.UI.Tabs.PanicBunkerTab">
+ xmlns:panic="clr-namespace:Content.Client.Administration.UI.Tabs.PanicBunkerTab"
+ xmlns:baby="clr-namespace:Content.Client.Administration.UI.Tabs.BabyJailTab">
@@ -14,6 +15,7 @@
+
diff --git a/Content.Client/Administration/UI/AdminMenuWindow.xaml.cs b/Content.Client/Administration/UI/AdminMenuWindow.xaml.cs
index c3ea67a3edb..f3aa2572f2f 100644
--- a/Content.Client/Administration/UI/AdminMenuWindow.xaml.cs
+++ b/Content.Client/Administration/UI/AdminMenuWindow.xaml.cs
@@ -21,8 +21,12 @@ public AdminMenuWindow()
MasterTabContainer.SetTabTitle(3, Loc.GetString("admin-menu-round-tab"));
MasterTabContainer.SetTabTitle(4, Loc.GetString("admin-menu-server-tab"));
MasterTabContainer.SetTabTitle(5, Loc.GetString("admin-menu-panic-bunker-tab"));
- MasterTabContainer.SetTabTitle(6, Loc.GetString("admin-menu-players-tab"));
- MasterTabContainer.SetTabTitle(7, Loc.GetString("admin-menu-objects-tab"));
+ /*
+ * TODO: Remove baby jail code once a more mature gateway process is established. This code is only being issued as a stopgap to help with potential tiding in the immediate future.
+ */
+ MasterTabContainer.SetTabTitle(6, Loc.GetString("admin-menu-baby-jail-tab"));
+ MasterTabContainer.SetTabTitle(7, Loc.GetString("admin-menu-players-tab"));
+ MasterTabContainer.SetTabTitle(8, Loc.GetString("admin-menu-objects-tab"));
}
protected override void Dispose(bool disposing)
diff --git a/Content.Client/Administration/UI/BanPanel/BanPanel.xaml.cs b/Content.Client/Administration/UI/BanPanel/BanPanel.xaml.cs
index dc263d6055c..588d62e5603 100644
--- a/Content.Client/Administration/UI/BanPanel/BanPanel.xaml.cs
+++ b/Content.Client/Administration/UI/BanPanel/BanPanel.xaml.cs
@@ -147,7 +147,7 @@ public BanPanel()
var prototypeManager = IoCManager.Resolve();
foreach (var proto in prototypeManager.EnumeratePrototypes())
{
- CreateRoleGroup(proto.ID, proto.Roles, proto.Color);
+ CreateRoleGroup(proto.ID, proto.Roles.Select(p => p.Id), proto.Color);
}
CreateRoleGroup("Antagonist", prototypeManager.EnumeratePrototypes().Select(p => p.ID), Color.Red);
diff --git a/Content.Client/Administration/UI/Bwoink/BwoinkControl.xaml.cs b/Content.Client/Administration/UI/Bwoink/BwoinkControl.xaml.cs
index af977f763c6..ddd66623bd4 100644
--- a/Content.Client/Administration/UI/Bwoink/BwoinkControl.xaml.cs
+++ b/Content.Client/Administration/UI/Bwoink/BwoinkControl.xaml.cs
@@ -75,7 +75,7 @@ public BwoinkControl()
if (info.Antag && info.ActiveThisRound)
sb.Append(new Rune(0x1F5E1)); // 🗡
- if (info.OverallPlaytime <= TimeSpan.FromSeconds(_cfg.GetCVar(CCVars.NewPlayerThreshold)))
+ if (info.OverallPlaytime <= TimeSpan.FromMinutes(_cfg.GetCVar(CCVars.NewPlayerThreshold)))
sb.Append(new Rune(0x23F2)); // ⏲
sb.AppendFormat("\"{0}\"", text);
@@ -226,7 +226,7 @@ private string FormatTabTitle(ItemList.Item li, PlayerInfo? pl = default)
if (pl.Antag)
sb.Append(new Rune(0x1F5E1)); // 🗡
- if (pl.OverallPlaytime <= TimeSpan.FromSeconds(_cfg.GetCVar(CCVars.NewPlayerThreshold)))
+ if (pl.OverallPlaytime <= TimeSpan.FromMinutes(_cfg.GetCVar(CCVars.NewPlayerThreshold)))
sb.Append(new Rune(0x23F2)); // ⏲
sb.AppendFormat("\"{0}\"", pl.CharacterName);
@@ -243,9 +243,9 @@ private void SwitchToChannel(NetUserId? ch)
{
UpdateButtons();
+ AHelpHelper.HideAllPanels();
if (ch != null)
{
- AHelpHelper.HideAllPanels();
var panel = AHelpHelper.EnsurePanel(ch.Value);
panel.Visible = true;
}
diff --git a/Content.Client/Administration/UI/Bwoink/BwoinkWindow.xaml.cs b/Content.Client/Administration/UI/Bwoink/BwoinkWindow.xaml.cs
index f8d06f758f4..30f9d24df1d 100644
--- a/Content.Client/Administration/UI/Bwoink/BwoinkWindow.xaml.cs
+++ b/Content.Client/Administration/UI/Bwoink/BwoinkWindow.xaml.cs
@@ -16,14 +16,17 @@ public BwoinkWindow()
Bwoink.ChannelSelector.OnSelectionChanged += sel =>
{
- if (sel is not null)
+ if (sel is null)
{
- Title = $"{sel.CharacterName} / {sel.Username}";
+ Title = Loc.GetString("bwoink-title-none-selected");
+ return;
+ }
+
+ Title = $"{sel.CharacterName} / {sel.Username}";
- if (sel.OverallPlaytime != null)
- {
- Title += $" | {Loc.GetString("generic-playtime-title")}: {sel.PlaytimeString}";
- }
+ if (sel.OverallPlaytime != null)
+ {
+ Title += $" | {Loc.GetString("generic-playtime-title")}: {sel.PlaytimeString}";
}
};
diff --git a/Content.Client/Administration/UI/CustomControls/PlayerListControl.xaml.cs b/Content.Client/Administration/UI/CustomControls/PlayerListControl.xaml.cs
index dbe9bae9e6e..dffde2d2e99 100644
--- a/Content.Client/Administration/UI/CustomControls/PlayerListControl.xaml.cs
+++ b/Content.Client/Administration/UI/CustomControls/PlayerListControl.xaml.cs
@@ -20,7 +20,7 @@ public sealed partial class PlayerListControl : BoxContainer
private List _playerList = new();
private readonly List _sortedPlayerList = new();
- public event Action? OnSelectionChanged;
+ public event Action? OnSelectionChanged;
public IReadOnlyList PlayerInfo => _playerList;
public Func? OverrideText;
@@ -41,12 +41,19 @@ public PlayerListControl()
PlayerListContainer.ItemPressed += PlayerListItemPressed;
PlayerListContainer.ItemKeyBindDown += PlayerListItemKeyBindDown;
PlayerListContainer.GenerateItem += GenerateButton;
+ PlayerListContainer.NoItemSelected += PlayerListNoItemSelected;
PopulateList(_adminSystem.PlayerList);
FilterLineEdit.OnTextChanged += _ => FilterList();
_adminSystem.PlayerListChanged += PopulateList;
BackgroundPanel.PanelOverride = new StyleBoxFlat {BackgroundColor = new Color(32, 38, 32)};
}
+ private void PlayerListNoItemSelected()
+ {
+ _selectedPlayer = null;
+ OnSelectionChanged?.Invoke(null);
+ }
+
private void PlayerListItemPressed(BaseButton.ButtonEventArgs? args, ListData? data)
{
if (args == null || data is not PlayerListData {Info: var selectedPlayer})
diff --git a/Content.Client/Administration/UI/SpawnExplosion/ExplosionDebugOverlay.cs b/Content.Client/Administration/UI/SpawnExplosion/ExplosionDebugOverlay.cs
index eede3a6217f..d60094ad897 100644
--- a/Content.Client/Administration/UI/SpawnExplosion/ExplosionDebugOverlay.cs
+++ b/Content.Client/Administration/UI/SpawnExplosion/ExplosionDebugOverlay.cs
@@ -25,7 +25,7 @@ public sealed class ExplosionDebugOverlay : Overlay
public override OverlaySpace Space => OverlaySpace.WorldSpace | OverlaySpace.ScreenSpace;
- public Matrix3 SpaceMatrix;
+ public Matrix3x2 SpaceMatrix;
public MapId Map;
private readonly Font _font;
@@ -78,7 +78,8 @@ private void DrawScreen(OverlayDrawArgs args)
if (SpaceTiles == null)
return;
- gridBounds = Matrix3.Invert(SpaceMatrix).TransformBox(args.WorldBounds);
+ Matrix3x2.Invert(SpaceMatrix, out var invSpace);
+ gridBounds = invSpace.TransformBox(args.WorldBounds);
DrawText(handle, gridBounds, SpaceMatrix, SpaceTiles, SpaceTileSize);
}
@@ -86,7 +87,7 @@ private void DrawScreen(OverlayDrawArgs args)
private void DrawText(
DrawingHandleScreen handle,
Box2 gridBounds,
- Matrix3 transform,
+ Matrix3x2 transform,
Dictionary> tileSets,
ushort tileSize)
{
@@ -103,7 +104,7 @@ private void DrawText(
if (!gridBounds.Contains(centre))
continue;
- var worldCenter = transform.Transform(centre);
+ var worldCenter = Vector2.Transform(centre, transform);
var screenCenter = _eyeManager.WorldToScreen(worldCenter);
@@ -119,7 +120,7 @@ private void DrawText(
if (tileSets.TryGetValue(0, out var set))
{
var epicenter = set.First();
- var worldCenter = transform.Transform((epicenter + Vector2Helpers.Half) * tileSize);
+ var worldCenter = Vector2.Transform((epicenter + Vector2Helpers.Half) * tileSize, transform);
var screenCenter = _eyeManager.WorldToScreen(worldCenter) + new Vector2(-24, -24);
var text = $"{Intensity[0]:F2}\nΣ={TotalIntensity:F1}\nΔ={Slope:F1}";
handle.DrawString(_font, screenCenter, text);
@@ -148,11 +149,12 @@ private void DrawWorld(in OverlayDrawArgs args)
if (SpaceTiles == null)
return;
- gridBounds = Matrix3.Invert(SpaceMatrix).TransformBox(args.WorldBounds).Enlarged(2);
+ Matrix3x2.Invert(SpaceMatrix, out var invSpace);
+ gridBounds = invSpace.TransformBox(args.WorldBounds).Enlarged(2);
handle.SetTransform(SpaceMatrix);
DrawTiles(handle, gridBounds, SpaceTiles, SpaceTileSize);
- handle.SetTransform(Matrix3.Identity);
+ handle.SetTransform(Matrix3x2.Identity);
}
private void DrawTiles(
diff --git a/Content.Client/Administration/UI/SpawnExplosion/SpawnExplosionWindow.xaml.cs b/Content.Client/Administration/UI/SpawnExplosion/SpawnExplosionWindow.xaml.cs
index 5f187cad794..b0d8a946ec5 100644
--- a/Content.Client/Administration/UI/SpawnExplosion/SpawnExplosionWindow.xaml.cs
+++ b/Content.Client/Administration/UI/SpawnExplosion/SpawnExplosionWindow.xaml.cs
@@ -3,6 +3,7 @@
using JetBrains.Annotations;
using Robust.Client.AutoGenerated;
using Robust.Client.Console;
+using Robust.Client.GameObjects;
using Robust.Client.Player;
using Robust.Client.UserInterface.CustomControls;
using Robust.Client.UserInterface.XAML;
@@ -22,7 +23,7 @@ public sealed partial class SpawnExplosionWindow : DefaultWindow
[Dependency] private readonly IPlayerManager _playerManager = default!;
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private readonly IEntityManager _entMan = default!;
-
+ private readonly SharedTransformSystem _transform = default!;
private readonly SpawnExplosionEui _eui;
private List _mapData = new();
@@ -37,6 +38,7 @@ public SpawnExplosionWindow(SpawnExplosionEui eui)
{
RobustXamlLoader.Load(this);
IoCManager.InjectDependencies(this);
+ _transform = _entMan.System();
_eui = eui;
ExplosionOption.OnItemSelected += ExplosionSelected;
@@ -104,7 +106,7 @@ private void SetLocation()
_pausePreview = true;
MapOptions.Select(_mapData.IndexOf(transform.MapID));
- (MapX.Value, MapY.Value) = transform.MapPosition.Position;
+ (MapX.Value, MapY.Value) = _transform.GetMapCoordinates(_playerManager.LocalEntity!.Value, xform: transform).Position;
_pausePreview = false;
UpdatePreview();
diff --git a/Content.Client/Administration/UI/Tabs/BabyJailTab/BabyJailStatusWindow.xaml b/Content.Client/Administration/UI/Tabs/BabyJailTab/BabyJailStatusWindow.xaml
new file mode 100644
index 00000000000..b8034faf52a
--- /dev/null
+++ b/Content.Client/Administration/UI/Tabs/BabyJailTab/BabyJailStatusWindow.xaml
@@ -0,0 +1,6 @@
+
+
+
diff --git a/Content.Client/Administration/UI/Tabs/BabyJailTab/BabyJailStatusWindow.xaml.cs b/Content.Client/Administration/UI/Tabs/BabyJailTab/BabyJailStatusWindow.xaml.cs
new file mode 100644
index 00000000000..9e1d53818f2
--- /dev/null
+++ b/Content.Client/Administration/UI/Tabs/BabyJailTab/BabyJailStatusWindow.xaml.cs
@@ -0,0 +1,21 @@
+using Content.Client.Message;
+using Content.Client.UserInterface.Controls;
+using Robust.Client.AutoGenerated;
+using Robust.Client.UserInterface.CustomControls;
+using Robust.Client.UserInterface.XAML;
+
+namespace Content.Client.Administration.UI.Tabs.BabyJailTab;
+
+/*
+ * TODO: Remove me once a more mature gateway process is established. This code is only being issued as a stopgap to help with potential tiding in the immediate future.
+ */
+
+[GenerateTypedNameReferences]
+public sealed partial class BabyJailStatusWindow : FancyWindow
+{
+ public BabyJailStatusWindow()
+ {
+ RobustXamlLoader.Load(this);
+ MessageLabel.SetMarkup(Loc.GetString("admin-ui-baby-jail-is-enabled"));
+ }
+}
diff --git a/Content.Client/Administration/UI/Tabs/BabyJailTab/BabyJailTab.xaml b/Content.Client/Administration/UI/Tabs/BabyJailTab/BabyJailTab.xaml
new file mode 100644
index 00000000000..dd770c2be53
--- /dev/null
+++ b/Content.Client/Administration/UI/Tabs/BabyJailTab/BabyJailTab.xaml
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Content.Client/Administration/UI/Tabs/BabyJailTab/BabyJailTab.xaml.cs b/Content.Client/Administration/UI/Tabs/BabyJailTab/BabyJailTab.xaml.cs
new file mode 100644
index 00000000000..aa9d6ced951
--- /dev/null
+++ b/Content.Client/Administration/UI/Tabs/BabyJailTab/BabyJailTab.xaml.cs
@@ -0,0 +1,75 @@
+using Content.Shared.Administration.Events;
+using Robust.Client.AutoGenerated;
+using Robust.Client.UserInterface;
+using Robust.Client.UserInterface.XAML;
+using Robust.Shared.Console;
+
+/*
+ * TODO: Remove me once a more mature gateway process is established. This code is only being issued as a stopgap to help with potential tiding in the immediate future.
+ */
+
+namespace Content.Client.Administration.UI.Tabs.BabyJailTab;
+
+[GenerateTypedNameReferences]
+public sealed partial class BabyJailTab : Control
+{
+ [Dependency] private readonly IConsoleHost _console = default!;
+
+ private string _maxAccountAge;
+ private string _maxOverallMinutes;
+
+ public BabyJailTab()
+ {
+ RobustXamlLoader.Load(this);
+ IoCManager.InjectDependencies(this);
+
+ MaxAccountAge.OnTextEntered += args => SendMaxAccountAge(args.Text);
+ MaxAccountAge.OnFocusExit += args => SendMaxAccountAge(args.Text);
+ _maxAccountAge = MaxAccountAge.Text;
+
+ MaxOverallMinutes.OnTextEntered += args => SendMaxOverallMinutes(args.Text);
+ MaxOverallMinutes.OnFocusExit += args => SendMaxOverallMinutes(args.Text);
+ _maxOverallMinutes = MaxOverallMinutes.Text;
+ }
+
+ private void SendMaxAccountAge(string text)
+ {
+ if (string.IsNullOrWhiteSpace(text) ||
+ text == _maxAccountAge ||
+ !int.TryParse(text, out var minutes))
+ {
+ return;
+ }
+
+ _console.ExecuteCommand($"babyjail_max_account_age {minutes}");
+ }
+
+ private void SendMaxOverallMinutes(string text)
+ {
+ if (string.IsNullOrWhiteSpace(text) ||
+ text == _maxOverallMinutes ||
+ !int.TryParse(text, out var minutes))
+ {
+ return;
+ }
+
+ _console.ExecuteCommand($"babyjail_max_overall_minutes {minutes}");
+ }
+
+ public void UpdateStatus(BabyJailStatus status)
+ {
+ EnabledButton.Pressed = status.Enabled;
+ EnabledButton.Text = Loc.GetString(status.Enabled
+ ? "admin-ui-baby-jail-enabled"
+ : "admin-ui-baby-jail-disabled"
+ );
+ EnabledButton.ModulateSelfOverride = status.Enabled ? Color.Red : null;
+ ShowReasonButton.Pressed = status.ShowReason;
+
+ MaxAccountAge.Text = status.MaxAccountAgeMinutes.ToString();
+ _maxAccountAge = MaxAccountAge.Text;
+
+ MaxOverallMinutes.Text = status.MaxOverallMinutes.ToString();
+ _maxOverallMinutes = MaxOverallMinutes.Text;
+ }
+}
diff --git a/Content.Client/Administration/UI/Tabs/ObjectsTab/ObjectsTab.xaml b/Content.Client/Administration/UI/Tabs/ObjectsTab/ObjectsTab.xaml
index 0280018f14c..c8c12a16338 100644
--- a/Content.Client/Administration/UI/Tabs/ObjectsTab/ObjectsTab.xaml
+++ b/Content.Client/Administration/UI/Tabs/ObjectsTab/ObjectsTab.xaml
@@ -1,7 +1,12 @@
+ xmlns:cc="clr-namespace:Content.Client.Administration.UI.CustomControls"
+ xmlns:ot="clr-namespace:Content.Client.Administration.UI.Tabs.ObjectsTab"
+ xmlns:co="clr-namespace:Content.Client.UserInterface.Controls">
+
+
+
+
-
-
-
-
+
+
+
+
+
diff --git a/Content.Client/Administration/UI/Tabs/ObjectsTab/ObjectsTab.xaml.cs b/Content.Client/Administration/UI/Tabs/ObjectsTab/ObjectsTab.xaml.cs
index 30ec794f8ab..ecedc043076 100644
--- a/Content.Client/Administration/UI/Tabs/ObjectsTab/ObjectsTab.xaml.cs
+++ b/Content.Client/Administration/UI/Tabs/ObjectsTab/ObjectsTab.xaml.cs
@@ -1,8 +1,10 @@
using Content.Client.Salvage;
using Content.Client.Station;
+using Content.Client.UserInterface.Controls;
using Content.Server._NF.Worldgen.Components.Debris;
using Content.Shared.Shipyard.Components;
using Robust.Client.AutoGenerated;
+using Robust.Client.Graphics;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.XAML;
using Robust.Shared.Map.Components;
@@ -13,20 +15,20 @@ namespace Content.Client.Administration.UI.Tabs.ObjectsTab;
[GenerateTypedNameReferences]
public sealed partial class ObjectsTab : Control
{
- [Dependency] private readonly EntityManager _entityManager = default!;
+ [Dependency] private readonly IEntityManager _entityManager = default!;
[Dependency] private readonly IGameTiming _timing = default!;
private readonly List _objects = new();
- private List _selections = new();
+ private readonly List _selections = new();
+ private bool _ascending = false; // Set to false for descending order by default
+ private ObjectsTabHeader.Header _headerClicked = ObjectsTabHeader.Header.ObjectName;
+ private readonly Color _altColor = Color.FromHex("#292B38");
+ private readonly Color _defaultColor = Color.FromHex("#2F2F3B");
- public event Action? OnEntryKeyBindDown;
+ public event Action? OnEntryKeyBindDown;
- // Listen I could either have like 4 different event subscribers (for map / grid / station changes) and manage their lifetimes in AdminUIController
- // OR
- // I can do this.
- private TimeSpan _updateFrequency = TimeSpan.FromSeconds(2);
-
- private TimeSpan _nextUpdate = TimeSpan.FromSeconds(2);
+ private readonly TimeSpan _updateFrequency = TimeSpan.FromSeconds(2);
+ private TimeSpan _nextUpdate;
public ObjectsTab()
{
@@ -45,6 +47,30 @@ public ObjectsTab()
ObjectTypeOptions.AddItem(Enum.GetName((ObjectsTabSelection)type)!);
}
+ ListHeader.OnHeaderClicked += HeaderClicked;
+ SearchList.SearchBar = SearchLineEdit;
+ SearchList.GenerateItem += GenerateButton;
+ SearchList.DataFilterCondition += DataFilterCondition;
+
+ RefreshObjectList();
+ // Set initial selection and refresh the list to apply the initial sort order
+ var defaultSelection = ObjectsTabSelection.Grids;
+ ObjectTypeOptions.SelectId((int)defaultSelection); // Set the default selection
+ RefreshObjectList(defaultSelection); // Refresh the list with the default selection
+
+ // Initialize the next update time
+ _nextUpdate = TimeSpan.Zero;
+ }
+
+ protected override void FrameUpdate(FrameEventArgs args)
+ {
+ base.FrameUpdate(args);
+
+ if (_timing.CurTime < _nextUpdate)
+ return;
+
+ _nextUpdate = _timing.CurTime + _updateFrequency;
+
RefreshObjectList();
}
@@ -84,21 +110,22 @@ private void RefreshObjectList(ObjectsTabSelection selection)
throw new ArgumentOutOfRangeException(nameof(selection), selection, null);
}
- foreach (var control in _objects)
+ entities.Sort((a, b) =>
{
- ObjectList.RemoveChild(control);
- }
+ var valueA = GetComparableValue(a, _headerClicked);
+ var valueB = GetComparableValue(b, _headerClicked);
+ return _ascending ? Comparer