diff --git a/MLEM.Data/MLEM.Data.csproj b/MLEM.Data/MLEM.Data.csproj new file mode 100644 index 0000000..86a3a94 --- /dev/null +++ b/MLEM.Data/MLEM.Data.csproj @@ -0,0 +1,28 @@ + + + netstandard2.0 + + + + Ellpeck + Some simple data and network handling for (M)LEM (L)ibrary by (E)llpeck for (M)onoGame + monogame ellpeck mlem utility extensions data network serialize + https://github.com/Ellpeck/MLEM + https://github.com/Ellpeck/MLEM + https://github.com/Ellpeck/MLEM/blob/master/LICENSE + 1.0.0 + + + + + + all + + + + + + + + + \ No newline at end of file diff --git a/MLEM.Data/NetBufferSerializer.cs b/MLEM.Data/NetBufferSerializer.cs new file mode 100644 index 0000000..0f41bab --- /dev/null +++ b/MLEM.Data/NetBufferSerializer.cs @@ -0,0 +1,61 @@ +using System; +using System.Collections.Generic; +using System.Reflection; +using Lidgren.Network; + +namespace MLEM.Data { + public class NetBufferSerializer { + + private readonly Dictionary> writeFunctions = new Dictionary>(); + private readonly Dictionary> readFunctions = new Dictionary>(); + private readonly Dictionary fieldCache = new Dictionary(); + + public NetBufferSerializer() { + foreach (var method in typeof(NetBuffer).GetMethods(BindingFlags.Instance | BindingFlags.Public)) { + if (method.GetParameters().Length == 0 && method.Name.StartsWith("Read", StringComparison.Ordinal) && method.Name.Substring(4) == method.ReturnType.Name) + this.readFunctions[method.ReturnType] = buffer => method.Invoke(buffer, null); + } + foreach (var method in typeof(NetBuffer).GetMethods(BindingFlags.Instance | BindingFlags.Public)) { + if (method.Name.Equals("Write", StringComparison.InvariantCulture)) { + var parameters = method.GetParameters(); + if (parameters.Length == 1) + this.writeFunctions[parameters[0].ParameterType] = (buffer, o) => method.Invoke(buffer, new[] {o}); + } + } + this.AddHandler((buffer, o) => buffer.Write(o), buffer => buffer.ReadVector2()); + this.AddHandler((buffer, o) => buffer.Write(o), buffer => buffer.ReadGuid()); + this.AddHandler((buffer, o) => buffer.Write(o), buffer => buffer.ReadDirection()); + } + + public void Serialize(NetBuffer buffer, object o, BindingFlags flags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) { + foreach (var field in this.GetFields(o.GetType(), flags)) { + if (!this.writeFunctions.TryGetValue(field.FieldType, out var func)) + throw new ArgumentException($"The type {field.FieldType} doesn't have a writer"); + func(buffer, field.GetValue(o)); + } + } + + public void Deserialize(NetBuffer buffer, object o, BindingFlags flags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) { + foreach (var field in this.GetFields(o.GetType(), flags)) { + if (!this.readFunctions.TryGetValue(field.FieldType, out var func)) + throw new ArgumentException($"The type {field.FieldType} doesn't have a reader"); + field.SetValue(o, func(buffer)); + } + } + + private IEnumerable GetFields(Type type, BindingFlags flags) { + if (!this.fieldCache.TryGetValue(type, out var fields)) { + fields = type.GetFields(flags); + Array.Sort(fields, (f1, f2) => string.Compare(f1.Name, f2.Name, StringComparison.Ordinal)); + this.fieldCache.Add(type, fields); + } + return fields; + } + + public void AddHandler(Action write, Func read) { + this.writeFunctions.Add(typeof(T), (buffer, o) => write(buffer, (T) o)); + this.readFunctions.Add(typeof(T), buffer => read(buffer)); + } + + } +} \ No newline at end of file diff --git a/MLEM.Data/NetExtensions.cs b/MLEM.Data/NetExtensions.cs new file mode 100644 index 0000000..93489e2 --- /dev/null +++ b/MLEM.Data/NetExtensions.cs @@ -0,0 +1,54 @@ +using System; +using System.IO; +using System.IO.Compression; +using Lidgren.Network; +using Microsoft.Xna.Framework; +using MLEM.Misc; +using Newtonsoft.Json; +using Newtonsoft.Json.Bson; + +namespace MLEM.Data { + public static class NetExtensions { + + public static void Write(this NetBuffer buffer, Vector2 vector) { + buffer.Write(vector.X); + buffer.Write(vector.Y); + } + + public static Vector2 ReadVector2(this NetBuffer buffer) { + return new Vector2(buffer.ReadFloat(), buffer.ReadFloat()); + } + + public static void Write(this NetBuffer buffer, Guid guid) { + buffer.Write(guid.ToByteArray()); + } + + public static Guid ReadGuid(this NetBuffer buffer) { + return new Guid(buffer.ReadBytes(16)); + } + + public static void Write(this NetBuffer buffer, Direction2 direction) { + buffer.Write((short) direction); + } + + public static Direction2 ReadDirection(this NetBuffer buffer) { + return (Direction2) buffer.ReadInt16(); + } + + public static void WriteObject(this NetBuffer buffer, T obj, JsonSerializer serializer) { + using (var memory = new MemoryStream()) { + using (var gzip = new GZipStream(memory, CompressionLevel.Fastest, true)) + serializer.Serialize(new BsonDataWriter(gzip), obj, typeof(T)); + buffer.Write(memory.ToArray()); + } + } + + public static T ReadObject(this NetBuffer buffer, JsonSerializer serializer) { + using (var memory = new MemoryStream(buffer.ReadBytes(buffer.LengthBytes))) { + using (var gzip = new GZipStream(memory, CompressionMode.Decompress, true)) + return serializer.Deserialize(new BsonDataReader(gzip)); + } + } + + } +} \ No newline at end of file diff --git a/MLEM.sln b/MLEM.sln index 77b4d80..6d5b2e0 100644 --- a/MLEM.sln +++ b/MLEM.sln @@ -16,6 +16,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sandbox", "Sandbox\Sandbox. EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Demos.Android", "Demos.Android\Demos.Android.csproj", "{410C0262-131C-4D0E-910D-D01B4F7143E0}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MLEM.Data", "MLEM.Data\MLEM.Data.csproj", "{28938AAA-FB91-4E6F-8511-0DB99EC831F7}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -54,5 +56,9 @@ Global {410C0262-131C-4D0E-910D-D01B4F7143E0}.Debug|Any CPU.Build.0 = Debug|Any CPU {410C0262-131C-4D0E-910D-D01B4F7143E0}.Release|Any CPU.ActiveCfg = Release|Any CPU {410C0262-131C-4D0E-910D-D01B4F7143E0}.Release|Any CPU.Build.0 = Release|Any CPU + {28938AAA-FB91-4E6F-8511-0DB99EC831F7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {28938AAA-FB91-4E6F-8511-0DB99EC831F7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {28938AAA-FB91-4E6F-8511-0DB99EC831F7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {28938AAA-FB91-4E6F-8511-0DB99EC831F7}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection EndGlobal