1
0

ParallaxManager.cs 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. using System.Collections.Concurrent;
  2. using System.Numerics;
  3. using System.Threading;
  4. using System.Threading.Tasks;
  5. using Content.Client.Parallax.Data;
  6. using Content.Shared.CCVar;
  7. using Robust.Shared.Prototypes;
  8. using Robust.Shared.Configuration;
  9. using Robust.Shared.Utility;
  10. namespace Content.Client.Parallax.Managers;
  11. public sealed class ParallaxManager : IParallaxManager
  12. {
  13. [Dependency] private readonly IPrototypeManager _prototypeManager = default!;
  14. [Dependency] private readonly IConfigurationManager _configurationManager = default!;
  15. private ISawmill _sawmill = Logger.GetSawmill("parallax");
  16. public Vector2 ParallaxAnchor { get; set; }
  17. private readonly Dictionary<string, ParallaxLayerPrepared[]> _parallaxesLQ = new();
  18. private readonly Dictionary<string, ParallaxLayerPrepared[]> _parallaxesHQ = new();
  19. private readonly Dictionary<string, CancellationTokenSource> _loadingParallaxes = new();
  20. public bool IsLoaded(string name) => _parallaxesLQ.ContainsKey(name);
  21. public ParallaxLayerPrepared[] GetParallaxLayers(string name)
  22. {
  23. if (_configurationManager.GetCVar(CCVars.ParallaxLowQuality))
  24. {
  25. return !_parallaxesLQ.TryGetValue(name, out var lq) ? Array.Empty<ParallaxLayerPrepared>() : lq;
  26. }
  27. return !_parallaxesHQ.TryGetValue(name, out var hq) ? Array.Empty<ParallaxLayerPrepared>() : hq;
  28. }
  29. public void UnloadParallax(string name)
  30. {
  31. if (_loadingParallaxes.TryGetValue(name, out var loading))
  32. {
  33. loading.Cancel();
  34. _loadingParallaxes.Remove(name, out _);
  35. return;
  36. }
  37. if (!_parallaxesLQ.ContainsKey(name)) return;
  38. _parallaxesLQ.Remove(name);
  39. _parallaxesHQ.Remove(name);
  40. }
  41. public async void LoadDefaultParallax()
  42. {
  43. _sawmill.Level = LogLevel.Info;
  44. await LoadParallaxByName("Default");
  45. }
  46. public async Task LoadParallaxByName(string name)
  47. {
  48. if (_parallaxesLQ.ContainsKey(name) || _loadingParallaxes.ContainsKey(name)) return;
  49. // Cancel any existing load and setup the new cancellation token
  50. var token = new CancellationTokenSource();
  51. _loadingParallaxes[name] = token;
  52. var cancel = token.Token;
  53. // Begin (for real)
  54. _sawmill.Debug($"Loading parallax {name}");
  55. try
  56. {
  57. var parallaxPrototype = _prototypeManager.Index<ParallaxPrototype>(name);
  58. ParallaxLayerPrepared[][] layers;
  59. if (parallaxPrototype.LayersLQUseHQ)
  60. {
  61. layers = new ParallaxLayerPrepared[2][];
  62. layers[0] = layers[1] = await LoadParallaxLayers(parallaxPrototype.Layers, cancel);
  63. }
  64. else
  65. {
  66. layers = await Task.WhenAll(
  67. LoadParallaxLayers(parallaxPrototype.Layers, cancel),
  68. LoadParallaxLayers(parallaxPrototype.LayersLQ, cancel)
  69. );
  70. }
  71. _loadingParallaxes.Remove(name, out _);
  72. if (token.Token.IsCancellationRequested) return;
  73. _parallaxesLQ[name] = layers[1];
  74. _parallaxesHQ[name] = layers[0];
  75. }
  76. catch (Exception ex)
  77. {
  78. _sawmill.Error($"Failed to loaded parallax {name}: {ex}");
  79. }
  80. }
  81. private async Task<ParallaxLayerPrepared[]> LoadParallaxLayers(List<ParallaxLayerConfig> layersIn, CancellationToken cancel = default)
  82. {
  83. // Because this is async, make sure it doesn't change (prototype reloads could muck this up)
  84. // Since the tasks aren't awaited until the end, this should be fine
  85. var tasks = new Task<ParallaxLayerPrepared>[layersIn.Count];
  86. for (var i = 0; i < layersIn.Count; i++)
  87. {
  88. tasks[i] = LoadParallaxLayer(layersIn[i], cancel);
  89. }
  90. return await Task.WhenAll(tasks);
  91. }
  92. private async Task<ParallaxLayerPrepared> LoadParallaxLayer(ParallaxLayerConfig config, CancellationToken cancel = default)
  93. {
  94. return new ParallaxLayerPrepared()
  95. {
  96. Texture = await config.Texture.GenerateTexture(cancel),
  97. Config = config
  98. };
  99. }
  100. }