using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using Godot; using MessagePack; using Expression = System.Linq.Expressions.Expression; [Union(0, typeof(BlockLayer))] [Union(1, typeof(ColorLayer))] public interface IChunkLayer : IDeSerializable { Type AccessType { get; } bool IsDefault { get; } event Action Changed; } public interface IChunkLayer : IChunkLayer { T this[BlockPos pos] { get; set; } T this[int x, int y] { get; set; } T this[int index] { get; } } public class ArrayChunkLayer : IChunkLayer { private static readonly IEqualityComparer COMPARER = EqualityComparer.Default; private T[] _data = new T[Chunk.LENGTH * Chunk.LENGTH]; public int NonDefaultCount { get; protected set; } = 0; public Type AccessType => typeof(T); public bool IsDefault => NonDefaultCount == 0; public event Action Changed; public T this[int index] => _data[index]; public T this[int x, int y] { get => this[Chunk.GetIndex(x, y)]; set => this[new BlockPos(x, y)] = value; } public T this[BlockPos pos] { get => this[Chunk.GetIndex(pos.X, pos.Y)]; set { var index = Chunk.GetIndex(pos.X, pos.Y); var previous = _data[index]; if (COMPARER.Equals(value, previous)) return; _data[index] = value; if (!COMPARER.Equals(previous, default)) NonDefaultCount--; if (!COMPARER.Equals(value, default)) NonDefaultCount++; Changed?.Invoke(this, pos); } } public void Serialize(ref MessagePackWriter writer, MessagePackSerializerOptions options) { writer.Write(NonDefaultCount); MessagePackSerializer.Serialize(ref writer, _data); } public void Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options) { NonDefaultCount = reader.ReadInt32(); _data = MessagePackSerializer.Deserialize(ref reader); } } public class TranslationLayer : IChunkLayer { private readonly ArrayChunkLayer _data = new ArrayChunkLayer(); private readonly Func _from; private readonly Func _to; public TranslationLayer(Func from, Func to) { _from = from; _to = to; } public Type AccessType => typeof(TAccess); public bool IsDefault => _data.IsDefault; public event Action Changed { add => _data.Changed += value; remove => _data.Changed -= value; } public TAccess this[BlockPos pos] { get => _from(_data[pos]); set => _data[pos] = _to(value); } public TAccess this[int x, int y] { get => _from(_data[x, y]); set => _data[x, y] = _to(value); } public TAccess this[int index] => _from(_data[index]); public void Serialize(ref MessagePackWriter writer, MessagePackSerializerOptions options) => _data.Serialize(ref writer, options); public void Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options) => _data.Deserialize(ref reader, options); } [MessagePackFormatter(typeof(DeSerializableFormatter))] public class BlockLayer : TranslationLayer { public static readonly Block DEFAULT = Blocks.AIR; public BlockLayer() : base(i => BlockRegistry.Get(i), b => (byte)b.ID) { } } [MessagePackFormatter(typeof(DeSerializableFormatter))] public class ColorLayer : TranslationLayer { public static readonly Color DEFAULT = Colors.White; public ColorLayer() : base(i => new Color(i), c => c.ToRgba32()) { } } public static class ChunkLayerRegistry { private static readonly Dictionary> _factories = new Dictionary>(); private static readonly Dictionary _defaults = new Dictionary(); static ChunkLayerRegistry() { foreach (var attr in typeof(IChunkLayer).GetCustomAttributes()) { var id = (byte)attr.Key; var type = attr.SubType; var ctor = type.GetConstructor(Type.EmptyTypes); var fact = Expression.Lambda>(Expression.New(ctor)); var storedType = type.GetInterfaces() .Single(i => i.IsGenericType && (i.GetGenericTypeDefinition() == typeof(IChunkLayer<>))) .GenericTypeArguments[0]; _factories.Add(storedType, fact.Compile()); _defaults.Add(storedType, type.GetField("DEFAULT").GetValue(null)); } } public static bool Has() => _factories.ContainsKey(typeof(T)); public static bool TryGetDefault(out T @default) { if (_defaults.TryGetValue(typeof(T), out var defaultObj)) { @default = (T)defaultObj; return true; } else { @default = default; return false; } } public static IChunkLayer Create() => (IChunkLayer)Create(typeof(T)); public static IChunkLayer Create(Type type) => _factories[type](); // static ChunkLayerRegistry() // { // Register(0, Blocks.AIR, () => new BlockLayer()); // Register(1, Colors.White, () => new ColorLayer()); // } // public static void Register(byte id, T @default, Func> factory) // { // var info = new Info(id, @default, factory); // _byType.Add(typeof(T), info); // _byID.Add(id, info); // } // public interface IInfo // { // Type Type { get; } // byte ID { get; } // object Default { get; } // Func Factory { get; } // } // public class Info : IInfo // { // public byte ID { get; } // public T Default { get; } // public Func> Factory { get; } // Type IInfo.Type => typeof(T); // object IInfo.Default => Default; // Func IInfo.Factory => Factory; // public Info(byte id, T @default, Func> factory) // { ID = id; Default = @default; Factory = factory; } // } // public static bool TryGet(out Info info) // { // if (TryGet(typeof(T), out var infoObj)) // { info = (Info)infoObj; return true; } // else { info = null; return false; } // } // public static bool TryGet(Type type, out IInfo info) // => _byType.TryGetValue(type, out info); // public static bool TryGet(byte id, out IInfo info) // => _byID.TryGetValue(id, out info); }