SharedGasTileOverlaySystem.cs 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. using Content.Shared.Atmos.Components;
  2. using Content.Shared.Atmos.Prototypes;
  3. using Robust.Shared.GameStates;
  4. using Robust.Shared.Prototypes;
  5. using Robust.Shared.Serialization;
  6. namespace Content.Shared.Atmos.EntitySystems
  7. {
  8. public abstract class SharedGasTileOverlaySystem : EntitySystem
  9. {
  10. public const byte ChunkSize = 8;
  11. protected float AccumulatedFrameTime;
  12. protected bool PvsEnabled;
  13. [Dependency] protected readonly IPrototypeManager ProtoMan = default!;
  14. /// <summary>
  15. /// array of the ids of all visible gases.
  16. /// </summary>
  17. public int[] VisibleGasId = default!;
  18. public override void Initialize()
  19. {
  20. base.Initialize();
  21. SubscribeLocalEvent<GasTileOverlayComponent, ComponentGetState>(OnGetState);
  22. List<int> visibleGases = new();
  23. for (var i = 0; i < Atmospherics.TotalNumberOfGases; i++)
  24. {
  25. var gasPrototype = ProtoMan.Index<GasPrototype>(i.ToString());
  26. if (!string.IsNullOrEmpty(gasPrototype.GasOverlayTexture) || !string.IsNullOrEmpty(gasPrototype.GasOverlaySprite) && !string.IsNullOrEmpty(gasPrototype.GasOverlayState))
  27. visibleGases.Add(i);
  28. }
  29. VisibleGasId = visibleGases.ToArray();
  30. }
  31. private void OnGetState(EntityUid uid, GasTileOverlayComponent component, ref ComponentGetState args)
  32. {
  33. if (PvsEnabled && !args.ReplayState)
  34. return;
  35. // Should this be a full component state or a delta-state?
  36. if (args.FromTick <= component.CreationTick || args.FromTick <= component.ForceTick)
  37. {
  38. args.State = new GasTileOverlayState(component.Chunks);
  39. return;
  40. }
  41. var data = new Dictionary<Vector2i, GasOverlayChunk>();
  42. foreach (var (index, chunk) in component.Chunks)
  43. {
  44. if (chunk.LastUpdate >= args.FromTick)
  45. data[index] = chunk;
  46. }
  47. args.State = new GasTileOverlayDeltaState(data, new(component.Chunks.Keys));
  48. }
  49. public static Vector2i GetGasChunkIndices(Vector2i indices)
  50. {
  51. return new((int) MathF.Floor((float) indices.X / ChunkSize), (int) MathF.Floor((float) indices.Y / ChunkSize));
  52. }
  53. [Serializable, NetSerializable]
  54. public readonly struct GasOverlayData : IEquatable<GasOverlayData>
  55. {
  56. [ViewVariables]
  57. public readonly byte FireState;
  58. [ViewVariables]
  59. public readonly byte[] Opacity;
  60. // TODO change fire color based on temps
  61. // But also: dont dirty on a 0.01 kelvin change in temperatures.
  62. // Either have a temp tolerance, or map temperature -> byte levels
  63. public GasOverlayData(byte fireState, byte[] opacity)
  64. {
  65. FireState = fireState;
  66. Opacity = opacity;
  67. }
  68. public bool Equals(GasOverlayData other)
  69. {
  70. if (FireState != other.FireState)
  71. return false;
  72. if (Opacity?.Length != other.Opacity?.Length)
  73. return false;
  74. if (Opacity != null && other.Opacity != null)
  75. {
  76. for (var i = 0; i < Opacity.Length; i++)
  77. {
  78. if (Opacity[i] != other.Opacity[i])
  79. return false;
  80. }
  81. }
  82. return true;
  83. }
  84. }
  85. [Serializable, NetSerializable]
  86. public sealed class GasOverlayUpdateEvent : EntityEventArgs
  87. {
  88. public Dictionary<NetEntity, List<GasOverlayChunk>> UpdatedChunks = new();
  89. public Dictionary<NetEntity, HashSet<Vector2i>> RemovedChunks = new();
  90. }
  91. }
  92. }