diff --git a/Content.Client/EscapeMenu/UI/Tabs/KeyRebindTab.xaml.cs b/Content.Client/EscapeMenu/UI/Tabs/KeyRebindTab.xaml.cs index b87e757a7d..56b038a7b0 100644 --- a/Content.Client/EscapeMenu/UI/Tabs/KeyRebindTab.xaml.cs +++ b/Content.Client/EscapeMenu/UI/Tabs/KeyRebindTab.xaml.cs @@ -178,6 +178,7 @@ namespace Content.Client.EscapeMenu.UI.Tabs AddButton(EngineKeyFunctions.EditorGridPlace); AddButton(EngineKeyFunctions.EditorLinePlace); AddButton(EngineKeyFunctions.EditorRotateObject); + AddButton(ContentKeyFunctions.EditorCopyObject); AddHeader("ui-options-header-dev"); AddButton(EngineKeyFunctions.ShowDebugConsole); diff --git a/Content.Client/Input/ContentContexts.cs b/Content.Client/Input/ContentContexts.cs index bf68bbc607..2c588a9a29 100644 --- a/Content.Client/Input/ContentContexts.cs +++ b/Content.Client/Input/ContentContexts.cs @@ -29,6 +29,9 @@ namespace Content.Client.Input common.AddFunction(ContentKeyFunctions.Point); common.AddFunction(ContentKeyFunctions.OpenContextMenu); + // Not in engine, because engine cannot check for sanbox/admin status before starting placement. + common.AddFunction(ContentKeyFunctions.EditorCopyObject); + var human = contexts.GetContext("human"); human.AddFunction(ContentKeyFunctions.SwapHands); human.AddFunction(ContentKeyFunctions.Drop); diff --git a/Content.Client/Sandbox/SandboxSystem.cs b/Content.Client/Sandbox/SandboxSystem.cs index c1daa0e6e4..700278f3a4 100644 --- a/Content.Client/Sandbox/SandboxSystem.cs +++ b/Content.Client/Sandbox/SandboxSystem.cs @@ -12,12 +12,14 @@ using Robust.Client.Debugging; using Robust.Client.Graphics; using Robust.Client.Input; using Robust.Client.Placement; +using Robust.Client.Placement.Modes; using Robust.Client.ResourceManagement; using Robust.Client.UserInterface.Controls; using Robust.Client.UserInterface.CustomControls; using Robust.Shared.Input.Binding; using Robust.Shared.Map; using Robust.Shared.Network; +using Robust.Shared.Players; using static Robust.Client.UserInterface.Controls.BoxContainer; namespace Content.Client.Sandbox @@ -117,6 +119,7 @@ namespace Content.Client.Sandbox { [Dependency] private readonly IClientConsoleHost _consoleHost = default!; [Dependency] private readonly IGameHud _gameHud = default!; + [Dependency] private readonly IMapManager _mapManager = default!; [Dependency] private readonly IPlacementManager _placementManager = default!; [Dependency] private readonly IResourceCache _resourceCache = default!; [Dependency] private readonly ITileDefinitionManager _tileDefinitionManager = default!; @@ -148,6 +151,53 @@ namespace Content.Client.Sandbox InputCmdHandler.FromDelegate(session => ToggleTilesWindow())); _inputManager.SetInputCommand(ContentKeyFunctions.OpenDecalSpawnWindow, InputCmdHandler.FromDelegate(session => ToggleDecalsWindow())); + + CommandBinds.Builder + .Bind(ContentKeyFunctions.EditorCopyObject, new PointerInputCmdHandler(OnCopy)) + .Register(); + } + + private bool OnCopy(ICommonSession? session, EntityCoordinates coords, EntityUid uid) + { + if (!CanSandbox()) + return false; + + // Try copy entity. + if (uid.IsValid() + && EntityManager.TryGetComponent(uid, out MetaDataComponent? comp) + && !comp.EntityDeleted) + { + if (comp.EntityPrototype == null || comp.EntityPrototype.NoSpawn || comp.EntityPrototype.Abstract) + return false; + + if (_placementManager.Eraser) + _placementManager.ToggleEraser(); + + _placementManager.BeginPlacing(new() + { + EntityType = comp.EntityPrototype.ID, + IsTile = false, + TileType = 0, + PlacementOption = comp.EntityPrototype.PlacementMode + }); + return true; + } + + // Try copy tile. + if (!_mapManager.TryFindGridAt(coords.ToMap(EntityManager), out var grid) || !grid.TryGetTileRef(coords, out var tileRef)) + return false; + + if (_placementManager.Eraser) + _placementManager.ToggleEraser(); + + _placementManager.BeginPlacing(new() + { + EntityType = null, + IsTile = true, + TileType = tileRef.Tile.TypeId, + PlacementOption = nameof(AlignTileAny) + }); + return true; } private void OnAdminStatus() @@ -196,6 +246,7 @@ namespace Content.Client.Sandbox // TODO: Gamehud moment _gameHud.SandboxButtonToggled -= SandboxButtonPressed; _adminManager.AdminStatusUpdated -= OnAdminStatus; + CommandBinds.Unregister(); } private void OnSandboxStatus(MsgSandboxStatus ev) diff --git a/Content.Shared/Input/ContentKeyFunctions.cs b/Content.Shared/Input/ContentKeyFunctions.cs index b2f22cd015..be7276e44b 100644 --- a/Content.Shared/Input/ContentKeyFunctions.cs +++ b/Content.Shared/Input/ContentKeyFunctions.cs @@ -79,5 +79,6 @@ namespace Content.Shared.Input public static readonly BoundKeyFunction Vote7 = "Vote7"; public static readonly BoundKeyFunction Vote8 = "Vote8"; public static readonly BoundKeyFunction Vote9 = "Vote9"; + public static readonly BoundKeyFunction EditorCopyObject = "EditorCopyObject"; } } diff --git a/Resources/Locale/en-US/escape-menu/ui/options-menu.ftl b/Resources/Locale/en-US/escape-menu/ui/options-menu.ftl index 5547628b2c..e768feca9d 100644 --- a/Resources/Locale/en-US/escape-menu/ui/options-menu.ftl +++ b/Resources/Locale/en-US/escape-menu/ui/options-menu.ftl @@ -129,6 +129,7 @@ ui-options-function-editor-cancel-place = Cancel placement ui-options-function-editor-grid-place = Place in grid ui-options-function-editor-line-place = Place line ui-options-function-editor-rotate-object = Rotate +ui-options-function-editor-copy-object = Copy ui-options-function-open-abilities-menu = Open action menu ui-options-function-show-debug-console = Open Console diff --git a/Resources/keybinds.yml b/Resources/keybinds.yml index fc230fca01..c872f45f3c 100644 --- a/Resources/keybinds.yml +++ b/Resources/keybinds.yml @@ -101,6 +101,9 @@ binds: - function: EditorRotateObject type: State key: MouseMiddle +- function: EditorCopyObject + type: State + key: P - function: SwapHands type: State key: X