From 8066eb196be9db81a884c1d5e2f2a01ca5af94db Mon Sep 17 00:00:00 2001 From: Vera Aguilera Puerto Date: Sun, 25 Jul 2021 15:02:58 +0200 Subject: [PATCH 01/38] Remove Hotspot Start method. --- .../Atmos/EntitySystems/AtmosphereSystem.Hotspot.cs | 5 +++-- Content.Server/Atmos/Hotspot.cs | 6 ------ Content.Shared/Atmos/Atmospherics.cs | 1 + 3 files changed, 4 insertions(+), 8 deletions(-) diff --git a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Hotspot.cs b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Hotspot.cs index 1fbb4f0c7d..03052e17df 100644 --- a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Hotspot.cs +++ b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Hotspot.cs @@ -108,10 +108,11 @@ namespace Content.Server.Atmos.EntitySystems { Volume = exposedVolume * 25f, Temperature = exposedTemperature, - SkippedFirstProcess = tile.CurrentCycle > gridAtmosphere.UpdateCounter + SkippedFirstProcess = tile.CurrentCycle > gridAtmosphere.UpdateCounter, + Valid = true, + State = 1 }; - tile.Hotspot.Start(); AddActiveTile(gridAtmosphere, tile); gridAtmosphere.HotspotTiles.Add(tile); diff --git a/Content.Server/Atmos/Hotspot.cs b/Content.Server/Atmos/Hotspot.cs index 4597813c6f..36d24c03b3 100644 --- a/Content.Server/Atmos/Hotspot.cs +++ b/Content.Server/Atmos/Hotspot.cs @@ -24,11 +24,5 @@ namespace Content.Server.Atmos /// [ViewVariables] public byte State; - - public void Start() - { - Valid = true; - State = 1; - } } } diff --git a/Content.Shared/Atmos/Atmospherics.cs b/Content.Shared/Atmos/Atmospherics.cs index b2736ebf68..53d34fa40c 100644 --- a/Content.Shared/Atmos/Atmospherics.cs +++ b/Content.Shared/Atmos/Atmospherics.cs @@ -1,6 +1,7 @@ using Robust.Shared.Maths; using Robust.Shared.Serialization; using System; +// ReSharper disable InconsistentNaming namespace Content.Shared.Atmos { From 6d3863f8a0619c293587dca3b4de2b48fd9aeaa7 Mon Sep 17 00:00:00 2001 From: Vera Aguilera Puerto Date: Sun, 25 Jul 2021 15:05:05 +0200 Subject: [PATCH 02/38] Remove EntityNetworkUtils, move extension methods to AtmosDirection class. --- Content.Server/Atmos/EntityNetworkUtils.cs | 30 ---------------------- Content.Shared/Atmos/AtmosDirection.cs | 22 ++++++++++++++++ 2 files changed, 22 insertions(+), 30 deletions(-) delete mode 100644 Content.Server/Atmos/EntityNetworkUtils.cs diff --git a/Content.Server/Atmos/EntityNetworkUtils.cs b/Content.Server/Atmos/EntityNetworkUtils.cs deleted file mode 100644 index 7b1671b6e6..0000000000 --- a/Content.Server/Atmos/EntityNetworkUtils.cs +++ /dev/null @@ -1,30 +0,0 @@ -using System; -using Robust.Shared.Maths; - -namespace Content.Server.Atmos -{ - public static class EntityNetworkUtils - { - public static Vector2i CardinalToIntVec(this Direction dir) - { - switch (dir) - { - case Direction.North: - return new Vector2i(0, 1); - case Direction.East: - return new Vector2i(1, 0); - case Direction.South: - return new Vector2i(0, -1); - case Direction.West: - return new Vector2i(-1, 0); - default: - throw new ArgumentException($"Direction dir {dir} is not a cardinal direction", nameof(dir)); - } - } - - public static Vector2i Offset(this Vector2i pos, Direction dir) - { - return pos + (Vector2i) dir.CardinalToIntVec(); - } - } -} diff --git a/Content.Shared/Atmos/AtmosDirection.cs b/Content.Shared/Atmos/AtmosDirection.cs index 96023a55e8..5093b5245b 100644 --- a/Content.Shared/Atmos/AtmosDirection.cs +++ b/Content.Shared/Atmos/AtmosDirection.cs @@ -142,6 +142,28 @@ namespace Content.Shared.Atmos { return (direction & other) == other; } + + public static Vector2i CardinalToIntVec(this Direction dir) + { + switch (dir) + { + case Direction.North: + return new Vector2i(0, 1); + case Direction.East: + return new Vector2i(1, 0); + case Direction.South: + return new Vector2i(0, -1); + case Direction.West: + return new Vector2i(-1, 0); + default: + throw new ArgumentException($"Direction dir {dir} is not a cardinal direction", nameof(dir)); + } + } + + public static Vector2i Offset(this Vector2i pos, Direction dir) + { + return pos + dir.CardinalToIntVec(); + } } public sealed class AtmosDirectionFlags { } From e7eb3068a0a481fc08b697fed59607c14a5504d6 Mon Sep 17 00:00:00 2001 From: SethLafuente <84478872+SethLafuente@users.noreply.github.com> Date: Sun, 25 Jul 2021 08:30:41 -0700 Subject: [PATCH 03/38] Added Makeshift Handcuffs as a craftable item (#4294) Co-authored-by: SETh lafuente --- .../Prototypes/Entities/Objects/Misc/handcuffs.yml | 3 +++ .../Recipes/Crafting/Graphs/makeshifthandcuffs.yml | 14 ++++++++++++++ .../Recipes/Crafting/makeshifthandcuffs.yml | 11 +++++++++++ 3 files changed, 28 insertions(+) create mode 100644 Resources/Prototypes/Recipes/Crafting/Graphs/makeshifthandcuffs.yml create mode 100644 Resources/Prototypes/Recipes/Crafting/makeshifthandcuffs.yml diff --git a/Resources/Prototypes/Entities/Objects/Misc/handcuffs.yml b/Resources/Prototypes/Entities/Objects/Misc/handcuffs.yml index 675f7e2642..23229182c1 100644 --- a/Resources/Prototypes/Entities/Objects/Misc/handcuffs.yml +++ b/Resources/Prototypes/Entities/Objects/Misc/handcuffs.yml @@ -42,6 +42,9 @@ startUncuffSound: /Audio/Items/Handcuffs/rope_start.ogg endUncuffSound: /Audio/Items/Handcuffs/rope_breakout.ogg startBreakoutSound: /Audio/Items/Handcuffs/rope_takeoff.ogg + - type: Construction + graph: makeshifthandcuffs + node: cuffscable - type: Sprite sprite: Objects/Misc/cablecuffs.rsi diff --git a/Resources/Prototypes/Recipes/Crafting/Graphs/makeshifthandcuffs.yml b/Resources/Prototypes/Recipes/Crafting/Graphs/makeshifthandcuffs.yml new file mode 100644 index 0000000000..08d6d57fb9 --- /dev/null +++ b/Resources/Prototypes/Recipes/Crafting/Graphs/makeshifthandcuffs.yml @@ -0,0 +1,14 @@ +- type: constructionGraph + id: makeshifthandcuffs + start: start + graph: + - node: start + edges: + - to: cuffscable + steps: + - material: Cable + amount: 15 + doAfter: 5 + - node: cuffscable + entity: Cablecuffs + diff --git a/Resources/Prototypes/Recipes/Crafting/makeshifthandcuffs.yml b/Resources/Prototypes/Recipes/Crafting/makeshifthandcuffs.yml new file mode 100644 index 0000000000..b7b0344f11 --- /dev/null +++ b/Resources/Prototypes/Recipes/Crafting/makeshifthandcuffs.yml @@ -0,0 +1,11 @@ +- type: construction + name: makeshift handcuffs + id: makeshifthandcuffs + graph: makeshifthandcuffs + startNode: start + targetNode: cuffscable + category: Utility + description: "Homemade handcuffs crafted from spare cables." + icon: Objects/Misc/cablecuffs.rsi/cuff.png + objectType: Item + From 843f3757b03da8af03cb8604101814b32a415772 Mon Sep 17 00:00:00 2001 From: PJBot Date: Sun, 25 Jul 2021 11:31:44 -0400 Subject: [PATCH 04/38] Automatic changelog update --- Resources/Changelog/Changelog.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 95ed321f80..b7f32b7baa 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1588,3 +1588,8 @@ Entries: - {message: Items with missing inhand sprites no longer show a giant ERROR, type: Fix} id: 282 time: '2021-07-25T10:02:48.0000000+00:00' +- author: Seth + changes: + - {message: Added Makeshift Handcuffs into the construction list, type: Add} + id: 283 + time: '2021-07-25T15:30:42.0000000+00:00' From ae84ba07e6217adf31e9b8c8f6b68bdfa7ef6a7c Mon Sep 17 00:00:00 2001 From: Swept Date: Sun, 25 Jul 2021 15:40:21 +0000 Subject: [PATCH 05/38] Add botanical belt to botanist's locker --- Resources/Prototypes/Catalog/Fills/Lockers/service.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Resources/Prototypes/Catalog/Fills/Lockers/service.yml b/Resources/Prototypes/Catalog/Fills/Lockers/service.yml index b753048f50..d2e13f35e9 100644 --- a/Resources/Prototypes/Catalog/Fills/Lockers/service.yml +++ b/Resources/Prototypes/Catalog/Fills/Lockers/service.yml @@ -72,6 +72,8 @@ prob: 1 - id: ClothingOuterApronBotanist prob: 0.8 + - id: ClothingBeltPlant + prob: 1 - id: TowercapSeeds prob: 1 - id: BananaSeeds From a91f9190186c75ef01ffc57c140d98565cd38b61 Mon Sep 17 00:00:00 2001 From: mirrorcult Date: Sun, 25 Jul 2021 08:41:50 -0700 Subject: [PATCH 06/38] Remove FoodContainer, add whitelists, replace with SpawnItemsOnUse (#4358) --- Content.Client/Entry/IgnoredComponents.cs | 2 +- .../DrinkFoodContainerVisualizer.cs | 53 --------- .../Components/FoodContainerComponent.cs | 103 ------------------ .../Components/ServerStorageComponent.cs | 16 ++- .../Components/SpawnItemsOnUseComponent.cs | 36 ++++++ .../Components/StorageFillComponent.cs | 50 +-------- Content.Server/Storage/EntitySpawnEntry.cs | 59 ++++++++++ .../{ => EntitySystems}/ItemCounterSystem.cs | 2 +- .../EntitySystems/SpawnItemsOnUseSystem.cs | 68 ++++++++++++ .../{ => EntitySystems}/StorageSystem.cs | 4 +- .../SharedDrinkFoodContainerComponent.cs | 28 ----- .../Objects/Consumable/Food/Baked/donut.yml | 3 - .../Objects/Consumable/Food/Baked/pizza.yml | 6 + .../Consumable/Food/Containers/box.yml | 14 ++- .../Entities/Objects/Consumable/Food/egg.yml | 8 +- .../Smokeables/Cigarettes/rolling_paper.yml | 17 ++- .../Entities/Objects/Misc/monkeycube.yml | 27 +++-- Resources/Prototypes/tags.yml | 17 ++- 18 files changed, 253 insertions(+), 260 deletions(-) delete mode 100644 Content.Client/Nutrition/Visualizers/DrinkFoodContainerVisualizer.cs delete mode 100644 Content.Server/Nutrition/Components/FoodContainerComponent.cs create mode 100644 Content.Server/Storage/Components/SpawnItemsOnUseComponent.cs create mode 100644 Content.Server/Storage/EntitySpawnEntry.cs rename Content.Server/Storage/{ => EntitySystems}/ItemCounterSystem.cs (96%) create mode 100644 Content.Server/Storage/EntitySystems/SpawnItemsOnUseSystem.cs rename Content.Server/Storage/{ => EntitySystems}/StorageSystem.cs (98%) delete mode 100644 Content.Shared/Nutrition/Components/SharedDrinkFoodContainerComponent.cs diff --git a/Content.Client/Entry/IgnoredComponents.cs b/Content.Client/Entry/IgnoredComponents.cs index c8c591b40c..805c620ea0 100644 --- a/Content.Client/Entry/IgnoredComponents.cs +++ b/Content.Client/Entry/IgnoredComponents.cs @@ -57,7 +57,6 @@ namespace Content.Client.Entry "CablePlacer", "Drink", "Food", - "FoodContainer", "MagicMirror", "FloorTile", "ShuttleController", @@ -277,6 +276,7 @@ namespace Content.Client.Entry "Advertise", "PowerNetworkBattery", "BatteryCharger", + "SpawnItemsOnUse" }; } } diff --git a/Content.Client/Nutrition/Visualizers/DrinkFoodContainerVisualizer.cs b/Content.Client/Nutrition/Visualizers/DrinkFoodContainerVisualizer.cs deleted file mode 100644 index 5117ebe5e2..0000000000 --- a/Content.Client/Nutrition/Visualizers/DrinkFoodContainerVisualizer.cs +++ /dev/null @@ -1,53 +0,0 @@ -using System; -using Content.Shared.Nutrition.Components; -using Content.Shared.Rounding; -using JetBrains.Annotations; -using Robust.Client.GameObjects; -using Robust.Shared.Serialization.Manager.Attributes; - -namespace Content.Client.Nutrition.Visualizers -{ - [UsedImplicitly] - public sealed class FoodContainerVisualizer : AppearanceVisualizer - { - [DataField("base_state", required: true)] - private string? _baseState; - - [DataField("steps", required: true)] - private int _steps; - - [DataField("mode")] - private FoodContainerVisualMode _mode = FoodContainerVisualMode.Rounded; - - public override void OnChangeData(AppearanceComponent component) - { - var sprite = component.Owner.GetComponent(); - - if (!component.TryGetData(FoodContainerVisuals.Current, out var current)) - { - return; - } - - if (!component.TryGetData(FoodContainerVisuals.Capacity, out var capacity)) - { - return; - } - - int step; - - switch (_mode) - { - case FoodContainerVisualMode.Discrete: - step = Math.Min(_steps - 1, current); - break; - case FoodContainerVisualMode.Rounded: - step = ContentHelpers.RoundToLevels(current, capacity, _steps); - break; - default: - throw new NullReferenceException(); - } - - sprite.LayerSetState(0, $"{_baseState}-{step}"); - } - } -} diff --git a/Content.Server/Nutrition/Components/FoodContainerComponent.cs b/Content.Server/Nutrition/Components/FoodContainerComponent.cs deleted file mode 100644 index 3854928bca..0000000000 --- a/Content.Server/Nutrition/Components/FoodContainerComponent.cs +++ /dev/null @@ -1,103 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using Content.Server.Hands.Components; -using Content.Server.Items; -using Content.Shared.Interaction; -using Content.Shared.Nutrition.Components; -using Robust.Server.GameObjects; -using Robust.Shared.GameObjects; -using Robust.Shared.IoC; -using Robust.Shared.Random; -using Robust.Shared.Serialization.Manager.Attributes; -using Robust.Shared.Utility; -using Robust.Shared.ViewVariables; - -namespace Content.Server.Nutrition.Components -{ - /// - /// This container acts as a master object for things like Pizza, which holds slices. - /// - /// TODO: Perhaps implement putting food back (pizza boxes) but that really isn't mandatory. - /// This doesn't even need to have an actual Container for right now. - [RegisterComponent] - public sealed class FoodContainer : SharedFoodContainerComponent, IUse - { - [Dependency] private readonly IRobustRandom _random = default!; - public override string Name => "FoodContainer"; - - private AppearanceComponent? _appearance; - [DataField("prototypes")] - private Dictionary? _prototypes = default; - [DataField("capacity")] - private uint _capacity = 5; - - public int Capacity => (int)_capacity; - [ViewVariables] - public int Count => _count; - - private int _count = 0; - - protected override void Initialize() - { - base.Initialize(); - Owner.TryGetComponent(out _appearance); - _count = Capacity; - UpdateAppearance(); - - } - - bool IUse.UseEntity(UseEntityEventArgs eventArgs) - { - if (!eventArgs.User.TryGetComponent(out HandsComponent? handsComponent)) - { - return false; - } - - var itemToSpawn = Owner.EntityManager.SpawnEntity(GetRandomPrototype(), Owner.Transform.Coordinates); - handsComponent.PutInHandOrDrop(itemToSpawn.GetComponent()); - _count--; - if (_count < 1) - { - Owner.Delete(); - return false; - } - - return true; - } - - private string? GetRandomPrototype() - { - var defaultProto = _prototypes?.Keys.FirstOrDefault(); - - if (defaultProto == null) - { - return null; - } - - DebugTools.AssertNotNull(_prototypes); - - if (_prototypes!.Count == 1) - { - return defaultProto; - } - - var probResult = _random.Next(0, 100); - var total = 0; - foreach (var item in _prototypes) - { - total += item.Value; - if (probResult < total) - { - return item.Key; - } - } - - return defaultProto; - } - - private void UpdateAppearance() - { - _appearance?.SetData(FoodContainerVisuals.Current, Count); - } - } -} diff --git a/Content.Server/Storage/Components/ServerStorageComponent.cs b/Content.Server/Storage/Components/ServerStorageComponent.cs index 34a51e5bbc..50b579437a 100644 --- a/Content.Server/Storage/Components/ServerStorageComponent.cs +++ b/Content.Server/Storage/Components/ServerStorageComponent.cs @@ -15,6 +15,7 @@ using Content.Shared.Item; using Content.Shared.Notification; using Content.Shared.Notification.Managers; using Content.Shared.Storage; +using Content.Shared.Whitelist; using Robust.Server.GameObjects; using Robust.Server.Player; using Robust.Shared.Audio; @@ -47,10 +48,16 @@ namespace Content.Server.Storage.Components [DataField("occludesLight")] private bool _occludesLight = true; + [DataField("quickInsert")] - private bool _quickInsert; //Can insert storables by "attacking" them with the storage entity + private bool _quickInsert = false; // Can insert storables by "attacking" them with the storage entity + [DataField("areaInsert")] - private bool _areaInsert; //"Attacking" with the storage entity causes it to insert all nearby storables after a delay + private bool _areaInsert = false; // "Attacking" with the storage entity causes it to insert all nearby storables after a delay + + [DataField("whitelist")] + private EntityWhitelist? _whitelist = null; + private bool _storageInitialCalculated; private int _storageUsed; [DataField("capacity")] @@ -123,6 +130,11 @@ namespace Content.Server.Storage.Components return false; } + if (_whitelist != null && !_whitelist.IsValid(entity)) + { + return false; + } + return true; } diff --git a/Content.Server/Storage/Components/SpawnItemsOnUseComponent.cs b/Content.Server/Storage/Components/SpawnItemsOnUseComponent.cs new file mode 100644 index 0000000000..0956e8a5f3 --- /dev/null +++ b/Content.Server/Storage/Components/SpawnItemsOnUseComponent.cs @@ -0,0 +1,36 @@ +using System.Collections.Generic; +using Content.Shared.Sound; +using Robust.Shared.GameObjects; +using Robust.Shared.Serialization.Manager.Attributes; + +namespace Content.Server.Storage.Components +{ + /// + /// Spawns items when used in hand. + /// + [RegisterComponent] + public class SpawnItemsOnUseComponent : Component + { + public override string Name => "SpawnItemsOnUse"; + + /// + /// The list of entities to spawn, with amounts and orGroups. + /// + /// + [DataField("items", required: true)] + public List Items = new List(); + + /// + /// A sound to play when the items are spawned. For example, gift boxes being unwrapped. + /// + [DataField("sound")] + public SoundSpecifier? Sound = null; + + /// + /// How many uses before the item should delete itself. + /// + /// + [DataField("uses")] + public int Uses = 1; + } +} diff --git a/Content.Server/Storage/Components/StorageFillComponent.cs b/Content.Server/Storage/Components/StorageFillComponent.cs index 788a1727bb..ed56832fb8 100644 --- a/Content.Server/Storage/Components/StorageFillComponent.cs +++ b/Content.Server/Storage/Components/StorageFillComponent.cs @@ -17,9 +17,9 @@ namespace Content.Server.Storage.Components { public override string Name => "StorageFill"; - [DataField("contents")] private List _contents = new(); + [DataField("contents")] private List _contents = new(); - public IReadOnlyList Contents => _contents; + public IReadOnlyList Contents => _contents; void IMapInit.MapInit() { @@ -39,7 +39,6 @@ namespace Content.Server.Storage.Components var alreadySpawnedGroups = new List(); foreach (var storageItem in _contents) { - if (string.IsNullOrEmpty(storageItem.PrototypeId)) continue; if (!string.IsNullOrEmpty(storageItem.GroupId) && alreadySpawnedGroups.Contains(storageItem.GroupId)) continue; @@ -58,50 +57,5 @@ namespace Content.Server.Storage.Components if (!string.IsNullOrEmpty(storageItem.GroupId)) alreadySpawnedGroups.Add(storageItem.GroupId); } } - - [Serializable] - [DataDefinition] - public struct StorageFillEntry : IPopulateDefaultValues - { - [DataField("id", customTypeSerializer: typeof(PrototypeIdSerializer))] - public string? PrototypeId; - - [DataField("prob")] public float SpawnProbability; - - /// - /// The probability that an item will spawn. Takes decimal form so 0.05 is 5%, 0.50 is 50% etc. - /// - [DataField("orGroup")] public string GroupId; - - /// - /// orGroup signifies to pick between entities designated with an ID. - /// - /// - /// To define an orGroup in a StorageFill component you - /// need to add it to the entities you want to choose between and - /// add a prob field. In this example there is a 50% chance the storage - /// spawns with Y or Z. - /// - /// - /// - /// - type: StorageFill - /// contents: - /// - name: X - /// - name: Y - /// prob: 0.50 - /// orGroup: YOrZ - /// - name: Z - /// orGroup: YOrZ - /// - /// - /// - [DataField("amount")] public int Amount; - - public void PopulateDefaultValues() - { - Amount = 1; - SpawnProbability = 1; - } - } } } diff --git a/Content.Server/Storage/EntitySpawnEntry.cs b/Content.Server/Storage/EntitySpawnEntry.cs new file mode 100644 index 0000000000..99080980c0 --- /dev/null +++ b/Content.Server/Storage/EntitySpawnEntry.cs @@ -0,0 +1,59 @@ +using System; +using Robust.Shared.Prototypes; +using Robust.Shared.Serialization.Manager; +using Robust.Shared.Serialization.Manager.Attributes; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; + +namespace Content.Server.Storage +{ + /// + /// Dictates a list of items that can be spawned. + /// + [Serializable] + [DataDefinition] + public struct EntitySpawnEntry : IPopulateDefaultValues + { + [DataField("id", required: true, customTypeSerializer: typeof(PrototypeIdSerializer))] + public string PrototypeId; + + /// + /// The probability that an item will spawn. Takes decimal form so 0.05 is 5%, 0.50 is 50% etc. + /// + [DataField("prob")] + public float SpawnProbability; + + /// + /// orGroup signifies to pick between entities designated with an ID. + /// + /// + /// To define an orGroup in a StorageFill component you + /// need to add it to the entities you want to choose between and + /// add a prob field. In this example there is a 50% chance the storage + /// spawns with Y or Z. + /// + /// + /// + /// - type: StorageFill + /// contents: + /// - name: X + /// - name: Y + /// prob: 0.50 + /// orGroup: YOrZ + /// - name: Z + /// orGroup: YOrZ + /// + /// + /// + [DataField("orGroup")] + public string? GroupId; + + [DataField("amount")] + public int Amount; + + public void PopulateDefaultValues() + { + Amount = 1; + SpawnProbability = 1; + } + } +} diff --git a/Content.Server/Storage/ItemCounterSystem.cs b/Content.Server/Storage/EntitySystems/ItemCounterSystem.cs similarity index 96% rename from Content.Server/Storage/ItemCounterSystem.cs rename to Content.Server/Storage/EntitySystems/ItemCounterSystem.cs index 9e79ab984f..cdd53e335c 100644 --- a/Content.Server/Storage/ItemCounterSystem.cs +++ b/Content.Server/Storage/EntitySystems/ItemCounterSystem.cs @@ -5,7 +5,7 @@ using JetBrains.Annotations; using Robust.Shared.Containers; using Robust.Shared.GameObjects; -namespace Content.Server.Storage +namespace Content.Server.Storage.EntitySystems { [UsedImplicitly] public class ItemCounterSystem : SharedItemCounterSystem diff --git a/Content.Server/Storage/EntitySystems/SpawnItemsOnUseSystem.cs b/Content.Server/Storage/EntitySystems/SpawnItemsOnUseSystem.cs new file mode 100644 index 0000000000..e694aa237a --- /dev/null +++ b/Content.Server/Storage/EntitySystems/SpawnItemsOnUseSystem.cs @@ -0,0 +1,68 @@ +using System.Collections.Generic; +using Content.Server.Storage.Components; +using Content.Shared.Hands.Components; +using Content.Shared.Interaction; +using Robust.Shared.Audio; +using Robust.Shared.GameObjects; +using Robust.Shared.IoC; +using Robust.Shared.Player; +using Robust.Shared.Random; + +namespace Content.Server.Storage.EntitySystems +{ + public class SpawnItemsOnUseSystem : EntitySystem + { + [Dependency] private readonly IRobustRandom _random = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnUseInHand); + } + + private void OnUseInHand(EntityUid uid, SpawnItemsOnUseComponent component, UseInHandEvent args) + { + if (args.Handled) + return; + + var owner = EntityManager.GetEntity(uid); + var alreadySpawnedGroups = new List(); + IEntity? entityToPlaceInHands = null; + foreach (var storageItem in component.Items) + { + if (!string.IsNullOrEmpty(storageItem.GroupId) && + alreadySpawnedGroups.Contains(storageItem.GroupId)) continue; + + if (storageItem.SpawnProbability != 1f && + !_random.Prob(storageItem.SpawnProbability)) + { + continue; + } + + for (var i = 0; i < storageItem.Amount; i++) + { + entityToPlaceInHands = EntityManager.SpawnEntity(storageItem.PrototypeId, args.User.Transform.Coordinates); + } + + if (!string.IsNullOrEmpty(storageItem.GroupId)) alreadySpawnedGroups.Add(storageItem.GroupId); + } + + if (component.Sound != null) + SoundSystem.Play(Filter.Pvs(owner), component.Sound.GetSound()); + + component.Uses--; + if (component.Uses == 0) + { + args.Handled = true; + owner.Delete(); + } + + if (entityToPlaceInHands != null + && args.User.TryGetComponent(out var hands)) + { + hands.TryPutInAnyHand(entityToPlaceInHands); + } + } + } +} diff --git a/Content.Server/Storage/StorageSystem.cs b/Content.Server/Storage/EntitySystems/StorageSystem.cs similarity index 98% rename from Content.Server/Storage/StorageSystem.cs rename to Content.Server/Storage/EntitySystems/StorageSystem.cs index 73cf367254..d80a8e32a9 100644 --- a/Content.Server/Storage/StorageSystem.cs +++ b/Content.Server/Storage/EntitySystems/StorageSystem.cs @@ -6,7 +6,7 @@ using Robust.Server.Player; using Robust.Shared.Containers; using Robust.Shared.GameObjects; -namespace Content.Server.Storage +namespace Content.Server.Storage.EntitySystems { [UsedImplicitly] internal sealed class StorageSystem : EntitySystem @@ -54,7 +54,7 @@ namespace Content.Server.Storage { storageComp.HandleEntityMaybeInserted(message); } - + if (oldParentEntity.TryGetComponent(out var newStorageComp)) { newStorageComp.ContainerUpdateAppearance(message.Container); diff --git a/Content.Shared/Nutrition/Components/SharedDrinkFoodContainerComponent.cs b/Content.Shared/Nutrition/Components/SharedDrinkFoodContainerComponent.cs deleted file mode 100644 index a4fb1d0288..0000000000 --- a/Content.Shared/Nutrition/Components/SharedDrinkFoodContainerComponent.cs +++ /dev/null @@ -1,28 +0,0 @@ -using System; -using Robust.Shared.GameObjects; -using Robust.Shared.Serialization; - -namespace Content.Shared.Nutrition.Components -{ - public abstract class SharedFoodContainerComponent : Component - { - } - - [NetSerializable, Serializable] - public enum FoodContainerVisualMode - { - /// - /// Discrete: 50 eggs in a carton -> down to 25, will show 12/12 until it gets below max - /// Rounded: 50 eggs in a carton -> down to 25, will round it to 6 of 12 - /// - Discrete, - Rounded, - } - - [NetSerializable, Serializable] - public enum FoodContainerVisuals - { - Capacity, - Current, - } -} diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Food/Baked/donut.yml b/Resources/Prototypes/Entities/Objects/Consumable/Food/Baked/donut.yml index 32623c81ea..25b22164db 100644 --- a/Resources/Prototypes/Entities/Objects/Consumable/Food/Baked/donut.yml +++ b/Resources/Prototypes/Entities/Objects/Consumable/Food/Baked/donut.yml @@ -1,8 +1,5 @@ # Base -- type: Tag - id: Donut - - type: entity parent: BaseItem id: FoodDonutBase diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Food/Baked/pizza.yml b/Resources/Prototypes/Entities/Objects/Consumable/Food/Baked/pizza.yml index 87bfb0cd8c..c5d94a8ded 100644 --- a/Resources/Prototypes/Entities/Objects/Consumable/Food/Baked/pizza.yml +++ b/Resources/Prototypes/Entities/Objects/Consumable/Food/Baked/pizza.yml @@ -21,6 +21,9 @@ count: 8 - type: Item size: 8 + - type: Tag + tags: + - Pizza - type: entity parent: FoodPizzaBase @@ -37,6 +40,9 @@ Quantity: 5 - type: Item size: 1 + - type: Tag + tags: + - Pizza # Pizza diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Food/Containers/box.yml b/Resources/Prototypes/Entities/Objects/Consumable/Food/Containers/box.yml index b3264ef81e..da91d4b718 100644 --- a/Resources/Prototypes/Entities/Objects/Consumable/Food/Containers/box.yml +++ b/Resources/Prototypes/Entities/Objects/Consumable/Food/Containers/box.yml @@ -8,7 +8,7 @@ - type: entity parent: BaseItem id: FoodBoxDonut - name: donutbox + name: donut box description: Mmm, Donuts. components: - type: Sprite @@ -17,6 +17,9 @@ state: box - type: Storage capacity: 6 + whitelist: + tags: + - Donut - type: Item sprite: Objects/Consumable/Food/Baked/donut.rsi size: 6 @@ -48,7 +51,7 @@ - type: entity parent: BaseItem id: FoodContainerEgg - name: eggbox + name: egg carton description: Don't drop 'em! components: - type: Sprite @@ -57,6 +60,9 @@ state: box-closed - type: Storage capacity: 12 + whitelist: + tags: + - Egg - type: Item sprite: Objects/Consumable/Food/egg.rsi size: 12 @@ -114,6 +120,7 @@ - type: entity parent: FoodContainerEgg id: EggBoxBroken + suffix: Broken components: - type: StorageFill contents: @@ -261,6 +268,9 @@ sprite: Objects/Consumable/Food/Baked/donkpocket.rsi state: box - type: Storage + whitelist: + tags: + - DonkPocket capacity: 6 - type: Item sprite: Objects/Consumable/Food/Baked/donkpocket.rsi diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Food/egg.yml b/Resources/Prototypes/Entities/Objects/Consumable/Food/egg.yml index f2896a2ba0..886827dcd8 100644 --- a/Resources/Prototypes/Entities/Objects/Consumable/Food/egg.yml +++ b/Resources/Prototypes/Entities/Objects/Consumable/Food/egg.yml @@ -1,8 +1,5 @@ # Base -- type: Tag - id: Egg - - type: entity parent: BaseItem id: FoodEggBase @@ -66,7 +63,7 @@ - type: Puddle variants: 4 state: egg - + - type: entity name: eggshells parent: BaseItem @@ -86,6 +83,9 @@ reagents: - ReagentId: Egg Quantity: 1 + - type: Tag + tags: + - Egg # Egg diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Smokeables/Cigarettes/rolling_paper.yml b/Resources/Prototypes/Entities/Objects/Consumable/Smokeables/Cigarettes/rolling_paper.yml index 9a55077392..7308ac01ce 100644 --- a/Resources/Prototypes/Entities/Objects/Consumable/Smokeables/Cigarettes/rolling_paper.yml +++ b/Resources/Prototypes/Entities/Objects/Consumable/Smokeables/Cigarettes/rolling_paper.yml @@ -4,10 +4,15 @@ id: PackPaperRolling description: "A pack of thin pieces of paper used to make fine smokeables." components: - # I know but it just works. - - type: FoodContainer - prototypes: - PaperRolling: 100 + - type: Storage + whitelist: + tags: + - RollingPaper + capacity: 16 + - type: StorageFill + contents: + - id: PaperRolling + amount: 8 - type: Sprite sprite: Objects/Consumable/Smokeables/Cigarettes/paper.rsi state: cigpapers @@ -29,6 +34,10 @@ state: cigpaper - type: Item sprite: Objects/Consumable/Smokeables/Cigarettes/paper.rsi + size: 2 + - type: Tag + tags: + - RollingPaper - type: entity id: CigaretteFilter diff --git a/Resources/Prototypes/Entities/Objects/Misc/monkeycube.yml b/Resources/Prototypes/Entities/Objects/Misc/monkeycube.yml index 396e7ae7fe..263d026607 100644 --- a/Resources/Prototypes/Entities/Objects/Misc/monkeycube.yml +++ b/Resources/Prototypes/Entities/Objects/Misc/monkeycube.yml @@ -4,9 +4,15 @@ id: MonkeyCubeBox description: Drymate brand monkey cubes. Just add water! components: - - type: FoodContainer - prototypes: - MonkeyCubeWrapper: 100 + - type: Storage + whitelist: + tags: + - MonkeyCube + capacity: 30 + - type: StorageFill + contents: + - id: MonkeyCubeWrapped + amount: 6 - type: Sprite sprite: Objects/Misc/monkeycube.rsi state: box @@ -14,13 +20,18 @@ - type: entity parent: BaseItem name: monkey cube - id: MonkeyCubeWrapper + suffix: Wrapped + id: MonkeyCubeWrapped description: Unwrap this to get a monkey cube. components: - - type: FoodContainer - capacity: 1 - prototypes: - MonkeyCube: 100 + - type: SpawnItemsOnUse + items: + - id: MonkeyCube + sound: + path: /Audio/Effects/unwrap.ogg - type: Sprite sprite: Objects/Misc/monkeycube.rsi state: wrapper + - type: Tag + tags: + - MonkeyCube diff --git a/Resources/Prototypes/tags.yml b/Resources/Prototypes/tags.yml index 07adc2a9fc..3b4028d5e7 100644 --- a/Resources/Prototypes/tags.yml +++ b/Resources/Prototypes/tags.yml @@ -58,6 +58,12 @@ - type: Tag id: DoorElectronics +- type: Tag + id: Donut + +- type: Tag + id: Egg + - type: Tag id: ExplosivePassable @@ -84,13 +90,19 @@ - type: Tag id: JawsOfLife - + +- type: Tag + id: MonkeyCube + - type: Tag id: NoSpinOnThrow - type: Tag id: Ore +- type: Tag + id: Pizza + - type: Tag id: PlantAnalyzer @@ -103,6 +115,9 @@ - type: Tag id: Powerdrill +- type: Tag + id: RollingPaper + - type: Tag id: Screwdriver From d3beadbb38cbe076cec960b024e31a500fbebcbc Mon Sep 17 00:00:00 2001 From: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com> Date: Mon, 26 Jul 2021 01:48:22 +1000 Subject: [PATCH 07/38] Grid-relative movement (#4327) * Grid-relative movement Might add a test for it, but not today as it's obvious when it's on / off. * Comment --- Content.Shared/CCVar/CCVars.cs | 6 ++++ .../Movement/SharedMoverController.cs | 35 ++++++++++++++----- 2 files changed, 32 insertions(+), 9 deletions(-) diff --git a/Content.Shared/CCVar/CCVars.cs b/Content.Shared/CCVar/CCVars.cs index 3656505a4e..966377ae77 100644 --- a/Content.Shared/CCVar/CCVars.cs +++ b/Content.Shared/CCVar/CCVars.cs @@ -175,6 +175,12 @@ namespace Content.Shared.CCVar * Physics */ + /// + /// When a mob is walking should its X / Y movement be relative to its parent (true) or the map (false). + /// + public static readonly CVarDef RelativeMovement = + CVarDef.Create("physics.relative_movement", true, CVar.ARCHIVE | CVar.REPLICATED); + public static readonly CVarDef TileFrictionModifier = CVarDef.Create("physics.tile_friction", 40.0f); diff --git a/Content.Shared/Movement/SharedMoverController.cs b/Content.Shared/Movement/SharedMoverController.cs index d48d7ff3b9..0c1bc416a9 100644 --- a/Content.Shared/Movement/SharedMoverController.cs +++ b/Content.Shared/Movement/SharedMoverController.cs @@ -1,7 +1,9 @@ using Content.Shared.ActionBlocker; +using Content.Shared.CCVar; using Content.Shared.MobState; using Content.Shared.Movement.Components; using Content.Shared.Pulling.Components; +using Robust.Shared.Configuration; using Robust.Shared.GameObjects; using Robust.Shared.IoC; using Robust.Shared.Map; @@ -9,6 +11,7 @@ using Robust.Shared.Maths; using Robust.Shared.Physics; using Robust.Shared.Physics.Broadphase; using Robust.Shared.Physics.Controllers; +using Robust.Shared.Utility; namespace Content.Shared.Movement { @@ -22,10 +25,14 @@ namespace Content.Shared.Movement private SharedBroadphaseSystem _broadPhaseSystem = default!; + private bool _relativeMovement; + public override void Initialize() { base.Initialize(); _broadPhaseSystem = EntitySystem.Get(); + var configManager = IoCManager.Resolve(); + configManager.OnValueChanged(CCVars.RelativeMovement, value => _relativeMovement = value, true); } /// @@ -39,12 +46,14 @@ namespace Content.Shared.Movement // Target velocity. var total = (walkDir * mover.CurrentWalkSpeed + sprintDir * mover.CurrentSprintSpeed); - if (total != Vector2.Zero) + var worldTotal = _relativeMovement ? new Angle(mover.Owner.Transform.Parent!.WorldRotation.Theta).RotateVec(total) : total; + + if (worldTotal != Vector2.Zero) { - mover.Owner.Transform.LocalRotation = total.GetDir().ToAngle(); + mover.Owner.Transform.WorldRotation = worldTotal.GetDir().ToAngle(); } - physicsComponent.LinearVelocity = total; + physicsComponent.LinearVelocity = worldTotal; } /// @@ -53,7 +62,8 @@ namespace Content.Shared.Movement /// /// /// - protected void HandleMobMovement(IMoverComponent mover, PhysicsComponent physicsComponent, IMobMoverComponent mobMover) + protected void HandleMobMovement(IMoverComponent mover, PhysicsComponent physicsComponent, + IMobMoverComponent mobMover) { // TODO: Look at https://gameworksdocs.nvidia.com/PhysX/4.1/documentation/physxguide/Manual/CharacterControllers.html?highlight=controller as it has some adviceo n kinematic controllersx if (!UseMobMovement(_broadPhaseSystem, physicsComponent, _mapManager)) @@ -74,30 +84,37 @@ namespace Content.Shared.Movement if (!touching) { - transform.LocalRotation = physicsComponent.LinearVelocity.GetDir().ToAngle(); + transform.WorldRotation = physicsComponent.LinearVelocity.GetDir().ToAngle(); return; } } // Regular movement. // Target velocity. + // This is relative to the map / grid we're on. var total = (walkDir * mover.CurrentWalkSpeed + sprintDir * mover.CurrentSprintSpeed); + var worldTotal = _relativeMovement ? + new Angle(transform.Parent!.WorldRotation.Theta).RotateVec(total) : + total; + + DebugTools.Assert(MathHelper.CloseTo(total.Length, worldTotal.Length)); + if (weightless) { - total *= mobMover.WeightlessStrength; + worldTotal *= mobMover.WeightlessStrength; } - if (total != Vector2.Zero) + if (worldTotal != Vector2.Zero) { // This should have its event run during island solver soooo transform.DeferUpdates = true; - transform.LocalRotation = total.GetDir().ToAngle(); + transform.WorldRotation = worldTotal.GetDir().ToAngle(); transform.DeferUpdates = false; HandleFootsteps(mover, mobMover); } - physicsComponent.LinearVelocity = total; + physicsComponent.LinearVelocity = worldTotal; } public static bool UseMobMovement(SharedBroadphaseSystem broadPhaseSystem, PhysicsComponent body, IMapManager mapManager) From e17fe6f008e381d43ff3ae4537f210047856b805 Mon Sep 17 00:00:00 2001 From: PJBot Date: Sun, 25 Jul 2021 11:49:25 -0400 Subject: [PATCH 08/38] Automatic changelog update --- Resources/Changelog/Changelog.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index b7f32b7baa..866ea757d5 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1593,3 +1593,8 @@ Entries: - {message: Added Makeshift Handcuffs into the construction list, type: Add} id: 283 time: '2021-07-25T15:30:42.0000000+00:00' +- author: metalgearsloth + changes: + - {message: Shuttle-relative movement for when we get shuttle rotation., type: Add} + id: 284 + time: '2021-07-25T15:48:22.0000000+00:00' From cad7a9ad5457879b3c8b376985ad24d08128a53c Mon Sep 17 00:00:00 2001 From: SethLafuente <84478872+SethLafuente@users.noreply.github.com> Date: Sun, 25 Jul 2021 22:36:27 -0700 Subject: [PATCH 09/38] Gave lab Coats Storage Room (#4370) Co-authored-by: SETh lafuente --- .../Entities/Clothing/OuterClothing/coats.yml | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/Resources/Prototypes/Entities/Clothing/OuterClothing/coats.yml b/Resources/Prototypes/Entities/Clothing/OuterClothing/coats.yml index b6654eec1b..e8662570c4 100644 --- a/Resources/Prototypes/Entities/Clothing/OuterClothing/coats.yml +++ b/Resources/Prototypes/Entities/Clothing/OuterClothing/coats.yml @@ -8,6 +8,8 @@ sprite: Clothing/OuterClothing/Coats/bomber.rsi - type: Clothing sprite: Clothing/OuterClothing/Coats/bomber.rsi + - type: Storage + capacity: 10 - type: entity parent: ClothingOuterBase @@ -19,6 +21,8 @@ sprite: Clothing/OuterClothing/Coats/detective.rsi - type: Clothing sprite: Clothing/OuterClothing/Coats/detective.rsi + - type: Storage + capacity: 10 - type: entity parent: ClothingOuterBase @@ -30,6 +34,8 @@ sprite: Clothing/OuterClothing/Coats/gentlecoat.rsi - type: Clothing sprite: Clothing/OuterClothing/Coats/gentlecoat.rsi + - type: Storage + capacity: 10 - type: entity parent: ClothingOuterBase @@ -41,6 +47,8 @@ sprite: Clothing/OuterClothing/Coats/hos_trenchcoat.rsi - type: Clothing sprite: Clothing/OuterClothing/Coats/hos_trenchcoat.rsi + - type: Storage + capacity: 10 - type: entity parent: ClothingOuterBase @@ -52,6 +60,8 @@ sprite: Clothing/OuterClothing/Coats/insp_coat.rsi - type: Clothing sprite: Clothing/OuterClothing/Coats/insp_coat.rsi + - type: Storage + capacity: 10 - type: entity parent: ClothingOuterBase @@ -63,6 +73,8 @@ sprite: Clothing/OuterClothing/Coats/jensencoat.rsi - type: Clothing sprite: Clothing/OuterClothing/Coats/jensencoat.rsi + - type: Storage + capacity: 10 - type: entity parent: ClothingOuterBase @@ -74,6 +86,8 @@ sprite: Clothing/OuterClothing/Coats/labcoat.rsi - type: Clothing sprite: Clothing/OuterClothing/Coats/labcoat.rsi + - type: Storage + capacity: 10 - type: entity parent: ClothingOuterBase @@ -85,6 +99,8 @@ sprite: Clothing/OuterClothing/Coats/labcoat_chem.rsi - type: Clothing sprite: Clothing/OuterClothing/Coats/labcoat_chem.rsi + - type: Storage + capacity: 10 - type: entity parent: ClothingOuterBase @@ -96,6 +112,8 @@ sprite: Clothing/OuterClothing/Coats/labcoat_cmo.rsi - type: Clothing sprite: Clothing/OuterClothing/Coats/labcoat_cmo.rsi + - type: Storage + capacity: 10 - type: entity parent: ClothingOuterBase @@ -107,3 +125,5 @@ sprite: Clothing/OuterClothing/Coats/pirate.rsi - type: Clothing sprite: Clothing/OuterClothing/Coats/pirate.rsi + - type: Storage + capacity: 10 From 4dcc384deda7d7772692804c7970b1427fcce0e3 Mon Sep 17 00:00:00 2001 From: PJBot Date: Mon, 26 Jul 2021 01:37:30 -0400 Subject: [PATCH 10/38] Automatic changelog update --- Resources/Changelog/Changelog.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 866ea757d5..2987e1d464 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1598,3 +1598,8 @@ Entries: - {message: Shuttle-relative movement for when we get shuttle rotation., type: Add} id: 284 time: '2021-07-25T15:48:22.0000000+00:00' +- author: Seth + changes: + - {message: Added Storage Room to Coats, type: Add} + id: 285 + time: '2021-07-26T05:36:27.0000000+00:00' From 8661bdf3da6255fab45afe52a98d7fe7b837d702 Mon Sep 17 00:00:00 2001 From: ShadowCommander <10494922+ShadowCommander@users.noreply.github.com> Date: Mon, 26 Jul 2021 00:04:47 -0700 Subject: [PATCH 11/38] Fix typo in inventory component throw --- Content.Server/Inventory/Components/InventoryComponent.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Content.Server/Inventory/Components/InventoryComponent.cs b/Content.Server/Inventory/Components/InventoryComponent.cs index 6ba250d52d..8f1d0d7ad1 100644 --- a/Content.Server/Inventory/Components/InventoryComponent.cs +++ b/Content.Server/Inventory/Components/InventoryComponent.cs @@ -460,7 +460,7 @@ namespace Content.Server.Inventory.Components { if (!HasSlot(slot)) { - throw new InvalidOperationException($"Slow '{slot}' does not exist."); + throw new InvalidOperationException($"Slot '{slot}' does not exist."); } ForceUnequip(slot); From e826615f81ec514ff2232b87e121deeca7e3e630 Mon Sep 17 00:00:00 2001 From: Swept Date: Mon, 26 Jul 2021 07:10:00 +0000 Subject: [PATCH 12/38] Updates broken description in sprays.yml --- .../Prototypes/Entities/Objects/Specific/Hydroponics/sprays.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Resources/Prototypes/Entities/Objects/Specific/Hydroponics/sprays.yml b/Resources/Prototypes/Entities/Objects/Specific/Hydroponics/sprays.yml index a53113ae72..abc6ffceea 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/Hydroponics/sprays.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/Hydroponics/sprays.yml @@ -50,7 +50,7 @@ name: pest spray id: PestSpray parent: WeedSpray - description: Objects/Tools/Hydroponics/sprays.rsi + description: It's some pest eliminator spray! Do not inhale! suffix: "Filled" components: - type: Sprite From 7fa10bd17bbb9d063625eb65705fd4119c52829b Mon Sep 17 00:00:00 2001 From: Vera Aguilera Puerto Date: Mon, 26 Jul 2021 11:05:43 +0200 Subject: [PATCH 13/38] Remove atmos archiving. --- .../EntitySystems/AtmosphereSystem.Gases.cs | 25 +++++++------------ .../EntitySystems/AtmosphereSystem.LINDA.cs | 11 -------- .../AtmosphereSystem.Superconductivity.cs | 9 ++----- Content.Server/Atmos/GasMixture.cs | 21 ---------------- Content.Server/Atmos/TileAtmosphere.cs | 6 ----- 5 files changed, 11 insertions(+), 61 deletions(-) diff --git a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Gases.cs b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Gases.cs index ba11dd0740..16469a0a58 100644 --- a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Gases.cs +++ b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Gases.cs @@ -42,13 +42,6 @@ namespace Content.Server.Atmos.EntitySystems return MathF.Max(NumericsHelpers.HorizontalAdd(tmp), Atmospherics.MinimumHeatCapacity); } - public float GetHeatCapacityArchived(GasMixture mixture) - { - Span tmp = stackalloc float[mixture.Moles.Length]; - NumericsHelpers.Multiply(mixture.MolesArchived, GasSpecificHeats, tmp); - return MathF.Max(NumericsHelpers.HorizontalAdd(tmp), Atmospherics.MinimumHeatCapacity); - } - public float GetThermalEnergy(GasMixture mixture) { return mixture.Temperature * GetHeatCapacity(mixture); @@ -79,7 +72,7 @@ namespace Content.Server.Atmos.EntitySystems public float Share(GasMixture receiver, GasMixture sharer, int atmosAdjacentTurfs) { - var temperatureDelta = receiver.TemperatureArchived - sharer.TemperatureArchived; + var temperatureDelta = receiver.Temperature - sharer.Temperature; var absTemperatureDelta = Math.Abs(temperatureDelta); var oldHeatCapacity = 0f; var oldSharerHeatCapacity = 0f; @@ -130,12 +123,12 @@ namespace Content.Server.Atmos.EntitySystems // Transfer of thermal energy (via changed heat capacity) between self and sharer. if (!receiver.Immutable && newHeatCapacity > Atmospherics.MinimumHeatCapacity) { - receiver.Temperature = ((oldHeatCapacity * receiver.Temperature) - (heatCapacityToSharer * receiver.TemperatureArchived) + (heatCapacitySharerToThis * sharer.TemperatureArchived)) / newHeatCapacity; + receiver.Temperature = ((oldHeatCapacity * receiver.Temperature) - (heatCapacityToSharer * receiver.Temperature) + (heatCapacitySharerToThis * sharer.Temperature)) / newHeatCapacity; } if (!sharer.Immutable && newSharerHeatCapacity > Atmospherics.MinimumHeatCapacity) { - sharer.Temperature = ((oldSharerHeatCapacity * sharer.Temperature) - (heatCapacitySharerToThis * sharer.TemperatureArchived) + (heatCapacityToSharer*receiver.TemperatureArchived)) / newSharerHeatCapacity; + sharer.Temperature = ((oldSharerHeatCapacity * sharer.Temperature) - (heatCapacitySharerToThis * sharer.Temperature) + (heatCapacityToSharer*receiver.Temperature)) / newSharerHeatCapacity; } // Thermal energy of the system (self and sharer) is unchanged. @@ -154,17 +147,17 @@ namespace Content.Server.Atmos.EntitySystems var moles = receiver.TotalMoles; var theirMoles = sharer.TotalMoles; - return (receiver.TemperatureArchived * (moles + movedMoles)) - (sharer.TemperatureArchived * (theirMoles - movedMoles)) * Atmospherics.R / receiver.Volume; + return (receiver.Temperature * (moles + movedMoles)) - (sharer.Temperature * (theirMoles - movedMoles)) * Atmospherics.R / receiver.Volume; } public float TemperatureShare(GasMixture receiver, GasMixture sharer, float conductionCoefficient) { - var temperatureDelta = receiver.TemperatureArchived - sharer.TemperatureArchived; + var temperatureDelta = receiver.Temperature - sharer.Temperature; if (MathF.Abs(temperatureDelta) > Atmospherics.MinimumTemperatureDeltaToConsider) { - var heatCapacity = GetHeatCapacityArchived(receiver); - var sharerHeatCapacity = GetHeatCapacityArchived(sharer); + var heatCapacity = GetHeatCapacity(receiver); + var sharerHeatCapacity = GetHeatCapacity(sharer); if (sharerHeatCapacity > Atmospherics.MinimumHeatCapacity && heatCapacity > Atmospherics.MinimumHeatCapacity) { @@ -183,10 +176,10 @@ namespace Content.Server.Atmos.EntitySystems public float TemperatureShare(GasMixture receiver, float conductionCoefficient, float sharerTemperature, float sharerHeatCapacity) { - var temperatureDelta = receiver.TemperatureArchived - sharerTemperature; + var temperatureDelta = receiver.Temperature - sharerTemperature; if (MathF.Abs(temperatureDelta) > Atmospherics.MinimumTemperatureDeltaToConsider) { - var heatCapacity = GetHeatCapacityArchived(receiver); + var heatCapacity = GetHeatCapacity(receiver); if (sharerHeatCapacity > Atmospherics.MinimumHeatCapacity && heatCapacity > Atmospherics.MinimumHeatCapacity) { diff --git a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.LINDA.cs b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.LINDA.cs index 93b73458b1..12c7179a45 100644 --- a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.LINDA.cs +++ b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.LINDA.cs @@ -16,9 +16,6 @@ namespace Content.Server.Atmos.EntitySystems return; } - if (tile.ArchivedCycle < fireCount) - Archive(tile, fireCount); - tile.CurrentCycle = fireCount; var adjacentTileLength = 0; @@ -38,7 +35,6 @@ namespace Content.Server.Atmos.EntitySystems // If the tile is null or has no air, we don't do anything for it. if(enemyTile?.Air == null) continue; if (fireCount <= enemyTile.CurrentCycle) continue; - Archive(enemyTile, fireCount); var shouldShareAir = false; @@ -110,13 +106,6 @@ namespace Content.Server.Atmos.EntitySystems RemoveActiveTile(gridAtmosphere, tile); } - private void Archive(TileAtmosphere tile, int fireCount) - { - tile.Air?.Archive(); - tile.ArchivedCycle = fireCount; - tile.TemperatureArchived = tile.Temperature; - } - private void LastShareCheck(TileAtmosphere tile) { if (tile.Air == null || tile.ExcitedGroup == null) diff --git a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Superconductivity.cs b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Superconductivity.cs index 2853a6934e..fe21db69d4 100644 --- a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Superconductivity.cs +++ b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Superconductivity.cs @@ -21,9 +21,6 @@ namespace Content.Server.Atmos.EntitySystems if (adjacent == null || adjacent.ThermalConductivity == 0f) continue; - if(adjacent.ArchivedCycle < gridAtmosphere.UpdateCounter) - Archive(adjacent, gridAtmosphere.UpdateCounter); - NeighborConductWithSource(gridAtmosphere, adjacent, tile); ConsiderSuperconductivity(gridAtmosphere, adjacent); @@ -37,8 +34,6 @@ namespace Content.Server.Atmos.EntitySystems { if(tile.Air == null) { - if(tile.ArchivedCycle < gridAtmosphere.UpdateCounter) - Archive(tile, gridAtmosphere.UpdateCounter); return AtmosDirection.All; } @@ -128,7 +123,7 @@ namespace Content.Server.Atmos.EntitySystems private void TemperatureShareMutualSolid(TileAtmosphere tile, TileAtmosphere other, float conductionCoefficient) { - var deltaTemperature = (tile.TemperatureArchived - other.TemperatureArchived); + var deltaTemperature = (tile.Temperature - other.Temperature); if (MathF.Abs(deltaTemperature) > Atmospherics.MinimumTemperatureDeltaToConsider && tile.HeatCapacity != 0f && other.HeatCapacity != 0f) { @@ -146,7 +141,7 @@ namespace Content.Server.Atmos.EntitySystems if (tile.Temperature > Atmospherics.T0C) { // Hardcoded space temperature. - var deltaTemperature = (tile.TemperatureArchived - Atmospherics.TCMB); + var deltaTemperature = (tile.Temperature - Atmospherics.TCMB); if ((tile.HeatCapacity > 0) && (MathF.Abs(deltaTemperature) > Atmospherics.MinimumTemperatureDeltaToConsider)) { var heat = tile.ThermalConductivity * deltaTemperature * (tile.HeatCapacity * diff --git a/Content.Server/Atmos/GasMixture.cs b/Content.Server/Atmos/GasMixture.cs index dddad7366f..f4d013b2ab 100644 --- a/Content.Server/Atmos/GasMixture.cs +++ b/Content.Server/Atmos/GasMixture.cs @@ -26,9 +26,6 @@ namespace Content.Server.Atmos [DataField("moles")] [ViewVariables] public float[] Moles = new float[Atmospherics.AdjustedNumberOfGases]; - [DataField("molesArchived")] [ViewVariables] - public float[] MolesArchived = new float[Atmospherics.AdjustedNumberOfGases]; - [DataField("temperature")] [ViewVariables] private float _temperature = Atmospherics.TCMB; @@ -73,9 +70,6 @@ namespace Content.Server.Atmos } } - [DataField("temperatureArchived")] [ViewVariables] - public float TemperatureArchived { get; private set; } - [DataField("volume")] [ViewVariables] public float Volume { get; set; } @@ -96,13 +90,6 @@ namespace Content.Server.Atmos Immutable = true; } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Archive() - { - Moles.AsSpan().CopyTo(MolesArchived.AsSpan()); - TemperatureArchived = Temperature; - } - [MethodImpl(MethodImplOptions.AggressiveInlining)] public float GetMoles(int gasId) { @@ -253,7 +240,6 @@ namespace Content.Server.Atmos { // The arrays MUST have a specific length. Array.Resize(ref Moles, Atmospherics.AdjustedNumberOfGases); - Array.Resize(ref MolesArchived, Atmospherics.AdjustedNumberOfGases); } public override bool Equals(object? obj) @@ -268,12 +254,10 @@ namespace Content.Server.Atmos if (ReferenceEquals(null, other)) return false; if (ReferenceEquals(this, other)) return true; return Moles.SequenceEqual(other.Moles) - && MolesArchived.SequenceEqual(other.MolesArchived) && _temperature.Equals(other._temperature) && ReactionResults.SequenceEqual(other.ReactionResults) && Immutable == other.Immutable && LastShare.Equals(other.LastShare) - && TemperatureArchived.Equals(other.TemperatureArchived) && Volume.Equals(other.Volume); } @@ -284,13 +268,10 @@ namespace Content.Server.Atmos for (var i = 0; i < Atmospherics.TotalNumberOfGases; i++) { var moles = Moles[i]; - var molesArchived = MolesArchived[i]; hashCode.Add(moles); - hashCode.Add(molesArchived); } hashCode.Add(_temperature); - hashCode.Add(TemperatureArchived); hashCode.Add(Immutable); hashCode.Add(LastShare); hashCode.Add(Volume); @@ -303,11 +284,9 @@ namespace Content.Server.Atmos var newMixture = new GasMixture() { Moles = (float[])Moles.Clone(), - MolesArchived = (float[])MolesArchived.Clone(), _temperature = _temperature, Immutable = Immutable, LastShare = LastShare, - TemperatureArchived = TemperatureArchived, Volume = Volume, }; return newMixture; diff --git a/Content.Server/Atmos/TileAtmosphere.cs b/Content.Server/Atmos/TileAtmosphere.cs index 5bcfc710b4..b90ced4c02 100644 --- a/Content.Server/Atmos/TileAtmosphere.cs +++ b/Content.Server/Atmos/TileAtmosphere.cs @@ -13,18 +13,12 @@ namespace Content.Server.Atmos /// public class TileAtmosphere : IGasMixtureHolder { - [ViewVariables] - public int ArchivedCycle; - [ViewVariables] public int CurrentCycle; [ViewVariables] public float Temperature { get; set; } = Atmospherics.T20C; - [ViewVariables] - public float TemperatureArchived { get; set; } = Atmospherics.T20C; - [ViewVariables] public TileAtmosphere? PressureSpecificTarget { get; set; } From 86cecd3b5e09668da97ed5ca46a5c148ac898199 Mon Sep 17 00:00:00 2001 From: Vera Aguilera Puerto Date: Mon, 26 Jul 2021 11:06:34 +0200 Subject: [PATCH 14/38] Add CVar for disabling/enabling excited groups. --- .../EntitySystems/AtmosphereSystem.CVars.cs | 2 ++ .../EntitySystems/AtmosphereSystem.LINDA.cs | 31 ++++++++++--------- .../AtmosphereSystem.Processing.cs | 3 +- Content.Shared/CCVar/CCVars.cs | 8 ++++- 4 files changed, 28 insertions(+), 16 deletions(-) diff --git a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.CVars.cs b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.CVars.cs index 4693761b33..df9fbd7c1e 100644 --- a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.CVars.cs +++ b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.CVars.cs @@ -15,6 +15,7 @@ namespace Content.Server.Atmos.EntitySystems public bool MonstermosRipTiles { get; private set; } public bool GridImpulse { get; private set; } public bool Superconduction { get; private set; } + public bool ExcitedGroups { get; private set; } public bool ExcitedGroupsSpaceIsAllConsuming { get; private set; } public float AtmosMaxProcessTime { get; private set; } public float AtmosTickRate { get; private set; } @@ -31,6 +32,7 @@ namespace Content.Server.Atmos.EntitySystems _cfg.OnValueChanged(CCVars.Superconduction, value => Superconduction = value, true); _cfg.OnValueChanged(CCVars.AtmosMaxProcessTime, value => AtmosMaxProcessTime = value, true); _cfg.OnValueChanged(CCVars.AtmosTickRate, value => AtmosTickRate = value, true); + _cfg.OnValueChanged(CCVars.ExcitedGroups, value => ExcitedGroups = value, true); _cfg.OnValueChanged(CCVars.ExcitedGroupsSpaceIsAllConsuming, value => ExcitedGroupsSpaceIsAllConsuming = value, true); } } diff --git a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.LINDA.cs b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.LINDA.cs index 12c7179a45..2629bb4d33 100644 --- a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.LINDA.cs +++ b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.LINDA.cs @@ -38,7 +38,7 @@ namespace Content.Server.Atmos.EntitySystems var shouldShareAir = false; - if (tile.ExcitedGroup != null && enemyTile.ExcitedGroup != null) + if (ExcitedGroups && tile.ExcitedGroup != null && enemyTile.ExcitedGroup != null) { if (tile.ExcitedGroup != enemyTile.ExcitedGroup) { @@ -53,21 +53,24 @@ namespace Content.Server.Atmos.EntitySystems AddActiveTile(gridAtmosphere, enemyTile); } - var excitedGroup = tile.ExcitedGroup; - excitedGroup ??= enemyTile.ExcitedGroup; - - if (excitedGroup == null) + if (ExcitedGroups) { - excitedGroup = new ExcitedGroup(); - gridAtmosphere.ExcitedGroups.Add(excitedGroup); + var excitedGroup = tile.ExcitedGroup; + excitedGroup ??= enemyTile.ExcitedGroup; + + if (excitedGroup == null) + { + excitedGroup = new ExcitedGroup(); + gridAtmosphere.ExcitedGroups.Add(excitedGroup); + } + + if (tile.ExcitedGroup == null) + ExcitedGroupAddTile(excitedGroup, tile); + + if(enemyTile.ExcitedGroup == null) + ExcitedGroupAddTile(excitedGroup, enemyTile); } - if (tile.ExcitedGroup == null) - ExcitedGroupAddTile(excitedGroup, tile); - - if(enemyTile.ExcitedGroup == null) - ExcitedGroupAddTile(excitedGroup, enemyTile); - shouldShareAir = true; } @@ -102,7 +105,7 @@ namespace Content.Server.Atmos.EntitySystems if (ConsiderSuperconductivity(gridAtmosphere, tile, true)) remove = false; - if(tile.ExcitedGroup == null && remove) + if(ExcitedGroups && tile.ExcitedGroup == null && remove) RemoveActiveTile(gridAtmosphere, tile); } diff --git a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Processing.cs b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Processing.cs index 184e0bf9f5..db87ed7c10 100644 --- a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Processing.cs +++ b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Processing.cs @@ -281,7 +281,8 @@ namespace Content.Server.Atmos.EntitySystems } atmosphere.ProcessingPaused = false; - atmosphere.State = AtmosphereProcessingState.ExcitedGroups; + // Next state depends on whether excited groups are enabled or not. + atmosphere.State = ExcitedGroups ? AtmosphereProcessingState.ExcitedGroups : AtmosphereProcessingState.HighPressureDelta; continue; case AtmosphereProcessingState.ExcitedGroups: if (!ProcessExcitedGroups(atmosphere)) diff --git a/Content.Shared/CCVar/CCVars.cs b/Content.Shared/CCVar/CCVars.cs index 966377ae77..3b2091492c 100644 --- a/Content.Shared/CCVar/CCVars.cs +++ b/Content.Shared/CCVar/CCVars.cs @@ -291,7 +291,6 @@ namespace Content.Shared.CCVar public static readonly CVarDef AtmosGridImpulse = CVarDef.Create("atmos.grid_impulse", false, CVar.SERVERONLY); - /// /// Whether atmos superconduction is enabled. /// @@ -299,10 +298,17 @@ namespace Content.Shared.CCVar public static readonly CVarDef Superconduction = CVarDef.Create("atmos.superconduction", false, CVar.SERVERONLY); + /// + /// Whether excited groups will be processed and created. + /// + public static readonly CVarDef ExcitedGroups = + CVarDef.Create("atmos.excited_groups", true, CVar.SERVERONLY); + /// /// Whether all tiles in an excited group will clear themselves once being exposed to space. /// Similar to , without none of the tile ripping or /// things being thrown around very violently. + /// Needs to be enabled to work. /// public static readonly CVarDef ExcitedGroupsSpaceIsAllConsuming = CVarDef.Create("atmos.excited_groups_space_is_all_consuming", false, CVar.SERVERONLY); From 5d929485edfdbd26ae95bdecf0405149cc3a56c8 Mon Sep 17 00:00:00 2001 From: Vera Aguilera Puerto Date: Mon, 26 Jul 2021 11:28:43 +0200 Subject: [PATCH 15/38] Hotspot passes MapManager to GetTileRef. --- Content.Server/Atmos/EntitySystems/AtmosphereSystem.Hotspot.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Hotspot.cs b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Hotspot.cs index 03052e17df..df78bc015d 100644 --- a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Hotspot.cs +++ b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Hotspot.cs @@ -140,7 +140,7 @@ namespace Content.Server.Atmos.EntitySystems Merge(tile.Air, affected); } - var tileRef = tile.GridIndices.GetTileRef(tile.GridIndex); + var tileRef = tile.GridIndices.GetTileRef(tile.GridIndex, _mapManager); foreach (var entity in tileRef.GetEntitiesInTileFast()) { From 995f1dbf1a8bd2dbe5b8fc16263f961945154ff8 Mon Sep 17 00:00:00 2001 From: Vera Aguilera Puerto Date: Mon, 26 Jul 2021 11:32:59 +0200 Subject: [PATCH 16/38] Remove archived moles from saltern. --- Resources/Maps/saltern.yml | 9 --------- 1 file changed, 9 deletions(-) diff --git a/Resources/Maps/saltern.yml b/Resources/Maps/saltern.yml index 2c0fd2c5ac..8ca177e8e3 100644 --- a/Resources/Maps/saltern.yml +++ b/Resources/Maps/saltern.yml @@ -12318,15 +12318,6 @@ entities: uniqueMixes: - volume: 2500 temperature: 293.15 - molesArchived: - - 0 - - 0 - - 0 - - 0 - - 0 - - 0 - - 0 - - 0 moles: - 21.824879 - 82.10312 From 4e93340fb0ffa78047df1263c733b4e836147934 Mon Sep 17 00:00:00 2001 From: Vera Aguilera Puerto Date: Mon, 26 Jul 2021 12:13:16 +0200 Subject: [PATCH 17/38] Update engine submodule to v0.5.0 --- RobustToolbox | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RobustToolbox b/RobustToolbox index 3a86c827ea..8c1e075c91 160000 --- a/RobustToolbox +++ b/RobustToolbox @@ -1 +1 @@ -Subproject commit 3a86c827ea02f46b213f473f6479fbfaed35095e +Subproject commit 8c1e075c919604fe2e27cd6a2bbe22fceeb89249 From 1033d8bbe5d3bbec4b12b15b7b2063411bc03e52 Mon Sep 17 00:00:00 2001 From: Vera Aguilera Puerto Date: Mon, 26 Jul 2021 12:58:17 +0200 Subject: [PATCH 18/38] Use EntitySystem dependencies in a bunch of systems. --- .../EntitySystems/GasTileOverlaySystem.cs | 5 +---- Content.Client/Audio/BackgroundAudioSystem.cs | 7 +++--- Content.Client/DragDrop/DragDropSystem.cs | 6 ++--- .../Weapons/Melee/MeleeWeaponSystem.cs | 5 +++-- .../Weapons/Ranged/RangedWeaponSystem.cs | 13 ++--------- .../Accessible/AiReachableSystem.cs | 4 +--- .../AI/Steering/AiSteeringSystem.cs | 4 +--- .../Atmos/EntitySystems/AirtightSystem.cs | 8 +++---- .../EntitySystems/AtmosDebugOverlaySystem.cs | 4 ++-- .../EntitySystems/AtmosphereSystem.Grid.cs | 5 +---- .../Atmos/EntitySystems/GasTankSystem.cs | 7 +++--- .../EntitySystems/GasTileOverlaySystem.cs | 4 +--- .../GasDualPortVentPumpSystem.cs | 10 +++++---- .../EntitySystems/GasVolumePumpSystem.cs | 8 +++---- .../Piping/EntitySystems/AtmosDeviceSystem.cs | 5 +++-- .../AtmosUnsafeUnanchorSystem.cs | 13 ++++++----- .../Other/EntitySystems/GasMinerSystem.cs | 15 +++++++------ .../Unary/EntitySystems/GasCanisterSystem.cs | 21 +++++++++--------- .../EntitySystems/GasOutletInjectorSystem.cs | 8 ++++--- .../EntitySystems/GasPassiveVentSystem.cs | 8 ++++--- .../EntitySystems/GasThermoMachineSystem.cs | 5 ++++- .../Unary/EntitySystems/GasVentPumpSystem.cs | 8 ++++--- .../EntitySystems/GasVentScrubberSystem.cs | 12 +++++----- .../Surgery/Components/SurgeryToolSystem.cs | 5 ++++- .../Construction/ConstructionSystem.cs | 8 +++---- .../Destructible/DestructibleSystem.cs | 14 ++---------- .../EntitySystems/SpawnAfterInteractSystem.cs | 8 ++++--- Content.Server/Hands/HandsSystem.cs | 8 +++++-- .../Interaction/InteractionSystem.cs | 22 +++++++++---------- .../Pointing/EntitySystems/PointingSystem.cs | 3 ++- .../Interaction/SharedInteractionSystem.cs | 7 ++++-- 31 files changed, 130 insertions(+), 130 deletions(-) diff --git a/Content.Client/Atmos/EntitySystems/GasTileOverlaySystem.cs b/Content.Client/Atmos/EntitySystems/GasTileOverlaySystem.cs index 9beb61a3c9..ee46b25881 100644 --- a/Content.Client/Atmos/EntitySystems/GasTileOverlaySystem.cs +++ b/Content.Client/Atmos/EntitySystems/GasTileOverlaySystem.cs @@ -19,6 +19,7 @@ namespace Content.Client.Atmos.EntitySystems { [Dependency] private readonly IMapManager _mapManager = default!; [Dependency] private readonly IResourceCache _resourceCache = default!; + [Dependency] private readonly AtmosphereSystem _atmosphereSystem = default!; // Gas overlays private readonly float[] _timer = new float[Atmospherics.TotalNumberOfGases]; @@ -38,16 +39,12 @@ namespace Content.Client.Atmos.EntitySystems private readonly Dictionary> _tileData = new(); - private AtmosphereSystem _atmosphereSystem = default!; - public override void Initialize() { base.Initialize(); SubscribeNetworkEvent(HandleGasOverlayMessage); _mapManager.OnGridRemoved += OnGridRemoved; - _atmosphereSystem = Get(); - for (var i = 0; i < Atmospherics.TotalNumberOfGases; i++) { var overlay = _atmosphereSystem.GetOverlay(i); diff --git a/Content.Client/Audio/BackgroundAudioSystem.cs b/Content.Client/Audio/BackgroundAudioSystem.cs index 4d79891649..8a6f2b2607 100644 --- a/Content.Client/Audio/BackgroundAudioSystem.cs +++ b/Content.Client/Audio/BackgroundAudioSystem.cs @@ -25,6 +25,7 @@ namespace Content.Client.Audio [Dependency] private readonly IConfigurationManager _configManager = default!; [Dependency] private readonly IStateManager _stateManager = default!; [Dependency] private readonly IBaseClient _client = default!; + [Dependency] private readonly ClientGameTicker _gameTicker = default!; private SoundCollectionPrototype _ambientCollection = default!; @@ -48,7 +49,7 @@ namespace Content.Client.Audio _client.PlayerJoinedServer += OnJoin; _client.PlayerLeaveServer += OnLeave; - Get().LobbyStatusUpdated += LobbySongReceived; + _gameTicker.LobbyStatusUpdated += LobbySongReceived; } public override void Shutdown() @@ -60,7 +61,7 @@ namespace Content.Client.Audio _client.PlayerJoinedServer -= OnJoin; _client.PlayerLeaveServer -= OnLeave; - Get().LobbyStatusUpdated -= LobbySongReceived; + _gameTicker.LobbyStatusUpdated -= LobbySongReceived; EndAmbience(); EndLobbyMusic(); @@ -165,7 +166,7 @@ namespace Content.Client.Audio private void StartLobbyMusic() { EndLobbyMusic(); - var file = Get().LobbySong; + var file = _gameTicker.LobbySong; if (file == null) // We have not received the lobby song yet. { return; diff --git a/Content.Client/DragDrop/DragDropSystem.cs b/Content.Client/DragDrop/DragDropSystem.cs index 7051978def..7163623a4b 100644 --- a/Content.Client/DragDrop/DragDropSystem.cs +++ b/Content.Client/DragDrop/DragDropSystem.cs @@ -36,6 +36,8 @@ namespace Content.Client.DragDrop [Dependency] private readonly IEyeManager _eyeManager = default!; [Dependency] private readonly IPlayerManager _playerManager = default!; [Dependency] private readonly IPrototypeManager _prototypeManager = default!; + [Dependency] private readonly SharedInteractionSystem _interactionSystem = default!; + [Dependency] private readonly InputSystem _inputSystem = default!; // how often to recheck possible targets (prevents calling expensive // check logic each update) @@ -69,8 +71,6 @@ namespace Content.Client.DragDrop private ShaderInstance? _dropTargetInRangeShader; private ShaderInstance? _dropTargetOutOfRangeShader; - private SharedInteractionSystem _interactionSystem = default!; - private InputSystem _inputSystem = default!; private readonly List _highlightedSprites = new(); @@ -80,8 +80,6 @@ namespace Content.Client.DragDrop _dropTargetInRangeShader = _prototypeManager.Index(ShaderDropTargetInRange).Instance(); _dropTargetOutOfRangeShader = _prototypeManager.Index(ShaderDropTargetOutOfRange).Instance(); - _interactionSystem = Get(); - _inputSystem = Get(); // needs to fire on mouseup and mousedown so we can detect a drag / drop CommandBinds.Builder .Bind(EngineKeyFunctions.Use, new PointerInputCmdHandler(OnUse, false)) diff --git a/Content.Client/Weapons/Melee/MeleeWeaponSystem.cs b/Content.Client/Weapons/Melee/MeleeWeaponSystem.cs index d793e3c501..0253c71f76 100644 --- a/Content.Client/Weapons/Melee/MeleeWeaponSystem.cs +++ b/Content.Client/Weapons/Melee/MeleeWeaponSystem.cs @@ -18,6 +18,7 @@ namespace Content.Client.Weapons.Melee { [Dependency] private readonly IPrototypeManager _prototypeManager = default!; [Dependency] private readonly IGameTiming _gameTiming = default!; + [Dependency] private readonly EffectSystem _effectSystem = default!; public override void Initialize() { @@ -67,7 +68,6 @@ namespace Content.Client.Weapons.Melee source.TryGetComponent(out ISpriteComponent? sourceSprite) && sourceSprite.BaseRSI?.Path != null) { - var sys = Get(); var curTime = _gameTiming.CurTime; var effect = new EffectSystemMessage { @@ -81,7 +81,8 @@ namespace Content.Client.Weapons.Melee Born = curTime, DeathTime = curTime.Add(TimeSpan.FromMilliseconds(300f)), }; - sys.CreateEffect(effect); + + _effectSystem.CreateEffect(effect); } } diff --git a/Content.Client/Weapons/Ranged/RangedWeaponSystem.cs b/Content.Client/Weapons/Ranged/RangedWeaponSystem.cs index 85de5e4d55..38ffb63802 100644 --- a/Content.Client/Weapons/Ranged/RangedWeaponSystem.cs +++ b/Content.Client/Weapons/Ranged/RangedWeaponSystem.cs @@ -24,21 +24,12 @@ namespace Content.Client.Weapons.Ranged [Dependency] private readonly IMapManager _mapManager = default!; [Dependency] private readonly IInputManager _inputManager = default!; [Dependency] private readonly IGameTiming _gameTiming = default!; + [Dependency] private readonly InputSystem _inputSystem = default!; + [Dependency] private readonly CombatModeSystem _combatModeSystem = default!; - private InputSystem _inputSystem = default!; - private CombatModeSystem _combatModeSystem = default!; private bool _blocked; private int _shotCounter; - public override void Initialize() - { - base.Initialize(); - - IoCManager.InjectDependencies(this); - _inputSystem = Get(); - _combatModeSystem = Get(); - } - public override void Update(float frameTime) { base.Update(frameTime); diff --git a/Content.Server/AI/Pathfinding/Accessible/AiReachableSystem.cs b/Content.Server/AI/Pathfinding/Accessible/AiReachableSystem.cs index 5f66ec5e2e..64791ce9ff 100644 --- a/Content.Server/AI/Pathfinding/Accessible/AiReachableSystem.cs +++ b/Content.Server/AI/Pathfinding/Accessible/AiReachableSystem.cs @@ -37,8 +37,7 @@ namespace Content.Server.AI.Pathfinding.Accessible */ [Dependency] private readonly IMapManager _mapManager = default!; [Dependency] private readonly IGameTiming _gameTiming = default!; - - private PathfindingSystem _pathfindingSystem = default!; + [Dependency] private readonly PathfindingSystem _pathfindingSystem = default!; /// /// Queued region updates @@ -80,7 +79,6 @@ namespace Content.Server.AI.Pathfinding.Accessible public override void Initialize() { - _pathfindingSystem = Get(); SubscribeLocalEvent(Reset); SubscribeLocalEvent(RecalculateNodeRegions); #if DEBUG diff --git a/Content.Server/AI/Steering/AiSteeringSystem.cs b/Content.Server/AI/Steering/AiSteeringSystem.cs index 7db0a97349..b7e1e468c6 100644 --- a/Content.Server/AI/Steering/AiSteeringSystem.cs +++ b/Content.Server/AI/Steering/AiSteeringSystem.cs @@ -27,8 +27,7 @@ namespace Content.Server.AI.Steering // http://www.red3d.com/cwr/papers/1999/gdc99steer.html for a steering overview [Dependency] private readonly IMapManager _mapManager = default!; [Dependency] private readonly IPauseManager _pauseManager = default!; - - private PathfindingSystem _pathfindingSystem = default!; + [Dependency] private readonly PathfindingSystem _pathfindingSystem = default!; /// /// Whether we try to avoid non-blocking physics objects @@ -87,7 +86,6 @@ namespace Content.Server.AI.Steering public override void Initialize() { base.Initialize(); - _pathfindingSystem = Get(); for (var i = 0; i < AgentListCount; i++) { diff --git a/Content.Server/Atmos/EntitySystems/AirtightSystem.cs b/Content.Server/Atmos/EntitySystems/AirtightSystem.cs index a1fea661a1..b3b0d4dd5a 100644 --- a/Content.Server/Atmos/EntitySystems/AirtightSystem.cs +++ b/Content.Server/Atmos/EntitySystems/AirtightSystem.cs @@ -12,6 +12,7 @@ namespace Content.Server.Atmos.EntitySystems public class AirtightSystem : EntitySystem { [Dependency] private readonly IMapManager _mapManager = default!; + [Dependency] private readonly AtmosphereSystem _atmosphereSystem = default!; public override void Initialize() { @@ -42,7 +43,7 @@ namespace Content.Server.Atmos.EntitySystems if (airtight.FixVacuum) { - Get().FixVacuum(airtight.LastPosition.Item1, airtight.LastPosition.Item2); + _atmosphereSystem.FixVacuum(airtight.LastPosition.Item1, airtight.LastPosition.Item2); } } @@ -93,9 +94,8 @@ namespace Content.Server.Atmos.EntitySystems if (!gridId.IsValid()) return; - var atmosphereSystem = Get(); - atmosphereSystem.UpdateAdjacent(gridId, pos); - atmosphereSystem.InvalidateTile(gridId, pos); + _atmosphereSystem.UpdateAdjacent(gridId, pos); + _atmosphereSystem.InvalidateTile(gridId, pos); } private AtmosDirection Rotate(AtmosDirection myDirection, Angle myAngle) diff --git a/Content.Server/Atmos/EntitySystems/AtmosDebugOverlaySystem.cs b/Content.Server/Atmos/EntitySystems/AtmosDebugOverlaySystem.cs index 87a9bc0952..d28ac4324f 100644 --- a/Content.Server/Atmos/EntitySystems/AtmosDebugOverlaySystem.cs +++ b/Content.Server/Atmos/EntitySystems/AtmosDebugOverlaySystem.cs @@ -21,6 +21,7 @@ namespace Content.Server.Atmos.EntitySystems [Dependency] private readonly IPlayerManager _playerManager = default!; [Dependency] private readonly IMapManager _mapManager = default!; [Dependency] private readonly IConfigurationManager _configManager = default!; + [Dependency] private readonly AtmosphereSystem _atmosphereSystem = default!; /// /// Players allowed to see the atmos debug overlay. @@ -127,7 +128,6 @@ namespace Content.Server.Atmos.EntitySystems AccumulatedFrameTime -= _updateCooldown; var currentTick = _gameTiming.CurTick; - var atmosphereSystem = Get(); // Now we'll go through each player, then through each chunk in range of that player checking if the player is still in range // If they are, check if they need the new data to send (i.e. if there's an overlay for the gas). @@ -157,7 +157,7 @@ namespace Content.Server.Atmos.EntitySystems for (var x = 0; x < LocalViewRange; x++) { var Vector2i = new Vector2i(baseTile.X + x, baseTile.Y + y); - debugOverlayContent[index++] = ConvertTileToData(atmosphereSystem.GetTileAtmosphereOrCreateSpace(grid, gam, Vector2i)); + debugOverlayContent[index++] = ConvertTileToData(_atmosphereSystem.GetTileAtmosphereOrCreateSpace(grid, gam, Vector2i)); } } diff --git a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Grid.cs b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Grid.cs index 41424c990a..661b5b169f 100644 --- a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Grid.cs +++ b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Grid.cs @@ -23,13 +23,10 @@ namespace Content.Server.Atmos.EntitySystems public partial class AtmosphereSystem { [Dependency] private readonly ITileDefinitionManager _tileDefinitionManager = default!; - - private GasTileOverlaySystem _gasTileOverlaySystem = default!; + [Dependency] private readonly GasTileOverlaySystem _gasTileOverlaySystem = default!; private void InitializeGrid() { - _gasTileOverlaySystem = Get(); - SubscribeLocalEvent(OnGridAtmosphereInit); } diff --git a/Content.Server/Atmos/EntitySystems/GasTankSystem.cs b/Content.Server/Atmos/EntitySystems/GasTankSystem.cs index 2d3da529e9..0cebc10603 100644 --- a/Content.Server/Atmos/EntitySystems/GasTankSystem.cs +++ b/Content.Server/Atmos/EntitySystems/GasTankSystem.cs @@ -1,12 +1,15 @@ using Content.Server.Atmos.Components; using JetBrains.Annotations; using Robust.Shared.GameObjects; +using Robust.Shared.IoC; namespace Content.Server.Atmos.EntitySystems { [UsedImplicitly] public class GasTankSystem : EntitySystem { + [Dependency] private readonly AtmosphereSystem _atmosphereSystem = default!; + private const float TimerDelay = 0.5f; private float _timer = 0f; @@ -19,11 +22,9 @@ namespace Content.Server.Atmos.EntitySystems if (_timer < TimerDelay) return; _timer -= TimerDelay; - var atmosphereSystem = Get(); - foreach (var gasTank in EntityManager.ComponentManager.EntityQuery()) { - atmosphereSystem.React(gasTank.Air, gasTank); + _atmosphereSystem.React(gasTank.Air, gasTank); gasTank.CheckStatus(); gasTank.UpdateUserInterface(); } diff --git a/Content.Server/Atmos/EntitySystems/GasTileOverlaySystem.cs b/Content.Server/Atmos/EntitySystems/GasTileOverlaySystem.cs index 3a24573cc3..ee9d880ca7 100644 --- a/Content.Server/Atmos/EntitySystems/GasTileOverlaySystem.cs +++ b/Content.Server/Atmos/EntitySystems/GasTileOverlaySystem.cs @@ -29,6 +29,7 @@ namespace Content.Server.Atmos.EntitySystems [Dependency] private readonly IGameTiming _gameTiming = default!; [Dependency] private readonly IPlayerManager _playerManager = default!; [Dependency] private readonly IMapManager _mapManager = default!; + [Dependency] private readonly AtmosphereSystem _atmosphereSystem = default!; /// /// The tiles that have had their atmos data updated since last tick @@ -58,8 +59,6 @@ namespace Content.Server.Atmos.EntitySystems /// private float _updateCooldown; - private AtmosphereSystem _atmosphereSystem = default!; - private int _thresholds; public override void Initialize() @@ -68,7 +67,6 @@ namespace Content.Server.Atmos.EntitySystems SubscribeLocalEvent(Reset); - _atmosphereSystem = Get(); _playerManager.PlayerStatusChanged += OnPlayerStatusChanged; _mapManager.OnGridRemoved += OnGridRemoved; var configManager = IoCManager.Resolve(); diff --git a/Content.Server/Atmos/Piping/Binary/EntitySystems/GasDualPortVentPumpSystem.cs b/Content.Server/Atmos/Piping/Binary/EntitySystems/GasDualPortVentPumpSystem.cs index 0782523559..24c03e399e 100644 --- a/Content.Server/Atmos/Piping/Binary/EntitySystems/GasDualPortVentPumpSystem.cs +++ b/Content.Server/Atmos/Piping/Binary/EntitySystems/GasDualPortVentPumpSystem.cs @@ -10,12 +10,15 @@ using Content.Shared.Atmos.Visuals; using JetBrains.Annotations; using Robust.Server.GameObjects; using Robust.Shared.GameObjects; +using Robust.Shared.IoC; namespace Content.Server.Atmos.Piping.Binary.EntitySystems { [UsedImplicitly] public class GasDualPortVentPumpSystem : EntitySystem { + [Dependency] private readonly AtmosphereSystem _atmosphereSystem = default!; + public override void Initialize() { base.Initialize(); @@ -46,8 +49,7 @@ namespace Content.Server.Atmos.Piping.Binary.EntitySystems || !nodeContainer.TryGetNode(vent.OutletName, out PipeNode? outlet)) return; - var atmosphereSystem = Get(); - var environment = atmosphereSystem.GetTileMixture(vent.Owner.Transform.Coordinates, true); + var environment = _atmosphereSystem.GetTileMixture(vent.Owner.Transform.Coordinates, true); // We're in an air-blocked tile... Do nothing. if (environment == null) @@ -68,7 +70,7 @@ namespace Content.Server.Atmos.Piping.Binary.EntitySystems { var transferMoles = pressureDelta * environment.Volume / inlet.Air.Temperature * Atmospherics.R; var removed = inlet.Air.Remove(transferMoles); - atmosphereSystem.Merge(environment, removed); + _atmosphereSystem.Merge(environment, removed); } } else if (vent.PumpDirection == VentPumpDirection.Siphoning && environment.Pressure > 0f) @@ -89,7 +91,7 @@ namespace Content.Server.Atmos.Piping.Binary.EntitySystems { var removed = environment.Remove(molesDelta); - Get().Merge(outlet.Air, removed); + _atmosphereSystem.Merge(outlet.Air, removed); } } } diff --git a/Content.Server/Atmos/Piping/Binary/EntitySystems/GasVolumePumpSystem.cs b/Content.Server/Atmos/Piping/Binary/EntitySystems/GasVolumePumpSystem.cs index ba4fd92866..555385d401 100644 --- a/Content.Server/Atmos/Piping/Binary/EntitySystems/GasVolumePumpSystem.cs +++ b/Content.Server/Atmos/Piping/Binary/EntitySystems/GasVolumePumpSystem.cs @@ -13,7 +13,8 @@ namespace Content.Server.Atmos.Piping.Binary.EntitySystems [UsedImplicitly] public class GasVolumePumpSystem : EntitySystem { - [Dependency] private IGameTiming _gameTiming = default!; + [Dependency] private readonly IGameTiming _gameTiming = default!; + [Dependency] private readonly AtmosphereSystem _atmosphereSystem = default!; public override void Initialize() { @@ -56,13 +57,12 @@ namespace Content.Server.Atmos.Piping.Binary.EntitySystems // Some of the gas from the mixture leaks when overclocked. if (pump.Overclocked) { - var atmosphereSystem = Get(); - var tile = atmosphereSystem.GetTileMixture(pump.Owner.Transform.Coordinates, true); + var tile = _atmosphereSystem.GetTileMixture(pump.Owner.Transform.Coordinates, true); if (tile != null) { var leaked = removed.RemoveRatio(pump.LeakRatio); - atmosphereSystem.Merge(tile, leaked); + _atmosphereSystem.Merge(tile, leaked); } } diff --git a/Content.Server/Atmos/Piping/EntitySystems/AtmosDeviceSystem.cs b/Content.Server/Atmos/Piping/EntitySystems/AtmosDeviceSystem.cs index 5c0d7826c6..166a4d07b8 100644 --- a/Content.Server/Atmos/Piping/EntitySystems/AtmosDeviceSystem.cs +++ b/Content.Server/Atmos/Piping/EntitySystems/AtmosDeviceSystem.cs @@ -13,6 +13,7 @@ namespace Content.Server.Atmos.Piping.EntitySystems public class AtmosDeviceSystem : EntitySystem { [Dependency] private IGameTiming _gameTiming = default!; + [Dependency] private readonly AtmosphereSystem _atmosphereSystem = default!; public override void Initialize() { @@ -35,7 +36,7 @@ namespace Content.Server.Atmos.Piping.EntitySystems return; // We try to add the device to a valid atmosphere. - if (!Get().AddAtmosDevice(component)) + if (!_atmosphereSystem.AddAtmosDevice(component)) return; component.LastProcess = _gameTiming.CurTime; @@ -45,7 +46,7 @@ namespace Content.Server.Atmos.Piping.EntitySystems public void LeaveAtmosphere(AtmosDeviceComponent component) { - if (!Get().RemoveAtmosDevice(component)) + if (!_atmosphereSystem.RemoveAtmosDevice(component)) return; component.LastProcess = TimeSpan.Zero; diff --git a/Content.Server/Atmos/Piping/EntitySystems/AtmosUnsafeUnanchorSystem.cs b/Content.Server/Atmos/Piping/EntitySystems/AtmosUnsafeUnanchorSystem.cs index c14fc7dafa..9e8935d0d3 100644 --- a/Content.Server/Atmos/Piping/EntitySystems/AtmosUnsafeUnanchorSystem.cs +++ b/Content.Server/Atmos/Piping/EntitySystems/AtmosUnsafeUnanchorSystem.cs @@ -8,6 +8,7 @@ using Content.Shared.Atmos; using Content.Shared.Notification.Managers; using JetBrains.Annotations; using Robust.Shared.GameObjects; +using Robust.Shared.IoC; using Robust.Shared.Localization; namespace Content.Server.Atmos.Piping.EntitySystems @@ -15,6 +16,8 @@ namespace Content.Server.Atmos.Piping.EntitySystems [UsedImplicitly] public class AtmosUnsafeUnanchorSystem : EntitySystem { + [Dependency] private readonly AtmosphereSystem _atmosphereSystem = default!; + public override void Initialize() { SubscribeLocalEvent(OnBeforeUnanchored); @@ -26,7 +29,7 @@ namespace Content.Server.Atmos.Piping.EntitySystems if (!component.Enabled || !ComponentManager.TryGetComponent(uid, out NodeContainerComponent? nodes)) return; - if (Get().GetTileMixture(component.Owner.Transform.Coordinates) is not {} environment) + if (_atmosphereSystem.GetTileMixture(component.Owner.Transform.Coordinates) is not {} environment) return; foreach (var node in nodes.Nodes.Values) @@ -47,9 +50,7 @@ namespace Content.Server.Atmos.Piping.EntitySystems if (!component.Enabled || !ComponentManager.TryGetComponent(uid, out NodeContainerComponent? nodes)) return; - var atmosphereSystem = Get(); - - if (atmosphereSystem.GetTileMixture(component.Owner.Transform.Coordinates, true) is not {} environment) + if (_atmosphereSystem.GetTileMixture(component.Owner.Transform.Coordinates, true) is not {} environment) environment = GasMixture.SpaceGas; var lost = 0f; @@ -71,10 +72,10 @@ namespace Content.Server.Atmos.Piping.EntitySystems { if (node is not PipeNode pipe) continue; - atmosphereSystem.Merge(buffer, pipe.Air.Remove(sharedLoss)); + _atmosphereSystem.Merge(buffer, pipe.Air.Remove(sharedLoss)); } - atmosphereSystem.Merge(environment, buffer); + _atmosphereSystem.Merge(environment, buffer); } } } diff --git a/Content.Server/Atmos/Piping/Other/EntitySystems/GasMinerSystem.cs b/Content.Server/Atmos/Piping/Other/EntitySystems/GasMinerSystem.cs index d1e61c7b98..0a4379d7f6 100644 --- a/Content.Server/Atmos/Piping/Other/EntitySystems/GasMinerSystem.cs +++ b/Content.Server/Atmos/Piping/Other/EntitySystems/GasMinerSystem.cs @@ -6,12 +6,15 @@ using Content.Server.Atmos.Piping.Other.Components; using Content.Shared.Atmos; using JetBrains.Annotations; using Robust.Shared.GameObjects; +using Robust.Shared.IoC; namespace Content.Server.Atmos.Piping.Other.EntitySystems { [UsedImplicitly] public class GasMinerSystem : EntitySystem { + [Dependency] private readonly AtmosphereSystem _atmosphereSystem = default!; + public override void Initialize() { base.Initialize(); @@ -21,9 +24,7 @@ namespace Content.Server.Atmos.Piping.Other.EntitySystems private void OnMinerUpdated(EntityUid uid, GasMinerComponent miner, AtmosDeviceUpdateEvent args) { - var atmosphereSystem = Get(); - - if (!CheckMinerOperation(atmosphereSystem, miner, out var environment) || !miner.Enabled || !miner.SpawnGas.HasValue || miner.SpawnAmount <= 0f) + if (!CheckMinerOperation(miner, out var environment) || !miner.Enabled || !miner.SpawnGas.HasValue || miner.SpawnAmount <= 0f) return; // Time to mine some gas. @@ -31,15 +32,15 @@ namespace Content.Server.Atmos.Piping.Other.EntitySystems var merger = new GasMixture(1) { Temperature = miner.SpawnTemperature }; merger.SetMoles(miner.SpawnGas.Value, miner.SpawnAmount); - atmosphereSystem.Merge(environment, merger); + _atmosphereSystem.Merge(environment, merger); } - private bool CheckMinerOperation(AtmosphereSystem atmosphereSystem, GasMinerComponent miner, [NotNullWhen(true)] out GasMixture? environment) + private bool CheckMinerOperation(GasMinerComponent miner, [NotNullWhen(true)] out GasMixture? environment) { - environment = atmosphereSystem.GetTileMixture(miner.Owner.Transform.Coordinates, true); + environment = _atmosphereSystem.GetTileMixture(miner.Owner.Transform.Coordinates, true); // Space. - if (atmosphereSystem.IsTileSpace(miner.Owner.Transform.Coordinates)) + if (_atmosphereSystem.IsTileSpace(miner.Owner.Transform.Coordinates)) { miner.Broken = true; return false; diff --git a/Content.Server/Atmos/Piping/Unary/EntitySystems/GasCanisterSystem.cs b/Content.Server/Atmos/Piping/Unary/EntitySystems/GasCanisterSystem.cs index afc56ec96c..18b4c52433 100644 --- a/Content.Server/Atmos/Piping/Unary/EntitySystems/GasCanisterSystem.cs +++ b/Content.Server/Atmos/Piping/Unary/EntitySystems/GasCanisterSystem.cs @@ -19,6 +19,7 @@ using JetBrains.Annotations; using Robust.Server.GameObjects; using Robust.Shared.Containers; using Robust.Shared.GameObjects; +using Robust.Shared.IoC; using Robust.Shared.Maths; namespace Content.Server.Atmos.Piping.Unary.EntitySystems @@ -26,6 +27,8 @@ namespace Content.Server.Atmos.Piping.Unary.EntitySystems [UsedImplicitly] public class GasCanisterSystem : EntitySystem { + [Dependency] private readonly AtmosphereSystem _atmosphereSystem = default!; + public override void Initialize() { base.Initialize(); @@ -131,23 +134,21 @@ namespace Content.Server.Atmos.Piping.Unary.EntitySystems if (!nodeContainer.TryGetNode(canister.PortName, out PortablePipeNode? portNode)) return; - var atmosphereSystem = Get(); - - atmosphereSystem.React(canister.Air, portNode); + _atmosphereSystem.React(canister.Air, portNode); if (portNode.NodeGroup is PipeNet {NodeCount: > 1} net) { var buffer = new GasMixture(net.Air.Volume + canister.Air.Volume); - atmosphereSystem.Merge(buffer, net.Air); - atmosphereSystem.Merge(buffer, canister.Air); + _atmosphereSystem.Merge(buffer, net.Air); + _atmosphereSystem.Merge(buffer, canister.Air); net.Air.Clear(); - atmosphereSystem.Merge(net.Air, buffer); + _atmosphereSystem.Merge(net.Air, buffer); net.Air.Multiply(net.Air.Volume / buffer.Volume); canister.Air.Clear(); - atmosphereSystem.Merge(canister.Air, buffer); + _atmosphereSystem.Merge(canister.Air, buffer); canister.Air.Multiply(canister.Air.Volume / buffer.Volume); } @@ -161,12 +162,12 @@ namespace Content.Server.Atmos.Piping.Unary.EntitySystems if (container.ContainedEntities.Count > 0) { var gasTank = container.ContainedEntities[0].GetComponent(); - atmosphereSystem.ReleaseGasTo(canister.Air, gasTank.Air, canister.ReleasePressure); + _atmosphereSystem.ReleaseGasTo(canister.Air, gasTank.Air, canister.ReleasePressure); } else { - var environment = atmosphereSystem.GetTileMixture(canister.Owner.Transform.Coordinates, true); - atmosphereSystem.ReleaseGasTo(canister.Air, environment, canister.ReleasePressure); + var environment = _atmosphereSystem.GetTileMixture(canister.Owner.Transform.Coordinates, true); + _atmosphereSystem.ReleaseGasTo(canister.Air, environment, canister.ReleasePressure); } } diff --git a/Content.Server/Atmos/Piping/Unary/EntitySystems/GasOutletInjectorSystem.cs b/Content.Server/Atmos/Piping/Unary/EntitySystems/GasOutletInjectorSystem.cs index 63f9665d44..c716f72c04 100644 --- a/Content.Server/Atmos/Piping/Unary/EntitySystems/GasOutletInjectorSystem.cs +++ b/Content.Server/Atmos/Piping/Unary/EntitySystems/GasOutletInjectorSystem.cs @@ -6,12 +6,15 @@ using Content.Server.NodeContainer.Nodes; using Content.Shared.Atmos; using JetBrains.Annotations; using Robust.Shared.GameObjects; +using Robust.Shared.IoC; namespace Content.Server.Atmos.Piping.Unary.EntitySystems { [UsedImplicitly] public class GasOutletInjectorSystem : EntitySystem { + [Dependency] private readonly AtmosphereSystem _atmosphereSystem = default!; + public override void Initialize() { base.Initialize(); @@ -32,8 +35,7 @@ namespace Content.Server.Atmos.Piping.Unary.EntitySystems if (!nodeContainer.TryGetNode(injector.InletName, out PipeNode? inlet)) return; - var atmosphereSystem = Get(); - var environment = atmosphereSystem.GetTileMixture(injector.Owner.Transform.Coordinates, true); + var environment = _atmosphereSystem.GetTileMixture(injector.Owner.Transform.Coordinates, true); if (environment == null) return; @@ -44,7 +46,7 @@ namespace Content.Server.Atmos.Piping.Unary.EntitySystems var removed = inlet.Air.Remove(transferMoles); - atmosphereSystem.Merge(environment, removed); + _atmosphereSystem.Merge(environment, removed); } } } diff --git a/Content.Server/Atmos/Piping/Unary/EntitySystems/GasPassiveVentSystem.cs b/Content.Server/Atmos/Piping/Unary/EntitySystems/GasPassiveVentSystem.cs index 5a61cbc350..e484e80da0 100644 --- a/Content.Server/Atmos/Piping/Unary/EntitySystems/GasPassiveVentSystem.cs +++ b/Content.Server/Atmos/Piping/Unary/EntitySystems/GasPassiveVentSystem.cs @@ -7,12 +7,15 @@ using Content.Server.NodeContainer.Nodes; using Content.Shared.Atmos; using JetBrains.Annotations; using Robust.Shared.GameObjects; +using Robust.Shared.IoC; namespace Content.Server.Atmos.Piping.Unary.EntitySystems { [UsedImplicitly] public class GasPassiveVentSystem : EntitySystem { + [Dependency] private readonly AtmosphereSystem _atmosphereSystem = default!; + public override void Initialize() { base.Initialize(); @@ -22,8 +25,7 @@ namespace Content.Server.Atmos.Piping.Unary.EntitySystems private void OnPassiveVentUpdated(EntityUid uid, GasPassiveVentComponent vent, AtmosDeviceUpdateEvent args) { - var atmosphereSystem = Get(); - var environment = atmosphereSystem.GetTileMixture(vent.Owner.Transform.Coordinates, true); + var environment = _atmosphereSystem.GetTileMixture(vent.Owner.Transform.Coordinates, true); if (environment == null) return; @@ -44,7 +46,7 @@ namespace Content.Server.Atmos.Piping.Unary.EntitySystems var airTemperature = environment.Temperature > 0 ? environment.Temperature : inlet.Air.Temperature; var transferMoles = pressureDelta * environment.Volume / (airTemperature * Atmospherics.R); var removed = inlet.Air.Remove(transferMoles); - atmosphereSystem.Merge(environment, removed); + _atmosphereSystem.Merge(environment, removed); } else { diff --git a/Content.Server/Atmos/Piping/Unary/EntitySystems/GasThermoMachineSystem.cs b/Content.Server/Atmos/Piping/Unary/EntitySystems/GasThermoMachineSystem.cs index 748700d13e..f48aa149f5 100644 --- a/Content.Server/Atmos/Piping/Unary/EntitySystems/GasThermoMachineSystem.cs +++ b/Content.Server/Atmos/Piping/Unary/EntitySystems/GasThermoMachineSystem.cs @@ -7,12 +7,15 @@ using Content.Shared.Atmos.Piping; using JetBrains.Annotations; using Robust.Server.GameObjects; using Robust.Shared.GameObjects; +using Robust.Shared.IoC; namespace Content.Server.Atmos.Piping.Unary.EntitySystems { [UsedImplicitly] public class GasThermoMachineSystem : EntitySystem { + [Dependency] private readonly AtmosphereSystem _atmosphereSystem = default!; + public override void Initialize() { base.Initialize(); @@ -35,7 +38,7 @@ namespace Content.Server.Atmos.Piping.Unary.EntitySystems if (!nodeContainer.TryGetNode(thermoMachine.InletName, out PipeNode? inlet)) return; - var airHeatCapacity = Get().GetHeatCapacity(inlet.Air); + var airHeatCapacity = _atmosphereSystem.GetHeatCapacity(inlet.Air); var combinedHeatCapacity = airHeatCapacity + thermoMachine.HeatCapacity; var oldTemperature = inlet.Air.Temperature; diff --git a/Content.Server/Atmos/Piping/Unary/EntitySystems/GasVentPumpSystem.cs b/Content.Server/Atmos/Piping/Unary/EntitySystems/GasVentPumpSystem.cs index 5e69a4f3b4..f9af0231f6 100644 --- a/Content.Server/Atmos/Piping/Unary/EntitySystems/GasVentPumpSystem.cs +++ b/Content.Server/Atmos/Piping/Unary/EntitySystems/GasVentPumpSystem.cs @@ -9,12 +9,15 @@ using Content.Shared.Atmos.Visuals; using JetBrains.Annotations; using Robust.Server.GameObjects; using Robust.Shared.GameObjects; +using Robust.Shared.IoC; namespace Content.Server.Atmos.Piping.Unary.EntitySystems { [UsedImplicitly] public class GasVentPumpSystem : EntitySystem { + [Dependency] private readonly AtmosphereSystem _atmosphereSystem = default!; + public override void Initialize() { base.Initialize(); @@ -44,8 +47,7 @@ namespace Content.Server.Atmos.Piping.Unary.EntitySystems if (!nodeContainer.TryGetNode(vent.InletName, out PipeNode? pipe)) return; - var atmosphereSystem = Get(); - var environment = atmosphereSystem.GetTileMixture(vent.Owner.Transform.Coordinates, true); + var environment = _atmosphereSystem.GetTileMixture(vent.Owner.Transform.Coordinates, true); // We're in an air-blocked tile... Do nothing. if (environment == null) @@ -66,7 +68,7 @@ namespace Content.Server.Atmos.Piping.Unary.EntitySystems { var transferMoles = pressureDelta * environment.Volume / (pipe.Air.Temperature * Atmospherics.R); - atmosphereSystem.Merge(environment, pipe.Air.Remove(transferMoles)); + _atmosphereSystem.Merge(environment, pipe.Air.Remove(transferMoles)); } } else if (vent.PumpDirection == VentPumpDirection.Siphoning && environment.Pressure > 0) diff --git a/Content.Server/Atmos/Piping/Unary/EntitySystems/GasVentScrubberSystem.cs b/Content.Server/Atmos/Piping/Unary/EntitySystems/GasVentScrubberSystem.cs index 399ba29a38..190fd86228 100644 --- a/Content.Server/Atmos/Piping/Unary/EntitySystems/GasVentScrubberSystem.cs +++ b/Content.Server/Atmos/Piping/Unary/EntitySystems/GasVentScrubberSystem.cs @@ -9,6 +9,7 @@ using Content.Shared.Atmos.Piping.Unary.Visuals; using JetBrains.Annotations; using Robust.Server.GameObjects; using Robust.Shared.GameObjects; +using Robust.Shared.IoC; using Robust.Shared.Maths; namespace Content.Server.Atmos.Piping.Unary.EntitySystems @@ -16,6 +17,8 @@ namespace Content.Server.Atmos.Piping.Unary.EntitySystems [UsedImplicitly] public class GasVentScrubberSystem : EntitySystem { + [Dependency] private readonly AtmosphereSystem _atmosphereSystem = default!; + public override void Initialize() { base.Initialize(); @@ -45,17 +48,16 @@ namespace Content.Server.Atmos.Piping.Unary.EntitySystems if (!nodeContainer.TryGetNode(scrubber.OutletName, out PipeNode? outlet)) return; - var atmosphereSystem = Get(); - var environment = atmosphereSystem.GetTileMixture(scrubber.Owner.Transform.Coordinates, true); + var environment = _atmosphereSystem.GetTileMixture(scrubber.Owner.Transform.Coordinates, true); - Scrub(atmosphereSystem, scrubber, appearance, environment, outlet); + Scrub(_atmosphereSystem, scrubber, appearance, environment, outlet); if (!scrubber.WideNet) return; // Scrub adjacent tiles too. - foreach (var adjacent in atmosphereSystem.GetAdjacentTileMixtures(scrubber.Owner.Transform.Coordinates, false, true)) + foreach (var adjacent in _atmosphereSystem.GetAdjacentTileMixtures(scrubber.Owner.Transform.Coordinates, false, true)) { - Scrub(atmosphereSystem, scrubber, null, adjacent, outlet); + Scrub(_atmosphereSystem, scrubber, null, adjacent, outlet); } } diff --git a/Content.Server/Body/Surgery/Components/SurgeryToolSystem.cs b/Content.Server/Body/Surgery/Components/SurgeryToolSystem.cs index b628e7f89c..5e95ace8be 100644 --- a/Content.Server/Body/Surgery/Components/SurgeryToolSystem.cs +++ b/Content.Server/Body/Surgery/Components/SurgeryToolSystem.cs @@ -6,12 +6,15 @@ using Content.Shared.Interaction.Events; using Content.Shared.Interaction.Helpers; using JetBrains.Annotations; using Robust.Shared.GameObjects; +using Robust.Shared.IoC; namespace Content.Server.Body.Surgery.Components { [UsedImplicitly] public class SurgeryToolSystem : EntitySystem { + [Dependency] private readonly ActionBlockerSystem _actionBlockerSystem = default!; + private readonly HashSet _openSurgeryUIs = new(); public override void Initialize() @@ -54,7 +57,7 @@ namespace Content.Server.Body.Surgery.Components continue; } - if (!Get().CanInteract(tool.PerformerCache) || + if (!_actionBlockerSystem.CanInteract(tool.PerformerCache) || !tool.PerformerCache.InRangeUnobstructed(tool.BodyCache)) { tool.CloseAllSurgeryUIs(); diff --git a/Content.Server/Construction/ConstructionSystem.cs b/Content.Server/Construction/ConstructionSystem.cs index 11e7c41f72..f69cffd012 100644 --- a/Content.Server/Construction/ConstructionSystem.cs +++ b/Content.Server/Construction/ConstructionSystem.cs @@ -39,6 +39,8 @@ namespace Content.Server.Construction { [Dependency] private readonly IPrototypeManager _prototypeManager = default!; [Dependency] private readonly IRobustRandom _robustRandom = default!; + [Dependency] private readonly DoAfterSystem _doAfterSystem = default!; + [Dependency] private readonly StackSystem _stackSystem = default!; private readonly Dictionary> _beingBuilt = new(); @@ -170,7 +172,7 @@ namespace Content.Server.Construction if (!materialStep.EntityValid(entity, out var stack)) continue; - var splitStack = Get().Split(entity.Uid, stack, materialStep.Amount, user.ToCoordinates()); + var splitStack = _stackSystem.Split(entity.Uid, stack, materialStep.Amount, user.ToCoordinates()); if (splitStack == null) continue; @@ -226,8 +228,6 @@ namespace Content.Server.Construction return null; } - var doAfterSystem = Get(); - var doAfterArgs = new DoAfterEventArgs(user, doAfterTime) { BreakOnDamage = true, @@ -237,7 +237,7 @@ namespace Content.Server.Construction NeedHand = false, }; - if (await doAfterSystem.WaitDoAfter(doAfterArgs) == DoAfterStatus.Cancelled) + if (await _doAfterSystem.WaitDoAfter(doAfterArgs) == DoAfterStatus.Cancelled) { FailCleanup(); return null; diff --git a/Content.Server/Destructible/DestructibleSystem.cs b/Content.Server/Destructible/DestructibleSystem.cs index f2ad5d4922..1be935c9f6 100644 --- a/Content.Server/Destructible/DestructibleSystem.cs +++ b/Content.Server/Destructible/DestructibleSystem.cs @@ -11,17 +11,7 @@ namespace Content.Server.Destructible public class DestructibleSystem : EntitySystem { [Dependency] public readonly IRobustRandom Random = default!; - - public AudioSystem AudioSystem { get; private set; } = default!; - - public ActSystem ActSystem { get; private set; } = default!; - - public override void Initialize() - { - base.Initialize(); - - AudioSystem = Get(); - ActSystem = Get(); - } + [Dependency] public readonly AudioSystem AudioSystem = default!; + [Dependency] public readonly ActSystem ActSystem = default!; } } diff --git a/Content.Server/Engineering/EntitySystems/SpawnAfterInteractSystem.cs b/Content.Server/Engineering/EntitySystems/SpawnAfterInteractSystem.cs index fcf4bb1d85..61bfad8791 100644 --- a/Content.Server/Engineering/EntitySystems/SpawnAfterInteractSystem.cs +++ b/Content.Server/Engineering/EntitySystems/SpawnAfterInteractSystem.cs @@ -16,6 +16,8 @@ namespace Content.Server.Engineering.EntitySystems public class SpawnAfterInteractSystem : EntitySystem { [Dependency] private readonly IMapManager _mapManager = default!; + [Dependency] private readonly DoAfterSystem _doAfterSystem = default!; + [Dependency] private readonly StackSystem _stackSystem = default!; public override void Initialize() { @@ -41,7 +43,7 @@ namespace Content.Server.Engineering.EntitySystems if (!IsTileClear()) return; - if (component.DoAfterTime > 0 && TryGet(out var doAfterSystem)) + if (component.DoAfterTime > 0) { var doAfterArgs = new DoAfterEventArgs(args.User, component.DoAfterTime) { @@ -49,7 +51,7 @@ namespace Content.Server.Engineering.EntitySystems BreakOnStun = true, PostCheck = IsTileClear, }; - var result = await doAfterSystem.WaitDoAfter(doAfterArgs); + var result = await _doAfterSystem.WaitDoAfter(doAfterArgs); if (result != DoAfterStatus.Finished) return; @@ -59,7 +61,7 @@ namespace Content.Server.Engineering.EntitySystems return; if (component.Owner.TryGetComponent(out var stackComp) - && component.RemoveOnInteract && !Get().Use(uid, stackComp, 1)) + && component.RemoveOnInteract && !_stackSystem.Use(uid, stackComp, 1)) { return; } diff --git a/Content.Server/Hands/HandsSystem.cs b/Content.Server/Hands/HandsSystem.cs index 712c0867a6..4a76d07101 100644 --- a/Content.Server/Hands/HandsSystem.cs +++ b/Content.Server/Hands/HandsSystem.cs @@ -18,6 +18,7 @@ using Robust.Server.Player; using Robust.Shared.Containers; using Robust.Shared.GameObjects; using Robust.Shared.Input.Binding; +using Robust.Shared.IoC; using Robust.Shared.Localization; using Robust.Shared.Map; using Robust.Shared.Maths; @@ -29,6 +30,9 @@ namespace Content.Server.Hands [UsedImplicitly] internal sealed class HandsSystem : SharedHandsSystem { + [Dependency] private readonly InteractionSystem _interactionSystem = default!; + [Dependency] private readonly StackSystem _stackSystem = default!; + public override void Initialize() { base.Initialize(); @@ -113,12 +117,12 @@ namespace Content.Server.Hands if (!hands.TryGetActiveHeldEntity(out var throwEnt)) return false; - if (!Get().TryThrowInteraction(hands.Owner, throwEnt)) + if (!_interactionSystem.TryThrowInteraction(hands.Owner, throwEnt)) return false; if (throwEnt.TryGetComponent(out StackComponent? stack) && stack.Count > 1 && stack.ThrowIndividually) { - var splitStack = Get().Split(throwEnt.Uid, stack, 1, playerEnt.Transform.Coordinates); + var splitStack = _stackSystem.Split(throwEnt.Uid, stack, 1, playerEnt.Transform.Coordinates); if (splitStack == null) return false; diff --git a/Content.Server/Interaction/InteractionSystem.cs b/Content.Server/Interaction/InteractionSystem.cs index efb01638c4..61a5ce724e 100644 --- a/Content.Server/Interaction/InteractionSystem.cs +++ b/Content.Server/Interaction/InteractionSystem.cs @@ -4,6 +4,7 @@ using System.Linq; using System.Threading.Tasks; using Content.Server.Buckle.Components; using Content.Server.CombatMode; +using Content.Server.DoAfter; using Content.Server.Hands.Components; using Content.Server.Items; using Content.Server.Pulling; @@ -46,6 +47,7 @@ namespace Content.Server.Interaction { [Dependency] private readonly IEntityManager _entityManager = default!; [Dependency] private readonly IRobustRandom _random = default!; + [Dependency] private readonly ActionBlockerSystem _actionBlockerSystem = default!; public override void Initialize() { @@ -175,9 +177,7 @@ namespace Content.Server.Interaction private void InteractionActivate(IEntity user, IEntity used) { - var actionBlocker = Get(); - - if (!actionBlocker.CanInteract(user) || ! actionBlocker.CanUse(user)) + if (!_actionBlockerSystem.CanInteract(user) || ! _actionBlockerSystem.CanUse(user)) return; // all activates should only fire when in range / unobstructed @@ -275,7 +275,7 @@ namespace Content.Server.Interaction if (!ValidateInteractAndFace(user, coordinates)) return; - if (!Get().CanInteract(user)) + if (!_actionBlockerSystem.CanInteract(user)) return; // Get entity clicked upon from UID if valid UID, if not assume no entity clicked upon and null @@ -344,7 +344,7 @@ namespace Content.Server.Interaction if (diff.LengthSquared <= 0.01f) return; var diffAngle = Angle.FromWorldVec(diff); - if (Get().CanChangeDirection(user)) + if (_actionBlockerSystem.CanChangeDirection(user)) { user.Transform.WorldRotation = diffAngle; } @@ -394,7 +394,7 @@ namespace Content.Server.Interaction /// public async Task InteractUsing(IEntity user, IEntity used, IEntity target, EntityCoordinates clickLocation) { - if (!Get().CanInteract(user)) + if (!_actionBlockerSystem.CanInteract(user)) return; // all interactions should only happen when in range / unobstructed, so no range check is needed @@ -424,7 +424,7 @@ namespace Content.Server.Interaction /// public void InteractHand(IEntity user, IEntity target) { - if (!Get().CanInteract(user)) + if (!_actionBlockerSystem.CanInteract(user)) return; // all interactions should only happen when in range / unobstructed, so no range check is needed @@ -457,7 +457,7 @@ namespace Content.Server.Interaction /// public void TryUseInteraction(IEntity user, IEntity used) { - if (user != null && used != null && Get().CanUse(user)) + if (user != null && used != null && _actionBlockerSystem.CanUse(user)) { UseInteraction(user, used); } @@ -501,7 +501,7 @@ namespace Content.Server.Interaction /// public bool TryThrowInteraction(IEntity user, IEntity item) { - if (user == null || item == null || !Get().CanThrow(user)) return false; + if (user == null || item == null || !_actionBlockerSystem.CanThrow(user)) return false; ThrownInteraction(user, item); return true; @@ -618,7 +618,7 @@ namespace Content.Server.Interaction /// public bool TryDroppedInteraction(IEntity user, IEntity item, bool intentional) { - if (user == null || item == null || !Get().CanDrop(user)) return false; + if (user == null || item == null || !_actionBlockerSystem.CanDrop(user)) return false; DroppedInteraction(user, item, intentional); return true; @@ -726,7 +726,7 @@ namespace Content.Server.Interaction if (!ValidateInteractAndFace(user, coordinates)) return; - if (!Get().CanAttack(user)) + if (!_actionBlockerSystem.CanAttack(user)) return; IEntity? targetEnt = null; diff --git a/Content.Server/Pointing/EntitySystems/PointingSystem.cs b/Content.Server/Pointing/EntitySystems/PointingSystem.cs index f31155ff11..e855c9270c 100644 --- a/Content.Server/Pointing/EntitySystems/PointingSystem.cs +++ b/Content.Server/Pointing/EntitySystems/PointingSystem.cs @@ -31,6 +31,7 @@ namespace Content.Server.Pointing.EntitySystems [Dependency] private readonly IPlayerManager _playerManager = default!; [Dependency] private readonly ITileDefinitionManager _tileDefinitionManager = default!; [Dependency] private readonly IGameTiming _gameTiming = default!; + [Dependency] private readonly ActionBlockerSystem _actionBlockerSystem = default!; private static readonly TimeSpan PointDelay = TimeSpan.FromSeconds(0.5f); @@ -112,7 +113,7 @@ namespace Content.Server.Pointing.EntitySystems return false; } - if (EntitySystem.Get().CanChangeDirection(player)) + if (_actionBlockerSystem.CanChangeDirection(player)) { var diff = coords.ToMapPos(EntityManager) - player.Transform.MapPosition.Position; if (diff.LengthSquared > 0.01f) diff --git a/Content.Shared/Interaction/SharedInteractionSystem.cs b/Content.Shared/Interaction/SharedInteractionSystem.cs index 7f50cf0063..0d02792593 100644 --- a/Content.Shared/Interaction/SharedInteractionSystem.cs +++ b/Content.Shared/Interaction/SharedInteractionSystem.cs @@ -4,6 +4,7 @@ using Content.Shared.Notification.Managers; using Content.Shared.Physics; using JetBrains.Annotations; using Robust.Shared.GameObjects; +using Robust.Shared.IoC; using Robust.Shared.Localization; using Robust.Shared.Map; using Robust.Shared.Physics; @@ -17,6 +18,8 @@ namespace Content.Shared.Interaction [UsedImplicitly] public class SharedInteractionSystem : EntitySystem { + [Dependency] private readonly SharedBroadphaseSystem _sharedBroadphaseSystem = default!; + public const float InteractionRange = 2; public const float InteractionRangeSquared = InteractionRange * InteractionRange; @@ -46,7 +49,7 @@ namespace Content.Shared.Interaction predicate ??= _ => false; var ray = new CollisionRay(origin.Position, dir.Normalized, collisionMask); - var rayResults = Get().IntersectRayWithPredicate(origin.MapId, ray, dir.Length, predicate.Invoke, false).ToList(); + var rayResults = _sharedBroadphaseSystem.IntersectRayWithPredicate(origin.MapId, ray, dir.Length, predicate.Invoke, false).ToList(); if (rayResults.Count == 0) return dir.Length; return (rayResults[0].HitPos - origin.Position).Length; @@ -122,7 +125,7 @@ namespace Content.Shared.Interaction predicate ??= _ => false; var ray = new CollisionRay(origin.Position, dir.Normalized, (int) collisionMask); - var rayResults = Get().IntersectRayWithPredicate(origin.MapId, ray, dir.Length, predicate.Invoke, false).ToList(); + var rayResults = _sharedBroadphaseSystem.IntersectRayWithPredicate(origin.MapId, ray, dir.Length, predicate.Invoke, false).ToList(); if (rayResults.Count == 0) return true; From 8357fcd7c2f21d39f089c0b9c531cc9e93f9a755 Mon Sep 17 00:00:00 2001 From: Paul Date: Mon, 26 Jul 2021 18:17:42 +0200 Subject: [PATCH 19/38] fixes enpendablelight to actually be expendable --- Content.Server/Light/Components/ExpendableLightComponent.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Content.Server/Light/Components/ExpendableLightComponent.cs b/Content.Server/Light/Components/ExpendableLightComponent.cs index 1f1c4a9df5..ef74376c01 100644 --- a/Content.Server/Light/Components/ExpendableLightComponent.cs +++ b/Content.Server/Light/Components/ExpendableLightComponent.cs @@ -56,7 +56,7 @@ namespace Content.Server.Light.Components /// private bool TryActivate() { - if (!Activated) + if (!Activated && CurrentState == ExpendableLightState.BrandNew) { if (Owner.TryGetComponent(out var item)) { From 70a16427f471b65bd30cc08f2535713702b71f8c Mon Sep 17 00:00:00 2001 From: Paul Date: Mon, 26 Jul 2021 18:28:04 +0200 Subject: [PATCH 20/38] fixes #4372 --- Content.Server/Light/Components/EmergencyLightComponent.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Content.Server/Light/Components/EmergencyLightComponent.cs b/Content.Server/Light/Components/EmergencyLightComponent.cs index 5d7fd2a933..b5df55fb28 100644 --- a/Content.Server/Light/Components/EmergencyLightComponent.cs +++ b/Content.Server/Light/Components/EmergencyLightComponent.cs @@ -142,7 +142,7 @@ namespace Content.Server.Light.Components void IExamine.Examine(FormattedMessage message, bool inDetailsRange) { - message.AddMarkup(Loc.GetString("emergency-light-component-on-examine",("batteryStateText", BatteryStateText[State]))); + message.AddMarkup(Loc.GetString("emergency-light-component-on-examine",("batteryStateText", Loc.GetString(BatteryStateText[State])))); } public enum EmergencyLightState From aa4727d18506c1d7beffc7548ae3315319f00fcd Mon Sep 17 00:00:00 2001 From: Swept Date: Mon, 26 Jul 2021 09:39:12 -0700 Subject: [PATCH 21/38] Gas tanks have proper item sizes --- Resources/Prototypes/Entities/Objects/Tools/gas_tanks.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Resources/Prototypes/Entities/Objects/Tools/gas_tanks.yml b/Resources/Prototypes/Entities/Objects/Tools/gas_tanks.yml index 4c93eab341..48b667a26d 100644 --- a/Resources/Prototypes/Entities/Objects/Tools/gas_tanks.yml +++ b/Resources/Prototypes/Entities/Objects/Tools/gas_tanks.yml @@ -11,6 +11,7 @@ - key: enum.SharedGasTankUiKey.Key type: GasTankBoundUserInterface - type: Clothing + size: 15 sprite: Objects/Tanks/generic.rsi QuickEquip: false - type: GasTank @@ -80,6 +81,7 @@ volume: 2 temperature: 293.15 - type: Clothing + size: 10 sprite: Objects/Tanks/emergency.rsi Slots: - Pocket @@ -100,6 +102,7 @@ volume: 6 temperature: 293.15 - type: Clothing + size: 10 sprite: Objects/Tanks/emergency_yellow.rsi Slots: - Pocket @@ -118,6 +121,7 @@ volume: 10 temperature: 293.15 - type: Clothing + size: 10 sprite: Objects/Tanks/emergency_double.rsi Slots: - Pocket @@ -157,6 +161,7 @@ volume: 70 temperature: 293.15 - type: Clothing + size: 10 sprite: Objects/Tanks/plasma.rsi Slots: - Belt From 86aa1caddb7bd167445f5907703f054dcd2b44d5 Mon Sep 17 00:00:00 2001 From: Swept Date: Mon, 26 Jul 2021 09:49:43 -0700 Subject: [PATCH 22/38] Updated bucket's size to 100 --- Resources/Prototypes/Entities/Objects/Tools/bucket.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/Resources/Prototypes/Entities/Objects/Tools/bucket.yml b/Resources/Prototypes/Entities/Objects/Tools/bucket.yml index 9646bdce26..be03c43997 100644 --- a/Resources/Prototypes/Entities/Objects/Tools/bucket.yml +++ b/Resources/Prototypes/Entities/Objects/Tools/bucket.yml @@ -12,6 +12,7 @@ sprite: Objects/Tools/bucket.rsi state: icon - type: Clothing + size: 100 sprite: Objects/Tools/bucket.rsi Slots: - Helmet From 283dcb0802aae6a6d3a62dd3f2a4575b9fa742dc Mon Sep 17 00:00:00 2001 From: SethLafuente <84478872+SethLafuente@users.noreply.github.com> Date: Mon, 26 Jul 2021 15:14:10 -0700 Subject: [PATCH 23/38] Gives RD locker a hardsuit (#4376) Co-authored-by: SETh lafuente --- Resources/Prototypes/Catalog/Fills/Lockers/heads.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Resources/Prototypes/Catalog/Fills/Lockers/heads.yml b/Resources/Prototypes/Catalog/Fills/Lockers/heads.yml index f8df3df691..415db3246d 100644 --- a/Resources/Prototypes/Catalog/Fills/Lockers/heads.yml +++ b/Resources/Prototypes/Catalog/Fills/Lockers/heads.yml @@ -147,6 +147,10 @@ prob: 1 - id: ClothingHeadsetMedicalScience prob: 1 + - id: ClothingHeadHelmetHardsuitRd + prob: 1 + - id: ClothingOuterHardsuitRd + prob: 1 - id: PlushieSlime prob: 0.1 From af4dec27ab2c6a96c6ac1a9fe47eb0306c9e4693 Mon Sep 17 00:00:00 2001 From: PJBot Date: Mon, 26 Jul 2021 18:15:13 -0400 Subject: [PATCH 24/38] Automatic changelog update --- Resources/Changelog/Changelog.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 2987e1d464..ce4f52b54b 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1603,3 +1603,8 @@ Entries: - {message: Added Storage Room to Coats, type: Add} id: 285 time: '2021-07-26T05:36:27.0000000+00:00' +- author: Seth + changes: + - {message: Added a hardsuit into research directors locker, type: Add} + id: 286 + time: '2021-07-26T22:14:10.0000000+00:00' From 3e7b0fe7a211b57faad67d74e6fa56a880f7ba2d Mon Sep 17 00:00:00 2001 From: Kara Dinyes Date: Mon, 26 Jul 2021 17:38:27 -0700 Subject: [PATCH 25/38] Fix patron OOC message wrap --- Resources/Locale/en-US/chat/managers/chat-manager.ftl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Resources/Locale/en-US/chat/managers/chat-manager.ftl b/Resources/Locale/en-US/chat/managers/chat-manager.ftl index 02b71db263..01b43a67c6 100644 --- a/Resources/Locale/en-US/chat/managers/chat-manager.ftl +++ b/Resources/Locale/en-US/chat/managers/chat-manager.ftl @@ -13,7 +13,7 @@ chat-manager-sender-announcement-wrap-message = {$sender} Announcement: chat-manager-entity-say-wrap-message = {$entityName} says: "{"{0}"}" chat-manager-entity-me-wrap-message = {$entityName} {"{0}"} chat-manager-send-ooc-wrap-message = OOC: {$playerName}: {"{0}"} -chat-manager-send-ooc-patron-wrap-message = OOC: [color={$patronColor}]{$playerName}[/color]: {"{0}"}: +chat-manager-send-ooc-patron-wrap-message = OOC: [color={$patronColor}]{$playerName}[/color]: {"{0}"} chat-manager-send-dead-chat-wrap-message = {$deadChannelName}: {$playerName}: {"{0}"} chat-manager-send-admin-dead-chat-wrap-message = {$adminChannelName}:({$userName}): {"{0}"} chat-manager-send-admin-chat-wrap-message = {$adminChannelName}: {$playerName}: {"{0}"} @@ -21,4 +21,4 @@ chat-manager-send-admin-announcement-wrap-message = {$adminChannelName}: {"{0}"} chat-manager-send-hook-ooc-wrap-message = OOC: (D){$senderName}: {"{0}"} chat-manager-dead-channel-name = DEAD -chat-manager-admin-channel-name = ADMIN \ No newline at end of file +chat-manager-admin-channel-name = ADMIN From af948d00d80dc9e0fe25eb63a22188e1d9743bfb Mon Sep 17 00:00:00 2001 From: Paul Ritter Date: Tue, 27 Jul 2021 14:54:26 +0200 Subject: [PATCH 26/38] adds a integrationtest that tries out all reactions (#4374) Co-authored-by: Paul --- .../Tests/Chemistry/TryAllReactionsTest.cs | 77 +++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 Content.IntegrationTests/Tests/Chemistry/TryAllReactionsTest.cs diff --git a/Content.IntegrationTests/Tests/Chemistry/TryAllReactionsTest.cs b/Content.IntegrationTests/Tests/Chemistry/TryAllReactionsTest.cs new file mode 100644 index 0000000000..9587897442 --- /dev/null +++ b/Content.IntegrationTests/Tests/Chemistry/TryAllReactionsTest.cs @@ -0,0 +1,77 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Content.Server.Chemistry.Components; +using Content.Server.Fluids.Components; +using Content.Shared.Chemistry.Reaction; +using Content.Shared.Chemistry.Reagent; +using Content.Shared.Coordinates; +using NUnit.Framework; +using Robust.Shared.GameObjects; +using Robust.Shared.Map; +using Robust.Shared.Prototypes; +using Robust.Shared.Timing; +using Robust.Shared.Utility; + +namespace Content.IntegrationTests.Tests.Chemistry +{ + [TestFixture] + [TestOf(typeof(ReactionPrototype))] + public class TryAllReactionsTest : ContentIntegrationTest + { + [Test] + public async Task TryAllTest() + { + var server = StartServerDummyTicker(); + + await server.WaitIdleAsync(); + + var mapManager = server.ResolveDependency(); + var entityManager = server.ResolveDependency(); + var prototypeManager = server.ResolveDependency(); + + foreach (var reactionPrototype in prototypeManager.EnumeratePrototypes()) + { + //since i have no clue how to isolate each loop assert-wise im just gonna throw this one in for good measure + Console.WriteLine($"Testing {reactionPrototype.ID}"); + + IEntity beaker; + SolutionContainerComponent component = null; + + server.Assert(() => + { + mapManager.CreateNewMapEntity(MapId.Nullspace); + + beaker = entityManager.SpawnEntity("BluespaceBeaker", MapCoordinates.Nullspace); + Assert.That(beaker.TryGetComponent(out component)); + foreach (var (id, reactant) in reactionPrototype.Reactants) + { + Assert.That(component.TryAddReagent(id, reactant.Amount, out var quantity)); + Assert.That(reactant.Amount, Is.EqualTo(quantity)); + } + }); + + await server.WaitIdleAsync(); + + server.Assert(() => + { + //you just got linq'd fool + //(i'm sorry) + var foundProductsMap = reactionPrototype.Products + .Concat(reactionPrototype.Reactants.Where(x => x.Value.Catalyst).ToDictionary(x => x.Key, x => x.Value.Amount)) + .ToDictionary(x => x, x => false); + foreach (var reagent in component.Solution.Contents) + { + Assert.That(foundProductsMap.TryFirstOrNull(x => x.Key.Key == reagent.ReagentId && x.Key.Value == reagent.Quantity, out var foundProduct)); + foundProductsMap[foundProduct.Value.Key] = true; + } + + Assert.That(foundProductsMap.All(x => x.Value)); + }); + } + + } + } + +} From e38d7e0a2f76367aaf229b8d227d48bed9dda0d1 Mon Sep 17 00:00:00 2001 From: metalgearsloth Date: Wed, 28 Jul 2021 00:30:39 +1000 Subject: [PATCH 27/38] Update submodule --- RobustToolbox | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RobustToolbox b/RobustToolbox index 8c1e075c91..7bac32d18e 160000 --- a/RobustToolbox +++ b/RobustToolbox @@ -1 +1 @@ -Subproject commit 8c1e075c919604fe2e27cd6a2bbe22fceeb89249 +Subproject commit 7bac32d18ebd71547c76565dc4cd86f8007c0e8c From 273eaa493fc2570c4a3811163cf41ff0eca8a360 Mon Sep 17 00:00:00 2001 From: Visne <39844191+Visne@users.noreply.github.com> Date: Tue, 27 Jul 2021 20:09:12 +0200 Subject: [PATCH 28/38] XAMLify ID card computer, Alerts and AME window (#4322) * Refactor ID card computer to XAML UI * Alerts * XAMLify AME window * Use Control.SetButtonDisabledRecursive() instead --- .../AME/UI/AMEControllerBoundUserInterface.cs | 9 +- Content.Client/AME/UI/AMEWindow.cs | 173 --------------- Content.Client/AME/UI/AMEWindow.xaml | 46 ++++ Content.Client/AME/UI/AMEWindow.xaml.cs | 73 ++++++ .../Access/UI/IdCardConsoleWindow.cs | 208 ------------------ .../Access/UI/IdCardConsoleWindow.xaml | 30 +++ .../Access/UI/IdCardConsoleWindow.xaml.cs | 121 ++++++++++ Content.Client/Alerts/UI/AlertsUI.xaml | 10 + .../UI/{AlertsUI.cs => AlertsUI.xaml.cs} | 38 ++-- .../Chemistry/UI/ChemMasterWindow.cs | 23 -- .../Chemistry/UI/ReagentDispenserWindow.cs | 23 -- 11 files changed, 295 insertions(+), 459 deletions(-) delete mode 100644 Content.Client/AME/UI/AMEWindow.cs create mode 100644 Content.Client/AME/UI/AMEWindow.xaml create mode 100644 Content.Client/AME/UI/AMEWindow.xaml.cs delete mode 100644 Content.Client/Access/UI/IdCardConsoleWindow.cs create mode 100644 Content.Client/Access/UI/IdCardConsoleWindow.xaml create mode 100644 Content.Client/Access/UI/IdCardConsoleWindow.xaml.cs create mode 100644 Content.Client/Alerts/UI/AlertsUI.xaml rename Content.Client/Alerts/UI/{AlertsUI.cs => AlertsUI.xaml.cs} (71%) diff --git a/Content.Client/AME/UI/AMEControllerBoundUserInterface.cs b/Content.Client/AME/UI/AMEControllerBoundUserInterface.cs index 3765d45fa2..aaeaf538f3 100644 --- a/Content.Client/AME/UI/AMEControllerBoundUserInterface.cs +++ b/Content.Client/AME/UI/AMEControllerBoundUserInterface.cs @@ -19,14 +19,9 @@ namespace Content.Client.AME.UI { base.Open(); - _window = new AMEWindow(); + _window = new AMEWindow(this); _window.OnClose += Close; _window.OpenCentered(); - - _window.EjectButton.OnPressed += _ => ButtonPressed(UiButton.Eject); - _window.ToggleInjection.OnPressed += _ => ButtonPressed(UiButton.ToggleInjection); - _window.IncreaseFuelButton.OnPressed += _ => ButtonPressed(UiButton.IncreaseFuel); - _window.DecreaseFuelButton.OnPressed += _ => ButtonPressed(UiButton.DecreaseFuel); } /// @@ -44,7 +39,7 @@ namespace Content.Client.AME.UI _window?.UpdateState(castState); //Update window state } - private void ButtonPressed(UiButton button, int dispenseIndex = -1) + public void ButtonPressed(UiButton button, int dispenseIndex = -1) { SendMessage(new UiButtonPressedMessage(button)); } diff --git a/Content.Client/AME/UI/AMEWindow.cs b/Content.Client/AME/UI/AMEWindow.cs deleted file mode 100644 index e9104e6f67..0000000000 --- a/Content.Client/AME/UI/AMEWindow.cs +++ /dev/null @@ -1,173 +0,0 @@ -using Content.Client.Stylesheets; -using Robust.Client.UserInterface; -using Robust.Client.UserInterface.Controls; -using Robust.Client.UserInterface.CustomControls; -using Robust.Shared.GameObjects; -using Robust.Shared.IoC; -using Robust.Shared.Localization; -using static Content.Shared.AME.SharedAMEControllerComponent; -using static Robust.Client.UserInterface.Controls.BoxContainer; - -namespace Content.Client.AME.UI -{ - public class AMEWindow : SS14Window - { - public Label InjectionStatus { get; set; } - public Button EjectButton { get; set; } - public Button ToggleInjection { get; set; } - public Button IncreaseFuelButton { get; set; } - public Button DecreaseFuelButton { get; set; } - public ProgressBar? FuelMeter { get; set; } - public Label FuelAmount { get; set; } - public Label InjectionAmount { get; set; } - public Label CoreCount { get; set; } - - - public AMEWindow() - { - IoCManager.InjectDependencies(this); - - Title = Loc.GetString("ame-window-title"); - - MinSize = SetSize = (250, 250); - - Contents.AddChild(new BoxContainer - { - Orientation = LayoutOrientation.Vertical, - Children = - { - new BoxContainer - { - Orientation = LayoutOrientation.Horizontal, - Children = - { - new Label {Text = Loc.GetString("ame-window-engine-status-label") + " "}, - (InjectionStatus = new Label {Text = Loc.GetString("ame-window-engine-injection-status-not-injecting-label")}) - } - }, - new BoxContainer - { - Orientation = LayoutOrientation.Horizontal, - Children = - { - (ToggleInjection = new Button {Text = Loc.GetString("ame-window-toggle-injection-button"), StyleClasses = {StyleBase.ButtonOpenBoth}, Disabled = true}), - } - }, - new BoxContainer - { - Orientation = LayoutOrientation.Horizontal, - Children = - { - new Label {Text = Loc.GetString("ame-window-fuel-status-label") + " "}, - (FuelAmount = new Label {Text = Loc.GetString("ame-window-fuel-not-inserted-text")}) - } - }, - new BoxContainer - { - Orientation = LayoutOrientation.Horizontal, - Children = - { - (EjectButton = new Button {Text = Loc.GetString("ame-window-eject-button"), StyleClasses = {StyleBase.ButtonOpenBoth}, Disabled = true}), - } - }, - new BoxContainer - { - Orientation = LayoutOrientation.Horizontal, - Children = - { - new Label {Text = Loc.GetString("ame-window-injection-amount-label") + " "}, - (InjectionAmount = new Label {Text = "0"}) - } - }, - new BoxContainer - { - Orientation = LayoutOrientation.Horizontal, - Children = - { - (IncreaseFuelButton = new Button {Text = Loc.GetString("ame-window-increase-fuel-button"), StyleClasses = {StyleBase.ButtonOpenRight}}), - (DecreaseFuelButton = new Button {Text = Loc.GetString("ame-window-decrease-fuel-button"), StyleClasses = {StyleBase.ButtonOpenLeft}}), - } - }, - new BoxContainer - { - Orientation = LayoutOrientation.Horizontal, - Children = - { - new Label { Text = Loc.GetString("ame-window-core-count-label") + " "}, - (CoreCount = new Label { Text = "0"}), - } - } - } - }); - } - - /// - /// This searches recursively through all the children of "parent" - /// and sets the Disabled value of any buttons found to "val" - /// - /// The control which childrens get searched - /// The value to which disabled gets set - private void SetButtonDisabledRecursive(Control parent, bool val) - { - foreach (var child in parent.Children) - { - if (child is Button but) - { - but.Disabled = val; - continue; - } - - if (child.Children != null) - { - SetButtonDisabledRecursive(child, val); - } - } - } - - /// - /// Update the UI state when new state data is received from the server. - /// - /// State data sent by the server. - public void UpdateState(BoundUserInterfaceState state) - { - var castState = (AMEControllerBoundUserInterfaceState) state; - - // Disable all buttons if not powered - if (Contents.Children != null) - { - SetButtonDisabledRecursive(Contents, !castState.HasPower); - EjectButton.Disabled = false; - } - - if (!castState.HasFuelJar) - { - EjectButton.Disabled = true; - ToggleInjection.Disabled = true; - FuelAmount.Text = Loc.GetString("ame-window-fuel-not-inserted-text"); - } - else - { - EjectButton.Disabled = false; - ToggleInjection.Disabled = false; - FuelAmount.Text = $"{castState.FuelAmount}"; - } - - if (!castState.IsMaster) - { - ToggleInjection.Disabled = true; - } - - if (!castState.Injecting) - { - InjectionStatus.Text = Loc.GetString("ame-window-engine-injection-status-not-injecting-label") + " "; - } - else - { - InjectionStatus.Text = Loc.GetString("ame-window-engine-injection-status-injecting-label") + " "; - } - - CoreCount.Text = $"{castState.CoreCount}"; - InjectionAmount.Text = $"{castState.InjectionAmount}"; - } - } -} diff --git a/Content.Client/AME/UI/AMEWindow.xaml b/Content.Client/AME/UI/AMEWindow.xaml new file mode 100644 index 0000000000..bc1e7d9ded --- /dev/null +++ b/Content.Client/AME/UI/AMEWindow.xaml @@ -0,0 +1,46 @@ + + + + + + [RegisterComponent] - [ComponentReference(typeof(IActivate))] - public class ReagentGrinderComponent : SharedReagentGrinderComponent, IActivate, IInteractUsing + public class ReagentGrinderComponent : SharedReagentGrinderComponent { - private AudioSystem _audioSystem = default!; - [ViewVariables] private ContainerSlot _beakerContainer = default!; + [ViewVariables] public ContainerSlot BeakerContainer = default!; /// /// Can be null since we won't always have a beaker in the grinder. /// - [ViewVariables] private SolutionContainerComponent? _heldBeaker = default!; + [ViewVariables] public SolutionContainerComponent? HeldBeaker = default!; /// /// Contains the things that are going to be ground or juiced. /// - [ViewVariables] private Container _chamber = default!; + [ViewVariables] public Container Chamber = default!; - [ViewVariables] private bool ChamberEmpty => _chamber.ContainedEntities.Count <= 0; - [ViewVariables] private bool HasBeaker => _beakerContainer.ContainedEntity != null; - [ViewVariables] private BoundUserInterface? UserInterface => Owner.GetUIOrNull(ReagentGrinderUiKey.Key); - - private bool Powered => !Owner.TryGetComponent(out ApcPowerReceiverComponent? receiver) || receiver.Powered; - - /// - /// Should the BoundUI be told to update? - /// - private bool _uiDirty = true; /// /// Is the machine actively doing something and can't be used right now? /// - private bool _busy = false; + public bool Busy; //YAML serialization vars - [ViewVariables(VVAccess.ReadWrite)] [DataField("chamberCapacity")] private int _storageCap = 16; - [ViewVariables(VVAccess.ReadWrite)] [DataField("workTime")] private int _workTime = 3500; //3.5 seconds, completely arbitrary for now. - - protected override void Initialize() - { - base.Initialize(); - //A slot for the beaker where the grounds/juices will go. - _beakerContainer = - ContainerHelpers.EnsureContainer(Owner, $"{Name}-reagentContainerContainer"); - - //A container for the things that WILL be ground/juiced. Useful for ejecting them instead of deleting them from the hands of the user. - _chamber = - ContainerHelpers.EnsureContainer(Owner, $"{Name}-entityContainerContainer"); - - if (UserInterface != null) - { - UserInterface.OnReceiveMessage += UserInterfaceOnReceiveMessage; - } - - _audioSystem = EntitySystem.Get(); - } - - public override void HandleMessage(ComponentMessage message, IComponent? component) - { - base.HandleMessage(message, component); - switch (message) - { - case PowerChangedMessage powerChanged: - OnPowerStateChanged(powerChanged); - break; - } - } - - protected override void OnRemove() - { - base.OnRemove(); - if (UserInterface != null) - { - UserInterface.OnReceiveMessage -= UserInterfaceOnReceiveMessage; - } - } - - private void UserInterfaceOnReceiveMessage(ServerBoundUserInterfaceMessage message) - { - if(_busy) - { - return; - } - - switch(message.Message) - { - case ReagentGrinderGrindStartMessage msg: - if (!Powered) break; - ClickSound(); - DoWork(message.Session.AttachedEntity!, GrinderProgram.Grind); - break; - - case ReagentGrinderJuiceStartMessage msg: - if (!Powered) break; - ClickSound(); - DoWork(message.Session.AttachedEntity!, GrinderProgram.Juice); - break; - - case ReagentGrinderEjectChamberAllMessage msg: - if(!ChamberEmpty) - { - ClickSound(); - for (var i = _chamber.ContainedEntities.Count - 1; i >= 0; i--) - { - EjectSolid(_chamber.ContainedEntities.ElementAt(i).Uid); - } - } - break; - - case ReagentGrinderEjectChamberContentMessage msg: - if (!ChamberEmpty) - { - EjectSolid(msg.EntityID); - ClickSound(); - _uiDirty = true; - } - break; - - case ReagentGrinderEjectBeakerMessage msg: - ClickSound(); - EjectBeaker(message.Session.AttachedEntity); - //EjectBeaker will dirty the UI for us, we don't have to do it explicitly here. - break; - } - } - - private void OnPowerStateChanged(PowerChangedMessage e) - { - _uiDirty = true; - } - - private void ClickSound() - { - SoundSystem.Play(Filter.Pvs(Owner), "/Audio/Machines/machine_switch.ogg", Owner, AudioParams.Default.WithVolume(-2f)); - } - - private void SetAppearance() - { - if (Owner.TryGetComponent(out AppearanceComponent? appearance)) - { - appearance.SetData(ReagentGrinderVisualState.BeakerAttached, HasBeaker); - } - } - - public void OnUpdate() - { - if(_uiDirty) - { - UpdateInterface(); - _uiDirty = false; - } - } - - // This doesn't check for UI dirtiness so handle that when calling this. - private void UpdateInterface() - { - bool canJuice = false; - bool canGrind = false; - if (HasBeaker) - { - foreach (var entity in _chamber.ContainedEntities) - { - if (!canJuice && entity.HasComponent()) canJuice = true; - if (!canGrind && entity.HasTag("Grindable")) canGrind = true; - if (canJuice && canGrind) break; - } - } - - UserInterface?.SetState(new ReagentGrinderInterfaceState - ( - _busy, - HasBeaker, - Powered, - canJuice, - canGrind, - _chamber.ContainedEntities.Select(item => item.Uid).ToArray(), - //Remember the beaker can be null! - _heldBeaker?.Solution.Contents.ToArray() - )); - _uiDirty = false; - } - - private void EjectSolid(EntityUid entityID) - { - if (_busy) - return; - - if (Owner.EntityManager.TryGetEntity(entityID, out var entity)) - { - _chamber.Remove(entity); - - //Give the ejected entity a tiny bit of offset so each one is apparent in case of a big stack, - //but (hopefully) not enough to clip it through a solid (wall). - entity.RandomOffset(0.4f); - } - _uiDirty = true; - } - - /// - /// Tries to eject whatever is in the beaker slot. Puts the item in the user's hands or failing that on top - /// of the grinder. - /// - private void EjectBeaker(IEntity? user) - { - if (!HasBeaker || _heldBeaker == null || _busy) - return; - - var beaker = _beakerContainer.ContainedEntity; - if(beaker is null) - return; - - _beakerContainer.Remove(beaker); - - if (user == null || !user.TryGetComponent(out var hands) || !_heldBeaker.Owner.TryGetComponent(out var item)) - return; - hands.PutInHandOrDrop(item); - - _heldBeaker = null; - _uiDirty = true; - SetAppearance(); - } - - void IActivate.Activate(ActivateEventArgs eventArgs) - { - if (!eventArgs.User.TryGetComponent(out ActorComponent? actor)) - { - return; - } - _uiDirty = true; - UserInterface?.Toggle(actor.PlayerSession); - } - - async Task IInteractUsing.InteractUsing(InteractUsingEventArgs eventArgs) - { - if (!eventArgs.User.TryGetComponent(out IHandsComponent? hands)) - { - Owner.PopupMessage(eventArgs.User, Loc.GetString("reagent-grinder-component-interact-using-no-hands")); - return true; - } - - IEntity heldEnt = eventArgs.Using; - - //First, check if user is trying to insert a beaker. - //No promise it will be a beaker right now, but whatever. - //Maybe this should whitelist "beaker" in the prototype id of heldEnt? - if(heldEnt.TryGetComponent(out SolutionContainerComponent? beaker) && beaker.Capabilities.HasFlag(SolutionContainerCaps.FitsInDispenser)) - { - _beakerContainer.Insert(heldEnt); - _heldBeaker = beaker; - _uiDirty = true; - //We are done, return. Insert the beaker and exit! - SetAppearance(); - ClickSound(); - return true; - } - - //Next, see if the user is trying to insert something they want to be ground/juiced. - if(!heldEnt.HasTag("Grindable") && !heldEnt.TryGetComponent(out JuiceableComponent? juice)) - { - //Entity did NOT pass the whitelist for grind/juice. - //Wouldn't want the clown grinding up the Captain's ID card now would you? - //Why am I asking you? You're biased. - return false; - } - - //Cap the chamber. Don't want someone putting in 500 entities and ejecting them all at once. - //Maybe I should have done that for the microwave too? - if (_chamber.ContainedEntities.Count >= _storageCap) - { - return false; - } - - if (!_chamber.Insert(heldEnt)) - return false; - - _uiDirty = true; - return true; - } - - /// - /// The wzhzhzh of the grinder. Processes the contents of the grinder and puts the output in the beaker. - /// - /// true for wanting to juice, false for wanting to grind. - private async void DoWork(IEntity user, GrinderProgram program) - { - //Have power, are we busy, chamber has anything to grind, a beaker for the grounds to go? - if(!Powered || _busy || ChamberEmpty || !HasBeaker || _heldBeaker == null) - { - return; - } - - _busy = true; - - UserInterface?.SendMessage(new ReagentGrinderWorkStartedMessage(program)); - switch (program) - { - case GrinderProgram.Grind: - SoundSystem.Play(Filter.Pvs(Owner), "/Audio/Machines/blender.ogg", Owner, AudioParams.Default); - //Get each item inside the chamber and get the reagents it contains. Transfer those reagents to the beaker, given we have one in. - Owner.SpawnTimer(_workTime, (Action) (() => - { - foreach (var item in _chamber.ContainedEntities.ToList()) - { - if (!item.HasTag("Grindable")) continue; - if (!item.TryGetComponent(out var solution)) continue; - if (_heldBeaker.CurrentVolume + solution.CurrentVolume > _heldBeaker.MaxVolume) continue; - _heldBeaker.TryAddSolution(solution.Solution); - solution.RemoveAllSolution(); - item.Delete(); - } - - _busy = false; - _uiDirty = true; - UserInterface?.SendMessage(new ReagentGrinderWorkCompleteMessage()); - })); - break; - - case GrinderProgram.Juice: - SoundSystem.Play(Filter.Pvs(Owner), "/Audio/Machines/juicer.ogg", Owner, AudioParams.Default); - Owner.SpawnTimer(_workTime, (Action) (() => - { - foreach (var item in _chamber.ContainedEntities.ToList()) - { - if (!item.TryGetComponent(out var juiceMe)) continue; - if (_heldBeaker.CurrentVolume + juiceMe.JuiceResultSolution.TotalVolume > _heldBeaker.MaxVolume) continue; - _heldBeaker.TryAddSolution(juiceMe.JuiceResultSolution); - item.Delete(); - } - UserInterface?.SendMessage(new ReagentGrinderWorkCompleteMessage()); - _busy = false; - _uiDirty = true; - })); - break; - } - } + [ViewVariables(VVAccess.ReadWrite)] [DataField("chamberCapacity")] public int StorageCap = 16; + [ViewVariables(VVAccess.ReadWrite)] [DataField("workTime")] public int WorkTime = 3500; //3.5 seconds, completely arbitrary for now. } } diff --git a/Content.Server/Kitchen/EntitySystems/ReagentGrinderSystem.cs b/Content.Server/Kitchen/EntitySystems/ReagentGrinderSystem.cs index 95f3dbe5f8..c58c5b32ee 100644 --- a/Content.Server/Kitchen/EntitySystems/ReagentGrinderSystem.cs +++ b/Content.Server/Kitchen/EntitySystems/ReagentGrinderSystem.cs @@ -1,19 +1,314 @@ -using Content.Server.Kitchen.Components; +using System; +using System.Collections.Generic; +using System.Linq; +using Content.Server.Chemistry.Components; +using Content.Server.Hands.Components; +using Content.Server.Items; +using Content.Server.Kitchen.Components; +using Content.Server.Power.Components; +using Content.Server.UserInterface; +using Content.Shared.Chemistry.Solution; +using Content.Shared.Interaction; +using Content.Shared.Kitchen.Components; +using Content.Shared.Notification.Managers; +using Content.Shared.Random.Helpers; +using Content.Shared.Tag; using JetBrains.Annotations; +using Robust.Server.GameObjects; +using Robust.Shared.Audio; +using Robust.Shared.Containers; using Robust.Shared.GameObjects; +using Robust.Shared.IoC; +using Robust.Shared.Localization; +using Robust.Shared.Player; +using Robust.Shared.Utility; namespace Content.Server.Kitchen.EntitySystems { [UsedImplicitly] internal sealed class ReagentGrinderSystem : EntitySystem { + [Dependency] private readonly IEntityManager _entityManager = default!; + + private Queue _uiUpdateQueue = new (); + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnComponentInit); + SubscribeLocalEvent((_, component, _) => EnqueueUiUpdate(component)); + SubscribeLocalEvent(OnInteractHand); + SubscribeLocalEvent(OnInteractUsing); + } + + private void OnInteractUsing(EntityUid uid, ReagentGrinderComponent component, InteractUsingEvent args) + { + if(args.Handled) return; + + if (!args.User.TryGetComponent(out IHandsComponent? hands)) + { + component.Owner.PopupMessage(args.User, Loc.GetString("reagent-grinder-component-interact-using-no-hands")); + args.Handled = true; + return; + } + + IEntity heldEnt = args.Used; + + //First, check if user is trying to insert a beaker. + //No promise it will be a beaker right now, but whatever. + //Maybe this should whitelist "beaker" in the prototype id of heldEnt? + if(heldEnt.TryGetComponent(out SolutionContainerComponent? beaker) && beaker.Capabilities.HasFlag(SolutionContainerCaps.FitsInDispenser)) + { + component.BeakerContainer.Insert(heldEnt); + component.HeldBeaker = beaker; + EnqueueUiUpdate(component); + //We are done, return. Insert the beaker and exit! + if (component.Owner.TryGetComponent(out AppearanceComponent? appearance)) + { + appearance.SetData(SharedReagentGrinderComponent.ReagentGrinderVisualState.BeakerAttached, component.BeakerContainer.ContainedEntity != null); + } + ClickSound(component); + args.Handled = true; + return; + } + + //Next, see if the user is trying to insert something they want to be ground/juiced. + if(!heldEnt.HasTag("Grindable") && !heldEnt.TryGetComponent(out JuiceableComponent? juice)) + { + //Entity did NOT pass the whitelist for grind/juice. + //Wouldn't want the clown grinding up the Captain's ID card now would you? + //Why am I asking you? You're biased. + return; + } + + //Cap the chamber. Don't want someone putting in 500 entities and ejecting them all at once. + //Maybe I should have done that for the microwave too? + if (component.Chamber.ContainedEntities.Count >= component.StorageCap) + { + return; + } + + if (!component.Chamber.Insert(heldEnt)) + { + return; + } + + EnqueueUiUpdate(component); + args.Handled = true; + } + + private void OnInteractHand(EntityUid uid, ReagentGrinderComponent component, InteractHandEvent args) + { + if (args.Handled) return; + + if (!args.User.TryGetComponent(out ActorComponent? actor)) + { + return; + } + EnqueueUiUpdate(component); + component.Owner.GetUIOrNull(SharedReagentGrinderComponent.ReagentGrinderUiKey.Key)?.Toggle(actor.PlayerSession); + args.Handled = true; + } + + private void EnqueueUiUpdate(ReagentGrinderComponent component) + { + if(!_uiUpdateQueue.Contains(component)) _uiUpdateQueue.Enqueue(component); + } + + private void OnComponentInit(EntityUid uid, ReagentGrinderComponent component, ComponentInit args) + { + EnqueueUiUpdate(component); + + //A slot for the beaker where the grounds/juices will go. + component.BeakerContainer = + ContainerHelpers.EnsureContainer(component.Owner, $"{component.Name}-reagentContainerContainer"); + + //A container for the things that WILL be ground/juiced. Useful for ejecting them instead of deleting them from the hands of the user. + component.Chamber = + ContainerHelpers.EnsureContainer(component.Owner, $"{component.Name}-entityContainerContainer"); + + var bui = component.Owner.GetUIOrNull(SharedReagentGrinderComponent.ReagentGrinderUiKey.Key); + if (bui != null) + { + bui.OnReceiveMessage += msg => OnUIMessageReceived(uid, component, msg); + } + } + + private void OnUIMessageReceived(EntityUid uid, ReagentGrinderComponent component, + ServerBoundUserInterfaceMessage message) + { + if(component.Busy) + { + return; + } + + switch(message.Message) + { + case SharedReagentGrinderComponent.ReagentGrinderGrindStartMessage msg: + if (!component.Owner.TryGetComponent(out ApcPowerReceiverComponent? receiver) || !receiver.Powered) break; + ClickSound(component); + DoWork(component, message.Session.AttachedEntity!, SharedReagentGrinderComponent.GrinderProgram.Grind); + break; + + case SharedReagentGrinderComponent.ReagentGrinderJuiceStartMessage msg: + if (!component.Owner.TryGetComponent(out ApcPowerReceiverComponent? receiver2) || !receiver2.Powered) break; + ClickSound(component); + DoWork(component, message.Session.AttachedEntity!, SharedReagentGrinderComponent.GrinderProgram.Juice); + break; + + case SharedReagentGrinderComponent.ReagentGrinderEjectChamberAllMessage msg: + if(component.Chamber.ContainedEntities.Count > 0) + { + ClickSound(component); + for (var i = component.Chamber.ContainedEntities.Count - 1; i >= 0; i--) + { + var entity = component.Chamber.ContainedEntities[i]; + component.Chamber.Remove(entity); + entity.RandomOffset(0.4f); + } + EnqueueUiUpdate(component); + } + break; + + case SharedReagentGrinderComponent.ReagentGrinderEjectChamberContentMessage msg: + if (component.Chamber.ContainedEntities.TryFirstOrDefault(x => x.Uid == msg.EntityID, out var ent)) + { + component.Chamber.Remove(ent); + ent.RandomOffset(0.4f); + EnqueueUiUpdate(component); + ClickSound(component); + } + break; + + case SharedReagentGrinderComponent.ReagentGrinderEjectBeakerMessage msg: + ClickSound(component); + EjectBeaker(component, message.Session.AttachedEntity); + EnqueueUiUpdate(component); + break; + } + } + public override void Update(float frameTime) { base.Update(frameTime); - foreach (var comp in ComponentManager.EntityQuery(true)) + + while (_uiUpdateQueue.TryDequeue(out var comp)) { - comp.OnUpdate(); + bool canJuice = false; + bool canGrind = false; + if (comp.BeakerContainer.ContainedEntity != null) + { + foreach (var entity in comp.Chamber.ContainedEntities) + { + if (!canJuice && entity.HasComponent()) canJuice = true; + if (!canGrind && entity.HasTag("Grindable")) canGrind = true; + if (canJuice && canGrind) break; + } + } + + comp.Owner.GetUIOrNull(SharedReagentGrinderComponent.ReagentGrinderUiKey.Key)?.SetState(new ReagentGrinderInterfaceState + ( + comp.Busy, + comp.BeakerContainer.ContainedEntity != null, + comp.Owner.TryGetComponent(out ApcPowerReceiverComponent? receiver) && receiver.Powered, + canJuice, + canGrind, + comp.Chamber.ContainedEntities.Select(item => item.Uid).ToArray(), + //Remember the beaker can be null! + comp.HeldBeaker?.Solution.Contents.ToArray() + )); } } + + /// + /// Tries to eject whatever is in the beaker slot. Puts the item in the user's hands or failing that on top + /// of the grinder. + /// + private void EjectBeaker(ReagentGrinderComponent component, IEntity? user) + { + if (component.BeakerContainer.ContainedEntity == null || component.HeldBeaker == null || component.Busy) + return; + + var beaker = component.BeakerContainer.ContainedEntity; + if(beaker is null) + return; + + component.BeakerContainer.Remove(beaker); + + if (user == null || !user.TryGetComponent(out var hands) || !component.HeldBeaker.Owner.TryGetComponent(out var item)) + return; + hands.PutInHandOrDrop(item); + + component.HeldBeaker = null; + EnqueueUiUpdate(component); + if (component.Owner.TryGetComponent(out AppearanceComponent? appearance)) + { + appearance.SetData(SharedReagentGrinderComponent.ReagentGrinderVisualState.BeakerAttached, component.BeakerContainer.ContainedEntity != null); + } + } + + /// + /// The wzhzhzh of the grinder. Processes the contents of the grinder and puts the output in the beaker. + /// + /// true for wanting to juice, false for wanting to grind. + private void DoWork(ReagentGrinderComponent component, IEntity user, SharedReagentGrinderComponent.GrinderProgram program) + { + //Have power, are we busy, chamber has anything to grind, a beaker for the grounds to go? + if(!component.Owner.TryGetComponent(out ApcPowerReceiverComponent? receiver) || !receiver.Powered || component.Busy || component.Chamber.ContainedEntities.Count <= 0 || component.BeakerContainer.ContainedEntity == null || component.HeldBeaker == null) + { + return; + } + + component.Busy = true; + + var bui = component.Owner.GetUIOrNull(SharedReagentGrinderComponent.ReagentGrinderUiKey.Key); + bui?.SendMessage(new SharedReagentGrinderComponent.ReagentGrinderWorkStartedMessage(program)); + switch (program) + { + case SharedReagentGrinderComponent.GrinderProgram.Grind: + SoundSystem.Play(Filter.Pvs(component.Owner), "/Audio/Machines/blender.ogg", component.Owner, AudioParams.Default); + //Get each item inside the chamber and get the reagents it contains. Transfer those reagents to the beaker, given we have one in. + component.Owner.SpawnTimer(component.WorkTime, (Action) (() => + { + foreach (var item in component.Chamber.ContainedEntities.ToList()) + { + if (!item.HasTag("Grindable")) continue; + if (!item.TryGetComponent(out var solution)) continue; + if (component.HeldBeaker.CurrentVolume + solution.CurrentVolume > component.HeldBeaker.MaxVolume) continue; + component.HeldBeaker.TryAddSolution(solution.Solution); + solution.RemoveAllSolution(); + item.Delete(); + } + + component.Busy = false; + EnqueueUiUpdate(component); + bui?.SendMessage(new SharedReagentGrinderComponent.ReagentGrinderWorkCompleteMessage()); + })); + break; + + case SharedReagentGrinderComponent.GrinderProgram.Juice: + SoundSystem.Play(Filter.Pvs(component.Owner), "/Audio/Machines/juicer.ogg", component.Owner, AudioParams.Default); + component.Owner.SpawnTimer(component.WorkTime, (Action) (() => + { + foreach (var item in component.Chamber.ContainedEntities.ToList()) + { + if (!item.TryGetComponent(out var juiceMe)) continue; + if (component.HeldBeaker.CurrentVolume + juiceMe.JuiceResultSolution.TotalVolume > component.HeldBeaker.MaxVolume) continue; + component.HeldBeaker.TryAddSolution(juiceMe.JuiceResultSolution); + item.Delete(); + } + bui?.SendMessage(new SharedReagentGrinderComponent.ReagentGrinderWorkCompleteMessage()); + component.Busy = false; + EnqueueUiUpdate(component); + })); + break; + } + } + + private void ClickSound(ReagentGrinderComponent component) + { + SoundSystem.Play(Filter.Pvs(component.Owner), "/Audio/Machines/machine_switch.ogg", component.Owner, AudioParams.Default.WithVolume(-2f)); + } } } diff --git a/Content.Shared/Kitchen/Components/SharedReagentGrinderComponent.cs b/Content.Shared/Kitchen/Components/SharedReagentGrinderComponent.cs index ca1eae6923..0effbe15db 100644 --- a/Content.Shared/Kitchen/Components/SharedReagentGrinderComponent.cs +++ b/Content.Shared/Kitchen/Components/SharedReagentGrinderComponent.cs @@ -51,16 +51,6 @@ namespace Content.Shared.Kitchen.Components } } - [Serializable, NetSerializable] - public class ReagentGrinderVaporizeReagentIndexedMessage : BoundUserInterfaceMessage - { - public Solution.ReagentQuantity ReagentQuantity; - public ReagentGrinderVaporizeReagentIndexedMessage(Solution.ReagentQuantity reagentQuantity) - { - ReagentQuantity = reagentQuantity; - } - } - [Serializable, NetSerializable] public class ReagentGrinderWorkStartedMessage : BoundUserInterfaceMessage { From 8ed1a9e19cc7badc262a3a5eb2620af05b1b2c45 Mon Sep 17 00:00:00 2001 From: Vera Aguilera Puerto Date: Thu, 29 Jul 2021 12:55:22 +0200 Subject: [PATCH 33/38] Add ButtonHelpers and the SetButtonDisabledRecursive helper. Fixes the mess from the other day. --- Content.Client/AME/UI/AMEWindow.xaml.cs | 3 +- .../Chemistry/UI/ChemMasterWindow.cs | 3 +- .../Chemistry/UI/ReagentDispenserWindow.cs | 3 +- Content.Client/UserInterface/ButtonHelpers.cs | 31 +++++++++++++++++++ 4 files changed, 37 insertions(+), 3 deletions(-) create mode 100644 Content.Client/UserInterface/ButtonHelpers.cs diff --git a/Content.Client/AME/UI/AMEWindow.xaml.cs b/Content.Client/AME/UI/AMEWindow.xaml.cs index c55a18efcf..90c345faf7 100644 --- a/Content.Client/AME/UI/AMEWindow.xaml.cs +++ b/Content.Client/AME/UI/AMEWindow.xaml.cs @@ -1,3 +1,4 @@ +using Content.Client.UserInterface; using Robust.Client.AutoGenerated; using Robust.Client.UserInterface; using Robust.Client.UserInterface.Controls; @@ -35,7 +36,7 @@ namespace Content.Client.AME.UI // Disable all buttons if not powered if (Contents.Children != null) { - SetButtonDisabledRecursive(Contents, !castState.HasPower); + ButtonHelpers.SetButtonDisabledRecursive(Contents, !castState.HasPower); EjectButton.Disabled = false; } diff --git a/Content.Client/Chemistry/UI/ChemMasterWindow.cs b/Content.Client/Chemistry/UI/ChemMasterWindow.cs index 1bd7b63202..5f3a895e35 100644 --- a/Content.Client/Chemistry/UI/ChemMasterWindow.cs +++ b/Content.Client/Chemistry/UI/ChemMasterWindow.cs @@ -1,6 +1,7 @@ using System; using System.Linq; using Content.Client.Stylesheets; +using Content.Client.UserInterface; using Content.Shared.Chemistry.Components; using Content.Shared.Chemistry.Reagent; using Robust.Client.Graphics; @@ -279,7 +280,7 @@ namespace Content.Client.Chemistry.UI UpdatePanelInfo(castState); if (Contents.Children != null) { - SetButtonDisabledRecursive(Contents, !castState.HasPower); + ButtonHelpers.SetButtonDisabledRecursive(Contents, !castState.HasPower); EjectButton.Disabled = !castState.HasBeaker; } } diff --git a/Content.Client/Chemistry/UI/ReagentDispenserWindow.cs b/Content.Client/Chemistry/UI/ReagentDispenserWindow.cs index 4dc65be1ad..34311fb74d 100644 --- a/Content.Client/Chemistry/UI/ReagentDispenserWindow.cs +++ b/Content.Client/Chemistry/UI/ReagentDispenserWindow.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using Content.Client.Stylesheets; +using Content.Client.UserInterface; using Content.Shared.Chemistry.Dispenser; using Content.Shared.Chemistry.Reagent; using Robust.Client.Graphics; @@ -186,7 +187,7 @@ namespace Content.Client.Chemistry.UI // Disable all buttons if not powered if (Contents.Children != null) { - SetButtonDisabledRecursive(Contents, !castState.HasPower); + ButtonHelpers.SetButtonDisabledRecursive(Contents, !castState.HasPower); EjectButton.Disabled = false; } diff --git a/Content.Client/UserInterface/ButtonHelpers.cs b/Content.Client/UserInterface/ButtonHelpers.cs new file mode 100644 index 0000000000..38abc8684c --- /dev/null +++ b/Content.Client/UserInterface/ButtonHelpers.cs @@ -0,0 +1,31 @@ +using Robust.Client.UserInterface; +using Robust.Client.UserInterface.Controls; + +namespace Content.Client.UserInterface +{ + public static class ButtonHelpers + { + /// + /// This searches recursively through all the children of "parent" + /// and sets the Disabled value of any buttons found to "val" + /// + /// The control which childrens get searched + /// The value to which disabled gets set + public static void SetButtonDisabledRecursive(Control parent, bool val) + { + foreach (var child in parent.Children) + { + if (child is Button but) + { + but.Disabled = val; + continue; + } + + if (child.ChildCount > 0) + { + SetButtonDisabledRecursive(child, val); + } + } + } + } +} From 9b42c1f69b1670537931a784f9a5201b557e20b8 Mon Sep 17 00:00:00 2001 From: Pieter-Jan Briers Date: Thu, 29 Jul 2021 13:06:18 +0200 Subject: [PATCH 34/38] Fix bad localization string in secret stash. --- Content.Server/Storage/Components/SecretStashComponent.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Content.Server/Storage/Components/SecretStashComponent.cs b/Content.Server/Storage/Components/SecretStashComponent.cs index b202ab19db..30af3865fc 100644 --- a/Content.Server/Storage/Components/SecretStashComponent.cs +++ b/Content.Server/Storage/Components/SecretStashComponent.cs @@ -81,7 +81,7 @@ namespace Content.Server.Storage.Components if (_itemContainer.ContainedEntity == null) return false; - Owner.PopupMessage(user, Loc.GetString("There was something inside {0}!", ("stash", SecretPartName))); + Owner.PopupMessage(user, Loc.GetString("comp-secret-stash-action-get-item-found-something", ("stash", SecretPartName))); if (user.TryGetComponent(out HandsComponent? hands)) { From 8c362fcd9b8065aa92bb684f7610fe4d4c74e5e9 Mon Sep 17 00:00:00 2001 From: Pieter-Jan Briers Date: Thu, 29 Jul 2021 16:55:09 +0200 Subject: [PATCH 35/38] Use non-directed event for powernet battery sync. Most of the CPU time in the power system was sending these events. --- .../Power/EntitySystems/BatterySystem.cs | 24 ++++++++++--------- .../Power/EntitySystems/PowerNetSystem.cs | 14 ++++------- 2 files changed, 17 insertions(+), 21 deletions(-) diff --git a/Content.Server/Power/EntitySystems/BatterySystem.cs b/Content.Server/Power/EntitySystems/BatterySystem.cs index 44126d6810..e97b007861 100644 --- a/Content.Server/Power/EntitySystems/BatterySystem.cs +++ b/Content.Server/Power/EntitySystems/BatterySystem.cs @@ -11,23 +11,25 @@ namespace Content.Server.Power.EntitySystems { base.Initialize(); - SubscribeLocalEvent(PreSync); - SubscribeLocalEvent(PostSync); + SubscribeLocalEvent(PreSync); + SubscribeLocalEvent(PostSync); } - private void PreSync(EntityUid uid, BatteryComponent component, NetworkBatteryPreSync args) + private void PreSync(NetworkBatteryPreSync ev) { - var networkBattery = ComponentManager.GetComponent(uid); - - networkBattery.NetworkBattery.Capacity = component.MaxCharge; - networkBattery.NetworkBattery.CurrentStorage = component.CurrentCharge; + foreach (var (bat, netBat) in ComponentManager.EntityQuery()) + { + netBat.NetworkBattery.Capacity = bat.MaxCharge; + netBat.NetworkBattery.CurrentStorage = bat.CurrentCharge; + } } - private void PostSync(EntityUid uid, BatteryComponent component, NetworkBatteryPostSync args) + private void PostSync(NetworkBatteryPostSync ev) { - var networkBattery = ComponentManager.GetComponent(uid); - - component.CurrentCharge = networkBattery.NetworkBattery.CurrentStorage; + foreach (var (bat, netBat) in ComponentManager.EntityQuery()) + { + bat.CurrentCharge = netBat.NetworkBattery.CurrentStorage; + } } public override void Update(float frameTime) diff --git a/Content.Server/Power/EntitySystems/PowerNetSystem.cs b/Content.Server/Power/EntitySystems/PowerNetSystem.cs index 3b7f81fb25..84b65289b5 100644 --- a/Content.Server/Power/EntitySystems/PowerNetSystem.cs +++ b/Content.Server/Power/EntitySystems/PowerNetSystem.cs @@ -175,19 +175,13 @@ namespace Content.Server.Power.EntitySystems } // Synchronize batteries - foreach (var battery in ComponentManager.EntityQuery()) - { - RaiseLocalEvent(battery.Owner.Uid, new NetworkBatteryPreSync()); - } + RaiseLocalEvent(new NetworkBatteryPreSync()); // Run power solver. _solver.Tick(frameTime, _powerState); // Synchronize batteries, the other way around. - foreach (var battery in ComponentManager.EntityQuery()) - { - RaiseLocalEvent(battery.Owner.Uid, new NetworkBatteryPostSync()); - } + RaiseLocalEvent(new NetworkBatteryPostSync()); // Send events where necessary. { @@ -313,7 +307,7 @@ namespace Content.Server.Power.EntitySystems /// Raised before power network simulation happens, to synchronize battery state from /// components like into . /// - public sealed class NetworkBatteryPreSync : EntityEventArgs + public struct NetworkBatteryPreSync { } @@ -321,7 +315,7 @@ namespace Content.Server.Power.EntitySystems /// Raised after power network simulation happens, to synchronize battery charge changes from /// to components like . /// - public sealed class NetworkBatteryPostSync : EntityEventArgs + public struct NetworkBatteryPostSync { } From f4769c00d7891a2dd428bb6ee153f77b20ff9805 Mon Sep 17 00:00:00 2001 From: Vera Aguilera Puerto Date: Fri, 30 Jul 2021 12:25:58 +0200 Subject: [PATCH 36/38] SubFloorHide requires entities to be anchored by default. --- Content.Shared/SubFloor/SubFloorHideComponent.cs | 9 +++++++++ Content.Shared/SubFloor/SubFloorHideSystem.cs | 16 ++++++++++++++-- SpaceStation14.sln.DotSettings | 2 ++ 3 files changed, 25 insertions(+), 2 deletions(-) diff --git a/Content.Shared/SubFloor/SubFloorHideComponent.cs b/Content.Shared/SubFloor/SubFloorHideComponent.cs index a76c73473e..93587e6f8c 100644 --- a/Content.Shared/SubFloor/SubFloorHideComponent.cs +++ b/Content.Shared/SubFloor/SubFloorHideComponent.cs @@ -1,4 +1,6 @@ using Robust.Shared.GameObjects; +using Robust.Shared.Serialization.Manager.Attributes; +using Robust.Shared.ViewVariables; namespace Content.Shared.SubFloor { @@ -13,5 +15,12 @@ namespace Content.Shared.SubFloor { /// public override string Name => "SubFloorHide"; + + /// + /// This entity needs to be anchored to be hid in the subfloor. + /// + [ViewVariables(VVAccess.ReadWrite)] + [DataField("requireAnchored")] + public bool RequireAnchored { get; set; } = true; } } diff --git a/Content.Shared/SubFloor/SubFloorHideSystem.cs b/Content.Shared/SubFloor/SubFloorHideSystem.cs index 5dd30a86a3..6f3f5bd9f2 100644 --- a/Content.Shared/SubFloor/SubFloorHideSystem.cs +++ b/Content.Shared/SubFloor/SubFloorHideSystem.cs @@ -68,8 +68,7 @@ namespace Content.Shared.SubFloor var transform = ComponentManager.GetComponent(uid); // We do this directly instead of calling UpdateEntity. - if(_mapManager.TryGetGrid(transform.GridID, out var grid)) - UpdateTile(grid, grid.TileIndicesFor(transform.Coordinates)); + UpdateEntity(uid); } private void MapManagerOnTileChanged(object? sender, TileChangedEventArgs e) @@ -113,6 +112,7 @@ namespace Content.Shared.SubFloor private void UpdateEntity(EntityUid uid) { var transform = ComponentManager.GetComponent(uid); + if (!_mapManager.TryGetGrid(transform.GridID, out var grid)) { // Not being on a grid counts as no subfloor, unhide this. @@ -134,6 +134,18 @@ namespace Content.Shared.SubFloor if (subFloorHideEvent.Handled) return; + // This might look weird, but basically we only need to query the SubFloorHide and Transform components + // if we are gonna hide the entity and we require it to be anchored to be hidden. Because getting components + // is "expensive", we have a slow path where we query them, and a fast path where we don't. + if (!subFloor + && ComponentManager.TryGetComponent(uid, out SubFloorHideComponent? subFloorHideComponent) && + subFloorHideComponent.RequireAnchored + && ComponentManager.TryGetComponent(uid, out ITransformComponent? transformComponent)) + { + // If we require the entity to be anchored but it's not, this will set subfloor to true, unhiding it. + subFloor = !transformComponent.Anchored; + } + // Show sprite if (ComponentManager.TryGetComponent(uid, out SharedSpriteComponent? spriteComponent)) { diff --git a/SpaceStation14.sln.DotSettings b/SpaceStation14.sln.DotSettings index 5ff7f8d1e5..692912bc33 100644 --- a/SpaceStation14.sln.DotSettings +++ b/SpaceStation14.sln.DotSettings @@ -264,6 +264,7 @@ True True True + True True True True @@ -284,6 +285,7 @@ True True True + True True True True From e256cb7bb0d9b1e57c03eb63ea423e424eb46a8e Mon Sep 17 00:00:00 2001 From: Vera Aguilera Puerto Date: Fri, 30 Jul 2021 14:00:14 +0200 Subject: [PATCH 37/38] Optimize atmos devices' appearance updating. --- .../GasDualPortVentPumpSystem.cs | 18 ++++++------- .../EntitySystems/GasPressurePumpSystem.cs | 17 +++++++------ .../EntitySystems/GasThermoMachineSystem.cs | 14 +++++------ .../Unary/EntitySystems/GasVentPumpSystem.cs | 18 ++++++------- .../EntitySystems/GasVentScrubberSystem.cs | 25 ++++++++----------- 5 files changed, 44 insertions(+), 48 deletions(-) diff --git a/Content.Server/Atmos/Piping/Binary/EntitySystems/GasDualPortVentPumpSystem.cs b/Content.Server/Atmos/Piping/Binary/EntitySystems/GasDualPortVentPumpSystem.cs index 24c03e399e..78205ef201 100644 --- a/Content.Server/Atmos/Piping/Binary/EntitySystems/GasDualPortVentPumpSystem.cs +++ b/Content.Server/Atmos/Piping/Binary/EntitySystems/GasDualPortVentPumpSystem.cs @@ -37,23 +37,23 @@ namespace Content.Server.Atmos.Piping.Binary.EntitySystems return; } - appearance?.SetData(VentPumpVisuals.State, VentPumpState.Off); - - if (!vent.Enabled) - return; - - if (!ComponentManager.TryGetComponent(uid, out NodeContainerComponent? nodeContainer)) - return; - - if (!nodeContainer.TryGetNode(vent.InletName, out PipeNode? inlet) + if (!vent.Enabled + || !ComponentManager.TryGetComponent(uid, out NodeContainerComponent? nodeContainer) + || !nodeContainer.TryGetNode(vent.InletName, out PipeNode? inlet) || !nodeContainer.TryGetNode(vent.OutletName, out PipeNode? outlet)) + { + appearance?.SetData(VentPumpVisuals.State, VentPumpState.Off); return; + } var environment = _atmosphereSystem.GetTileMixture(vent.Owner.Transform.Coordinates, true); // We're in an air-blocked tile... Do nothing. if (environment == null) + { + appearance?.SetData(VentPumpVisuals.State, VentPumpState.Off); return; + } if (vent.PumpDirection == VentPumpDirection.Releasing) { diff --git a/Content.Server/Atmos/Piping/Binary/EntitySystems/GasPressurePumpSystem.cs b/Content.Server/Atmos/Piping/Binary/EntitySystems/GasPressurePumpSystem.cs index dc38b4da76..3d2b9ca2ae 100644 --- a/Content.Server/Atmos/Piping/Binary/EntitySystems/GasPressurePumpSystem.cs +++ b/Content.Server/Atmos/Piping/Binary/EntitySystems/GasPressurePumpSystem.cs @@ -25,22 +25,23 @@ namespace Content.Server.Atmos.Piping.Binary.EntitySystems private void OnPumpUpdated(EntityUid uid, GasPressurePumpComponent pump, AtmosDeviceUpdateEvent args) { var appearance = pump.Owner.GetComponentOrNull(); - appearance?.SetData(PressurePumpVisuals.Enabled, false); - if (!pump.Enabled) - return; - - if (!ComponentManager.TryGetComponent(uid, out NodeContainerComponent? nodeContainer)) - return; - - if (!nodeContainer.TryGetNode(pump.InletName, out PipeNode? inlet) + if (!pump.Enabled + || !ComponentManager.TryGetComponent(uid, out NodeContainerComponent? nodeContainer) + || !nodeContainer.TryGetNode(pump.InletName, out PipeNode? inlet) || !nodeContainer.TryGetNode(pump.OutletName, out PipeNode? outlet)) + { + appearance?.SetData(PressurePumpVisuals.Enabled, false); return; + } var outputStartingPressure = outlet.Air.Pressure; if (MathHelper.CloseTo(pump.TargetPressure, outputStartingPressure)) + { + appearance?.SetData(PressurePumpVisuals.Enabled, false); return; // No need to pump gas if target has been reached. + } if (inlet.Air.TotalMoles > 0 && inlet.Air.Temperature > 0) { diff --git a/Content.Server/Atmos/Piping/Unary/EntitySystems/GasThermoMachineSystem.cs b/Content.Server/Atmos/Piping/Unary/EntitySystems/GasThermoMachineSystem.cs index f48aa149f5..8706a22156 100644 --- a/Content.Server/Atmos/Piping/Unary/EntitySystems/GasThermoMachineSystem.cs +++ b/Content.Server/Atmos/Piping/Unary/EntitySystems/GasThermoMachineSystem.cs @@ -27,16 +27,14 @@ namespace Content.Server.Atmos.Piping.Unary.EntitySystems private void OnThermoMachineUpdated(EntityUid uid, GasThermoMachineComponent thermoMachine, AtmosDeviceUpdateEvent args) { var appearance = thermoMachine.Owner.GetComponentOrNull(); - appearance?.SetData(ThermoMachineVisuals.Enabled, false); - if (!thermoMachine.Enabled) - return; - - if (!ComponentManager.TryGetComponent(uid, out NodeContainerComponent? nodeContainer)) - return; - - if (!nodeContainer.TryGetNode(thermoMachine.InletName, out PipeNode? inlet)) + if (!thermoMachine.Enabled + || !ComponentManager.TryGetComponent(uid, out NodeContainerComponent? nodeContainer) + || !nodeContainer.TryGetNode(thermoMachine.InletName, out PipeNode? inlet)) + { + appearance?.SetData(ThermoMachineVisuals.Enabled, false); return; + } var airHeatCapacity = _atmosphereSystem.GetHeatCapacity(inlet.Air); var combinedHeatCapacity = airHeatCapacity + thermoMachine.HeatCapacity; diff --git a/Content.Server/Atmos/Piping/Unary/EntitySystems/GasVentPumpSystem.cs b/Content.Server/Atmos/Piping/Unary/EntitySystems/GasVentPumpSystem.cs index f9af0231f6..a008cde4ca 100644 --- a/Content.Server/Atmos/Piping/Unary/EntitySystems/GasVentPumpSystem.cs +++ b/Content.Server/Atmos/Piping/Unary/EntitySystems/GasVentPumpSystem.cs @@ -36,22 +36,22 @@ namespace Content.Server.Atmos.Piping.Unary.EntitySystems return; } - appearance?.SetData(VentPumpVisuals.State, VentPumpState.Off); - - if (!vent.Enabled) - return; - - if (!ComponentManager.TryGetComponent(uid, out NodeContainerComponent? nodeContainer)) - return; - - if (!nodeContainer.TryGetNode(vent.InletName, out PipeNode? pipe)) + if (!vent.Enabled + || !ComponentManager.TryGetComponent(uid, out NodeContainerComponent? nodeContainer) + || !nodeContainer.TryGetNode(vent.InletName, out PipeNode? pipe)) + { + appearance?.SetData(VentPumpVisuals.State, VentPumpState.Off); return; + } var environment = _atmosphereSystem.GetTileMixture(vent.Owner.Transform.Coordinates, true); // We're in an air-blocked tile... Do nothing. if (environment == null) + { + appearance?.SetData(VentPumpVisuals.State, VentPumpState.Off); return; + } if (vent.PumpDirection == VentPumpDirection.Releasing) { diff --git a/Content.Server/Atmos/Piping/Unary/EntitySystems/GasVentScrubberSystem.cs b/Content.Server/Atmos/Piping/Unary/EntitySystems/GasVentScrubberSystem.cs index 190fd86228..9b6722411d 100644 --- a/Content.Server/Atmos/Piping/Unary/EntitySystems/GasVentScrubberSystem.cs +++ b/Content.Server/Atmos/Piping/Unary/EntitySystems/GasVentScrubberSystem.cs @@ -37,16 +37,13 @@ namespace Content.Server.Atmos.Piping.Unary.EntitySystems return; } - appearance?.SetData(ScrubberVisuals.State, ScrubberState.Off); - - if (!scrubber.Enabled) - return; - - if (!ComponentManager.TryGetComponent(uid, out NodeContainerComponent? nodeContainer)) - return; - - if (!nodeContainer.TryGetNode(scrubber.OutletName, out PipeNode? outlet)) + if (!scrubber.Enabled + || !ComponentManager.TryGetComponent(uid, out NodeContainerComponent? nodeContainer) + || !nodeContainer.TryGetNode(scrubber.OutletName, out PipeNode? outlet)) + { + appearance?.SetData(ScrubberVisuals.State, ScrubberState.Off); return; + } var environment = _atmosphereSystem.GetTileMixture(scrubber.Owner.Transform.Coordinates, true); @@ -72,12 +69,12 @@ namespace Content.Server.Atmos.Piping.Unary.EntitySystems private void Scrub(AtmosphereSystem atmosphereSystem, GasVentScrubberComponent scrubber, AppearanceComponent? appearance, GasMixture? tile, PipeNode outlet) { // Cannot scrub if tile is null or air-blocked. - if (tile == null) - return; - - // Cannot scrub if pressure too high. - if (outlet.Air.Pressure >= 50 * Atmospherics.OneAtmosphere) + if (tile == null + || outlet.Air.Pressure >= 50 * Atmospherics.OneAtmosphere) // Cannot scrub if pressure too high. + { + appearance?.SetData(ScrubberVisuals.State, ScrubberState.Off); return; + } if (scrubber.PumpDirection == ScrubberPumpDirection.Scrubbing) { From 898bdc949149554d5f9e7cd95bfd08a5744cb451 Mon Sep 17 00:00:00 2001 From: Galactic Chimp <63882831+GalacticChimp@users.noreply.github.com> Date: Fri, 30 Jul 2021 19:22:06 +0200 Subject: [PATCH 38/38] #4420 Replaced SecureEntityStorageComp with LockComponent (new ECS) (#4228) * #4420 moved sound components to a better spot in the project * MWF-4420 - ported SecureEntityStorageComponent to new ECS system, as a LockComponent * MWF-4420 - removed unused usings * #4420 removed dumb ToggleLockVerb override workaround * #4420 added SoundSpecifier to LockComponent --- Content.Client/Entry/IgnoredComponents.cs | 1 + .../Storage/Visualizers/StorageVisualizer.cs | 2 +- Content.Server/Lock/LockComponent.cs | 64 ++++++++ Content.Server/Lock/LockSystem.cs | 116 ++++++++++++++ .../Components/EntityStorageComponent.cs | 18 ++- .../SecureEntityStorageComponent.cs | 148 ------------------ .../Locale/en-US/lock/lock-component.ftl | 10 ++ .../secure-entity-storage-component.ftl | 6 - .../Storage/Closets/Lockers/base.yml | 2 +- .../Structures/Storage/Crates/crates.yml | 18 +-- 10 files changed, 215 insertions(+), 170 deletions(-) create mode 100644 Content.Server/Lock/LockComponent.cs create mode 100644 Content.Server/Lock/LockSystem.cs delete mode 100644 Content.Server/Storage/Components/SecureEntityStorageComponent.cs create mode 100644 Resources/Locale/en-US/lock/lock-component.ftl delete mode 100644 Resources/Locale/en-US/storage/components/secure-entity-storage-component.ftl diff --git a/Content.Client/Entry/IgnoredComponents.cs b/Content.Client/Entry/IgnoredComponents.cs index 805c620ea0..f5d976796d 100644 --- a/Content.Client/Entry/IgnoredComponents.cs +++ b/Content.Client/Entry/IgnoredComponents.cs @@ -92,6 +92,7 @@ namespace Content.Client.Entry "ExaminableBattery", "PottedPlantHide", "SecureEntityStorage", + "Lock", "PresetIdCard", "SolarControlConsole", "FlashOnTrigger", diff --git a/Content.Client/Storage/Visualizers/StorageVisualizer.cs b/Content.Client/Storage/Visualizers/StorageVisualizer.cs index 7b7aaf28c4..43a8df5684 100644 --- a/Content.Client/Storage/Visualizers/StorageVisualizer.cs +++ b/Content.Client/Storage/Visualizers/StorageVisualizer.cs @@ -1,4 +1,4 @@ -using Content.Shared.Storage; +using Content.Shared.Storage; using JetBrains.Annotations; using Robust.Client.GameObjects; using Robust.Shared.GameObjects; diff --git a/Content.Server/Lock/LockComponent.cs b/Content.Server/Lock/LockComponent.cs new file mode 100644 index 0000000000..966548e607 --- /dev/null +++ b/Content.Server/Lock/LockComponent.cs @@ -0,0 +1,64 @@ +using Content.Server.Lock; +using Content.Shared.ActionBlocker; +using Content.Shared.Interaction; +using Content.Shared.Interaction.Helpers; +using Content.Shared.Sound; +using Content.Shared.Verbs; +using Robust.Shared.GameObjects; +using Robust.Shared.Localization; +using Robust.Shared.Serialization.Manager.Attributes; +using Robust.Shared.ViewVariables; + +namespace Content.Server.Storage.Components +{ + /// + /// Allows locking/unlocking, with access determined by AccessReader + /// + [RegisterComponent] + public class LockComponent : Component + { + public override string Name => "Lock"; + + [ViewVariables(VVAccess.ReadWrite)] [DataField("locked")] public bool Locked { get; set; } = true; + [ViewVariables(VVAccess.ReadWrite)] [DataField("unlockingSound")] public SoundSpecifier? UnlockSound { get; set; } = new SoundPathSpecifier("/Audio/Machines/door_lock_off.ogg"); + [ViewVariables(VVAccess.ReadWrite)] [DataField("lockingSound")] public SoundSpecifier? LockSound { get; set; } = new SoundPathSpecifier("/Audio/Machines/door_lock_off.ogg"); + + [Verb] + private sealed class ToggleLockVerb : Verb + { + protected override void GetData(IEntity user, LockComponent component, VerbData data) + { + if (!EntitySystem.Get().CanInteract(user) || + component.Owner.TryGetComponent(out EntityStorageComponent? entityStorageComponent) && entityStorageComponent.Open) + { + data.Visibility = VerbVisibility.Invisible; + return; + } + + data.Text = Loc.GetString(component.Locked ? "toggle-lock-verb-unlock" : "toggle-lock-verb-lock"); + } + + protected override void Activate(IEntity user, LockComponent component) + { + // Do checks + if (!EntitySystem.Get().CanInteract(user) || + !user.InRangeUnobstructed(component)) + { + return; + } + + // Call relevant entity system + var lockSystem = user.EntityManager.EntitySysManager.GetEntitySystem(); + var eventData = new ActivateInWorldEvent(user, component.Owner); + if (component.Locked) + { + lockSystem.DoUnlock(component, eventData); + } + else + { + lockSystem.DoLock(component, eventData); + } + } + } + } +} diff --git a/Content.Server/Lock/LockSystem.cs b/Content.Server/Lock/LockSystem.cs new file mode 100644 index 0000000000..063ac1656a --- /dev/null +++ b/Content.Server/Lock/LockSystem.cs @@ -0,0 +1,116 @@ +using Content.Server.Access.Components; +using Content.Server.Storage.Components; +using Content.Shared.Examine; +using Content.Shared.Interaction; +using Content.Shared.Notification.Managers; +using Content.Shared.Storage; +using JetBrains.Annotations; +using Robust.Server.GameObjects; +using Robust.Shared.Audio; +using Robust.Shared.GameObjects; +using Robust.Shared.Localization; +using Robust.Shared.Player; + +namespace Content.Server.Lock +{ + /// + /// Handles (un)locking and examining of Lock components + /// + [UsedImplicitly] + public class LockSystem : EntitySystem + { + /// + public override void Initialize() + { + base.Initialize(); + SubscribeLocalEvent(OnStartup); + SubscribeLocalEvent(OnActivated); + SubscribeLocalEvent(OnExamined); + } + + private void OnStartup(EntityUid eUI, LockComponent lockComp, ComponentStartup args) + { + if (lockComp.Owner.TryGetComponent(out AppearanceComponent? appearance)) + { + appearance.SetData(StorageVisuals.CanLock, true); + } + } + + private void OnActivated(EntityUid eUI, LockComponent lockComp, ActivateInWorldEvent args) + { + // Only attempt an unlock by default on Activate + if (lockComp.Locked) + { + DoUnlock(lockComp, args); + } + } + + private void OnExamined(EntityUid eUI, LockComponent lockComp, ExaminedEvent args) + { + args.Message.AddText("\n"); + args.Message.AddText(Loc.GetString(lockComp.Locked + ? "lock-comp-on-examined-is-locked" + : "lock-comp-on-examined-is-unlocked", + ("entityName", lockComp.Owner.Name))); + } + + public void DoLock(LockComponent lockComp, ActivateInWorldEvent args) + { + if (!HasUserAccess(lockComp, args.User)) + { + return; + } + + lockComp.Owner.PopupMessage(args.User, Loc.GetString("lock-comp-do-lock-success", ("entityName",lockComp.Owner.Name))); + lockComp.Locked = true; + if(lockComp.LockSound != null) + { + SoundSystem.Play(Filter.Pvs(lockComp.Owner), lockComp.LockSound.GetSound(), lockComp.Owner, AudioParams.Default.WithVolume(-5)); + } + + if (lockComp.Owner.TryGetComponent(out AppearanceComponent? appearanceComp)) + { + appearanceComp.SetData(StorageVisuals.Locked, true); + } + + args.Handled = true; + } + + public void DoUnlock(LockComponent lockComp, ActivateInWorldEvent args ) + { + if (!HasUserAccess(lockComp, args.User)) + { + return; + } + + lockComp.Owner.PopupMessage(args.User, Loc.GetString("lock-comp-do-unlock-success", ("entityName", lockComp.Owner.Name))); + lockComp.Locked = false; + if(lockComp.UnlockSound != null) + { + SoundSystem.Play(Filter.Pvs(lockComp.Owner), lockComp.UnlockSound.GetSound(), lockComp.Owner, AudioParams.Default.WithVolume(-5)); + } + + if (lockComp.Owner.TryGetComponent(out AppearanceComponent? appearanceComp)) + { + appearanceComp.SetData(StorageVisuals.Locked, false); + } + + // To stop EntityStorageComponent from opening right after the container gets unlocked + args.Handled = true; + } + + private static bool HasUserAccess(LockComponent lockComp, IEntity user) + { + if (lockComp.Owner.TryGetComponent(out AccessReader? reader)) + { + if (!reader.IsAllowed(user)) + { + lockComp.Owner.PopupMessage(user, Loc.GetString("lock-comp-has-user-access-fail")); + return false; + } + } + + return true; + } + } +} diff --git a/Content.Server/Storage/Components/EntityStorageComponent.cs b/Content.Server/Storage/Components/EntityStorageComponent.cs index 5face20f31..cbe6f9affd 100644 --- a/Content.Server/Storage/Components/EntityStorageComponent.cs +++ b/Content.Server/Storage/Components/EntityStorageComponent.cs @@ -24,7 +24,6 @@ using Robust.Shared.IoC; using Robust.Shared.Localization; using Robust.Shared.Maths; using Robust.Shared.Physics; -using Robust.Shared.Physics.Broadphase; using Robust.Shared.Player; using Robust.Shared.Serialization.Manager.Attributes; using Robust.Shared.Timing; @@ -131,7 +130,8 @@ namespace Content.Server.Storage.Components private bool _beingWelded; [ViewVariables(VVAccess.ReadWrite)] - public bool CanWeldShut { + public bool CanWeldShut + { get => _canWeldShut; set { @@ -160,6 +160,13 @@ namespace Content.Server.Storage.Components public virtual void Activate(ActivateEventArgs eventArgs) { + // HACK until EntityStorageComponent gets refactored to the new ECS system + if (Owner.TryGetComponent(out var @lock) && @lock.Locked) + { + // Do nothing, LockSystem is responsible for handling this case + return; + } + ToggleOpen(eventArgs.User); } @@ -167,7 +174,7 @@ namespace Content.Server.Storage.Components { if (IsWeldedShut) { - if(!silent) Owner.PopupMessage(user, Loc.GetString("entity-storage-component-welded-shut-message")); + if (!silent) Owner.PopupMessage(user, Loc.GetString("entity-storage-component-welded-shut-message")); return false; } return true; @@ -465,7 +472,8 @@ namespace Content.Server.Storage.Components protected virtual void OpenVerbGetData(IEntity user, EntityStorageComponent component, VerbData data) { - if (!EntitySystem.Get().CanInteract(user)) + if (!EntitySystem.Get().CanInteract(user) || + component.Owner.TryGetComponent(out LockComponent? lockComponent) && lockComponent.Locked) // HACK extra check, until EntityStorage gets refactored { data.Visibility = VerbVisibility.Invisible; return; @@ -475,7 +483,7 @@ namespace Content.Server.Storage.Components { data.Visibility = VerbVisibility.Disabled; var verb = Loc.GetString(component.Open ? "open-toggle-verb-close" : "open-toggle-verb-open"); - data.Text = Loc.GetString("open-toggle-verb-welded-shut-message",("verb", verb)); + data.Text = Loc.GetString("open-toggle-verb-welded-shut-message", ("verb", verb)); return; } diff --git a/Content.Server/Storage/Components/SecureEntityStorageComponent.cs b/Content.Server/Storage/Components/SecureEntityStorageComponent.cs deleted file mode 100644 index 5dcaf78cf4..0000000000 --- a/Content.Server/Storage/Components/SecureEntityStorageComponent.cs +++ /dev/null @@ -1,148 +0,0 @@ -using Content.Server.Access.Components; -using Content.Shared.ActionBlocker; -using Content.Shared.Interaction; -using Content.Shared.Interaction.Events; -using Content.Shared.Notification.Managers; -using Content.Shared.Storage; -using Content.Shared.Verbs; -using Robust.Server.GameObjects; -using Robust.Shared.Audio; -using Robust.Shared.GameObjects; -using Robust.Shared.Localization; -using Robust.Shared.Player; -using Robust.Shared.Serialization.Manager.Attributes; -using Robust.Shared.ViewVariables; - -namespace Content.Server.Storage.Components -{ - [RegisterComponent] - [ComponentReference(typeof(EntityStorageComponent))] - [ComponentReference(typeof(IActivate))] - [ComponentReference(typeof(IStorageComponent))] - public class SecureEntityStorageComponent : EntityStorageComponent - { - public override string Name => "SecureEntityStorage"; - [DataField("locked")] - private bool _locked = true; - - [ViewVariables(VVAccess.ReadWrite)] - public bool Locked - { - get => _locked; - set - { - _locked = value; - - if (Owner.TryGetComponent(out AppearanceComponent? appearance)) - { - appearance.SetData(StorageVisuals.Locked, _locked); - } - } - } - - protected override void Startup() - { - base.Startup(); - - if (Owner.TryGetComponent(out AppearanceComponent? appearance)) - { - appearance.SetData(StorageVisuals.CanLock, true); - } - } - - public override void Activate(ActivateEventArgs eventArgs) - { - if (Locked) - { - DoToggleLock(eventArgs.User); - return; - } - - base.Activate(eventArgs); - } - - public override bool CanOpen(IEntity user, bool silent = false) - { - if (Locked) - { - Owner.PopupMessage(user, "It's locked!"); - return false; - } - return base.CanOpen(user, silent); - } - - protected override void OpenVerbGetData(IEntity user, EntityStorageComponent component, VerbData data) - { - if (Locked) - { - data.Visibility = VerbVisibility.Invisible; - - return; - } - - base.OpenVerbGetData(user, component, data); - } - - private void DoToggleLock(IEntity user) - { - if (Locked) - { - DoUnlock(user); - } - else - { - DoLock(user); - } - } - - private void DoUnlock(IEntity user) - { - if (!CheckAccess(user)) return; - - Locked = false; - SoundSystem.Play(Filter.Pvs(Owner), "/Audio/Machines/door_lock_off.ogg", Owner, AudioParams.Default.WithVolume(-5)); - } - - private void DoLock(IEntity user) - { - if (!CheckAccess(user)) return; - - Locked = true; - SoundSystem.Play(Filter.Pvs(Owner), "/Audio/Machines/door_lock_on.ogg", Owner, AudioParams.Default.WithVolume(-5)); - } - - private bool CheckAccess(IEntity user) - { - if (Owner.TryGetComponent(out AccessReader? reader)) - { - if (!reader.IsAllowed(user)) - { - Owner.PopupMessage(user, Loc.GetString("secure-entity-storage-component-not-allowed-message")); - return false; - } - } - - return true; - } - - [Verb] - private sealed class ToggleLockVerb : Verb - { - protected override void GetData(IEntity user, SecureEntityStorageComponent component, VerbData data) - { - if (!EntitySystem.Get().CanInteract(user) || component.Open) - { - data.Visibility = VerbVisibility.Invisible; - return; - } - - data.Text = Loc.GetString(component.Locked ? "toggle-lock-verb-unlock" : "toggle-lock-verb-lock"); - } - - protected override void Activate(IEntity user, SecureEntityStorageComponent component) - { - component.DoToggleLock(user); - } - } - } -} diff --git a/Resources/Locale/en-US/lock/lock-component.ftl b/Resources/Locale/en-US/lock/lock-component.ftl new file mode 100644 index 0000000000..f9f975c96e --- /dev/null +++ b/Resources/Locale/en-US/lock/lock-component.ftl @@ -0,0 +1,10 @@ +lock-comp-on-examined-is-locked = The {$entityName} seems to be locked. +lock-comp-on-examined-is-unlocked = The {$entityName} seems to be unlocked. +lock-comp-do-lock-success = You lock the {$entityName}. +lock-comp-do-unlock-success = You unlock the {$entityName}. +lock-comp-has-user-access-fail = Access denied + +## ToggleLockVerb + +toggle-lock-verb-unlock = Unlock +toggle-lock-verb-lock = Lock \ No newline at end of file diff --git a/Resources/Locale/en-US/storage/components/secure-entity-storage-component.ftl b/Resources/Locale/en-US/storage/components/secure-entity-storage-component.ftl deleted file mode 100644 index 02082f2dcc..0000000000 --- a/Resources/Locale/en-US/storage/components/secure-entity-storage-component.ftl +++ /dev/null @@ -1,6 +0,0 @@ -secure-entity-storage-component-not-allowed-message = Access denied - -## ToggleLockVerb - -toggle-lock-verb-unlock = Unlock -toggle-lock-verb-lock = Lock \ No newline at end of file diff --git a/Resources/Prototypes/Entities/Structures/Storage/Closets/Lockers/base.yml b/Resources/Prototypes/Entities/Structures/Storage/Closets/Lockers/base.yml index 1b33400a9f..a8fe9b1a7e 100644 --- a/Resources/Prototypes/Entities/Structures/Storage/Closets/Lockers/base.yml +++ b/Resources/Prototypes/Entities/Structures/Storage/Closets/Lockers/base.yml @@ -4,7 +4,7 @@ abstract: true components: - type: AccessReader - - type: SecureEntityStorage + - type: Lock - type: Sprite netsync: false sprite: Structures/Storage/closet.rsi diff --git a/Resources/Prototypes/Entities/Structures/Storage/Crates/crates.yml b/Resources/Prototypes/Entities/Structures/Storage/Crates/crates.yml index dae7bc4c1c..70e4f09b5d 100644 --- a/Resources/Prototypes/Entities/Structures/Storage/Crates/crates.yml +++ b/Resources/Prototypes/Entities/Structures/Storage/Crates/crates.yml @@ -261,7 +261,7 @@ components: - type: AccessReader access: [["Security"]] - - type: SecureEntityStorage + - type: Lock - type: Sprite sprite: Structures/Storage/Crates/sec_gear.rsi layers: @@ -290,7 +290,7 @@ components: - type: AccessReader access: [["Engineering"]] - - type: SecureEntityStorage + - type: Lock - type: Sprite sprite: Structures/Storage/Crates/engicrate_secure.rsi layers: @@ -319,7 +319,7 @@ components: - type: AccessReader access: [["Medical"]] - - type: SecureEntityStorage + - type: Lock - type: Sprite sprite: Structures/Storage/Crates/medicalcrate_secure.rsi layers: @@ -347,7 +347,7 @@ parent: CrateGeneric components: - type: AccessReader - - type: SecureEntityStorage + - type: Lock - type: Sprite sprite: Structures/Storage/Crates/privatecrate_secure.rsi layers: @@ -376,7 +376,7 @@ components: - type: AccessReader access: [["Research"]] - - type: SecureEntityStorage + - type: Lock - type: Sprite sprite: Structures/Storage/Crates/scicrate_secure.rsi layers: @@ -405,7 +405,7 @@ components: - type: AccessReader access: [["Engineering"]] - - type: SecureEntityStorage + - type: Lock - type: Sprite sprite: Structures/Storage/Crates/plasma.rsi layers: @@ -433,7 +433,7 @@ parent: CrateGeneric components: - type: AccessReader - - type: SecureEntityStorage + - type: Lock - type: Sprite sprite: Structures/Storage/Crates/secure.rsi layers: @@ -462,7 +462,7 @@ components: - type: AccessReader access: [["Service"]] - - type: SecureEntityStorage + - type: Lock - type: Sprite sprite: Structures/Storage/Crates/hydro_secure.rsi layers: @@ -491,7 +491,7 @@ components: - type: AccessReader access: [["Security"]] - - type: SecureEntityStorage + - type: Lock - type: Sprite sprite: Structures/Storage/Crates/weapon.rsi layers: