Przeglądaj źródła

1.Bson自定义SortedDictionary序列化类
2.MemoryPack自定义SortedDictionary序列化
3.修改Entity,去掉ChildrenDB跟ComponentDB

tanghai 1 rok temu
rodzic
commit
c9c74c5112
19 zmienionych plików z 1384 dodań i 66 usunięć
  1. 1 1
      Unity/Assets/Resources/GlobalConfig.asset
  2. 25 61
      Unity/Assets/Scripts/Core/Entity/Entity.cs
  3. 294 0
      Unity/Assets/Scripts/Core/Serialize/BsonSortedDictionaryInterfaceImplementerSerializer.cs
  4. 11 0
      Unity/Assets/Scripts/Core/Serialize/BsonSortedDictionaryInterfaceImplementerSerializer.cs.meta
  5. 770 0
      Unity/Assets/Scripts/Core/Serialize/BsonSortedDictionarySerializerBase.cs
  6. 11 0
      Unity/Assets/Scripts/Core/Serialize/BsonSortedDictionarySerializerBase.cs.meta
  7. 97 0
      Unity/Assets/Scripts/Core/Serialize/MemoryPackSortedDictionaryFormatter.cs
  8. 11 0
      Unity/Assets/Scripts/Core/Serialize/MemoryPackSortedDictionaryFormatter.cs.meta
  9. 8 0
      Unity/Assets/Scripts/Editor/EntitySerializePlugin.meta
  10. 20 0
      Unity/Assets/Scripts/Editor/EntitySerializePlugin/EntityMonoBehaviourEditor.cs
  11. 11 0
      Unity/Assets/Scripts/Editor/EntitySerializePlugin/EntityMonoBehaviourEditor.cs.meta
  12. 31 0
      Unity/Assets/Scripts/Editor/EntitySerializePlugin/EntitySerializer.cs
  13. 11 0
      Unity/Assets/Scripts/Editor/EntitySerializePlugin/EntitySerializer.cs.meta
  14. 24 1
      Unity/Assets/Scripts/Hotfix/Share/FiberInit_Main.cs
  15. 8 0
      Unity/Assets/Scripts/Loader/Plugins/EntityMonoBehaviour.meta
  16. 9 0
      Unity/Assets/Scripts/Loader/Plugins/EntityMonoBehaviour/EntityMonoBehaviour.cs
  17. 11 0
      Unity/Assets/Scripts/Loader/Plugins/EntityMonoBehaviour/EntityMonoBehaviour.cs.meta
  18. 29 3
      Unity/Assets/Scripts/Model/Share/Entry.cs
  19. 2 0
      Unity/Assets/Scripts/Model/Share/MongoRegister.cs

+ 1 - 1
Unity/Assets/Resources/GlobalConfig.asset

@@ -14,6 +14,6 @@ MonoBehaviour:
   m_EditorClassIdentifier: 
   CodeMode: 3
   EnableDll: 1
-  BuildType: 1
+  BuildType: 0
   AppType: 7
   EPlayMode: 0

+ 25 - 61
Unity/Assets/Scripts/Core/Entity/Entity.cs

@@ -2,6 +2,7 @@
 using System.Collections.Generic;
 using MemoryPack;
 using MongoDB.Bson.Serialization.Attributes;
+using MongoDB.Bson.Serialization.Options;
 
 namespace ET
 {
@@ -221,11 +222,11 @@ namespace ET
                 this.ViewGO.GetComponent<ComponentView>().Component = this;
                 this.ViewGO.transform.SetParent(this.Parent == null ?
                         UnityEngine.GameObject.Find("Global").transform : this.Parent.ViewGO.transform);
-                foreach (var child in this.Children.Values)
+                foreach (Entity child in this.Children.Values)
                 {
                     child.ViewGO.transform.SetParent(this.ViewGO.transform);
                 }
-                foreach (var comp in this.Components.Values)
+                foreach (Entity comp in this.Components.Values)
                 {
                     comp.ViewGO.transform.SetParent(this.ViewGO.transform);
                 }
@@ -330,9 +331,9 @@ namespace ET
                     this.IsRegister = true;
 
                     // 反序列化出来的需要设置父子关系
-                    if (this.componentsDB != null)
+                    if (this.components != null)
                     {
-                        foreach (Entity component in this.componentsDB)
+                        foreach ((long _, Entity component) in this.components)
                         {
                             component.IsComponent = true;
                             this.Components.Add(this.GetLongHashCode(component.GetType()), component);
@@ -340,9 +341,9 @@ namespace ET
                         }
                     }
 
-                    if (this.childrenDB != null)
+                    if (this.children != null)
                     {
-                        foreach (Entity child in this.childrenDB)
+                        foreach ((long _, Entity child) in this.children)
                         {
                             child.IsComponent = false;
                             this.Children.Add(child.Id, child);
@@ -377,11 +378,9 @@ namespace ET
         }
 
         [MemoryPackInclude]
-        [BsonElement("Children")]
+        [BsonElement]
         [BsonIgnoreIfNull]
-        protected List<Entity> childrenDB;
-
-        [BsonIgnore]
+        [BsonDictionaryOptions(DictionaryRepresentation.ArrayOfArrays)]
         private SortedDictionary<long, Entity> children;
 
         [MemoryPackIgnore]
@@ -416,11 +415,9 @@ namespace ET
         }
 
         [MemoryPackInclude]
-        [BsonElement("C")]
+        [BsonElement]
         [BsonIgnoreIfNull]
-        protected List<Entity> componentsDB;
-
-        [BsonIgnore]
+        [BsonDictionaryOptions(DictionaryRepresentation.ArrayOfArrays)]
         private SortedDictionary<long, Entity> components;
 
         [MemoryPackIgnore]
@@ -471,19 +468,12 @@ namespace ET
                 }
 
                 this.children.Clear();
-                objectPool.Recycle(this.children);
-                this.children = null;
 
-                if (this.childrenDB != null)
+                if (this.IsNew)
                 {
-                    this.childrenDB.Clear();
-                    // 创建的才需要回到池中,从db中不需要回收
-                    if (this.IsNew)
-                    {
-                        objectPool.Recycle(this.childrenDB);
-                        this.childrenDB = null;
-                    }
+                    objectPool.Recycle(this.children);
                 }
+                this.children = null;
             }
 
             // 清理Component
@@ -495,19 +485,11 @@ namespace ET
                 }
 
                 this.components.Clear();
-                objectPool.Recycle(this.components);
-                this.components = null;
-
-                // 创建的才需要回到池中,从db中不需要回收
-                if (this.componentsDB != null)
+                if (this.IsNew)
                 {
-                    this.componentsDB.Clear();
-                    if (this.IsNew)
-                    {
-                        objectPool.Recycle(this.componentsDB);
-                        this.componentsDB = null;
-                    }
+                    objectPool.Recycle(this.components);
                 }
+                this.components = null;
             }
 
             // 触发Destroy事件
@@ -581,12 +563,11 @@ namespace ET
                 return;
             }
 
-            if (!this.children.TryGetValue(id, out Entity child))
+            if (!this.children.Remove(id, out Entity child))
             {
                 return;
             }
 
-            this.children.Remove(id);
             child.Dispose();
         }
 
@@ -939,42 +920,25 @@ namespace ET
 
         public override void BeginInit()
         {
+            if (this is not ISerializeToEntity)
+            {
+                return;
+            }
+            
             EntitySystemSingleton.Instance.Serialize(this);
             
-            if (!this.IsCreated) return;
-
-            this.componentsDB?.Clear();
             if (this.components != null && this.components.Count != 0)
             {
-                ObjectPool objectPool = ObjectPool.Instance;
-                foreach (Entity entity in this.components.Values)
+                foreach ((long _, Entity entity) in this.components)
                 {
-                    if (entity is not ISerializeToEntity)
-                    {
-                        continue;
-                    }
-
-                    this.componentsDB ??= objectPool.Fetch<List<Entity>>();
-                    this.componentsDB.Add(entity);
-
                     entity.BeginInit();
                 }
             }
 
-            this.childrenDB?.Clear();
             if (this.children != null && this.children.Count != 0)
             {
-                ObjectPool objectPool = ObjectPool.Instance;
-                foreach (Entity entity in this.children.Values)
+                foreach ((long _, Entity entity) in this.children)
                 {
-                    if (entity is not ISerializeToEntity)
-                    {
-                        continue;
-                    }
-
-                    this.childrenDB ??= objectPool.Fetch<List<Entity>>();
-                    this.childrenDB.Add(entity);
-
                     entity.BeginInit();
                 }
             }

+ 294 - 0
Unity/Assets/Scripts/Core/Serialize/BsonSortedDictionaryInterfaceImplementerSerializer.cs

@@ -0,0 +1,294 @@
+/* Copyright 2010-present MongoDB Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using MongoDB.Bson.Serialization;
+using MongoDB.Bson.Serialization.Options;
+using MongoDB.Bson.Serialization.Serializers;
+
+namespace ET
+{
+    /// <summary>
+    /// Represents a serializer for a class that implements IDictionary.
+    /// </summary>
+    /// <typeparam name="TDictionary">The type of the dictionary.</typeparam>
+    public class BsonSortedDictionaryInterfaceImplementerSerializer<TDictionary> :
+        BsonSortedDictionarySerializerBase<TDictionary>,
+        IChildSerializerConfigurable,
+        IDictionaryRepresentationConfigurable
+            where TDictionary : class, IDictionary, new()
+    {
+        /// <summary>
+        /// Initializes a new instance of the <see cref="DictionaryInterfaceImplementerSerializer{TDictionary}"/> class.
+        /// </summary>
+        public BsonSortedDictionaryInterfaceImplementerSerializer()
+        {
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="DictionaryInterfaceImplementerSerializer{TDictionary}"/> class.
+        /// </summary>
+        /// <param name="dictionaryRepresentation">The dictionary representation.</param>
+        public BsonSortedDictionaryInterfaceImplementerSerializer(DictionaryRepresentation dictionaryRepresentation)
+            : base(dictionaryRepresentation)
+        {
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="DictionaryInterfaceImplementerSerializer{TDictionary}"/> class.
+        /// </summary>
+        /// <param name="dictionaryRepresentation">The dictionary representation.</param>
+        /// <param name="keySerializer">The key serializer.</param>
+        /// <param name="valueSerializer">The value serializer.</param>
+        public BsonSortedDictionaryInterfaceImplementerSerializer(DictionaryRepresentation dictionaryRepresentation, IBsonSerializer keySerializer, IBsonSerializer valueSerializer)
+            : base(dictionaryRepresentation, keySerializer, valueSerializer)
+        {
+        }
+
+        // public methods
+        /// <summary>
+        /// Returns a serializer that has been reconfigured with the specified dictionary representation.
+        /// </summary>
+        /// <param name="dictionaryRepresentation">The dictionary representation.</param>
+        /// <returns>The reconfigured serializer.</returns>
+        public BsonSortedDictionaryInterfaceImplementerSerializer<TDictionary> WithDictionaryRepresentation(DictionaryRepresentation dictionaryRepresentation)
+        {
+            if (dictionaryRepresentation == DictionaryRepresentation)
+            {
+                return this;
+            }
+            else
+            {
+                return new BsonSortedDictionaryInterfaceImplementerSerializer<TDictionary>(dictionaryRepresentation, KeySerializer, ValueSerializer);
+            }
+        }
+
+        /// <summary>
+        /// Returns a serializer that has been reconfigured with the specified dictionary representation and key value serializers.
+        /// </summary>
+        /// <param name="dictionaryRepresentation">The dictionary representation.</param>
+        /// <param name="keySerializer">The key serializer.</param>
+        /// <param name="valueSerializer">The value serializer.</param>
+        /// <returns>The reconfigured serializer.</returns>
+        public BsonSortedDictionaryInterfaceImplementerSerializer<TDictionary> WithDictionaryRepresentation(DictionaryRepresentation dictionaryRepresentation, IBsonSerializer keySerializer, IBsonSerializer valueSerializer)
+        {
+            if (dictionaryRepresentation == DictionaryRepresentation && keySerializer == KeySerializer && valueSerializer == ValueSerializer)
+            {
+                return this;
+            }
+            else
+            {
+                return new BsonSortedDictionaryInterfaceImplementerSerializer<TDictionary>(dictionaryRepresentation, keySerializer, valueSerializer);
+            }
+        }
+
+        /// <summary>
+        /// Returns a serializer that has been reconfigured with the specified key serializer.
+        /// </summary>
+        /// <param name="keySerializer">The key serializer.</param>
+        /// <returns>The reconfigured serializer.</returns>
+        public BsonSortedDictionaryInterfaceImplementerSerializer<TDictionary> WithKeySerializer(IBsonSerializer keySerializer)
+        {
+            if (keySerializer == KeySerializer)
+            {
+                return this;
+            }
+            else
+            {
+                return new BsonSortedDictionaryInterfaceImplementerSerializer<TDictionary>(DictionaryRepresentation, keySerializer, ValueSerializer);
+            }
+        }
+
+        /// <summary>
+        /// Returns a serializer that has been reconfigured with the specified value serializer.
+        /// </summary>
+        /// <param name="valueSerializer">The value serializer.</param>
+        /// <returns>The reconfigured serializer.</returns>
+        public BsonSortedDictionaryInterfaceImplementerSerializer<TDictionary> WithValueSerializer(IBsonSerializer valueSerializer)
+        {
+            if (valueSerializer == ValueSerializer)
+            {
+                return this;
+            }
+            else
+            {
+                return new BsonSortedDictionaryInterfaceImplementerSerializer<TDictionary>(DictionaryRepresentation, KeySerializer, valueSerializer);
+            }
+        }
+
+        // protected methods
+        /// <summary>
+        /// Creates the instance.
+        /// </summary>
+        /// <returns>The instance.</returns>
+        protected override TDictionary CreateInstance()
+        {
+            return new TDictionary();
+        }
+
+        // explicit interface implementations
+        IBsonSerializer IChildSerializerConfigurable.ChildSerializer
+        {
+            get { return ValueSerializer; }
+        }
+
+        IBsonSerializer IChildSerializerConfigurable.WithChildSerializer(IBsonSerializer childSerializer)
+        {
+            return WithValueSerializer(childSerializer);
+        }
+
+        IBsonSerializer IDictionaryRepresentationConfigurable.WithDictionaryRepresentation(DictionaryRepresentation dictionaryRepresentation)
+        {
+            return WithDictionaryRepresentation(dictionaryRepresentation);
+        }
+    }
+
+    /// <summary>
+    /// Represents a serializer for a class that implements <see cref="IDictionary{TKey, TValue}"/>.
+    /// </summary>
+    /// <typeparam name="TDictionary">The type of the dictionary.</typeparam>
+    /// <typeparam name="TKey">The type of the key.</typeparam>
+    /// <typeparam name="TValue">The type of the value.</typeparam>
+    public class BsonSortedDictionaryInterfaceImplementerSerializer<TDictionary, TKey, TValue> :
+        SortedDictionarySerializerBase<TDictionary, TKey, TValue>,
+        IChildSerializerConfigurable,
+        IDictionaryRepresentationConfigurable<BsonSortedDictionaryInterfaceImplementerSerializer<TDictionary, TKey, TValue>>
+            where TDictionary : class, IDictionary<TKey, TValue>
+    {
+        /// <summary>
+        /// Initializes a new instance of the <see cref="DictionaryInterfaceImplementerSerializer{TDictionary, TKey, TValue}"/> class.
+        /// </summary>
+        public BsonSortedDictionaryInterfaceImplementerSerializer()
+        {
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="DictionaryInterfaceImplementerSerializer{TDictionary, TKey, TValue}"/> class.
+        /// </summary>
+        /// <param name="dictionaryRepresentation">The dictionary representation.</param>
+        public BsonSortedDictionaryInterfaceImplementerSerializer(DictionaryRepresentation dictionaryRepresentation)
+            : base(dictionaryRepresentation)
+        {
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="DictionaryInterfaceImplementerSerializer{TDictionary, TKey, TValue}"/> class.
+        /// </summary>
+        /// <param name="dictionaryRepresentation">The dictionary representation.</param>
+        /// <param name="keySerializer">The key serializer.</param>
+        /// <param name="valueSerializer">The value serializer.</param>
+        public BsonSortedDictionaryInterfaceImplementerSerializer(DictionaryRepresentation dictionaryRepresentation, IBsonSerializer<TKey> keySerializer, IBsonSerializer<TValue> valueSerializer)
+            : base(dictionaryRepresentation, keySerializer, valueSerializer)
+        {
+        }
+
+        // public methods
+        /// <summary>
+        /// Returns a serializer that has been reconfigured with the specified dictionary representation.
+        /// </summary>
+        /// <param name="dictionaryRepresentation">The dictionary representation.</param>
+        /// <returns>The reconfigured serializer.</returns>
+        public BsonSortedDictionaryInterfaceImplementerSerializer<TDictionary, TKey, TValue> WithDictionaryRepresentation(DictionaryRepresentation dictionaryRepresentation)
+        {
+            if (dictionaryRepresentation == DictionaryRepresentation)
+            {
+                return this;
+            }
+            else
+            {
+                return new BsonSortedDictionaryInterfaceImplementerSerializer<TDictionary, TKey, TValue>(dictionaryRepresentation, KeySerializer, ValueSerializer);
+            }
+        }
+
+        /// <summary>
+        /// Returns a serializer that has been reconfigured with the specified dictionary representation and key value serializers.
+        /// </summary>
+        /// <param name="dictionaryRepresentation">The dictionary representation.</param>
+        /// <param name="keySerializer">The key serializer.</param>
+        /// <param name="valueSerializer">The value serializer.</param>
+        /// <returns>The reconfigured serializer.</returns>
+        public BsonSortedDictionaryInterfaceImplementerSerializer<TDictionary, TKey, TValue> WithDictionaryRepresentation(DictionaryRepresentation dictionaryRepresentation, IBsonSerializer<TKey> keySerializer, IBsonSerializer<TValue> valueSerializer)
+        {
+            if (dictionaryRepresentation == DictionaryRepresentation && keySerializer == KeySerializer && valueSerializer == ValueSerializer)
+            {
+                return this;
+            }
+            else
+            {
+                return new BsonSortedDictionaryInterfaceImplementerSerializer<TDictionary, TKey, TValue>(dictionaryRepresentation, keySerializer, valueSerializer);
+            }
+        }
+
+        /// <summary>
+        /// Returns a serializer that has been reconfigured with the specified key serializer.
+        /// </summary>
+        /// <param name="keySerializer">The key serializer.</param>
+        /// <returns>The reconfigured serializer.</returns>
+        public BsonSortedDictionaryInterfaceImplementerSerializer<TDictionary, TKey, TValue> WithKeySerializer(IBsonSerializer<TKey> keySerializer)
+        {
+            if (keySerializer == KeySerializer)
+            {
+                return this;
+            }
+            else
+            {
+                return new BsonSortedDictionaryInterfaceImplementerSerializer<TDictionary, TKey, TValue>(DictionaryRepresentation, keySerializer, ValueSerializer);
+            }
+        }
+
+        /// <summary>
+        /// Returns a serializer that has been reconfigured with the specified value serializer.
+        /// </summary>
+        /// <param name="valueSerializer">The value serializer.</param>
+        /// <returns>The reconfigured serializer.</returns>
+        public BsonSortedDictionaryInterfaceImplementerSerializer<TDictionary, TKey, TValue> WithValueSerializer(IBsonSerializer<TValue> valueSerializer)
+        {
+            if (valueSerializer == ValueSerializer)
+            {
+                return this;
+            }
+            else
+            {
+                return new BsonSortedDictionaryInterfaceImplementerSerializer<TDictionary, TKey, TValue>(DictionaryRepresentation, KeySerializer, valueSerializer);
+            }
+        }
+
+        // explicit interface implementations
+        IBsonSerializer IChildSerializerConfigurable.ChildSerializer
+        {
+            get { return ValueSerializer; }
+        }
+
+        IBsonSerializer IChildSerializerConfigurable.WithChildSerializer(IBsonSerializer childSerializer)
+        {
+            return WithValueSerializer((IBsonSerializer<TValue>)childSerializer);
+        }
+
+        IBsonSerializer IDictionaryRepresentationConfigurable.WithDictionaryRepresentation(DictionaryRepresentation dictionaryRepresentation)
+        {
+            return WithDictionaryRepresentation(dictionaryRepresentation);
+        }
+
+        /// <inheritdoc/>
+        protected override ICollection<KeyValuePair<TKey, TValue>> CreateAccumulator()
+        {
+            return Activator.CreateInstance<TDictionary>();
+        }
+
+    }
+}

+ 11 - 0
Unity/Assets/Scripts/Core/Serialize/BsonSortedDictionaryInterfaceImplementerSerializer.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 8bab69cac2e2e6c449839a3e28dd28c3
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 770 - 0
Unity/Assets/Scripts/Core/Serialize/BsonSortedDictionarySerializerBase.cs

@@ -0,0 +1,770 @@
+/* Copyright 2010-present MongoDB Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using MongoDB.Bson;
+using MongoDB.Bson.IO;
+using MongoDB.Bson.Serialization;
+using MongoDB.Bson.Serialization.Options;
+using MongoDB.Bson.Serialization.Serializers;
+
+namespace ET
+{
+    /// <summary>
+    /// Represents a serializer for dictionaries.
+    /// </summary>
+    /// <typeparam name="TDictionary">The type of the dictionary.</typeparam>
+    public abstract class BsonSortedDictionarySerializerBase<TDictionary> :
+        ClassSerializerBase<TDictionary>,
+        IBsonDocumentSerializer,
+        IBsonDictionarySerializer
+        where TDictionary : class, IDictionary
+    {
+        // private constants
+        private static class Flags
+        {
+            public const long Key = 1;
+            public const long Value = 2;
+        }
+
+        // private fields
+        private readonly DictionaryRepresentation _dictionaryRepresentation;
+        private readonly SerializerHelper _helper;
+        private readonly IBsonSerializer _keySerializer;
+        private readonly IBsonSerializer _valueSerializer;
+
+        // constructors
+        /// <summary>
+        /// Initializes a new instance of the <see cref="DictionarySerializerBase{TDictionary}"/> class.
+        /// </summary>
+        public BsonSortedDictionarySerializerBase()
+            : this(DictionaryRepresentation.Document)
+        {
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="DictionarySerializerBase{TDictionary}"/> class.
+        /// </summary>
+        /// <param name="dictionaryRepresentation">The dictionary representation.</param>
+        public BsonSortedDictionarySerializerBase(DictionaryRepresentation dictionaryRepresentation)
+            : this(dictionaryRepresentation, BsonSerializer.LookupSerializer<object>(), BsonSerializer.LookupSerializer<object>())
+        {
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="DictionarySerializerBase{TDictionary}"/> class.
+        /// </summary>
+        /// <param name="dictionaryRepresentation">The dictionary representation.</param>
+        /// <param name="keySerializer">The key serializer.</param>
+        /// <param name="valueSerializer">The value serializer.</param>
+        public BsonSortedDictionarySerializerBase(DictionaryRepresentation dictionaryRepresentation, IBsonSerializer keySerializer, IBsonSerializer valueSerializer)
+        {
+            _dictionaryRepresentation = dictionaryRepresentation;
+            _keySerializer = keySerializer;
+            _valueSerializer = valueSerializer;
+
+            _helper = new SerializerHelper
+            (
+                new SerializerHelper.Member("k", Flags.Key),
+                new SerializerHelper.Member("v", Flags.Value)
+            );
+        }
+
+        // public properties
+        /// <summary>
+        /// Gets the dictionary representation.
+        /// </summary>
+        /// <value>
+        /// The dictionary representation.
+        /// </value>
+        public DictionaryRepresentation DictionaryRepresentation
+        {
+            get { return _dictionaryRepresentation; }
+        }
+
+        /// <summary>
+        /// Gets the key serializer.
+        /// </summary>
+        /// <value>
+        /// The key serializer.
+        /// </value>
+        public IBsonSerializer KeySerializer
+        {
+            get { return _keySerializer; }
+        }
+
+        /// <summary>
+        /// Gets the value serializer.
+        /// </summary>
+        /// <value>
+        /// The value serializer.
+        /// </value>
+        public IBsonSerializer ValueSerializer
+        {
+            get { return _valueSerializer; }
+        }
+
+        // public methods
+        /// <inheritdoc/>
+        public bool TryGetMemberSerializationInfo(string memberName, out BsonSerializationInfo serializationInfo)
+        {
+            if (_dictionaryRepresentation != DictionaryRepresentation.Document)
+            {
+                serializationInfo = null;
+                return false;
+            }
+
+            serializationInfo = new BsonSerializationInfo(
+                memberName,
+                _valueSerializer,
+                _valueSerializer.ValueType);
+            return true;
+        }
+
+        // protected methods
+        /// <summary>
+        /// Deserializes a value.
+        /// </summary>
+        /// <param name="context">The deserialization context.</param>
+        /// <param name="args">The deserialization args.</param>
+        /// <returns>A deserialized value.</returns>
+        protected override TDictionary DeserializeValue(BsonDeserializationContext context, BsonDeserializationArgs args)
+        {
+            var bsonReader = context.Reader;
+            var bsonType = bsonReader.GetCurrentBsonType();
+            switch (bsonType)
+            {
+                case BsonType.Array:
+                    return DeserializeArrayRepresentation(context);
+                case BsonType.Document:
+                    return DeserializeDocumentRepresentation(context);
+                default:
+                    throw CreateCannotDeserializeFromBsonTypeException(bsonType);
+            }
+        }
+
+        /// <summary>
+        /// Serializes a value.
+        /// </summary>
+        /// <param name="context">The serialization context.</param>
+        /// <param name="args">The serialization args.</param>
+        /// <param name="value">The object.</param>
+        protected override void SerializeValue(BsonSerializationContext context, BsonSerializationArgs args, TDictionary value)
+        {
+            var bsonWriter = context.Writer;
+
+            switch (_dictionaryRepresentation)
+            {
+                case DictionaryRepresentation.Document:
+                    SerializeDocumentRepresentation(context, value);
+                    break;
+
+                case DictionaryRepresentation.ArrayOfArrays:
+                    SerializeArrayOfArraysRepresentation(context, value);
+                    break;
+
+                case DictionaryRepresentation.ArrayOfDocuments:
+                    SerializeArrayOfDocumentsRepresentation(context, value);
+                    break;
+
+                default:
+                    var message = string.Format("'{0}' is not a valid IDictionary representation.", _dictionaryRepresentation);
+                    throw new BsonSerializationException(message);
+            }
+        }
+
+        // protected methods
+        /// <summary>
+        /// Creates the instance.
+        /// </summary>
+        /// <returns>The instance.</returns>
+        protected abstract TDictionary CreateInstance();
+
+        // private methods
+        private TDictionary DeserializeArrayRepresentation(BsonDeserializationContext context)
+        {
+            var dictionary = CreateInstance();
+
+            var bsonReader = context.Reader;
+            bsonReader.ReadStartArray();
+            while (bsonReader.ReadBsonType() != BsonType.EndOfDocument)
+            {
+                object key;
+                object value;
+
+                var bsonType = bsonReader.GetCurrentBsonType();
+                switch (bsonType)
+                {
+                    case BsonType.Array:
+                        bsonReader.ReadStartArray();
+                        key = _keySerializer.Deserialize(context);
+                        value = _valueSerializer.Deserialize(context);
+                        bsonReader.ReadEndArray();
+                        break;
+
+                    case BsonType.Document:
+                        key = null;
+                        value = null;
+                        _helper.DeserializeMembers(context, (elementName, flag) =>
+                        {
+                            switch (flag)
+                            {
+                                case Flags.Key: key = _keySerializer.Deserialize(context); break;
+                                case Flags.Value: value = _valueSerializer.Deserialize(context); break;
+                            }
+                        });
+                        break;
+
+                    default:
+                        throw CreateCannotDeserializeFromBsonTypeException(bsonType);
+                }
+
+                dictionary.Add(key, value);
+            }
+            bsonReader.ReadEndArray();
+
+            return dictionary;
+        }
+
+        private TDictionary DeserializeDocumentRepresentation(BsonDeserializationContext context)
+        {
+            var dictionary = CreateInstance();
+            var bsonReader = context.Reader;
+            bsonReader.ReadStartDocument();
+            while (bsonReader.ReadBsonType() != BsonType.EndOfDocument)
+            {
+                var key = DeserializeKeyString(bsonReader.ReadName());
+                var value = _valueSerializer.Deserialize(context);
+                dictionary.Add(key, value);
+            }
+            bsonReader.ReadEndDocument();
+            return dictionary;
+        }
+
+        private object DeserializeKeyString(string keyString)
+        {
+            var keyDocument = new BsonDocument("k", keyString);
+            using (var keyReader = new BsonDocumentReader(keyDocument))
+            {
+                var context = BsonDeserializationContext.CreateRoot(keyReader);
+                keyReader.ReadStartDocument();
+                keyReader.ReadName("k");
+                var key = _keySerializer.Deserialize(context);
+                keyReader.ReadEndDocument();
+                return key;
+            }
+        }
+
+        private void SerializeArrayOfArraysRepresentation(BsonSerializationContext context, TDictionary value)
+        {
+            var bsonWriter = context.Writer;
+            bsonWriter.WriteStartArray();
+            foreach (DictionaryEntry dictionaryEntry in value)
+            {
+                if (dictionaryEntry.Value is not ISerializeToEntity)
+                {
+                    continue;
+                }
+                bsonWriter.WriteStartArray();
+                _keySerializer.Serialize(context, dictionaryEntry.Key);
+                _valueSerializer.Serialize(context, dictionaryEntry.Value);
+                bsonWriter.WriteEndArray();
+            }
+            bsonWriter.WriteEndArray();
+        }
+
+        private void SerializeArrayOfDocumentsRepresentation(BsonSerializationContext context, TDictionary value)
+        {
+            var bsonWriter = context.Writer;
+            bsonWriter.WriteStartArray();
+            foreach (DictionaryEntry dictionaryEntry in value)
+            {
+                if (dictionaryEntry.Value is not ISerializeToEntity)
+                {
+                    continue;
+                }
+                bsonWriter.WriteStartDocument();
+                bsonWriter.WriteName("k");
+                _keySerializer.Serialize(context, dictionaryEntry.Key);
+                bsonWriter.WriteName("v");
+                _valueSerializer.Serialize(context, dictionaryEntry.Value);
+                bsonWriter.WriteEndDocument();
+            }
+            bsonWriter.WriteEndArray();
+        }
+
+        private void SerializeDocumentRepresentation(BsonSerializationContext context, TDictionary value)
+        {
+            var bsonWriter = context.Writer;
+            bsonWriter.WriteStartDocument();
+            foreach (DictionaryEntry dictionaryEntry in value)
+            {
+                if (dictionaryEntry.Value is not ISerializeToEntity)
+                {
+                    continue;
+                }
+                bsonWriter.WriteName(SerializeKeyString(dictionaryEntry.Key));
+                _valueSerializer.Serialize(context, dictionaryEntry.Value);
+            }
+            bsonWriter.WriteEndDocument();
+        }
+
+        private string SerializeKeyString(object key)
+        {
+            var keyDocument = new BsonDocument();
+            using (var keyWriter = new BsonDocumentWriter(keyDocument))
+            {
+                var context = BsonSerializationContext.CreateRoot(keyWriter);
+                keyWriter.WriteStartDocument();
+                keyWriter.WriteName("k");
+                _keySerializer.Serialize(context, key);
+                keyWriter.WriteEndDocument();
+            }
+
+            var keyValue = keyDocument["k"];
+            if (keyValue.BsonType != BsonType.String)
+            {
+                throw new BsonSerializationException("When using DictionaryRepresentation.Document key values must serialize as strings.");
+            }
+
+            return (string)keyValue;
+        }
+    }
+
+    /// <summary>
+    /// Represents a serializer for dictionaries.
+    /// </summary>
+    /// <typeparam name="TDictionary">The type of the dictionary.</typeparam>
+    /// <typeparam name="TKey">The type of the keys.</typeparam>
+    /// <typeparam name="TValue">The type of the values.</typeparam>
+    public abstract class SortedDictionarySerializerBase<TDictionary, TKey, TValue> :
+        ClassSerializerBase<TDictionary>,
+        IBsonArraySerializer,
+        IBsonDocumentSerializer,
+        IBsonDictionarySerializer
+        where TDictionary : class, IEnumerable<KeyValuePair<TKey, TValue>>
+    {
+        // private constants
+        private static class Flags
+        {
+            public const long Key = 1;
+            public const long Value = 2;
+        }
+
+        // private fields
+        private readonly DictionaryRepresentation _dictionaryRepresentation;
+        private readonly SerializerHelper _helper;
+        private readonly Lazy<IBsonSerializer<TKey>> _lazyKeySerializer;
+        private readonly Lazy<IBsonSerializer<TValue>> _lazyValueSerializer;
+
+        // constructors
+        /// <summary>
+        /// Initializes a new instance of the <see cref="DictionarySerializerBase{TDictionary, TKey, TValue}"/> class.
+        /// </summary>
+        public SortedDictionarySerializerBase()
+            : this(DictionaryRepresentation.Document)
+        {
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="DictionarySerializerBase{TDictionary, TKey, TValue}" /> class.
+        /// </summary>
+        /// <param name="dictionaryRepresentation">The dictionary representation.</param>
+        public SortedDictionarySerializerBase(DictionaryRepresentation dictionaryRepresentation)
+            : this(dictionaryRepresentation, BsonSerializer.SerializerRegistry)
+        {
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="DictionarySerializerBase{TDictionary, TKey, TValue}" /> class.
+        /// </summary>
+        /// <param name="dictionaryRepresentation">The dictionary representation.</param>
+        /// <param name="keySerializer">The key serializer.</param>
+        /// <param name="valueSerializer">The value serializer.</param>
+        public SortedDictionarySerializerBase(DictionaryRepresentation dictionaryRepresentation, IBsonSerializer<TKey> keySerializer, IBsonSerializer<TValue> valueSerializer)
+            : this(
+                dictionaryRepresentation,
+                new Lazy<IBsonSerializer<TKey>>(() => keySerializer),
+                new Lazy<IBsonSerializer<TValue>>(() => valueSerializer))
+        {
+            if (keySerializer == null)
+            {
+                throw new ArgumentNullException("keySerializer");
+            }
+            if (valueSerializer == null)
+            {
+                throw new ArgumentNullException("valueSerializer");
+            }
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="DictionarySerializerBase{TDictionary, TKey, TValue}" /> class.
+        /// </summary>
+        /// <param name="dictionaryRepresentation">The dictionary representation.</param>
+        /// <param name="serializerRegistry">The serializer registry.</param>
+        public SortedDictionarySerializerBase(DictionaryRepresentation dictionaryRepresentation, IBsonSerializerRegistry serializerRegistry)
+            : this(
+                dictionaryRepresentation,
+                new Lazy<IBsonSerializer<TKey>>(() => serializerRegistry.GetSerializer<TKey>()),
+                new Lazy<IBsonSerializer<TValue>>(() => serializerRegistry.GetSerializer<TValue>()))
+        {
+            if (serializerRegistry == null)
+            {
+                throw new ArgumentNullException("serializerRegistry");
+            }
+        }
+
+        private SortedDictionarySerializerBase(
+            DictionaryRepresentation dictionaryRepresentation,
+            Lazy<IBsonSerializer<TKey>> lazyKeySerializer,
+            Lazy<IBsonSerializer<TValue>> lazyValueSerializer)
+        {
+            _dictionaryRepresentation = dictionaryRepresentation;
+            _lazyKeySerializer = lazyKeySerializer;
+            _lazyValueSerializer = lazyValueSerializer;
+
+            _helper = new SerializerHelper
+            (
+                new SerializerHelper.Member("k", Flags.Key),
+                new SerializerHelper.Member("v", Flags.Value)
+            );
+        }
+
+        // public properties
+        /// <summary>
+        /// Gets the dictionary representation.
+        /// </summary>
+        /// <value>
+        /// The dictionary representation.
+        /// </value>
+        public DictionaryRepresentation DictionaryRepresentation
+        {
+            get { return _dictionaryRepresentation; }
+        }
+
+        /// <summary>
+        /// Gets the key serializer.
+        /// </summary>
+        /// <value>
+        /// The key serializer.
+        /// </value>
+        public IBsonSerializer<TKey> KeySerializer
+        {
+            get { return _lazyKeySerializer.Value; }
+        }
+
+        /// <summary>
+        /// Gets the value serializer.
+        /// </summary>
+        /// <value>
+        /// The value serializer.
+        /// </value>
+        public IBsonSerializer<TValue> ValueSerializer
+        {
+            get { return _lazyValueSerializer.Value; }
+        }
+
+        // public methods
+        /// <inheritdoc/>
+        public bool TryGetItemSerializationInfo(out BsonSerializationInfo serializationInfo)
+        {
+            if (_dictionaryRepresentation != DictionaryRepresentation.ArrayOfDocuments)
+            {
+                serializationInfo = null;
+                return false;
+            }
+
+            var serializer = new KeyValuePairSerializer<TKey, TValue>(
+                BsonType.Document,
+                _lazyKeySerializer.Value,
+                _lazyValueSerializer.Value);
+            serializationInfo = new BsonSerializationInfo(
+                null,
+                serializer,
+                serializer.ValueType);
+            return true;
+        }
+
+        /// <inheritdoc/>
+        public bool TryGetMemberSerializationInfo(string memberName, out BsonSerializationInfo serializationInfo)
+        {
+            if (_dictionaryRepresentation != DictionaryRepresentation.Document)
+            {
+                serializationInfo = null;
+                return false;
+            }
+
+            serializationInfo = new BsonSerializationInfo(
+                memberName,
+                _lazyValueSerializer.Value,
+                _lazyValueSerializer.Value.ValueType);
+            return true;
+        }
+
+        // protected methods
+        /// <summary>
+        /// Deserializes a value.
+        /// </summary>
+        /// <param name="context">The deserialization context.</param>
+        /// <param name="args">The deserialization args.</param>
+        /// <returns>A deserialized value.</returns>
+        protected override TDictionary DeserializeValue(BsonDeserializationContext context, BsonDeserializationArgs args)
+        {
+            var bsonReader = context.Reader;
+
+            var bsonType = bsonReader.GetCurrentBsonType();
+            switch (bsonType)
+            {
+                case BsonType.Array:
+                    return DeserializeArrayRepresentation(context);
+                case BsonType.Document:
+                    return DeserializeDocumentRepresentation(context);
+                default:
+                    throw CreateCannotDeserializeFromBsonTypeException(bsonType);
+            }
+        }
+
+        /// <summary>
+        /// Serializes a value.
+        /// </summary>
+        /// <param name="context">The serialization context.</param>
+        /// <param name="args">The serialization args.</param>
+        /// <param name="value">The object.</param>
+        protected override void SerializeValue(BsonSerializationContext context, BsonSerializationArgs args, TDictionary value)
+        {
+            var bsonWriter = context.Writer;
+
+            switch (_dictionaryRepresentation)
+            {
+                case DictionaryRepresentation.Document:
+                    SerializeDocumentRepresentation(context, value);
+                    break;
+
+                case DictionaryRepresentation.ArrayOfArrays:
+                    SerializeArrayOfArraysRepresentation(context, value);
+                    break;
+
+                case DictionaryRepresentation.ArrayOfDocuments:
+                    SerializeArrayOfDocumentsRepresentation(context, value);
+                    break;
+
+                default:
+                    var message = string.Format("'{0}' is not a valid IDictionary<{1}, {2}> representation.",
+                        _dictionaryRepresentation,
+                        BsonUtils.GetFriendlyTypeName(typeof(TKey)),
+                        BsonUtils.GetFriendlyTypeName(typeof(TValue)));
+                    throw new BsonSerializationException(message);
+            }
+        }
+
+        // protected methods
+        /// <summary>
+        /// Creates an accumulator.
+        /// </summary>
+        /// <returns>The accumulator.</returns>
+        protected virtual ICollection<KeyValuePair<TKey, TValue>> CreateAccumulator()
+        {
+#pragma warning disable 618
+            return (ICollection<KeyValuePair<TKey, TValue>>)CreateInstance();
+#pragma warning restore 618
+        }
+
+        // protected methods
+        /// <summary>
+        /// Creates the instance.
+        /// </summary>
+        /// <returns>The instance.</returns>
+        [Obsolete("CreateInstance is deprecated. Please use CreateAccumulator instead.")]
+        protected virtual TDictionary CreateInstance()
+        {
+            throw new NotImplementedException();
+        }
+
+        /// <summary>
+        /// Finalizes an accumulator.
+        /// </summary>
+        /// <param name="accumulator">The accumulator to finalize</param>
+        /// <returns>The instance.</returns>
+        protected virtual TDictionary FinalizeAccumulator(ICollection<KeyValuePair<TKey, TValue>> accumulator)
+        {
+            return (TDictionary)accumulator;
+        }
+
+        // private methods
+        private TDictionary DeserializeArrayRepresentation(BsonDeserializationContext context)
+        {
+
+            var accumulator = CreateAccumulator();
+            var bsonReader = context.Reader;
+            bsonReader.ReadStartArray();
+            while (bsonReader.ReadBsonType() != BsonType.EndOfDocument)
+            {
+                TKey key;
+                TValue value;
+
+                var bsonType = bsonReader.GetCurrentBsonType();
+                switch (bsonType)
+                {
+                    case BsonType.Array:
+                        bsonReader.ReadStartArray();
+                        key = _lazyKeySerializer.Value.Deserialize(context);
+                        value = _lazyValueSerializer.Value.Deserialize(context);
+                        bsonReader.ReadEndArray();
+                        break;
+
+                    case BsonType.Document:
+                        key = default(TKey);
+                        value = default(TValue);
+                        _helper.DeserializeMembers(context, (elementName, flag) =>
+                        {
+                            switch (flag)
+                            {
+                                case Flags.Key: key = _lazyKeySerializer.Value.Deserialize(context); break;
+                                case Flags.Value: value = _lazyValueSerializer.Value.Deserialize(context); break;
+                            }
+                        });
+                        break;
+
+                    default:
+                        throw CreateCannotDeserializeFromBsonTypeException(bsonType);
+                }
+
+                accumulator.Add(new KeyValuePair<TKey, TValue>(key, value));
+            }
+            bsonReader.ReadEndArray();
+
+            return FinalizeAccumulator(accumulator);
+        }
+
+        private TDictionary DeserializeDocumentRepresentation(BsonDeserializationContext context)
+        {
+            var accumulator = CreateAccumulator();
+
+            var bsonReader = context.Reader;
+            bsonReader.ReadStartDocument();
+            while (bsonReader.ReadBsonType() != BsonType.EndOfDocument)
+            {
+                var key = DeserializeKeyString(bsonReader.ReadName());
+                var value = _lazyValueSerializer.Value.Deserialize(context);
+                accumulator.Add(new KeyValuePair<TKey, TValue>(key, value));
+            }
+            bsonReader.ReadEndDocument();
+
+            return FinalizeAccumulator(accumulator);
+        }
+
+        private TKey DeserializeKeyString(string keyString)
+        {
+            var keyDocument = new BsonDocument("k", keyString);
+            using (var keyReader = new BsonDocumentReader(keyDocument))
+            {
+                var context = BsonDeserializationContext.CreateRoot(keyReader);
+                keyReader.ReadStartDocument();
+                keyReader.ReadName("k");
+                var key = _lazyKeySerializer.Value.Deserialize(context);
+                keyReader.ReadEndDocument();
+                return key;
+            }
+        }
+
+        private void SerializeArrayOfArraysRepresentation(BsonSerializationContext context, TDictionary value)
+        {
+            var bsonWriter = context.Writer;
+            bsonWriter.WriteStartArray();
+            foreach (var keyValuePair in value)
+            {
+                if (keyValuePair.Value is not ISerializeToEntity)
+                {
+                    continue;
+                }
+                bsonWriter.WriteStartArray();
+                _lazyKeySerializer.Value.Serialize(context, keyValuePair.Key);
+                _lazyValueSerializer.Value.Serialize(context, keyValuePair.Value);
+                bsonWriter.WriteEndArray();
+            }
+            bsonWriter.WriteEndArray();
+        }
+
+        private void SerializeArrayOfDocumentsRepresentation(BsonSerializationContext context, TDictionary value)
+        {
+            var bsonWriter = context.Writer;
+            bsonWriter.WriteStartArray();
+            foreach (var keyValuePair in value)
+            {
+                if (keyValuePair.Value is not ISerializeToEntity)
+                {
+                    continue;
+                }
+                bsonWriter.WriteStartDocument();
+                bsonWriter.WriteName("k");
+                _lazyKeySerializer.Value.Serialize(context, keyValuePair.Key);
+                bsonWriter.WriteName("v");
+                _lazyValueSerializer.Value.Serialize(context, keyValuePair.Value);
+                bsonWriter.WriteEndDocument();
+            }
+            bsonWriter.WriteEndArray();
+        }
+
+        private void SerializeDocumentRepresentation(BsonSerializationContext context, TDictionary value)
+        {
+            var bsonWriter = context.Writer;
+            bsonWriter.WriteStartDocument();
+            foreach (var keyValuePair in value)
+            {
+                if (keyValuePair.Value is not ISerializeToEntity)
+                {
+                    continue;
+                }
+                bsonWriter.WriteName(SerializeKeyString(keyValuePair.Key));
+                _lazyValueSerializer.Value.Serialize(context, keyValuePair.Value);
+            }
+            bsonWriter.WriteEndDocument();
+        }
+
+        private string SerializeKeyString(TKey key)
+        {
+            var keyDocument = new BsonDocument();
+            using (var keyWriter = new BsonDocumentWriter(keyDocument))
+            {
+                var context = BsonSerializationContext.CreateRoot(keyWriter);
+                keyWriter.WriteStartDocument();
+                keyWriter.WriteName("k");
+                _lazyKeySerializer.Value.Serialize(context, key);
+                keyWriter.WriteEndDocument();
+            }
+
+            var keyValue = keyDocument["k"];
+            if (keyValue.BsonType != BsonType.String)
+            {
+                throw new BsonSerializationException("When using DictionaryRepresentation.Document key values must serialize as strings.");
+            }
+
+            return (string)keyValue;
+        }
+
+        // explicit interface implementations
+        IBsonSerializer IBsonDictionarySerializer.KeySerializer
+        {
+            get { return KeySerializer; }
+        }
+
+        IBsonSerializer IBsonDictionarySerializer.ValueSerializer
+        {
+            get { return ValueSerializer; }
+        }
+    }
+}

+ 11 - 0
Unity/Assets/Scripts/Core/Serialize/BsonSortedDictionarySerializerBase.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 85b74f85898776947981777ecfd95f3c
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 97 - 0
Unity/Assets/Scripts/Core/Serialize/MemoryPackSortedDictionaryFormatter.cs

@@ -0,0 +1,97 @@
+using MemoryPack.Internal;
+using System.Collections.Generic;
+using System.Runtime.CompilerServices;
+using MemoryPack;
+using MemoryPack.Formatters;
+
+#nullable enable
+namespace ET
+{
+    /// <summary>
+    /// 替换默认的SortedDictionaryFormatter
+    /// </summary>
+    /// <typeparam name="TKey"></typeparam>
+    /// <typeparam name="TValue"></typeparam>
+    [Preserve]
+    public sealed class MemoryPackSortedDictionaryFormatter<TKey, TValue> : MemoryPackFormatter<SortedDictionary<TKey, TValue?>>
+            where TKey : notnull
+    {
+        readonly IComparer<TKey>? comparer;
+
+        public MemoryPackSortedDictionaryFormatter()
+                : this(null)
+        {
+
+        }
+
+        public MemoryPackSortedDictionaryFormatter(IComparer<TKey>? comparer)
+        {
+            this.comparer = comparer;
+        }
+
+
+        [Preserve]
+#if UNITY
+        public override void Serialize(ref MemoryPackWriter writer, ref SortedDictionary<TKey, TValue?>? value)
+#else
+        public override void Serialize<TBufferWriter>(ref MemoryPackWriter<TBufferWriter> writer, scoped ref SortedDictionary<TKey, TValue?>? value)
+#endif
+        {
+            if (value == null)
+            {
+                writer.WriteNullCollectionHeader();
+                return;
+            }
+
+            var keyFormatter = writer.GetFormatter<TKey>();
+            var valueFormatter = writer.GetFormatter<TValue>();
+
+            // writer.WriteCollectionHeader(value.Count);
+            ref byte spanReference = ref writer.GetSpanReference(4);
+            writer.Advance(4);
+            int count = 0;
+            foreach (var item in value)
+            {
+                if (item.Value is not ISerializeToEntity)
+                {
+                    continue;
+                }
+                ++count;
+                KeyValuePairFormatter.Serialize(keyFormatter, valueFormatter, ref writer, item!);
+            }
+            Unsafe.WriteUnaligned(ref spanReference, count);
+        }
+
+        [Preserve]
+#if UNITY
+        public override void Deserialize(ref MemoryPackReader reader, ref SortedDictionary<TKey, TValue?>? value)
+#else
+        
+        public override void Deserialize(ref MemoryPackReader reader, scoped ref SortedDictionary<TKey, TValue?>? value)
+#endif
+        {
+            if (!reader.TryReadCollectionHeader(out var length))
+            {
+                value = null;
+                return;
+            }
+
+            if (value == null)
+            {
+                value = new SortedDictionary<TKey, TValue?>(comparer);
+            }
+            else
+            {
+                value.Clear();
+            }
+
+            var keyFormatter = reader.GetFormatter<TKey>();
+            var valueFormatter = reader.GetFormatter<TValue>();
+            for (int i = 0; i < length; i++)
+            {
+                KeyValuePairFormatter.Deserialize(keyFormatter, valueFormatter, ref reader, out var k, out var v);
+                value.Add(k!, v);
+            }
+        }
+    }
+}

+ 11 - 0
Unity/Assets/Scripts/Core/Serialize/MemoryPackSortedDictionaryFormatter.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 204521cc3ab453749a3c4f6faf154fe2
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 8 - 0
Unity/Assets/Scripts/Editor/EntitySerializePlugin.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: edbb7e60fe70c504f876cde1d85534ca
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 20 - 0
Unity/Assets/Scripts/Editor/EntitySerializePlugin/EntityMonoBehaviourEditor.cs

@@ -0,0 +1,20 @@
+
+using UnityEditor;
+
+namespace ET
+{
+    [CustomEditor(typeof(EntityMonoBehaviour))]
+    public class EntityMonoBehaviourEditor : Editor
+    {
+        [MenuItem("ET/Test _F8", false)]
+        static void MenuItemOfCompile()
+        {
+            Unit unit = new Unit();
+        }
+        
+        public override void OnInspectorGUI()
+        {
+            EntityMonoBehaviour entityMonoBehaviour = (EntityMonoBehaviour)target;
+        }
+    }
+}

+ 11 - 0
Unity/Assets/Scripts/Editor/EntitySerializePlugin/EntityMonoBehaviourEditor.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 0b643fffb30c4c5418d3082b4b465255
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 31 - 0
Unity/Assets/Scripts/Editor/EntitySerializePlugin/EntitySerializer.cs

@@ -0,0 +1,31 @@
+using System;
+using UnityEditor;
+using UnityEngine;
+
+namespace ET
+{
+    [CustomEditor(typeof(GameObject))] // 指定要修改的对象类型为 GameObject(Prefab)
+    public class MyPrefabEditor : Editor
+    {
+        [MenuItem("Assets/Edit Entity")] // 创建一个右键菜单项
+        private static void SaveToEntity()
+        {
+            // 获取当前选中的 Prefab
+            UnityEngine.Object[] selectedObjects = Selection.GetFiltered<UnityEngine.Object>(SelectionMode.Deep);
+
+            foreach (UnityEngine.Object obj in selectedObjects)
+            {
+                if (!AssetDatabase.Contains(obj))
+                {
+                    continue; // 确保只处理 Asset 文件而不是场景物体等其他内容
+                }
+
+                string path = AssetDatabase.GetAssetPath(obj); // 获取 Prefab 路径
+                Type prefabType = PrefabUtility.GetCorrespondingObjectFromOriginalSource(obj).GetType(); // 获取原始源的类型
+
+                // 根据需求进行操作,这里仅打印信息
+                Debug.Log($"Selected Prefab: {path}, Type: {prefabType}");
+            }
+        }
+    }
+}

+ 11 - 0
Unity/Assets/Scripts/Editor/EntitySerializePlugin/EntitySerializer.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 92d4b394a3a4f0c46a86f8e90337824a
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 24 - 1
Unity/Assets/Scripts/Hotfix/Share/FiberInit_Main.cs

@@ -1,4 +1,7 @@
-namespace ET
+using System.Collections.Generic;
+using MemoryPack;
+
+namespace ET
 {
     [Invoke((long)SceneType.Main)]
     public class FiberInit_Main: AInvokeHandler<FiberInit, ETTask>
@@ -10,6 +13,26 @@
             await EventSystem.Instance.PublishAsync(root, new EntryEvent1());
             await EventSystem.Instance.PublishAsync(root, new EntryEvent2());
             await EventSystem.Instance.PublishAsync(root, new EntryEvent3());
+
+
+            AA aa = root.AddComponent<AA>();
+
+            BB bb = aa.AddComponent<BB>();
+            CC cc = aa.AddComponent<CC>();
+            bb.B = 1;
+            cc.C = 2;
+
+            byte[] bytes = MemoryPackSerializer.Serialize(aa);
+
+            AA aa2 = MemoryPackSerializer.Deserialize<AA>(bytes);
+            
+            Log.Debug($"11111111111111111111111111: {aa2}");
+            
+            byte[] bytes2 = MongoHelper.Serialize(aa);
+
+            AA aa3 = MongoHelper.Deserialize<AA>(bytes2);
+            
+            Log.Debug($"11111111111111111111111111: {aa3}");
         }
     }
 }

+ 8 - 0
Unity/Assets/Scripts/Loader/Plugins/EntityMonoBehaviour.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: d8c12968e648ddc418c7642c8f43ec84
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 9 - 0
Unity/Assets/Scripts/Loader/Plugins/EntityMonoBehaviour/EntityMonoBehaviour.cs

@@ -0,0 +1,9 @@
+using UnityEngine;
+
+namespace ET
+{
+    public class EntityMonoBehaviour: MonoBehaviour
+    {
+        public Entity Entity { get; set; }
+    }
+}

+ 11 - 0
Unity/Assets/Scripts/Loader/Plugins/EntityMonoBehaviour/EntityMonoBehaviour.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 4a58f62662634ce409cf7d40c4623bf4
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 29 - 3
Unity/Assets/Scripts/Model/Share/Entry.cs

@@ -1,6 +1,7 @@
-using MemoryPack;
-using MongoDB.Bson;
-using MongoDB.Bson.Serialization.Serializers;
+using System;
+using System.Collections.Generic;
+using System.Reflection;
+using MemoryPack;
 
 namespace ET
 {
@@ -16,6 +17,28 @@ namespace ET
     {
     }
     
+    [MemoryPackable]
+    [ComponentOf(typeof(Scene))]
+    public partial class AA: Entity, IAwake
+    {
+    }
+
+    [MemoryPackable]
+    [ComponentOf(typeof(AA))]
+    public partial class BB : Entity, IAwake, ISerializeToEntity
+    {
+        [MemoryPackInclude]
+        public int B { get; set; }
+    }
+    
+    [MemoryPackable]
+    [ComponentOf(typeof(AA))]
+    public partial class CC : Entity, IAwake //, ISerializeToEntity
+    {
+        [MemoryPackInclude]
+        public int C { get; set; }
+    }
+    
     public static class Entry
     {
         public static void Init()
@@ -34,6 +57,9 @@ namespace ET
 
             // 注册Mongo type
             MongoRegister.Init();
+            
+            MemoryPackFormatterProvider.Register(new MemoryPackSortedDictionaryFormatter<long, Entity>());
+            
             // 注册Entity序列化器
             EntitySerializeRegister.Init();
             World.Instance.AddSingleton<IdGenerater>();

+ 2 - 0
Unity/Assets/Scripts/Model/Share/MongoRegister.cs

@@ -23,6 +23,8 @@ namespace ET
             MethodInfo registerIdGenerators = typeof (BsonSerializer).GetMethod("RegisterIdGenerators", BindingFlags.Static | BindingFlags.NonPublic);
             registerIdGenerators.Invoke(null, Array.Empty<object>());
             
+            BsonSerializer.RegisterSerializer(new BsonSortedDictionaryInterfaceImplementerSerializer<SortedDictionary<long, Entity>>());
+            
             
             // 自动注册IgnoreExtraElements
             ConventionPack conventionPack = new() { new IgnoreExtraElementsConvention(true) };