Gas overlay chunking (#1678)

Co-authored-by: Metal Gear Sloth <metalgearsloth@gmail.com>
This commit is contained in:
metalgearsloth
2020-08-18 00:12:21 +10:00
committed by GitHub
parent 0e6f55a23d
commit f54ba4b6d5
16 changed files with 786 additions and 306 deletions

View File

@@ -0,0 +1,103 @@
using System;
using System.Collections;
using System.Collections.Generic;
using Robust.Shared.Interfaces.Timing;
using Robust.Shared.IoC;
using Robust.Shared.Map;
using Robust.Shared.Timing;
using Robust.Shared.Utility;
namespace Content.Shared.GameObjects.EntitySystems.Atmos
{
public sealed class GasOverlayChunk
{
/// <summary>
/// Grid for this chunk
/// </summary>
public GridId GridIndices { get; }
/// <summary>
/// Origin of this chunk
/// </summary>
public MapIndices MapIndices { get; }
public SharedGasTileOverlaySystem.GasOverlayData[,] TileData = new SharedGasTileOverlaySystem.GasOverlayData[SharedGasTileOverlaySystem.ChunkSize, SharedGasTileOverlaySystem.ChunkSize];
public GameTick LastUpdate { get; private set; }
public GasOverlayChunk(GridId gridIndices, MapIndices mapIndices)
{
GridIndices = gridIndices;
MapIndices = mapIndices;
}
public void Dirty(GameTick currentTick)
{
LastUpdate = currentTick;
}
/// <summary>
/// Flags Dirty if the data is different.
/// </summary>
/// <param name="data"></param>
/// <param name="indices"></param>
public void Update(SharedGasTileOverlaySystem.GasOverlayData data, MapIndices indices)
{
DebugTools.Assert(InBounds(indices));
var (offsetX, offsetY) = (indices.X - MapIndices.X,
indices.Y - MapIndices.Y);
TileData[offsetX, offsetY] = data;
}
public void Update(SharedGasTileOverlaySystem.GasOverlayData data, byte x, byte y)
{
DebugTools.Assert(x < SharedGasTileOverlaySystem.ChunkSize && y < SharedGasTileOverlaySystem.ChunkSize);
TileData[x, y] = data;
}
public IEnumerable<SharedGasTileOverlaySystem.GasOverlayData> GetAllData()
{
for (var x = 0; x < SharedGasTileOverlaySystem.ChunkSize; x++)
{
for (var y = 0; y < SharedGasTileOverlaySystem.ChunkSize; y++)
{
yield return TileData[x, y];
}
}
}
public void GetData(List<(MapIndices, SharedGasTileOverlaySystem.GasOverlayData)> existingData, HashSet<MapIndices> indices)
{
foreach (var index in indices)
{
existingData.Add((index, GetData(index)));
}
}
public IEnumerable<MapIndices> GetAllIndices()
{
for (var x = 0; x < SharedGasTileOverlaySystem.ChunkSize; x++)
{
for (var y = 0; y < SharedGasTileOverlaySystem.ChunkSize; y++)
{
yield return new MapIndices(MapIndices.X + x, MapIndices.Y + y);
}
}
}
public SharedGasTileOverlaySystem.GasOverlayData GetData(MapIndices indices)
{
DebugTools.Assert(InBounds(indices));
return TileData[indices.X - MapIndices.X, indices.Y - MapIndices.Y];
}
private bool InBounds(MapIndices indices)
{
if (indices.X < MapIndices.X || indices.Y < MapIndices.Y) return false;
if (indices.X >= MapIndices.X + SharedGasTileOverlaySystem.ChunkSize || indices.Y >= MapIndices.Y + SharedGasTileOverlaySystem.ChunkSize) return false;
return true;
}
}
}

View File

@@ -0,0 +1,98 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Robust.Shared.GameObjects;
using Robust.Shared.GameObjects.Systems;
using Robust.Shared.Map;
using Robust.Shared.Serialization;
using Robust.Shared.Utility;
namespace Content.Shared.GameObjects.EntitySystems.Atmos
{
public abstract class SharedGasTileOverlaySystem : EntitySystem
{
public const byte ChunkSize = 8;
protected float AccumulatedFrameTime;
public static MapIndices GetGasChunkIndices(MapIndices indices)
{
return new MapIndices((int) Math.Floor((float) indices.X / ChunkSize) * ChunkSize, (int) MathF.Floor((float) indices.Y / ChunkSize) * ChunkSize);
}
[Serializable, NetSerializable]
public struct GasData
{
public byte Index { get; set; }
public byte Opacity { get; set; }
public GasData(byte gasId, byte opacity)
{
Index = gasId;
Opacity = opacity;
}
}
[Serializable, NetSerializable]
public readonly struct GasOverlayData : IEquatable<GasOverlayData>
{
public readonly byte FireState;
public readonly float FireTemperature;
public readonly GasData[] Gas;
public GasOverlayData(byte fireState, float fireTemperature, GasData[] gas)
{
FireState = fireState;
FireTemperature = fireTemperature;
Gas = gas;
}
public bool Equals(GasOverlayData other)
{
// TODO: Moony had a suggestion on how to do this faster with the hash
// https://discordapp.com/channels/310555209753690112/310555209753690112/744080145219846204
// Aside from that I can't really see any low-hanging fruit CPU perf wise.
if (Gas?.Length != other.Gas?.Length) return false;
if (FireState != other.FireState) return false;
if (FireTemperature != other.FireTemperature) return false;
if (Gas == null)
{
return true;
}
DebugTools.Assert(other.Gas != null);
for (var i = 0; i < Gas.Length; i++)
{
var thisGas = Gas[i];
var otherGas = other.Gas[i];
if (!thisGas.Equals(otherGas))
{
return false;
}
}
return true;
}
}
/// <summary>
/// Invalid tiles for the gas overlay.
/// No point re-sending every tile if only a subset might have been updated.
/// </summary>
[Serializable, NetSerializable]
public sealed class GasOverlayMessage : EntitySystemMessage
{
public GridId GridId { get; }
public List<(MapIndices, GasOverlayData)> OverlayData { get; }
public GasOverlayMessage(GridId gridIndices, List<(MapIndices,GasOverlayData)> overlayData)
{
GridId = gridIndices;
OverlayData = overlayData;
}
}
}
}

View File

@@ -1,72 +0,0 @@
using System;
using Robust.Shared.GameObjects;
using Robust.Shared.GameObjects.Systems;
using Robust.Shared.Map;
using Robust.Shared.Serialization;
namespace Content.Shared.GameObjects.EntitySystems
{
public abstract class SharedGasTileOverlaySystem : EntitySystem
{
[Serializable, NetSerializable]
public struct GasData
{
public int Index { get; set; }
public float Opacity { get; set; }
public GasData(int gasId, float opacity)
{
Index = gasId;
Opacity = opacity;
}
}
[Serializable, NetSerializable]
public readonly struct GasOverlayData
{
public readonly int FireState;
public readonly float FireTemperature;
public readonly GasData[] Gas;
public GasOverlayData(int fireState, float fireTemperature, GasData[] gas)
{
FireState = fireState;
FireTemperature = fireTemperature;
Gas = gas;
}
}
[Serializable, NetSerializable]
public readonly struct GasTileOverlayData
{
public readonly GridId GridIndex;
public readonly MapIndices GridIndices;
public readonly GasOverlayData Data;
public GasTileOverlayData(GridId gridIndex, MapIndices gridIndices, GasOverlayData data)
{
GridIndex = gridIndex;
GridIndices = gridIndices;
Data = data;
}
public override int GetHashCode()
{
return GridIndex.GetHashCode() ^ GridIndices.GetHashCode() ^ Data.GetHashCode();
}
}
[Serializable, NetSerializable]
public class GasTileOverlayMessage : EntitySystemMessage
{
public GasTileOverlayData[] OverlayData { get; }
public bool ClearAllOtherOverlays { get; }
public GasTileOverlayMessage(GasTileOverlayData[] overlayData, bool clearAllOtherOverlays = false)
{
OverlayData = overlayData;
ClearAllOtherOverlays = clearAllOtherOverlays;
}
}
}
}