diff --git a/Content.Client/ClientContentIoC.cs b/Content.Client/ClientContentIoC.cs index 690de5c18a..93e75a88f1 100644 --- a/Content.Client/ClientContentIoC.cs +++ b/Content.Client/ClientContentIoC.cs @@ -31,6 +31,7 @@ namespace Content.Client IoCManager.Register(); IoCManager.Register(); IoCManager.Register(); + IoCManager.Register(); } } } diff --git a/Content.Client/EntryPoint.cs b/Content.Client/EntryPoint.cs index c8ab1376c7..89681280c8 100644 --- a/Content.Client/EntryPoint.cs +++ b/Content.Client/EntryPoint.cs @@ -178,6 +178,7 @@ namespace Content.Client IoCManager.Resolve().LoadParallax(); IoCManager.Resolve().PlayerJoinedServer += SubscribePlayerAttachmentEvents; IoCManager.Resolve().Initialize(); + IoCManager.Resolve().Initialize(); IoCManager.InjectDependencies(this); diff --git a/Content.Client/Input/ContentContexts.cs b/Content.Client/Input/ContentContexts.cs index 26e850a3a3..5301d8ba4f 100644 --- a/Content.Client/Input/ContentContexts.cs +++ b/Content.Client/Input/ContentContexts.cs @@ -16,6 +16,8 @@ namespace Content.Client.Input common.AddFunction(ContentKeyFunctions.ExamineEntity); common.AddFunction(ContentKeyFunctions.OpenTutorial); common.AddFunction(ContentKeyFunctions.UseOrAttack); + common.AddFunction(ContentKeyFunctions.TakeScreenshot); + common.AddFunction(ContentKeyFunctions.TakeScreenshotNoUI); var human = contexts.GetContext("human"); human.AddFunction(ContentKeyFunctions.SwapHands); diff --git a/Content.Client/ScreenshotHook.cs b/Content.Client/ScreenshotHook.cs new file mode 100644 index 0000000000..529a469b72 --- /dev/null +++ b/Content.Client/ScreenshotHook.cs @@ -0,0 +1,85 @@ +using System; +using System.IO; +using System.Threading.Tasks; +using Content.Shared.Input; +using Robust.Client.Interfaces.Graphics; +using Robust.Client.Interfaces.Input; +using Robust.Shared.Input; +using Robust.Shared.Interfaces.Resources; +using Robust.Shared.IoC; +using Robust.Shared.Log; +using Robust.Shared.Utility; +using SixLabors.ImageSharp; + +namespace Content.Client +{ + internal class ScreenshotHook : IScreenshotHook + { + private static readonly ResourcePath BaseScreenshotPath = new ResourcePath("/Screenshots"); + + [Dependency] private readonly IInputManager _inputManager = default; + [Dependency] private readonly IClyde _clyde = default; + [Dependency] private readonly IResourceManager _resourceManager = default; + + public void Initialize() + { + _inputManager.SetInputCommand(ContentKeyFunctions.TakeScreenshot, InputCmdHandler.FromDelegate(_ => + { + Take(ScreenshotType.AfterUI); + })); + + _inputManager.SetInputCommand(ContentKeyFunctions.TakeScreenshotNoUI, InputCmdHandler.FromDelegate(_ => + { + Take(ScreenshotType.BeforeUI); + })); + } + + private async void Take(ScreenshotType type) + { + var screenshot = await _clyde.ScreenshotAsync(type); + + var time = DateTime.Now.ToString("yyyy-M-dd_HH.mm.ss"); + + if (!_resourceManager.UserData.IsDir(BaseScreenshotPath)) + { + _resourceManager.UserData.CreateDir(BaseScreenshotPath); + } + + for (var i = 0; i < 5; i++) + { + try + { + var filename = time; + + if (i != 0) + { + filename = $"{filename}-{i}"; + } + + await using var file = + _resourceManager.UserData.Open(BaseScreenshotPath / $"{filename}.png", FileMode.CreateNew); + + await Task.Run(() => + { + // Saving takes forever, so don't hang the game on it. + screenshot.SaveAsPng(file); + }); + + Logger.InfoS("screenshot", "Screenshot taken as {0}.png", filename); + return; + } + catch (IOException e) + { + Logger.WarningS("screenshot", "Failed to save screenshot, retrying?:\n{0}", e); + } + } + + Logger.ErrorS("screenshot", "Unable to save screenshot."); + } + } + + public interface IScreenshotHook + { + void Initialize(); + } +} diff --git a/Content.Shared/Input/ContentKeyFunctions.cs b/Content.Shared/Input/ContentKeyFunctions.cs index a0ae771de3..a713c7db54 100644 --- a/Content.Shared/Input/ContentKeyFunctions.cs +++ b/Content.Shared/Input/ContentKeyFunctions.cs @@ -24,5 +24,7 @@ namespace Content.Shared.Input public static readonly BoundKeyFunction OpenEntitySpawnWindow = "OpenEntitySpawnWindow"; public static readonly BoundKeyFunction OpenSandboxWindow = "OpenSandboxWindow"; public static readonly BoundKeyFunction OpenTileSpawnWindow = "OpenTileSpawnWindow"; + public static readonly BoundKeyFunction TakeScreenshot = "TakeScreenshot"; + public static readonly BoundKeyFunction TakeScreenshotNoUI = "TakeScreenshotNoUI"; } } diff --git a/Resources/keybinds.yml b/Resources/keybinds.yml index 504ec81af9..29eeb8fbc7 100644 --- a/Resources/keybinds.yml +++ b/Resources/keybinds.yml @@ -155,3 +155,10 @@ binds: - function: OpenSandboxWindow type: state key: B +- function: TakeScreenshot + type: state + key: F2 +- function: TakeScreenshotNoUI + type: state + key: F2 + mod1: Shift