ScreenshotHook.cs 3.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. using System;
  2. using System.IO;
  3. using System.Threading.Tasks;
  4. using Content.Client.Viewport;
  5. using Content.Shared.Input;
  6. using Robust.Client.Graphics;
  7. using Robust.Client.Input;
  8. using Robust.Client.State;
  9. using Robust.Shared.ContentPack;
  10. using Robust.Shared.Input.Binding;
  11. using Robust.Shared.IoC;
  12. using Robust.Shared.Log;
  13. using Robust.Shared.Utility;
  14. using SixLabors.ImageSharp;
  15. using SixLabors.ImageSharp.PixelFormats;
  16. namespace Content.Client.Screenshot
  17. {
  18. internal sealed class ScreenshotHook : IScreenshotHook
  19. {
  20. private static readonly ResPath BaseScreenshotPath = new("/Screenshots");
  21. [Dependency] private readonly IInputManager _inputManager = default!;
  22. [Dependency] private readonly IClyde _clyde = default!;
  23. [Dependency] private readonly IResourceManager _resourceManager = default!;
  24. [Dependency] private readonly IStateManager _stateManager = default!;
  25. public void Initialize()
  26. {
  27. _inputManager.SetInputCommand(ContentKeyFunctions.TakeScreenshot, InputCmdHandler.FromDelegate(_ =>
  28. {
  29. _clyde.Screenshot(ScreenshotType.Final, Take);
  30. }));
  31. _inputManager.SetInputCommand(ContentKeyFunctions.TakeScreenshotNoUI, InputCmdHandler.FromDelegate(_ =>
  32. {
  33. if (_stateManager.CurrentState is IMainViewportState state)
  34. {
  35. state.Viewport.Viewport.Screenshot(Take);
  36. }
  37. else
  38. {
  39. Logger.InfoS("screenshot", "Can't take no-UI screenshot: current state is not GameScreen");
  40. }
  41. }));
  42. }
  43. private async void Take<T>(Image<T> screenshot) where T : unmanaged, IPixel<T>
  44. {
  45. var time = DateTime.Now.ToString("yyyy-M-dd_HH.mm.ss");
  46. if (!_resourceManager.UserData.IsDir(BaseScreenshotPath))
  47. {
  48. _resourceManager.UserData.CreateDir(BaseScreenshotPath);
  49. }
  50. for (var i = 0; i < 5; i++)
  51. {
  52. try
  53. {
  54. var filename = time;
  55. if (i != 0)
  56. {
  57. filename = $"{filename}-{i}";
  58. }
  59. await using var file =
  60. _resourceManager.UserData.Open(BaseScreenshotPath / $"{filename}.png", FileMode.CreateNew, FileAccess.Write, FileShare.None);
  61. await Task.Run(() =>
  62. {
  63. // Saving takes forever, so don't hang the game on it.
  64. screenshot.SaveAsPng(file);
  65. });
  66. Logger.InfoS("screenshot", "Screenshot taken as {0}.png", filename);
  67. return;
  68. }
  69. catch (IOException e)
  70. {
  71. Logger.WarningS("screenshot", "Failed to save screenshot, retrying?:\n{0}", e);
  72. }
  73. }
  74. Logger.ErrorS("screenshot", "Unable to save screenshot.");
  75. }
  76. }
  77. public interface IScreenshotHook
  78. {
  79. void Initialize();
  80. }
  81. }