diff --git a/Content.Client/Construction/ConstructionMenu.cs b/Content.Client/Construction/ConstructionMenu.cs index 12e919752c..7ae220d099 100644 --- a/Content.Client/Construction/ConstructionMenu.cs +++ b/Content.Client/Construction/ConstructionMenu.cs @@ -1,8 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; -using Content.Client.GameObjects.Components.Construction; -using Content.Client.Interfaces.GameObjects; +using Content.Client.GameObjects.EntitySystems; using Content.Shared.Construction; using Content.Shared.GameObjects.Components.Interactable; using Robust.Client.Graphics; @@ -14,7 +13,7 @@ using Robust.Client.UserInterface.Controls; using Robust.Client.UserInterface.CustomControls; using Robust.Client.Utility; using Robust.Shared.Enums; -using Robust.Shared.Interfaces.GameObjects.Components; +using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.IoC; using Robust.Shared.Maths; using Robust.Shared.Prototypes; @@ -24,11 +23,11 @@ namespace Content.Client.Construction public class ConstructionMenu : SS14Window { #pragma warning disable CS0649 - [Dependency] readonly IPrototypeManager PrototypeManager; - [Dependency] readonly IResourceCache ResourceCache; + [Dependency] private readonly IPrototypeManager _prototypeManager; + [Dependency] private readonly IResourceCache _resourceCache; + [Dependency] private readonly IEntitySystemManager _systemManager; #pragma warning restore - public ConstructorComponent Owner { get; set; } private readonly Button BuildButton; private readonly Button EraseButton; private readonly LineEdit SearchBar; @@ -118,6 +117,7 @@ namespace Content.Client.Construction PopulateTree(); } + /// protected override void Dispose(bool disposing) { base.Dispose(disposing); @@ -128,7 +128,7 @@ namespace Content.Client.Construction } } - void OnItemSelected() + private void OnItemSelected() { var prototype = (ConstructionPrototype) RecipeList.Selected.Metadata; @@ -162,17 +162,17 @@ namespace Content.Client.Construction switch (mat.Material) { case ConstructionStepMaterial.MaterialType.Metal: - icon = ResourceCache.GetResource( + icon = _resourceCache.GetResource( "/Textures/Objects/Materials/sheet_metal.png"); text = $"Metal x{mat.Amount}"; break; case ConstructionStepMaterial.MaterialType.Glass: - icon = ResourceCache.GetResource( + icon = _resourceCache.GetResource( "/Textures/Objects/Materials/sheet_glass.png"); text = $"Glass x{mat.Amount}"; break; case ConstructionStepMaterial.MaterialType.Cable: - icon = ResourceCache.GetResource( + icon = _resourceCache.GetResource( "/Textures/Objects/Tools/cable_coil.png"); text = $"Cable Coil x{mat.Amount}"; break; @@ -185,25 +185,25 @@ namespace Content.Client.Construction switch (tool.ToolQuality) { case ToolQuality.Anchoring: - icon = ResourceCache.GetResource("/Textures/Objects/Tools/wrench.png"); + icon = _resourceCache.GetResource("/Textures/Objects/Tools/wrench.png"); text = "Wrench"; break; case ToolQuality.Prying: - icon = ResourceCache.GetResource("/Textures/Objects/Tools/crowbar.png"); + icon = _resourceCache.GetResource("/Textures/Objects/Tools/crowbar.png"); text = "Crowbar"; break; case ToolQuality.Screwing: - icon = ResourceCache.GetResource( + icon = _resourceCache.GetResource( "/Textures/Objects/Tools/screwdriver.png"); text = "Screwdriver"; break; case ToolQuality.Welding: - icon = ResourceCache.GetResource("/Textures/Objects/tools.rsi") + icon = _resourceCache.GetResource("/Textures/Objects/tools.rsi") .RSI["welder"].Frame0; text = $"Welding tool ({tool.Amount} fuel)"; break; case ToolQuality.Cutting: - icon = ResourceCache.GetResource( + icon = _resourceCache.GetResource( "/Textures/Objects/Tools/wirecutter.png"); text = "Wirecutters"; break; @@ -221,13 +221,13 @@ namespace Content.Client.Construction } } - void OnTextEntered(LineEdit.LineEditEventArgs args) + private void OnTextEntered(LineEdit.LineEditEventArgs args) { var str = args.Text; PopulateTree(string.IsNullOrWhiteSpace(str) ? null : str.ToLowerInvariant()); } - void OnBuildToggled(BaseButton.ButtonToggledEventArgs args) + private void OnBuildToggled(BaseButton.ButtonToggledEventArgs args) { if (args.Pressed) { @@ -239,7 +239,8 @@ namespace Content.Client.Construction if (prototype.Type == ConstructionType.Item) { - Owner.TryStartItemConstruction(prototype.ID); + var constructSystem = _systemManager.GetEntitySystem(); + constructSystem.TryStartItemConstruction(prototype.ID); BuildButton.Pressed = false; return; } @@ -250,7 +251,7 @@ namespace Content.Client.Construction IsTile = false, PlacementOption = prototype.PlacementMode }, - new ConstructionPlacementHijack(prototype, Owner)); + new ConstructionPlacementHijack(_systemManager.GetEntitySystem(), prototype)); } else { @@ -262,7 +263,7 @@ namespace Content.Client.Construction private void OnEraseToggled(BaseButton.ButtonToggledEventArgs args) { if (args.Pressed) Placement.Clear(); - Placement.ToggleEraserHijacked(new ConstructionPlacementHijack(null, Owner)); + Placement.ToggleEraserHijacked(new ConstructionPlacementHijack(_systemManager.GetEntitySystem(), null)); EraseButton.Pressed = args.Pressed; } @@ -272,12 +273,12 @@ namespace Content.Client.Construction EraseButton.Pressed = false; } - void PopulatePrototypeList() + private void PopulatePrototypeList() { RootCategory = new CategoryNode("", null); - int count = 1; + var count = 1; - foreach (var prototype in PrototypeManager.EnumeratePrototypes()) + foreach (var prototype in _prototypeManager.EnumeratePrototypes()) { var currentNode = RootCategory; @@ -316,7 +317,7 @@ namespace Content.Client.Construction Recurse(RootCategory); } - void PopulateTree(string searchTerm = null) + private void PopulateTree(string searchTerm = null) { RecipeList.Clear(); @@ -378,18 +379,18 @@ namespace Content.Client.Construction private static int ComparePrototype(ConstructionPrototype x, ConstructionPrototype y) { - return String.Compare(x.Name, y.Name, StringComparison.Ordinal); + return string.Compare(x.Name, y.Name, StringComparison.Ordinal); } - class CategoryNode + private class CategoryNode { public readonly string Name; public readonly CategoryNode Parent; - public SortedDictionary + public readonly SortedDictionary ChildCategories = new SortedDictionary(); - public List Prototypes = new List(); + public readonly List Prototypes = new List(); public int FlattenedIndex = -1; public CategoryNode(string name, CategoryNode parent) diff --git a/Content.Client/Construction/ConstructionPlacementHijack.cs b/Content.Client/Construction/ConstructionPlacementHijack.cs index 5a4f56859f..57f5503dbc 100644 --- a/Content.Client/Construction/ConstructionPlacementHijack.cs +++ b/Content.Client/Construction/ConstructionPlacementHijack.cs @@ -1,49 +1,51 @@ -using Content.Client.GameObjects.Components.Construction; +using Content.Client.GameObjects.Components.Construction; +using Content.Client.GameObjects.EntitySystems; using Content.Shared.Construction; -using Robust.Client.Interfaces.ResourceManagement; using Robust.Client.Placement; using Robust.Client.Utility; using Robust.Shared.Interfaces.GameObjects; -using Robust.Shared.IoC; using Robust.Shared.Map; namespace Content.Client.Construction { public class ConstructionPlacementHijack : PlacementHijack { - private readonly ConstructionPrototype Prototype; - private readonly ConstructorComponent Owner; + private readonly ConstructionSystem _constructionSystem; + private readonly ConstructionPrototype _prototype; - public ConstructionPlacementHijack(ConstructionPrototype prototype, ConstructorComponent owner) + public ConstructionPlacementHijack(ConstructionSystem constructionSystem, ConstructionPrototype prototype) { - Prototype = prototype; - Owner = owner; + _constructionSystem = constructionSystem; + _prototype = prototype; } + /// public override bool HijackPlacementRequest(GridCoordinates coords) { - if (Prototype != null) + if (_prototype != null) { var dir = Manager.Direction; - Owner.SpawnGhost(Prototype, coords, dir); + _constructionSystem.SpawnGhost(_prototype, coords, dir); } return true; } + /// public override bool HijackDeletion(IEntity entity) { if (entity.TryGetComponent(out ConstructionGhostComponent ghost)) { - Owner.ClearGhost(ghost.GhostID); + _constructionSystem.ClearGhost(ghost.GhostID); } return true; } + /// public override void StartHijack(PlacementManager manager) { base.StartHijack(manager); - manager.CurrentBaseSprite = Prototype.Icon.DirFrame0(); + manager.CurrentBaseSprite = _prototype.Icon.DirFrame0(); } } } diff --git a/Content.Client/GameObjects/Components/Construction/ConstructionGhostComponent.cs b/Content.Client/GameObjects/Components/Construction/ConstructionGhostComponent.cs index 0bfc7a274e..17cbb51629 100644 --- a/Content.Client/GameObjects/Components/Construction/ConstructionGhostComponent.cs +++ b/Content.Client/GameObjects/Components/Construction/ConstructionGhostComponent.cs @@ -10,7 +10,6 @@ namespace Content.Client.GameObjects.Components.Construction public override string Name => "ConstructionGhost"; [ViewVariables] public ConstructionPrototype Prototype { get; set; } - [ViewVariables] public ConstructorComponent Master { get; set; } [ViewVariables] public int GhostID { get; set; } } } diff --git a/Content.Client/GameObjects/Components/Construction/ConstructorComponent.cs b/Content.Client/GameObjects/Components/Construction/ConstructorComponent.cs deleted file mode 100644 index 3c44298631..0000000000 --- a/Content.Client/GameObjects/Components/Construction/ConstructorComponent.cs +++ /dev/null @@ -1,132 +0,0 @@ -using System.Collections.Generic; -using Content.Client.Construction; -using Content.Client.UserInterface; -using Content.Shared.Construction; -using Content.Shared.GameObjects.Components.Construction; -using Robust.Client.GameObjects; -using Robust.Client.Interfaces.GameObjects; -using Robust.Shared.GameObjects; -using Robust.Shared.Interfaces.GameObjects; -using Robust.Shared.Interfaces.GameObjects.Components; -using Robust.Shared.Interfaces.Network; -using Robust.Shared.IoC; -using Robust.Shared.Map; -using Robust.Shared.Maths; -using Robust.Shared.Players; - -namespace Content.Client.GameObjects.Components.Construction -{ - [RegisterComponent] - public class ConstructorComponent : SharedConstructorComponent - { -#pragma warning disable 649 - [Dependency] private readonly IGameHud _gameHud; -#pragma warning restore 649 - - private int nextId; - private readonly Dictionary Ghosts = new Dictionary(); - public ConstructionMenu ConstructionMenu { get; private set; } - - public override void Initialize() - { - base.Initialize(); - - Owner.GetComponent(); - } - - public override void HandleMessage(ComponentMessage message, IComponent component) - { - base.HandleMessage(message, component); - - switch (message) - { - case PlayerAttachedMsg _: - if (ConstructionMenu == null) - { - ConstructionMenu = new ConstructionMenu {Owner = this}; - ConstructionMenu.OnClose += () => _gameHud.CraftingButtonDown = false; - } - - _gameHud.CraftingButtonVisible = true; - _gameHud.CraftingButtonToggled = b => - { - if (b) - { - ConstructionMenu.Open(); - } - else - { - ConstructionMenu.Close(); - } - }; - break; - - case PlayerDetachedMsg _: - _gameHud.CraftingButtonVisible = false; - break; - - default: - break; - } - } - - public override void HandleNetworkMessage(ComponentMessage message, INetChannel channel, ICommonSession session = null) - { - base.HandleNetworkMessage(message, channel, session); - - switch (message) - { - case AckStructureConstructionMessage ackMsg: - ClearGhost(ackMsg.Ack); - break; - - default: - break; - } - } - - public override void OnRemove() - { - ConstructionMenu?.Dispose(); - } - - public void SpawnGhost(ConstructionPrototype prototype, GridCoordinates loc, Direction dir) - { - var entMgr = IoCManager.Resolve(); - var ghost = entMgr.SpawnEntity("constructionghost", loc); - var comp = ghost.GetComponent(); - comp.Prototype = prototype; - comp.Master = this; - comp.GhostID = nextId++; - ghost.GetComponent().LocalRotation = dir.ToAngle(); - var sprite = ghost.GetComponent(); - sprite.LayerSetSprite(0, prototype.Icon); - sprite.LayerSetVisible(0, true); - - Ghosts.Add(comp.GhostID, comp); - } - - public void TryStartConstruction(int ghostId) - { - var ghost = Ghosts[ghostId]; - var transform = ghost.Owner.GetComponent(); - var msg = new TryStartStructureConstructionMessage(transform.GridPosition, ghost.Prototype.ID, transform.LocalRotation, ghostId); - SendNetworkMessage(msg); - } - - public void TryStartItemConstruction(string prototypeName) - { - var msg = new TryStartItemConstructionMessage(prototypeName); - SendNetworkMessage(msg); - } - - public void ClearGhost(int ghostId) - { - if (Ghosts.TryGetValue(ghostId, out var ghost)) - { - ghost.Owner.Delete(); - Ghosts.Remove(ghostId); - } - } - } -} diff --git a/Content.Client/GameObjects/EntitySystems/ConstructionSystem.cs b/Content.Client/GameObjects/EntitySystems/ConstructionSystem.cs new file mode 100644 index 0000000000..327511cd82 --- /dev/null +++ b/Content.Client/GameObjects/EntitySystems/ConstructionSystem.cs @@ -0,0 +1,196 @@ +using System.Collections.Generic; +using Content.Client.Construction; +using Content.Client.GameObjects.Components.Construction; +using Content.Client.UserInterface; +using Content.Shared.Construction; +using Content.Shared.Input; +using JetBrains.Annotations; +using Robust.Client.GameObjects; +using Robust.Client.GameObjects.EntitySystems; +using Robust.Client.Player; +using Robust.Shared.Input; +using Robust.Shared.Input.Binding; +using Robust.Shared.Interfaces.GameObjects; +using Robust.Shared.IoC; +using Robust.Shared.Map; +using Robust.Shared.Maths; + +namespace Content.Client.GameObjects.EntitySystems +{ + /// + /// The client-side implementation of the construction system, which is used for constructing entities in game. + /// + [UsedImplicitly] + public class ConstructionSystem : Shared.GameObjects.EntitySystems.ConstructionSystem + { +#pragma warning disable 649 + [Dependency] private readonly IGameHud _gameHud; + [Dependency] private readonly IPlayerManager _playerManager; + [Dependency] private readonly IEntityManager _entityManager; +#pragma warning restore 649 + + private int _nextId; + private readonly Dictionary _ghosts = new Dictionary(); + private ConstructionMenu _constructionMenu; + + /// + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(HandlePlayerAttached); + SubscribeNetworkEvent(HandleAckStructure); + + CommandBinds.Builder + .Bind(ContentKeyFunctions.OpenCraftingMenu, + new PointerInputCmdHandler(HandleOpenCraftingMenu)) + .Bind(EngineKeyFunctions.Use, + new PointerInputCmdHandler(HandleUse)) + .Register(); + } + + private void HandleAckStructure(AckStructureConstructionMessage msg) + { + ClearGhost(msg.GhostId); + } + + private void HandlePlayerAttached(PlayerAttachSysMessage msg) + { + if (msg.AttachedEntity == null) + { + _gameHud.CraftingButtonVisible = false; + return; + } + + if (_constructionMenu == null) + { + _constructionMenu = new ConstructionMenu(); + _constructionMenu.OnClose += () => _gameHud.CraftingButtonDown = false; + } + + _gameHud.CraftingButtonVisible = true; + _gameHud.CraftingButtonToggled = b => + { + if (b) + { + _constructionMenu.Open(); + } + else + { + _constructionMenu.Close(); + } + }; + } + + /// + public override void Shutdown() + { + _constructionMenu?.Dispose(); + + CommandBinds.Unregister(); + base.Shutdown(); + } + + private bool HandleOpenCraftingMenu(in PointerInputCmdHandler.PointerInputCmdArgs args) + { + if (_playerManager.LocalPlayer.ControlledEntity == null) + { + return false; + } + + var menu = _constructionMenu; + + if (menu.IsOpen) + { + if (menu.IsAtFront()) + { + SetOpenValue(menu, false); + } + else + { + menu.MoveToFront(); + } + } + else + { + SetOpenValue(menu, true); + } + + return true; + } + + private bool HandleUse(in PointerInputCmdHandler.PointerInputCmdArgs args) + { + if (!args.EntityUid.IsValid() || !args.EntityUid.IsClientSide()) + return false; + + var entity = _entityManager.GetEntity(args.EntityUid); + + if (!entity.TryGetComponent(out ConstructionGhostComponent ghostComp)) + return false; + + TryStartConstruction(ghostComp.GhostID); + return true; + + } + + private void SetOpenValue(ConstructionMenu menu, bool value) + { + if (value) + { + _gameHud.CraftingButtonDown = true; + menu.OpenCentered(); + } + else + { + _gameHud.CraftingButtonDown = false; + menu.Close(); + } + } + + /// + /// Creates a construction ghost at the given location. + /// + public void SpawnGhost(ConstructionPrototype prototype, GridCoordinates loc, Direction dir) + { + var ghost = _entityManager.SpawnEntity("constructionghost", loc); + var comp = ghost.GetComponent(); + comp.Prototype = prototype; + comp.GhostID = _nextId++; + ghost.Transform.LocalRotation = dir.ToAngle(); + var sprite = ghost.GetComponent(); + sprite.LayerSetSprite(0, prototype.Icon); + sprite.LayerSetVisible(0, true); + + _ghosts.Add(comp.GhostID, comp); + } + + private void TryStartConstruction(int ghostId) + { + var ghost = _ghosts[ghostId]; + var transform = ghost.Owner.Transform; + var msg = new TryStartStructureConstructionMessage(transform.GridPosition, ghost.Prototype.ID, transform.LocalRotation, ghostId); + RaiseNetworkEvent(msg); + } + + /// + /// Starts constructing an item underneath the attached entity. + /// + public void TryStartItemConstruction(string prototypeName) + { + RaiseNetworkEvent(new TryStartItemConstructionMessage(prototypeName)); + } + + /// + /// Removes a construction ghost entity with the given ID. + /// + public void ClearGhost(int ghostId) + { + if (_ghosts.TryGetValue(ghostId, out var ghost)) + { + ghost.Owner.Delete(); + _ghosts.Remove(ghostId); + } + } + } +} diff --git a/Content.Client/GameObjects/EntitySystems/ConstructorSystem.cs b/Content.Client/GameObjects/EntitySystems/ConstructorSystem.cs deleted file mode 100644 index 95bec8cfd2..0000000000 --- a/Content.Client/GameObjects/EntitySystems/ConstructorSystem.cs +++ /dev/null @@ -1,101 +0,0 @@ -using Content.Client.Construction; -using Content.Client.GameObjects.Components.Construction; -using Content.Client.UserInterface; -using Content.Shared.Input; -using Robust.Client.GameObjects.EntitySystems; -using Robust.Client.Player; -using Robust.Shared.GameObjects.Systems; -using Robust.Shared.Input; -using Robust.Shared.Input.Binding; -using Robust.Shared.Interfaces.GameObjects; -using Robust.Shared.IoC; - -namespace Content.Client.GameObjects.EntitySystems -{ - public sealed class ConstructorSystem : EntitySystem - { -#pragma warning disable 649 - [Dependency] private readonly IGameHud _gameHud; - [Dependency] private readonly IPlayerManager _playerManager; - [Dependency] private readonly IEntityManager _entityManager; -#pragma warning restore 649 - - public override void Initialize() - { - base.Initialize(); - - var inputSys = EntitySystemManager.GetEntitySystem(); - - CommandBinds.Builder - .Bind(ContentKeyFunctions.OpenCraftingMenu, - new PointerInputCmdHandler(HandleOpenCraftingMenu)) - .Bind(EngineKeyFunctions.Use, - new PointerInputCmdHandler(HandleUse)) - .Register(); - } - - public override void Shutdown() - { - CommandBinds.Unregister(); - base.Shutdown(); - } - - private bool HandleOpenCraftingMenu(in PointerInputCmdHandler.PointerInputCmdArgs args) - { - if (_playerManager.LocalPlayer.ControlledEntity == null - || !_playerManager.LocalPlayer.ControlledEntity.TryGetComponent(out ConstructorComponent constructor)) - { - return false; - } - - var menu = constructor.ConstructionMenu; - - if (menu.IsOpen) - { - if (menu.IsAtFront()) - { - _setOpenValue(menu, false); - } - else - { - menu.MoveToFront(); - } - } - else - { - _setOpenValue(menu, true); - } - - return true; - } - - private bool HandleUse(in PointerInputCmdHandler.PointerInputCmdArgs args) - { - if (!args.EntityUid.IsValid() || !args.EntityUid.IsClientSide()) - return false; - - var entity = _entityManager.GetEntity(args.EntityUid); - - if (!entity.TryGetComponent(out ConstructionGhostComponent ghostComp)) - return false; - - ghostComp.Master.TryStartConstruction(ghostComp.GhostID); - return true; - - } - - private void _setOpenValue(ConstructionMenu menu, bool value) - { - if (value) - { - _gameHud.CraftingButtonDown = true; - menu.OpenCentered(); - } - else - { - _gameHud.CraftingButtonDown = false; - menu.Close(); - } - } - } -} diff --git a/Content.Server/GameObjects/Components/Construction/ConstructorComponent.cs b/Content.Server/GameObjects/EntitySystems/ConstructionSystem.cs similarity index 62% rename from Content.Server/GameObjects/Components/Construction/ConstructorComponent.cs rename to Content.Server/GameObjects/EntitySystems/ConstructionSystem.cs index 3a32edeea3..5d4a169a3a 100644 --- a/Content.Server/GameObjects/Components/Construction/ConstructorComponent.cs +++ b/Content.Server/GameObjects/EntitySystems/ConstructionSystem.cs @@ -1,26 +1,28 @@ using System; +using Content.Server.GameObjects.Components.Construction; using Content.Server.GameObjects.Components.Stack; using Content.Server.Utility; using Content.Shared.Construction; -using Content.Shared.GameObjects.Components.Construction; +using JetBrains.Annotations; using Robust.Server.GameObjects.EntitySystems; using Robust.Server.Interfaces.GameObjects; +using Robust.Server.Interfaces.Player; using Robust.Shared.GameObjects; using Robust.Shared.GameObjects.Systems; using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Interfaces.Map; -using Robust.Shared.Interfaces.Network; using Robust.Shared.IoC; using Robust.Shared.Map; using Robust.Shared.Maths; -using Robust.Shared.Players; using Robust.Shared.Prototypes; -using Robust.Shared.Utility; -namespace Content.Server.GameObjects.Components.Construction +namespace Content.Server.GameObjects.EntitySystems { - [RegisterComponent] - public class ConstructorComponent : SharedConstructorComponent + /// + /// The server-side implementation of the construction system, which is used for constructing entities in game. + /// + [UsedImplicitly] + internal class ConstructionSystem : Shared.GameObjects.EntitySystems.ConstructionSystem { #pragma warning disable 649 [Dependency] private readonly IPrototypeManager _prototypeManager; @@ -28,32 +30,41 @@ namespace Content.Server.GameObjects.Components.Construction [Dependency] private readonly IServerEntityManager _serverEntityManager; #pragma warning restore 649 - public override void HandleNetworkMessage(ComponentMessage message, INetChannel channel, ICommonSession session = null) + /// + public override void Initialize() { - base.HandleNetworkMessage(message, channel, session); + base.Initialize(); - switch (message) - { - case TryStartStructureConstructionMessage tryStart: - TryStartStructureConstruction(tryStart.Location, tryStart.PrototypeName, tryStart.Angle, tryStart.Ack); - break; - case TryStartItemConstructionMessage tryStart: - TryStartItemConstruction(tryStart.PrototypeName); - break; - } + SubscribeNetworkEvent(HandleStartStructureConstruction); + SubscribeNetworkEvent(HandleStartItemConstruction); } - void TryStartStructureConstruction(GridCoordinates loc, string prototypeName, Angle angle, int ack) + private void HandleStartStructureConstruction(TryStartStructureConstructionMessage msg, EntitySessionEventArgs args) + { + var placingEnt = args.SenderSession.AttachedEntity; + var result = TryStartStructureConstruction(placingEnt, msg.Location, msg.PrototypeName, msg.Angle); + if (!result) return; + var responseMsg = new AckStructureConstructionMessage(msg.Ack); + var channel = ((IPlayerSession) args.SenderSession).ConnectedClient; + RaiseNetworkEvent(responseMsg, channel); + } + + private void HandleStartItemConstruction(TryStartItemConstructionMessage msg, EntitySessionEventArgs args) + { + var placingEnt = args.SenderSession.AttachedEntity; + TryStartItemConstruction(placingEnt, msg.PrototypeName); + } + + private bool TryStartStructureConstruction(IEntity placingEnt, GridCoordinates loc, string prototypeName, Angle angle) { var prototype = _prototypeManager.Index(prototypeName); - if (!InteractionChecks.InRangeUnobstructed(Owner, loc.ToMap(_mapManager), - ignoredEnt: Owner, insideBlockerValid: prototype.CanBuildInImpassable)) + if (!InteractionChecks.InRangeUnobstructed(placingEnt, loc.ToMap(_mapManager), + ignoredEnt: placingEnt, insideBlockerValid: prototype.CanBuildInImpassable)) { - return; + return false; } - if (prototype.Stages.Count < 2) { throw new InvalidOperationException($"Prototype '{prototypeName}' does not have enough stages."); @@ -66,25 +77,25 @@ namespace Content.Server.GameObjects.Components.Construction } // Try to find the stack with the material in the user's hand. - var hands = Owner.GetComponent(); + var hands = placingEnt.GetComponent(); var activeHand = hands.GetActiveHand?.Owner; if (activeHand == null) { - return; + return false; } if (!activeHand.TryGetComponent(out StackComponent stack) || !ConstructionComponent.MaterialStackValidFor(matStep, stack)) { - return; + return false; } if (!stack.Use(matStep.Amount)) { - return; + return false; } // OK WE'RE GOOD CONSTRUCTION STARTED. - EntitySystem.Get().PlayAtCoords("/Audio/items/deconstruct.ogg", loc); + Get().PlayAtCoords("/Audio/items/deconstruct.ogg", loc); if (prototype.Stages.Count == 2) { // Exactly 2 stages, so don't make an intermediate frame. @@ -99,11 +110,10 @@ namespace Content.Server.GameObjects.Components.Construction frame.Transform.LocalRotation = angle; } - var msg = new AckStructureConstructionMessage(ack); - SendNetworkMessage(msg); + return true; } - void TryStartItemConstruction(string prototypeName) + private void TryStartItemConstruction(IEntity placingEnt, string prototypeName) { var prototype = _prototypeManager.Index(prototypeName); @@ -119,7 +129,7 @@ namespace Content.Server.GameObjects.Components.Construction } // Try to find the stack with the material in the user's hand. - var hands = Owner.GetComponent(); + var hands = placingEnt.GetComponent(); var activeHand = hands.GetActiveHand?.Owner; if (activeHand == null) { @@ -137,17 +147,17 @@ namespace Content.Server.GameObjects.Components.Construction } // OK WE'RE GOOD CONSTRUCTION STARTED. - EntitySystem.Get().PlayFromEntity("/Audio/items/deconstruct.ogg", Owner); + EntitySystem.Get().PlayFromEntity("/Audio/items/deconstruct.ogg", placingEnt); if (prototype.Stages.Count == 2) { // Exactly 2 stages, so don't make an intermediate frame. - var ent = _serverEntityManager.SpawnEntity(prototype.Result, Owner.Transform.GridPosition); + var ent = _serverEntityManager.SpawnEntity(prototype.Result, placingEnt.Transform.GridPosition); hands.PutInHandOrDrop(ent.GetComponent()); } else { //TODO: Make these viable as an item and try putting them in the players hands - var frame = _serverEntityManager.SpawnEntity("structureconstructionframe", Owner.Transform.GridPosition); + var frame = _serverEntityManager.SpawnEntity("structureconstructionframe", placingEnt.Transform.GridPosition); var construction = frame.GetComponent(); construction.Init(prototype); } diff --git a/Content.Shared/Content.Shared.csproj b/Content.Shared/Content.Shared.csproj index 4afb38c225..a01fa26d38 100644 --- a/Content.Shared/Content.Shared.csproj +++ b/Content.Shared/Content.Shared.csproj @@ -26,6 +26,7 @@ + diff --git a/Content.Shared/GameObjects/ContentNetIDs.cs b/Content.Shared/GameObjects/ContentNetIDs.cs index 44838998b2..5c37c53bb1 100644 --- a/Content.Shared/GameObjects/ContentNetIDs.cs +++ b/Content.Shared/GameObjects/ContentNetIDs.cs @@ -11,7 +11,8 @@ public const uint STORAGE = 1005; public const uint INVENTORY = 1006; public const uint POWER_DEBUG_TOOL = 1007; - public const uint CONSTRUCTOR = 1008; + // 1008 + // 1009 public const uint RANGED_WEAPON = 1010; public const uint CAMERA_RECOIL = 1011; public const uint SOUND = 1012; diff --git a/Content.Shared/GameObjects/Components/Construction/SharedConstructorComponent.cs b/Content.Shared/GameObjects/EntitySystems/ConstructionSystem.cs similarity index 69% rename from Content.Shared/GameObjects/Components/Construction/SharedConstructorComponent.cs rename to Content.Shared/GameObjects/EntitySystems/ConstructionSystem.cs index d7c9389fa2..c03e1dc632 100644 --- a/Content.Shared/GameObjects/Components/Construction/SharedConstructorComponent.cs +++ b/Content.Shared/GameObjects/EntitySystems/ConstructionSystem.cs @@ -1,25 +1,22 @@ -using System; +using System; +using JetBrains.Annotations; using Robust.Shared.GameObjects; +using Robust.Shared.GameObjects.Systems; using Robust.Shared.Map; using Robust.Shared.Maths; using Robust.Shared.Serialization; -namespace Content.Shared.GameObjects.Components.Construction +namespace Content.Shared.GameObjects.EntitySystems { - /// - /// Basically handles the logic of "this mob can do construction". - /// - public abstract class SharedConstructorComponent : Component + [UsedImplicitly] + public class ConstructionSystem : EntitySystem { - public override string Name => "Constructor"; - public override uint? NetID => ContentNetIDs.CONSTRUCTOR; - /// /// Sent client -> server to to tell the server that we started building /// a structure-construction. /// [Serializable, NetSerializable] - protected class TryStartStructureConstructionMessage : ComponentMessage + public class TryStartStructureConstructionMessage : EntitySystemMessage { /// /// Position to start building. @@ -40,7 +37,6 @@ namespace Content.Shared.GameObjects.Components.Construction public TryStartStructureConstructionMessage(GridCoordinates loc, string prototypeName, Angle angle, int ack) { - Directed = true; Location = loc; PrototypeName = prototypeName; Angle = angle; @@ -53,7 +49,7 @@ namespace Content.Shared.GameObjects.Components.Construction /// an item-construction. /// [Serializable, NetSerializable] - protected class TryStartItemConstructionMessage : ComponentMessage + public class TryStartItemConstructionMessage : EntitySystemMessage { /// /// The construction prototype to start building. @@ -62,21 +58,21 @@ namespace Content.Shared.GameObjects.Components.Construction public TryStartItemConstructionMessage(string prototypeName) { - Directed = true; PrototypeName = prototypeName; } } - + /// + /// Send server -> client to tell the client that a ghost has started to be constructed. + /// [Serializable, NetSerializable] - protected class AckStructureConstructionMessage : ComponentMessage + public class AckStructureConstructionMessage : EntitySystemMessage { - public readonly int Ack; + public readonly int GhostId; - public AckStructureConstructionMessage(int ack) + public AckStructureConstructionMessage(int ghostId) { - Directed = true; - Ack = ack; + GhostId = ghostId; } } } diff --git a/Resources/Prototypes/Entities/Mobs/human.yml b/Resources/Prototypes/Entities/Mobs/human.yml index 85af91f67b..5683331652 100644 --- a/Resources/Prototypes/Entities/Mobs/human.yml +++ b/Resources/Prototypes/Entities/Mobs/human.yml @@ -24,7 +24,6 @@ max_volume: 250 digestionDelay: 20 - type: Inventory - - type: Constructor - type: Clickable - type: InteractionOutline - type: Sprite