commit 25958f58c3808629a9345ffea3f0907fd394bbf4 Author: Bob.Song Date: Thu Mar 5 11:39:06 2026 +0800 提交示例代码 diff --git a/物品和背包的完整代码/Bin/.DS_Store b/物品和背包的完整代码/Bin/.DS_Store new file mode 100644 index 0000000..ed7a2d3 Binary files /dev/null and b/物品和背包的完整代码/Bin/.DS_Store differ diff --git a/物品和背包的完整代码/Client/.DS_Store b/物品和背包的完整代码/Client/.DS_Store new file mode 100644 index 0000000..71ea7b6 Binary files /dev/null and b/物品和背包的完整代码/Client/.DS_Store differ diff --git a/物品和背包的完整代码/Client/Unity/.DS_Store b/物品和背包的完整代码/Client/Unity/.DS_Store new file mode 100644 index 0000000..6154d7e Binary files /dev/null and b/物品和背包的完整代码/Client/Unity/.DS_Store differ diff --git a/物品和背包的完整代码/Client/Unity/.idea/.idea.Unity/.idea/indexLayout.xml b/物品和背包的完整代码/Client/Unity/.idea/.idea.Unity/.idea/indexLayout.xml new file mode 100644 index 0000000..7b08163 --- /dev/null +++ b/物品和背包的完整代码/Client/Unity/.idea/.idea.Unity/.idea/indexLayout.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/物品和背包的完整代码/Client/Unity/.idea/.idea.Unity/.idea/projectSettingsUpdater.xml b/物品和背包的完整代码/Client/Unity/.idea/.idea.Unity/.idea/projectSettingsUpdater.xml new file mode 100644 index 0000000..64af657 --- /dev/null +++ b/物品和背包的完整代码/Client/Unity/.idea/.idea.Unity/.idea/projectSettingsUpdater.xml @@ -0,0 +1,7 @@ + + + + + \ No newline at end of file diff --git a/物品和背包的完整代码/Client/Unity/.idea/.idea.Unity/.idea/workspace.xml b/物品和背包的完整代码/Client/Unity/.idea/.idea.Unity/.idea/workspace.xml new file mode 100644 index 0000000..26583d9 --- /dev/null +++ b/物品和背包的完整代码/Client/Unity/.idea/.idea.Unity/.idea/workspace.xml @@ -0,0 +1,113 @@ + + + + + + + + + + + + { + "customColor": "", + "associatedIndex": 7 +} + + + + { + "keyToString": { + "RunOnceActivity.ShowReadmeOnStart": "true", + "node.js.detected.package.eslint": "true", + "node.js.detected.package.tslint": "true", + "node.js.selected.package.eslint": "(autodetect)", + "node.js.selected.package.tslint": "(autodetect)", + "nodejs_package_manager_path": "npm", + "vue.rearranger.settings.migration": "true" + } +} + + + + + + + + + + + + + + + + + + + + + 1742279256284 + + + + + + + + + + + + \ No newline at end of file diff --git a/物品和背包的完整代码/Client/Unity/Assembly-CSharp.csproj b/物品和背包的完整代码/Client/Unity/Assembly-CSharp.csproj new file mode 100644 index 0000000..2243d89 --- /dev/null +++ b/物品和背包的完整代码/Client/Unity/Assembly-CSharp.csproj @@ -0,0 +1,824 @@ + + + + 9.0 + <_TargetFrameworkDirectories>non_empty_path_generated_by_unity.rider.package + <_FullFrameworkReferenceAssemblyPaths>non_empty_path_generated_by_unity.rider.package + true + + + Debug + AnyCPU + 10.0.20506 + 2.0 + + {03938ccd-4b40-8dfb-6b9b-21988d5cac0a} + {E097FAD1-6243-4DAD-9C02-E9B9EFC3FFC1};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + Library + Properties + Assembly-CSharp + v4.7.1 + 512 + . + + + true + full + false + Temp\Bin\Debug\Assembly-CSharp\ + UNITY_2021_3_14;UNITY_2021_3;UNITY_2021;UNITY_5_3_OR_NEWER;UNITY_5_4_OR_NEWER;UNITY_5_5_OR_NEWER;UNITY_5_6_OR_NEWER;UNITY_2017_1_OR_NEWER;UNITY_2017_2_OR_NEWER;UNITY_2017_3_OR_NEWER;UNITY_2017_4_OR_NEWER;UNITY_2018_1_OR_NEWER;UNITY_2018_2_OR_NEWER;UNITY_2018_3_OR_NEWER;UNITY_2018_4_OR_NEWER;UNITY_2019_1_OR_NEWER;UNITY_2019_2_OR_NEWER;UNITY_2019_3_OR_NEWER;UNITY_2019_4_OR_NEWER;UNITY_2020_1_OR_NEWER;UNITY_2020_2_OR_NEWER;UNITY_2020_3_OR_NEWER;UNITY_2021_1_OR_NEWER;UNITY_2021_2_OR_NEWER;UNITY_2021_3_OR_NEWER;PLATFORM_ARCH_64;UNITY_64;UNITY_INCLUDE_TESTS;USE_SEARCH_ENGINE_API;USE_SEARCH_TABLE;USE_SEARCH_MODULE;USE_PROPERTY_DATABASE;USE_SEARCH_EXTENSION_API;ENABLE_AR;ENABLE_AUDIO;ENABLE_CACHING;ENABLE_CLOTH;ENABLE_MICROPHONE;ENABLE_MULTIPLE_DISPLAYS;ENABLE_PHYSICS;ENABLE_TEXTURE_STREAMING;ENABLE_VIRTUALTEXTURING;ENABLE_UNET;ENABLE_LZMA;ENABLE_UNITYEVENTS;ENABLE_VR;ENABLE_WEBCAM;ENABLE_UNITYWEBREQUEST;ENABLE_WWW;ENABLE_CLOUD_SERVICES;ENABLE_CLOUD_SERVICES_COLLAB;ENABLE_CLOUD_SERVICES_COLLAB_SOFTLOCKS;ENABLE_CLOUD_SERVICES_ADS;ENABLE_CLOUD_SERVICES_USE_WEBREQUEST;ENABLE_CLOUD_SERVICES_CRASH_REPORTING;ENABLE_CLOUD_SERVICES_NATIVE_CRASH_REPORTING;ENABLE_CLOUD_SERVICES_PURCHASING;ENABLE_CLOUD_SERVICES_ANALYTICS;ENABLE_CLOUD_SERVICES_UNET;ENABLE_CLOUD_SERVICES_BUILD;ENABLE_CLOUD_LICENSE;ENABLE_EDITOR_HUB_LICENSE;ENABLE_WEBSOCKET_CLIENT;ENABLE_DIRECTOR_AUDIO;ENABLE_DIRECTOR_TEXTURE;ENABLE_MANAGED_JOBS;ENABLE_MANAGED_TRANSFORM_JOBS;ENABLE_MANAGED_ANIMATION_JOBS;ENABLE_MANAGED_AUDIO_JOBS;ENABLE_MANAGED_UNITYTLS;INCLUDE_DYNAMIC_GI;ENABLE_SCRIPTING_GC_WBARRIERS;PLATFORM_SUPPORTS_MONO;RENDER_SOFTWARE_CURSOR;ENABLE_VIDEO;ENABLE_ACCELERATOR_CLIENT_DEBUGGING;PLATFORM_STANDALONE;TEXTCORE_1_0_OR_NEWER;PLATFORM_STANDALONE_OSX;UNITY_STANDALONE_OSX;UNITY_STANDALONE;ENABLE_GAMECENTER;ENABLE_RUNTIME_GI;ENABLE_MOVIES;ENABLE_NETWORK;ENABLE_CRUNCH_TEXTURE_COMPRESSION;ENABLE_UNITY_GAME_SERVICES_ANALYTICS_SUPPORT;ENABLE_CLUSTER_SYNC;ENABLE_CLUSTERINPUT;ENABLE_SPATIALTRACKING;PLATFORM_UPDATES_TIME_OUTSIDE_OF_PLAYER_LOOP;ENABLE_WEBSOCKET_HOST;ENABLE_MONO;NET_STANDARD_2_0;NET_STANDARD;NET_STANDARD_2_1;NETSTANDARD;NETSTANDARD2_1;ENABLE_PROFILER;DEBUG;TRACE;UNITY_ASSERTIONS;UNITY_EDITOR;UNITY_EDITOR_64;UNITY_EDITOR_OSX;ENABLE_UNITY_COLLECTIONS_CHECKS;ENABLE_BURST_AOT;UNITY_TEAM_LICENSE;ENABLE_CUSTOM_RENDER_TEXTURE;ENABLE_DIRECTOR;ENABLE_LOCALIZATION;ENABLE_SPRITES;ENABLE_TERRAIN;ENABLE_TILEMAP;ENABLE_TIMELINE;ENABLE_LEGACY_INPUT_MANAGER;CSHARP_7_OR_LATER;CSHARP_7_3_OR_NEWER + prompt + 4 + 0169,0649 + False + False + + + true + true + false + false + false + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.AIModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.ARModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.AccessibilityModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.AndroidJNIModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.AnimationModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.AssetBundleModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.AudioModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.ClothModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.ClusterInputModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.ClusterRendererModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.CoreModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.CrashReportingModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.DSPGraphModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.DirectorModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.GIModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.GameCenterModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.GridModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.HotReloadModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.IMGUIModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.ImageConversionModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.InputModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.InputLegacyModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.JSONSerializeModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.LocalizationModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.ParticleSystemModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.PerformanceReportingModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.PhysicsModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.Physics2DModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.ProfilerModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.RuntimeInitializeOnLoadManagerInitializerModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.ScreenCaptureModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.SharedInternalsModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.SpriteMaskModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.SpriteShapeModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.StreamingModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.SubstanceModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.SubsystemsModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.TLSModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.TerrainModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.TerrainPhysicsModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.TextCoreFontEngineModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.TextCoreTextEngineModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.TextRenderingModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.TilemapModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.UIModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.UIElementsModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.UIElementsNativeModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.UNETModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.UmbraModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.UnityAnalyticsModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.UnityAnalyticsCommonModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.UnityConnectModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.UnityCurlModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.UnityTestProtocolModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.UnityWebRequestModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.UnityWebRequestAssetBundleModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.UnityWebRequestAudioModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.UnityWebRequestTextureModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.UnityWebRequestWWWModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.VFXModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.VRModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.VehiclesModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.VideoModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.VirtualTexturingModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.WindModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.XRModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEditor.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEditor.CoreModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEditor.DeviceSimulatorModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEditor.DiagnosticsModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEditor.GraphViewModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEditor.PackageManagerUIModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEditor.QuickSearchModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEditor.SceneTemplateModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEditor.TextCoreFontEngineModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEditor.TextCoreTextEngineModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEditor.UIBuilderModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEditor.UIElementsModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEditor.UIElementsSamplesModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEditor.UIServiceModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEditor.UnityConnectModule.dll + + + /Users/fantasy/Movies/物品背包开发之旅/B/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Other/System.Collections.Immutable.dll + + + /Users/fantasy/Movies/物品背包开发之旅/B/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Other/System.IO.Pipelines.dll + + + /Users/fantasy/Movies/物品背包开发之旅/B/Client/Unity/Library/PackageCache/com.unity.visualscripting@1.7.8/Runtime/VisualScripting.Flow/Dependencies/NCalc/Unity.VisualScripting.Antlr3.Runtime.dll + + + /Users/fantasy/Movies/物品背包开发之旅/B/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Other/System.Runtime.CompilerServices.Unsafe.dll + + + /Users/fantasy/Movies/物品背包开发之旅/B/Client/Unity/Library/PackageCache/com.unity.testtools.codecoverage@1.0.1/lib/ReportGenerator/ReportGeneratorMerged.dll + + + /Users/fantasy/Movies/物品背包开发之旅/B/Client/Unity/Library/PackageCache/com.unity.nuget.newtonsoft-json@3.2.1/Runtime/Newtonsoft.Json.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/PlaybackEngines/iOSSupport/UnityEditor.iOS.Extensions.Xcode.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/PlaybackEngines/iOSSupport/UnityEditor.iOS.Extensions.Common.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/PlaybackEngines/AndroidPlayer/Unity.Android.Types.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/PlaybackEngines/AndroidPlayer/Unity.Android.Gradle.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/ref/2.1.0/netstandard.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/Microsoft.Win32.Primitives.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.AppContext.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Buffers.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Collections.Concurrent.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Collections.NonGeneric.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Collections.Specialized.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Collections.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.ComponentModel.EventBasedAsync.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.ComponentModel.Primitives.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.ComponentModel.TypeConverter.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.ComponentModel.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Console.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Data.Common.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Diagnostics.Contracts.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Diagnostics.Debug.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Diagnostics.FileVersionInfo.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Diagnostics.Process.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Diagnostics.StackTrace.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Diagnostics.TextWriterTraceListener.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Diagnostics.Tools.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Diagnostics.TraceSource.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Diagnostics.Tracing.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Drawing.Primitives.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Dynamic.Runtime.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Globalization.Calendars.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Globalization.Extensions.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Globalization.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.IO.Compression.ZipFile.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.IO.Compression.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.IO.FileSystem.DriveInfo.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.IO.FileSystem.Primitives.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.IO.FileSystem.Watcher.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.IO.FileSystem.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.IO.IsolatedStorage.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.IO.MemoryMappedFiles.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.IO.Pipes.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.IO.UnmanagedMemoryStream.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.IO.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Linq.Expressions.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Linq.Parallel.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Linq.Queryable.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Linq.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Memory.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Net.Http.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Net.NameResolution.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Net.NetworkInformation.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Net.Ping.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Net.Primitives.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Net.Requests.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Net.Security.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Net.Sockets.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Net.WebHeaderCollection.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Net.WebSockets.Client.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Net.WebSockets.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Numerics.Vectors.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.ObjectModel.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Reflection.DispatchProxy.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Reflection.Emit.ILGeneration.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Reflection.Emit.Lightweight.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Reflection.Emit.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Reflection.Extensions.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Reflection.Primitives.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Reflection.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Resources.Reader.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Resources.ResourceManager.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Resources.Writer.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Runtime.CompilerServices.VisualC.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Runtime.Extensions.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Runtime.Handles.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Runtime.InteropServices.RuntimeInformation.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Runtime.InteropServices.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Runtime.Numerics.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Runtime.Serialization.Formatters.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Runtime.Serialization.Json.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Runtime.Serialization.Primitives.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Runtime.Serialization.Xml.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Runtime.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Security.Claims.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Security.Cryptography.Algorithms.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Security.Cryptography.Csp.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Security.Cryptography.Encoding.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Security.Cryptography.Primitives.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Security.Cryptography.X509Certificates.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Security.Principal.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Security.SecureString.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Text.Encoding.Extensions.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Text.Encoding.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Text.RegularExpressions.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Threading.Overlapped.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Threading.Tasks.Extensions.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Threading.Tasks.Parallel.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Threading.Tasks.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Threading.Thread.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Threading.ThreadPool.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Threading.Timer.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Threading.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.ValueTuple.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Xml.ReaderWriter.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Xml.XDocument.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Xml.XPath.XDocument.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Xml.XPath.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Xml.XmlDocument.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Xml.XmlSerializer.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/Extensions/2.0.0/System.Runtime.InteropServices.WindowsRuntime.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netfx/System.ComponentModel.Composition.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netfx/System.Core.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netfx/System.Data.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netfx/System.Drawing.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netfx/System.IO.Compression.FileSystem.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netfx/System.Net.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netfx/System.Numerics.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netfx/System.Runtime.Serialization.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netfx/System.ServiceModel.Web.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netfx/System.Transactions.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netfx/System.Web.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netfx/System.Windows.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netfx/System.Xml.Linq.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netfx/System.Xml.Serialization.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netfx/System.Xml.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netfx/System.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netfx/mscorlib.dll + + + /Users/fantasy/Movies/物品背包开发之旅/B/Client/Unity/Library/ScriptAssemblies/Unity.VisualScripting.Flow.Editor.dll + + + /Users/fantasy/Movies/物品背包开发之旅/B/Client/Unity/Library/ScriptAssemblies/Unity.VSCode.Editor.dll + + + /Users/fantasy/Movies/物品背包开发之旅/B/Client/Unity/Library/ScriptAssemblies/Unity.TextMeshPro.Editor.dll + + + /Users/fantasy/Movies/物品背包开发之旅/B/Client/Unity/Library/ScriptAssemblies/Unity.Performance.Profile-Analyzer.Editor.dll + + + /Users/fantasy/Movies/物品背包开发之旅/B/Client/Unity/Library/ScriptAssemblies/Unity.TestTools.CodeCoverage.Editor.OpenCover.Model.dll + + + /Users/fantasy/Movies/物品背包开发之旅/B/Client/Unity/Library/ScriptAssemblies/Unity.VisualStudio.Editor.dll + + + /Users/fantasy/Movies/物品背包开发之旅/B/Client/Unity/Library/ScriptAssemblies/Unity.Timeline.dll + + + /Users/fantasy/Movies/物品背包开发之旅/B/Client/Unity/Library/ScriptAssemblies/Unity.VisualScripting.Core.Editor.dll + + + /Users/fantasy/Movies/物品背包开发之旅/B/Client/Unity/Library/ScriptAssemblies/Unity.TextMeshPro.dll + + + /Users/fantasy/Movies/物品背包开发之旅/B/Client/Unity/Library/ScriptAssemblies/Unity.VisualScripting.State.Editor.dll + + + /Users/fantasy/Movies/物品背包开发之旅/B/Client/Unity/Library/ScriptAssemblies/Unity.VisualScripting.SettingsProvider.Editor.dll + + + /Users/fantasy/Movies/物品背包开发之旅/B/Client/Unity/Library/ScriptAssemblies/Unity.TestTools.CodeCoverage.Editor.OpenCover.Mono.Reflection.dll + + + /Users/fantasy/Movies/物品背包开发之旅/B/Client/Unity/Library/ScriptAssemblies/Unity.VisualScripting.Flow.dll + + + /Users/fantasy/Movies/物品背包开发之旅/B/Client/Unity/Library/ScriptAssemblies/UnityEditor.UI.dll + + + /Users/fantasy/Movies/物品背包开发之旅/B/Client/Unity/Library/ScriptAssemblies/Unity.PlasticSCM.Editor.dll + + + /Users/fantasy/Movies/物品背包开发之旅/B/Client/Unity/Library/ScriptAssemblies/Unity.Rider.Editor.dll + + + /Users/fantasy/Movies/物品背包开发之旅/B/Client/Unity/Library/ScriptAssemblies/UnityEngine.UI.dll + + + /Users/fantasy/Movies/物品背包开发之旅/B/Client/Unity/Library/ScriptAssemblies/Unity.Services.Core.dll + + + /Users/fantasy/Movies/物品背包开发之旅/B/Client/Unity/Library/ScriptAssemblies/Unity.VisualScripting.Core.dll + + + /Users/fantasy/Movies/物品背包开发之旅/B/Client/Unity/Library/ScriptAssemblies/Unity.EditorCoroutines.Editor.dll + + + /Users/fantasy/Movies/物品背包开发之旅/B/Client/Unity/Library/ScriptAssemblies/Unity.Services.Core.Analytics.dll + + + /Users/fantasy/Movies/物品背包开发之旅/B/Client/Unity/Library/ScriptAssemblies/Unity.VisualScripting.Shared.Editor.dll + + + /Users/fantasy/Movies/物品背包开发之旅/B/Client/Unity/Library/ScriptAssemblies/Unity.Services.Core.Environments.dll + + + /Users/fantasy/Movies/物品背包开发之旅/B/Client/Unity/Library/ScriptAssemblies/Unity.Timeline.Editor.dll + + + /Users/fantasy/Movies/物品背包开发之旅/B/Client/Unity/Library/ScriptAssemblies/Unity.TestTools.CodeCoverage.Editor.dll + + + /Users/fantasy/Movies/物品背包开发之旅/B/Client/Unity/Library/ScriptAssemblies/Unity.VisualScripting.State.dll + + + + + {8eb45200-d3be-6efd-d01e-a23e2721ecc7} + Fantasy.ConfigTable + + + {f09e7d37-0f11-85f5-9f5a-ea60c1261f78} + Fantasy.Editor + + + {d85fa58b-aca9-8bf0-e827-074457206988} + Fantasy.Unity + + + + + diff --git a/物品和背包的完整代码/Client/Unity/Assets/.DS_Store b/物品和背包的完整代码/Client/Unity/Assets/.DS_Store new file mode 100644 index 0000000..6a616b6 Binary files /dev/null and b/物品和背包的完整代码/Client/Unity/Assets/.DS_Store differ diff --git a/物品和背包的完整代码/Client/Unity/Assets/Bundles.meta b/物品和背包的完整代码/Client/Unity/Assets/Bundles.meta new file mode 100644 index 0000000..5af8c52 --- /dev/null +++ b/物品和背包的完整代码/Client/Unity/Assets/Bundles.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 882918c3267f043989dcd85a286be2c9 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Client/Unity/Assets/Bundles/.DS_Store b/物品和背包的完整代码/Client/Unity/Assets/Bundles/.DS_Store new file mode 100644 index 0000000..8779717 Binary files /dev/null and b/物品和背包的完整代码/Client/Unity/Assets/Bundles/.DS_Store differ diff --git a/物品和背包的完整代码/Client/Unity/Assets/Bundles/Config.meta b/物品和背包的完整代码/Client/Unity/Assets/Bundles/Config.meta new file mode 100644 index 0000000..3c94f1f --- /dev/null +++ b/物品和背包的完整代码/Client/Unity/Assets/Bundles/Config.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 947994f7c5cfe41e49ed25dfeadb07a1 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: config + assetBundleVariant: diff --git a/物品和背包的完整代码/Client/Unity/Assets/Bundles/Config/ContainerConfigData.bytes b/物品和背包的完整代码/Client/Unity/Assets/Bundles/Config/ContainerConfigData.bytes new file mode 100644 index 0000000..5f74585 --- /dev/null +++ b/物品和背包的完整代码/Client/Unity/Assets/Bundles/Config/ContainerConfigData.bytes @@ -0,0 +1,10 @@ + +Bag +( +08 +Equip +( +08 +Trade +( +08 \ No newline at end of file diff --git a/物品和背包的完整代码/Client/Unity/Assets/Bundles/Config/ContainerConfigData.bytes.meta b/物品和背包的完整代码/Client/Unity/Assets/Bundles/Config/ContainerConfigData.bytes.meta new file mode 100644 index 0000000..b1e20f0 --- /dev/null +++ b/物品和背包的完整代码/Client/Unity/Assets/Bundles/Config/ContainerConfigData.bytes.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 18b3ca5dd9ac140c0bfe37bbca653788 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Client/Unity/Assets/Bundles/Config/EquipAffixConfigData.bytes b/物品和背包的完整代码/Client/Unity/Assets/Bundles/Config/EquipAffixConfigData.bytes new file mode 100644 index 0000000..94dc7ae --- /dev/null +++ b/物品和背包的完整代码/Client/Unity/Assets/Bundles/Config/EquipAffixConfigData.bytes @@ -0,0 +1,4 @@ + +$ 装备上每秒恢复5点血 +Gš ?装备上每次攻击增加6点攻击力,最高增加了30点 +&Ú 装备上增加100点法力值 \ No newline at end of file diff --git a/物品和背包的完整代码/Client/Unity/Assets/Bundles/Config/EquipAffixConfigData.bytes.meta b/物品和背包的完整代码/Client/Unity/Assets/Bundles/Config/EquipAffixConfigData.bytes.meta new file mode 100644 index 0000000..9487cf5 --- /dev/null +++ b/物品和背包的完整代码/Client/Unity/Assets/Bundles/Config/EquipAffixConfigData.bytes.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 4fe08ccd5e9d64c0d86fdc05d5b37764 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Client/Unity/Assets/Bundles/Config/EquipEntryConfigData.bytes b/物品和背包的完整代码/Client/Unity/Assets/Bundles/Config/EquipEntryConfigData.bytes new file mode 100644 index 0000000..3d97c10 --- /dev/null +++ b/物品和背包的完整代码/Client/Unity/Assets/Bundles/Config/EquipEntryConfigData.bytes @@ -0,0 +1,9 @@ + +( (0008 88 8š 88 +8Ú 88 +( (0008 88 +8š 88 +8Ú 88 +( (0008 88 +8š 88 +8Ú 88 \ No newline at end of file diff --git a/物品和背包的完整代码/Client/Unity/Assets/Bundles/Config/EquipEntryConfigData.bytes.meta b/物品和背包的完整代码/Client/Unity/Assets/Bundles/Config/EquipEntryConfigData.bytes.meta new file mode 100644 index 0000000..d37d882 --- /dev/null +++ b/物品和背包的完整代码/Client/Unity/Assets/Bundles/Config/EquipEntryConfigData.bytes.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: f404ab74e1c414ce4b48a75124ab783b +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Client/Unity/Assets/Bundles/Config/EquipValueConfigData.bytes b/物品和背包的完整代码/Client/Unity/Assets/Bundles/Config/EquipValueConfigData.bytes new file mode 100644 index 0000000..99900bc --- /dev/null +++ b/物品和背包的完整代码/Client/Unity/Assets/Bundles/Config/EquipValueConfigData.bytes @@ -0,0 +1,13 @@ + +$= * +  +š  +Ú  +$„= * +  +š  +Ú  +$Ä= * +  +š  +Ú  \ No newline at end of file diff --git a/物品和背包的完整代码/Client/Unity/Assets/Bundles/Config/EquipValueConfigData.bytes.meta b/物品和背包的完整代码/Client/Unity/Assets/Bundles/Config/EquipValueConfigData.bytes.meta new file mode 100644 index 0000000..efaf8a1 --- /dev/null +++ b/物品和背包的完整代码/Client/Unity/Assets/Bundles/Config/EquipValueConfigData.bytes.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: a5ef48e9d971c4681bec1114de65961c +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Client/Unity/Assets/Bundles/Config/ErrorCodeData.bytes b/物品和背包的完整代码/Client/Unity/Assets/Bundles/Config/ErrorCodeData.bytes new file mode 100644 index 0000000..f32d886 --- /dev/null +++ b/物品和背包的完整代码/Client/Unity/Assets/Bundles/Config/ErrorCodeData.bytes @@ -0,0 +1,4 @@ + + +LoingError 登陆失败 +&LoginRoleError角色登陆失败 \ No newline at end of file diff --git a/物品和背包的完整代码/Client/Unity/Assets/Bundles/Config/ErrorCodeData.bytes.meta b/物品和背包的完整代码/Client/Unity/Assets/Bundles/Config/ErrorCodeData.bytes.meta new file mode 100644 index 0000000..6377a47 --- /dev/null +++ b/物品和背包的完整代码/Client/Unity/Assets/Bundles/Config/ErrorCodeData.bytes.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 8c42beeb8a8954fac915d537c0e83e18 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Client/Unity/Assets/Bundles/Config/ItemConfigData.bytes b/物品和背包的完整代码/Client/Unity/Assets/Bundles/Config/ItemConfigData.bytes new file mode 100644 index 0000000..a4a68cd --- /dev/null +++ b/物品和背包的完整代码/Client/Unity/Assets/Bundles/Config/ItemConfigData.bytes @@ -0,0 +1,13 @@ + +\ 恢复药剂A!使用后,会提升体力200点 *Item_0108 +@HPXX`j10000j200 +\ 恢复药剂B!使用后,会提升体力400点 *Item_0108 +@HPXX`j10001j400 +} 恢复药剂C6使用后,会提升体力400点,提升法力值300 *Item_0108 +@HPXX`j10000j400j10001j300 +P= 幻想大剑这个是介绍 *Item_018@HPXX`j10000j200pdx +P„= 幻想头盔这个是介绍 *Item_028@HPXX`j10000j200pdx +PÄ= 幻想衣服这个是介绍 *Item_038@HPXX`j10000j200pdx +PĄ= 幻想护腿这个是介绍 *Item_048@HPXX`j10000j200pdx +Pń= 幻想护腕这个是介绍 *Item_058@HPXX`j10000j200pdx +PƄ= 幻想鞋子这个是介绍 *Item_068@HPXX`j10000j200pdx \ No newline at end of file diff --git a/物品和背包的完整代码/Client/Unity/Assets/Bundles/Config/ItemConfigData.bytes.meta b/物品和背包的完整代码/Client/Unity/Assets/Bundles/Config/ItemConfigData.bytes.meta new file mode 100644 index 0000000..715ccae --- /dev/null +++ b/物品和背包的完整代码/Client/Unity/Assets/Bundles/Config/ItemConfigData.bytes.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 821d3ae21243f4cad86e04de1e07e327 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Client/Unity/Assets/Bundles/Config/LevelConfigData.bytes b/物品和背包的完整代码/Client/Unity/Assets/Bundles/Config/LevelConfigData.bytes new file mode 100644 index 0000000..25b9f15 --- /dev/null +++ b/物品和背包的完整代码/Client/Unity/Assets/Bundles/Config/LevelConfigData.bytes @@ -0,0 +1,5 @@ + +Unit01Unit01  +Unit02Unit02  +Unit03Unit03  +Unit04Unit04  \ No newline at end of file diff --git a/物品和背包的完整代码/Client/Unity/Assets/Bundles/Config/LevelConfigData.bytes.meta b/物品和背包的完整代码/Client/Unity/Assets/Bundles/Config/LevelConfigData.bytes.meta new file mode 100644 index 0000000..d30d85c --- /dev/null +++ b/物品和背包的完整代码/Client/Unity/Assets/Bundles/Config/LevelConfigData.bytes.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 96bfccf115fa348f2a92c90013f84ca8 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Client/Unity/Assets/Bundles/Config/UnitConfigData.bytes b/物品和背包的完整代码/Client/Unity/Assets/Bundles/Config/UnitConfigData.bytes new file mode 100644 index 0000000..fa60d14 --- /dev/null +++ b/物品和背包的完整代码/Client/Unity/Assets/Bundles/Config/UnitConfigData.bytes @@ -0,0 +1,4 @@ + +(地精投资公司职员Unit03 ( ++希尔瓦娜斯·风行者Unit02 0N + 牛头人Unit01 8 \ No newline at end of file diff --git a/物品和背包的完整代码/Client/Unity/Assets/Bundles/Config/UnitConfigData.bytes.meta b/物品和背包的完整代码/Client/Unity/Assets/Bundles/Config/UnitConfigData.bytes.meta new file mode 100644 index 0000000..db23ce5 --- /dev/null +++ b/物品和背包的完整代码/Client/Unity/Assets/Bundles/Config/UnitConfigData.bytes.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: eaf70b217678e4f4facf5905d990583f +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Client/Unity/Assets/Scenes.meta b/物品和背包的完整代码/Client/Unity/Assets/Scenes.meta new file mode 100644 index 0000000..83c741b --- /dev/null +++ b/物品和背包的完整代码/Client/Unity/Assets/Scenes.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 6ea315d0fd7389c41b19996891e99ae3 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Client/Unity/Assets/Scenes/MainScene.unity b/物品和背包的完整代码/Client/Unity/Assets/Scenes/MainScene.unity new file mode 100644 index 0000000..c9dac32 --- /dev/null +++ b/物品和背包的完整代码/Client/Unity/Assets/Scenes/MainScene.unity @@ -0,0 +1,1482 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!29 &1 +OcclusionCullingSettings: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_OcclusionBakeSettings: + smallestOccluder: 5 + smallestHole: 0.25 + backfaceThreshold: 100 + m_SceneGUID: 00000000000000000000000000000000 + m_OcclusionCullingData: {fileID: 0} +--- !u!104 &2 +RenderSettings: + m_ObjectHideFlags: 0 + serializedVersion: 9 + m_Fog: 0 + m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} + m_FogMode: 3 + m_FogDensity: 0.01 + m_LinearFogStart: 0 + m_LinearFogEnd: 300 + m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1} + m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1} + m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1} + m_AmbientIntensity: 1 + m_AmbientMode: 0 + m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} + m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0} + m_HaloStrength: 0.5 + m_FlareStrength: 1 + m_FlareFadeSpeed: 3 + m_HaloTexture: {fileID: 0} + m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0} + m_DefaultReflectionMode: 0 + m_DefaultReflectionResolution: 128 + m_ReflectionBounces: 1 + m_ReflectionIntensity: 1 + m_CustomReflection: {fileID: 0} + m_Sun: {fileID: 0} + m_IndirectSpecularColor: {r: 0.18028352, g: 0.22571363, b: 0.30692217, a: 1} + m_UseRadianceAmbientProbe: 0 +--- !u!157 &3 +LightmapSettings: + m_ObjectHideFlags: 0 + serializedVersion: 12 + m_GIWorkflowMode: 1 + m_GISettings: + serializedVersion: 2 + m_BounceScale: 1 + m_IndirectOutputScale: 1 + m_AlbedoBoost: 1 + m_EnvironmentLightingMode: 0 + m_EnableBakedLightmaps: 1 + m_EnableRealtimeLightmaps: 0 + m_LightmapEditorSettings: + serializedVersion: 12 + m_Resolution: 2 + m_BakeResolution: 40 + m_AtlasSize: 1024 + m_AO: 0 + m_AOMaxDistance: 1 + m_CompAOExponent: 1 + m_CompAOExponentDirect: 0 + m_ExtractAmbientOcclusion: 0 + m_Padding: 2 + m_LightmapParameters: {fileID: 0} + m_LightmapsBakeMode: 1 + m_TextureCompression: 1 + m_FinalGather: 0 + m_FinalGatherFiltering: 1 + m_FinalGatherRayCount: 256 + m_ReflectionCompression: 2 + m_MixedBakeMode: 2 + m_BakeBackend: 1 + m_PVRSampling: 1 + m_PVRDirectSampleCount: 32 + m_PVRSampleCount: 512 + m_PVRBounces: 2 + m_PVREnvironmentSampleCount: 256 + m_PVREnvironmentReferencePointCount: 2048 + m_PVRFilteringMode: 1 + m_PVRDenoiserTypeDirect: 1 + m_PVRDenoiserTypeIndirect: 1 + m_PVRDenoiserTypeAO: 1 + m_PVRFilterTypeDirect: 0 + m_PVRFilterTypeIndirect: 0 + m_PVRFilterTypeAO: 0 + m_PVREnvironmentMIS: 1 + m_PVRCulling: 1 + m_PVRFilteringGaussRadiusDirect: 1 + m_PVRFilteringGaussRadiusIndirect: 5 + m_PVRFilteringGaussRadiusAO: 2 + m_PVRFilteringAtrousPositionSigmaDirect: 0.5 + m_PVRFilteringAtrousPositionSigmaIndirect: 2 + m_PVRFilteringAtrousPositionSigmaAO: 1 + m_ExportTrainingData: 0 + m_TrainingDataDestination: TrainingData + m_LightProbeSampleCountMultiplier: 4 + m_LightingDataAsset: {fileID: 0} + m_LightingSettings: {fileID: 0} +--- !u!196 &4 +NavMeshSettings: + serializedVersion: 2 + m_ObjectHideFlags: 0 + m_BuildSettings: + serializedVersion: 2 + agentTypeID: 0 + agentRadius: 0.5 + agentHeight: 2 + agentSlope: 45 + agentClimb: 0.4 + ledgeDropHeight: 0 + maxJumpAcrossDistance: 0 + minRegionArea: 2 + manualCellSize: 0 + cellSize: 0.16666667 + manualTileSize: 0 + tileSize: 256 + accuratePlacement: 0 + maxJobWorkers: 0 + preserveTilesOutsideBounds: 0 + debug: + m_Flags: 0 + m_NavMeshData: {fileID: 0} +--- !u!1 &611034004 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 611034005} + - component: {fileID: 611034007} + - component: {fileID: 611034006} + m_Layer: 5 + m_Name: Panel + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &611034005 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 611034004} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 1792517802} + - {fileID: 898842535} + - {fileID: 1095190003} + - {fileID: 844966454} + m_Father: {fileID: 939207325} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &611034006 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 611034004} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 0.392} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10907, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &611034007 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 611034004} + m_CullTransparentMesh: 1 +--- !u!1 &844966453 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 844966454} + - component: {fileID: 844966457} + - component: {fileID: 844966456} + - component: {fileID: 844966455} + m_Layer: 5 + m_Name: UseItemId + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &844966454 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 844966453} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 1067676130} + - {fileID: 1410650195} + m_Father: {fileID: 611034005} + m_RootOrder: 3 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: -290.47, y: 404} + m_SizeDelta: {x: 687.58, y: 85.198} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &844966455 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 844966453} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d199490a83bb2b844b9695cbf13b01ef, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_WrapAround: 0 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Selected + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 844966456} + m_TextComponent: {fileID: 1410650196} + m_Placeholder: {fileID: 1067676131} + m_ContentType: 0 + m_InputType: 0 + m_AsteriskChar: 42 + m_KeyboardType: 0 + m_LineType: 0 + m_HideMobileInput: 0 + m_CharacterValidation: 0 + m_CharacterLimit: 0 + m_OnSubmit: + m_PersistentCalls: + m_Calls: [] + m_OnDidEndEdit: + m_PersistentCalls: + m_Calls: [] + m_OnValueChanged: + m_PersistentCalls: + m_Calls: [] + m_CaretColor: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} + m_CustomCaretColor: 0 + m_SelectionColor: {r: 0.65882355, g: 0.80784315, b: 1, a: 0.7529412} + m_Text: + m_CaretBlinkRate: 0.85 + m_CaretWidth: 1 + m_ReadOnly: 0 + m_ShouldActivateOnSelect: 1 +--- !u!114 &844966456 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 844966453} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10911, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &844966457 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 844966453} + m_CullTransparentMesh: 1 +--- !u!1 &857970052 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 857970053} + - component: {fileID: 857970055} + - component: {fileID: 857970054} + m_Layer: 5 + m_Name: Text (Legacy) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &857970053 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 857970052} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 1095190003} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &857970054 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 857970052} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 28 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 2 + m_MaxSize: 40 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: "\u4F7F\u7528\u4E00\u4E2A\u7269\u54C1" +--- !u!222 &857970055 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 857970052} + m_CullTransparentMesh: 1 +--- !u!1 &898842534 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 898842535} + - component: {fileID: 898842538} + - component: {fileID: 898842537} + - component: {fileID: 898842536} + m_Layer: 5 + m_Name: StartCreateItemButton + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &898842535 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 898842534} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 1933321769} + m_Father: {fileID: 611034005} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 1} + m_AnchorMax: {x: 0, y: 1} + m_AnchoredPosition: {x: 602, y: -115} + m_SizeDelta: {x: 291.6085, y: 105.51312} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &898842536 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 898842534} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_WrapAround: 0 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Selected + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 898842537} + m_OnClick: + m_PersistentCalls: + m_Calls: [] +--- !u!114 &898842537 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 898842534} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &898842538 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 898842534} + m_CullTransparentMesh: 1 +--- !u!1 &939207321 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 939207325} + - component: {fileID: 939207324} + - component: {fileID: 939207323} + - component: {fileID: 939207322} + m_Layer: 5 + m_Name: Canvas + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &939207322 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 939207321} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: dc42784cf147c0c48a680349fa168899, type: 3} + m_Name: + m_EditorClassIdentifier: + m_IgnoreReversedGraphics: 1 + m_BlockingObjects: 0 + m_BlockingMask: + serializedVersion: 2 + m_Bits: 4294967295 +--- !u!114 &939207323 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 939207321} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 0cd44c1031e13a943bb63640046fad76, type: 3} + m_Name: + m_EditorClassIdentifier: + m_UiScaleMode: 1 + m_ReferencePixelsPerUnit: 100 + m_ScaleFactor: 1 + m_ReferenceResolution: {x: 1920, y: 1080} + m_ScreenMatchMode: 0 + m_MatchWidthOrHeight: 0.5 + m_PhysicalUnit: 3 + m_FallbackScreenDPI: 96 + m_DefaultSpriteDPI: 96 + m_DynamicPixelsPerUnit: 1 + m_PresetInfoIsWorld: 0 +--- !u!223 &939207324 +Canvas: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 939207321} + m_Enabled: 1 + serializedVersion: 3 + m_RenderMode: 0 + m_Camera: {fileID: 0} + m_PlaneDistance: 100 + m_PixelPerfect: 0 + m_ReceivesEvents: 1 + m_OverrideSorting: 0 + m_OverridePixelPerfect: 0 + m_SortingBucketNormalizedSize: 0 + m_AdditionalShaderChannelsFlag: 0 + m_SortingLayerID: 0 + m_SortingOrder: 0 + m_TargetDisplay: 0 +--- !u!224 &939207325 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 939207321} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 0, y: 0, z: 0} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 611034005} + m_Father: {fileID: 0} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 0} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0, y: 0} +--- !u!1 &1039294658 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1039294660} + - component: {fileID: 1039294659} + m_Layer: 0 + m_Name: Directional Light + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!108 &1039294659 +Light: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1039294658} + m_Enabled: 1 + serializedVersion: 10 + m_Type: 1 + m_Shape: 0 + m_Color: {r: 1, g: 0.95686275, b: 0.8392157, a: 1} + m_Intensity: 1 + m_Range: 10 + m_SpotAngle: 30 + m_InnerSpotAngle: 21.80208 + m_CookieSize: 10 + m_Shadows: + m_Type: 2 + m_Resolution: -1 + m_CustomResolution: -1 + m_Strength: 1 + m_Bias: 0.05 + m_NormalBias: 0.4 + m_NearPlane: 0.2 + m_CullingMatrixOverride: + e00: 1 + e01: 0 + e02: 0 + e03: 0 + e10: 0 + e11: 1 + e12: 0 + e13: 0 + e20: 0 + e21: 0 + e22: 1 + e23: 0 + e30: 0 + e31: 0 + e32: 0 + e33: 1 + m_UseCullingMatrixOverride: 0 + m_Cookie: {fileID: 0} + m_DrawHalo: 0 + m_Flare: {fileID: 0} + m_RenderMode: 0 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingLayerMask: 1 + m_Lightmapping: 4 + m_LightShadowCasterMode: 0 + m_AreaSize: {x: 1, y: 1} + m_BounceIntensity: 1 + m_ColorTemperature: 6570 + m_UseColorTemperature: 0 + m_BoundingSphereOverride: {x: 0, y: 0, z: 0, w: 0} + m_UseBoundingSphereOverride: 0 + m_UseViewFrustumForShadowCasterCull: 1 + m_ShadowRadius: 0 + m_ShadowAngle: 0 +--- !u!4 &1039294660 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1039294658} + m_LocalRotation: {x: 0.40821788, y: -0.23456968, z: 0.10938163, w: 0.8754261} + m_LocalPosition: {x: 0, y: 3, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0} +--- !u!1 &1067676129 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1067676130} + - component: {fileID: 1067676132} + - component: {fileID: 1067676131} + m_Layer: 5 + m_Name: Placeholder + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1067676130 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1067676129} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 844966454} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: -0.5} + m_SizeDelta: {x: -20, y: -13} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1067676131 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1067676129} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 0.5} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 28 + m_FontStyle: 2 + m_BestFit: 0 + m_MinSize: 2 + m_MaxSize: 40 + m_Alignment: 3 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: "\u7269\u54C1\u7684Id..." +--- !u!222 &1067676132 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1067676129} + m_CullTransparentMesh: 1 +--- !u!1 &1095190002 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1095190003} + - component: {fileID: 1095190006} + - component: {fileID: 1095190005} + - component: {fileID: 1095190004} + m_Layer: 5 + m_Name: UseItemButton + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1095190003 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1095190002} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 857970053} + m_Father: {fileID: 611034005} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 1} + m_AnchorMax: {x: 0, y: 1} + m_AnchoredPosition: {x: 1007, y: -295} + m_SizeDelta: {x: 291.6085, y: 105.51312} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1095190004 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1095190002} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_WrapAround: 0 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Selected + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 1095190005} + m_OnClick: + m_PersistentCalls: + m_Calls: [] +--- !u!114 &1095190005 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1095190002} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &1095190006 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1095190002} + m_CullTransparentMesh: 1 +--- !u!1 &1192894275 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1192894278} + - component: {fileID: 1192894277} + - component: {fileID: 1192894276} + - component: {fileID: 1192894279} + m_Layer: 0 + m_Name: Main Camera + m_TagString: MainCamera + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!81 &1192894276 +AudioListener: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1192894275} + m_Enabled: 1 +--- !u!20 &1192894277 +Camera: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1192894275} + m_Enabled: 1 + serializedVersion: 2 + m_ClearFlags: 1 + m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0} + m_projectionMatrixMode: 1 + m_GateFitMode: 2 + m_FOVAxisMode: 0 + m_SensorSize: {x: 36, y: 24} + m_LensShift: {x: 0, y: 0} + m_FocalLength: 50 + m_NormalizedViewPortRect: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 + near clip plane: 0.3 + far clip plane: 1000 + field of view: 60 + orthographic: 0 + orthographic size: 5 + m_Depth: -1 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingPath: -1 + m_TargetTexture: {fileID: 0} + m_TargetDisplay: 0 + m_TargetEye: 3 + m_HDR: 1 + m_AllowMSAA: 1 + m_AllowDynamicResolution: 0 + m_ForceIntoRT: 0 + m_OcclusionCulling: 1 + m_StereoConvergence: 10 + m_StereoSeparation: 0.022 +--- !u!4 &1192894278 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1192894275} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 1, z: -10} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &1192894279 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1192894275} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: a7cc614dc83be4bedbca193be666bc99, type: 3} + m_Name: + m_EditorClassIdentifier: + GameInitCompleteButton: {fileID: 1792517803} + StartCreateItemButton: {fileID: 898842536} + UseItemButton: {fileID: 1095190004} + UseItemId: {fileID: 844966455} +--- !u!1 &1256238634 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1256238635} + - component: {fileID: 1256238637} + - component: {fileID: 1256238636} + m_Layer: 5 + m_Name: Text (Legacy) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1256238635 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1256238634} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 1792517802} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1256238636 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1256238634} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 28 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 2 + m_MaxSize: 40 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: "\u5BA2\u6237\u7AEF\u521D\u59CB\u5316\u5B8C\u6210" +--- !u!222 &1256238637 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1256238634} + m_CullTransparentMesh: 1 +--- !u!1 &1410650194 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1410650195} + - component: {fileID: 1410650197} + - component: {fileID: 1410650196} + m_Layer: 5 + m_Name: Text (Legacy) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1410650195 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1410650194} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 844966454} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: -0.5} + m_SizeDelta: {x: -20, y: -13} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1410650196 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1410650194} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 28 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 2 + m_MaxSize: 40 + m_Alignment: 3 + m_AlignByGeometry: 0 + m_RichText: 0 + m_HorizontalOverflow: 1 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: +--- !u!222 &1410650197 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1410650194} + m_CullTransparentMesh: 1 +--- !u!1 &1583481357 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1583481360} + - component: {fileID: 1583481359} + - component: {fileID: 1583481358} + m_Layer: 0 + m_Name: EventSystem + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1583481358 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1583481357} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4f231c4fb786f3946a6b90b886c48677, type: 3} + m_Name: + m_EditorClassIdentifier: + m_SendPointerHoverToParent: 1 + m_HorizontalAxis: Horizontal + m_VerticalAxis: Vertical + m_SubmitButton: Submit + m_CancelButton: Cancel + m_InputActionsPerSecond: 10 + m_RepeatDelay: 0.5 + m_ForceModuleActive: 0 +--- !u!114 &1583481359 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1583481357} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 76c392e42b5098c458856cdf6ecaaaa1, type: 3} + m_Name: + m_EditorClassIdentifier: + m_FirstSelected: {fileID: 0} + m_sendNavigationEvents: 1 + m_DragThreshold: 10 +--- !u!4 &1583481360 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1583481357} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 3 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1792517801 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1792517802} + - component: {fileID: 1792517805} + - component: {fileID: 1792517804} + - component: {fileID: 1792517803} + m_Layer: 5 + m_Name: GameInitCompleteButton + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1792517802 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1792517801} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 1256238635} + m_Father: {fileID: 611034005} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 1} + m_AnchorMax: {x: 0, y: 1} + m_AnchoredPosition: {x: 260, y: -115} + m_SizeDelta: {x: 291.6085, y: 105.51312} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1792517803 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1792517801} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_WrapAround: 0 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Selected + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 1792517804} + m_OnClick: + m_PersistentCalls: + m_Calls: [] +--- !u!114 &1792517804 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1792517801} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &1792517805 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1792517801} + m_CullTransparentMesh: 1 +--- !u!1 &1933321768 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1933321769} + - component: {fileID: 1933321771} + - component: {fileID: 1933321770} + m_Layer: 5 + m_Name: Text (Legacy) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1933321769 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1933321768} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 898842535} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1933321770 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1933321768} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 28 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 2 + m_MaxSize: 40 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: "\u521B\u5EFA\u4E00\u4E2A\u7269\u54C1" +--- !u!222 &1933321771 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1933321768} + m_CullTransparentMesh: 1 diff --git a/物品和背包的完整代码/Client/Unity/Assets/Scenes/MainScene.unity.meta b/物品和背包的完整代码/Client/Unity/Assets/Scenes/MainScene.unity.meta new file mode 100644 index 0000000..5527a34 --- /dev/null +++ b/物品和背包的完整代码/Client/Unity/Assets/Scenes/MainScene.unity.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 82fa49f0c44ed4b95a5b2b5ce2efabb1 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Client/Unity/Assets/Scenes/SampleScene.unity b/物品和背包的完整代码/Client/Unity/Assets/Scenes/SampleScene.unity new file mode 100644 index 0000000..2221b04 --- /dev/null +++ b/物品和背包的完整代码/Client/Unity/Assets/Scenes/SampleScene.unity @@ -0,0 +1,267 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!29 &1 +OcclusionCullingSettings: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_OcclusionBakeSettings: + smallestOccluder: 5 + smallestHole: 0.25 + backfaceThreshold: 100 + m_SceneGUID: 00000000000000000000000000000000 + m_OcclusionCullingData: {fileID: 0} +--- !u!104 &2 +RenderSettings: + m_ObjectHideFlags: 0 + serializedVersion: 9 + m_Fog: 0 + m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} + m_FogMode: 3 + m_FogDensity: 0.01 + m_LinearFogStart: 0 + m_LinearFogEnd: 300 + m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1} + m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1} + m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1} + m_AmbientIntensity: 1 + m_AmbientMode: 0 + m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} + m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0} + m_HaloStrength: 0.5 + m_FlareStrength: 1 + m_FlareFadeSpeed: 3 + m_HaloTexture: {fileID: 0} + m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0} + m_DefaultReflectionMode: 0 + m_DefaultReflectionResolution: 128 + m_ReflectionBounces: 1 + m_ReflectionIntensity: 1 + m_CustomReflection: {fileID: 0} + m_Sun: {fileID: 705507994} + m_IndirectSpecularColor: {r: 0, g: 0, b: 0, a: 1} + m_UseRadianceAmbientProbe: 0 +--- !u!157 &3 +LightmapSettings: + m_ObjectHideFlags: 0 + serializedVersion: 12 + m_GIWorkflowMode: 1 + m_GISettings: + serializedVersion: 2 + m_BounceScale: 1 + m_IndirectOutputScale: 1 + m_AlbedoBoost: 1 + m_EnvironmentLightingMode: 0 + m_EnableBakedLightmaps: 1 + m_EnableRealtimeLightmaps: 0 + m_LightmapEditorSettings: + serializedVersion: 12 + m_Resolution: 2 + m_BakeResolution: 40 + m_AtlasSize: 1024 + m_AO: 0 + m_AOMaxDistance: 1 + m_CompAOExponent: 1 + m_CompAOExponentDirect: 0 + m_ExtractAmbientOcclusion: 0 + m_Padding: 2 + m_LightmapParameters: {fileID: 0} + m_LightmapsBakeMode: 1 + m_TextureCompression: 1 + m_FinalGather: 0 + m_FinalGatherFiltering: 1 + m_FinalGatherRayCount: 256 + m_ReflectionCompression: 2 + m_MixedBakeMode: 2 + m_BakeBackend: 1 + m_PVRSampling: 1 + m_PVRDirectSampleCount: 32 + m_PVRSampleCount: 500 + m_PVRBounces: 2 + m_PVREnvironmentSampleCount: 500 + m_PVREnvironmentReferencePointCount: 2048 + m_PVRFilteringMode: 2 + m_PVRDenoiserTypeDirect: 0 + m_PVRDenoiserTypeIndirect: 0 + m_PVRDenoiserTypeAO: 0 + m_PVRFilterTypeDirect: 0 + m_PVRFilterTypeIndirect: 0 + m_PVRFilterTypeAO: 0 + m_PVREnvironmentMIS: 0 + m_PVRCulling: 1 + m_PVRFilteringGaussRadiusDirect: 1 + m_PVRFilteringGaussRadiusIndirect: 5 + m_PVRFilteringGaussRadiusAO: 2 + m_PVRFilteringAtrousPositionSigmaDirect: 0.5 + m_PVRFilteringAtrousPositionSigmaIndirect: 2 + m_PVRFilteringAtrousPositionSigmaAO: 1 + m_ExportTrainingData: 0 + m_TrainingDataDestination: TrainingData + m_LightProbeSampleCountMultiplier: 4 + m_LightingDataAsset: {fileID: 0} + m_LightingSettings: {fileID: 0} +--- !u!196 &4 +NavMeshSettings: + serializedVersion: 2 + m_ObjectHideFlags: 0 + m_BuildSettings: + serializedVersion: 2 + agentTypeID: 0 + agentRadius: 0.5 + agentHeight: 2 + agentSlope: 45 + agentClimb: 0.4 + ledgeDropHeight: 0 + maxJumpAcrossDistance: 0 + minRegionArea: 2 + manualCellSize: 0 + cellSize: 0.16666667 + manualTileSize: 0 + tileSize: 256 + accuratePlacement: 0 + debug: + m_Flags: 0 + m_NavMeshData: {fileID: 0} +--- !u!1 &705507993 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 705507995} + - component: {fileID: 705507994} + m_Layer: 0 + m_Name: Directional Light + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!108 &705507994 +Light: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 705507993} + m_Enabled: 1 + serializedVersion: 8 + m_Type: 1 + m_Color: {r: 1, g: 0.95686275, b: 0.8392157, a: 1} + m_Intensity: 1 + m_Range: 10 + m_SpotAngle: 30 + m_CookieSize: 10 + m_Shadows: + m_Type: 2 + m_Resolution: -1 + m_CustomResolution: -1 + m_Strength: 1 + m_Bias: 0.05 + m_NormalBias: 0.4 + m_NearPlane: 0.2 + m_Cookie: {fileID: 0} + m_DrawHalo: 0 + m_Flare: {fileID: 0} + m_RenderMode: 0 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_Lightmapping: 1 + m_LightShadowCasterMode: 0 + m_AreaSize: {x: 1, y: 1} + m_BounceIntensity: 1 + m_ColorTemperature: 6570 + m_UseColorTemperature: 0 + m_ShadowRadius: 0 + m_ShadowAngle: 0 +--- !u!4 &705507995 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 705507993} + m_LocalRotation: {x: 0.40821788, y: -0.23456968, z: 0.10938163, w: 0.8754261} + m_LocalPosition: {x: 0, y: 3, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0} +--- !u!1 &963194225 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 963194228} + - component: {fileID: 963194227} + - component: {fileID: 963194226} + m_Layer: 0 + m_Name: Main Camera + m_TagString: MainCamera + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!81 &963194226 +AudioListener: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 963194225} + m_Enabled: 1 +--- !u!20 &963194227 +Camera: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 963194225} + m_Enabled: 1 + serializedVersion: 2 + m_ClearFlags: 1 + m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0} + m_projectionMatrixMode: 1 + m_SensorSize: {x: 36, y: 24} + m_LensShift: {x: 0, y: 0} + m_GateFitMode: 2 + m_FocalLength: 50 + m_NormalizedViewPortRect: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 + near clip plane: 0.3 + far clip plane: 1000 + field of view: 60 + orthographic: 0 + orthographic size: 5 + m_Depth: -1 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingPath: -1 + m_TargetTexture: {fileID: 0} + m_TargetDisplay: 0 + m_TargetEye: 3 + m_HDR: 1 + m_AllowMSAA: 1 + m_AllowDynamicResolution: 0 + m_ForceIntoRT: 0 + m_OcclusionCulling: 1 + m_StereoConvergence: 10 + m_StereoSeparation: 0.022 +--- !u!4 &963194228 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 963194225} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 1, z: -10} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} diff --git a/物品和背包的完整代码/Client/Unity/Assets/Scenes/SampleScene.unity.meta b/物品和背包的完整代码/Client/Unity/Assets/Scenes/SampleScene.unity.meta new file mode 100644 index 0000000..952bd1e --- /dev/null +++ b/物品和背包的完整代码/Client/Unity/Assets/Scenes/SampleScene.unity.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 9fc0d4010bbf28b4594072e72b8655ab +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Client/Unity/Assets/Scripts.meta b/物品和背包的完整代码/Client/Unity/Assets/Scripts.meta new file mode 100644 index 0000000..ef49471 --- /dev/null +++ b/物品和背包的完整代码/Client/Unity/Assets/Scripts.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 781e2c0bcc0354c3db37fbd6ef6aa7bb +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Client/Unity/Assets/Scripts/.DS_Store b/物品和背包的完整代码/Client/Unity/Assets/Scripts/.DS_Store new file mode 100644 index 0000000..9c20d4b Binary files /dev/null and b/物品和背包的完整代码/Client/Unity/Assets/Scripts/.DS_Store differ diff --git a/物品和背包的完整代码/Client/Unity/Assets/Scripts/AssetsBundleManager.cs b/物品和背包的完整代码/Client/Unity/Assets/Scripts/AssetsBundleManager.cs new file mode 100644 index 0000000..bfcc8ce --- /dev/null +++ b/物品和背包的完整代码/Client/Unity/Assets/Scripts/AssetsBundleManager.cs @@ -0,0 +1,28 @@ +using System.IO; +using Fantasy.ConfigTable; +using UnityEditor; +using UnityEngine; + +namespace Fantasy +{ + public class AssetsBundleManager : IConfigTableAssetBundle + { + public string Combine(string assetBundleDirectoryPath, string dataConfig) + { + return Path.Combine(assetBundleDirectoryPath, $"{dataConfig}.bytes"); + } + + public byte[] LoadConfigTable(string assetBundlePath) + { +#if UNITY_EDITOR || UNITY_EDITOR_64 + if (File.Exists(assetBundlePath)) + { + return AssetDatabase.LoadAssetAtPath(assetBundlePath).bytes; + } + UnityEngine.Debug.LogError($"assetBundlePath:{assetBundlePath} not exist"); + return null; + #else +#endif + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Client/Unity/Assets/Scripts/AssetsBundleManager.cs.meta b/物品和背包的完整代码/Client/Unity/Assets/Scripts/AssetsBundleManager.cs.meta new file mode 100644 index 0000000..2df1a32 --- /dev/null +++ b/物品和背包的完整代码/Client/Unity/Assets/Scripts/AssetsBundleManager.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 87e30a9fb6ff422780ee0c1592fe053e +timeCreated: 1742869780 \ No newline at end of file diff --git a/物品和背包的完整代码/Client/Unity/Assets/Scripts/Entry.cs b/物品和背包的完整代码/Client/Unity/Assets/Scripts/Entry.cs new file mode 100644 index 0000000..00cbd4e --- /dev/null +++ b/物品和背包的完整代码/Client/Unity/Assets/Scripts/Entry.cs @@ -0,0 +1,107 @@ +using System.Collections; +using System.Collections.Generic; +using Fantasy; +using Fantasy.Async; +using Fantasy.ConfigTable; +using Fantasy.Network; +using UnityEngine; +using UnityEngine.UI; +using ErrorCode = UnityEditor.PackageManager.ErrorCode; + +public class Entry : MonoBehaviour +{ + private Scene _scene; + private Session _session; + + public Button GameInitCompleteButton; + public Button StartCreateItemButton; + public Button UseItemButton; + public InputField UseItemId; + + void Start() + { + StartAsync().Coroutine(); + } + + private async FTask StartAsync() + { + // 第一个参数,主要是为了兼容不容包管理器的路径 + // Yoo、Addressable + // 路径 + 包名字 = 完整的路径 + // Assets/Bundles/Config + Config.bytes = Assets/Bundles/Config/Config.bytes + ConfigTableHelper.Initialize("Assets/Bundles/Config", new AssetsBundleManager()); + // 初始化框架 + await Fantasy.Platform.Unity.Entry.Initialize(GetType().Assembly); + // 创建一个Scene,这个Scene代表一个客户端的场景,客户端的所有逻辑都可以写这里 + // 如果有自己的框架,也可以就单纯拿这个Scene做网络通讯也没问题。 + _scene = await Scene.Create(SceneRuntimeType.MainThread); + // 用当前的Scene创建一个新的网络连接 + _session = _scene.Connect( + "127.0.0.1:20000", + NetworkProtocolType.KCP, + OnConnectComplete, + OnConnectFail, + OnConnectDisconnect, + false, 5000); + var response = (G2C_LoginResponse)await _session.Call(new C2G_LoginRequest() + { + UserName = "Fantasy6666",PassWord = "666" + }); + if (response.ErrorCode != 0) + { + Log.Error($"登陆失败,错误码 = {response.ErrorCode}"); + return; + } + + Log.Debug("收到G2C_TestResponse UserName:\"Fantasy\""); + GameInitCompleteButton.onClick.AddListener(() => OnGameInitCompleteButton().Coroutine()); + StartCreateItemButton.onClick.AddListener(OnStartCreateItemButton); + UseItemButton.onClick.AddListener(() => OnUseItemButton().Coroutine()); + } + + private async FTask OnUseItemButton() + { + var itemId = long.Parse(UseItemId.text); + var response = await _session.Call(new C2G_UseItemRequest() + { + ItemId = itemId, Count = 1, ContainerType = 1 + }); + if (response.ErrorCode != 0) + { + Log.Error($"无法使用物品 ErrorCode:{response.ErrorCode}"); + } + } + + private async FTask OnGameInitCompleteButton() + { + var response = await _session.Call(new C2G_GameInitCompleteRequest() + { + PushContainer = true + }); + if (response.ErrorCode != 0) + { + Log.Error($"无法跟服务器建立连接 ErrorCode:{response.ErrorCode}"); + } + } + + private void OnStartCreateItemButton() + { + _session.Send(new C2G_StartCreateItem()); + } + + private void OnConnectComplete() + { + Log.Debug("OnConnectComplete"); + _session.AddComponent().Start(ConstValue.Heartbeat); + } + + private void OnConnectFail() + { + Log.Debug("OnConnectFail"); + } + + private void OnConnectDisconnect() + { + Log.Debug("OnConnectDisconnect"); + } +} diff --git a/物品和背包的完整代码/Client/Unity/Assets/Scripts/Entry.cs.meta b/物品和背包的完整代码/Client/Unity/Assets/Scripts/Entry.cs.meta new file mode 100644 index 0000000..98a3703 --- /dev/null +++ b/物品和背包的完整代码/Client/Unity/Assets/Scripts/Entry.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a7cc614dc83be4bedbca193be666bc99 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Client/Unity/Assets/Scripts/Handler.meta b/物品和背包的完整代码/Client/Unity/Assets/Scripts/Handler.meta new file mode 100644 index 0000000..3d8c6c0 --- /dev/null +++ b/物品和背包的完整代码/Client/Unity/Assets/Scripts/Handler.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: c9c81b2068ae74b20aba26c2fb77a6ce +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Client/Unity/Assets/Scripts/Handler/G2C_PushAllContainerInfoHandler.cs b/物品和背包的完整代码/Client/Unity/Assets/Scripts/Handler/G2C_PushAllContainerInfoHandler.cs new file mode 100644 index 0000000..8cc0b46 --- /dev/null +++ b/物品和背包的完整代码/Client/Unity/Assets/Scripts/Handler/G2C_PushAllContainerInfoHandler.cs @@ -0,0 +1,23 @@ +using Fantasy.Async; +using Fantasy.Network; +using Fantasy.Network.Interface; + +namespace Fantasy.Handler +{ + public sealed class G2C_PushAllContainerInfoHandler : Message + { + protected override async FTask Run(Session session, G2C_PushAllContainerInfo message) + { + Log.Debug($"接收到服务器推送的容器消息 Containers : {message.Containers.Count}"); + foreach (var messageContainer in message.Containers) + { + Log.Debug($"容器Id:{messageContainer.ConfigId} 容器格子数量:{messageContainer.Items.Count}"); + foreach (var messageContainerItem in messageContainer.Items) + { + Log.Debug($"Id:{messageContainerItem.ItemId} ConfigId:{messageContainerItem.ConfigId} Count:{messageContainerItem.Count}"); + } + } + await FTask.CompletedTask; + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Client/Unity/Assets/Scripts/Handler/G2C_PushAllContainerInfoHandler.cs.meta b/物品和背包的完整代码/Client/Unity/Assets/Scripts/Handler/G2C_PushAllContainerInfoHandler.cs.meta new file mode 100644 index 0000000..474c889 --- /dev/null +++ b/物品和背包的完整代码/Client/Unity/Assets/Scripts/Handler/G2C_PushAllContainerInfoHandler.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9e9eb318a5ed942d39f01628a53981de +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Client/Unity/Assets/Scripts/Handler/G2C_UpdateItemsHandler.cs b/物品和背包的完整代码/Client/Unity/Assets/Scripts/Handler/G2C_UpdateItemsHandler.cs new file mode 100644 index 0000000..328610f --- /dev/null +++ b/物品和背包的完整代码/Client/Unity/Assets/Scripts/Handler/G2C_UpdateItemsHandler.cs @@ -0,0 +1,19 @@ +using Fantasy.Async; +using Fantasy.Network; +using Fantasy.Network.Interface; + +namespace Fantasy +{ + public sealed class G2C_UpdateItemsHandler : Message + { + protected override async FTask Run(Session session, G2C_UpdateItems message) + { + Log.Debug($"收到容器中物品更新的消息 ItemReason:{message.ItemReason} Items:{message.Items.Count}"); + foreach (var messageItem in message.Items) + { + Log.Debug($" ContainerType:{messageItem.Container} Id:{messageItem.ItemId} ConfigId:{messageItem.ConfigId} Count:{messageItem.Count}"); + } + await FTask.CompletedTask; + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Client/Unity/Assets/Scripts/Handler/G2C_UpdateItemsHandler.cs.meta b/物品和背包的完整代码/Client/Unity/Assets/Scripts/Handler/G2C_UpdateItemsHandler.cs.meta new file mode 100644 index 0000000..06b4058 --- /dev/null +++ b/物品和背包的完整代码/Client/Unity/Assets/Scripts/Handler/G2C_UpdateItemsHandler.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3431f1cc55ad245ef90e96510bad6f47 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix.meta b/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix.meta new file mode 100644 index 0000000..2677600 --- /dev/null +++ b/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 6f1daa49d4fac4511b093893b2d5a056 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/.DS_Store b/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/.DS_Store new file mode 100644 index 0000000..aa835f4 Binary files /dev/null and b/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/.DS_Store differ diff --git a/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate.meta b/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate.meta new file mode 100644 index 0000000..e1413c4 --- /dev/null +++ b/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: eea06cf63e0d24f0c878a1ea9aae9751 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/.DS_Store b/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/.DS_Store new file mode 100644 index 0000000..e74825a Binary files /dev/null and b/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/.DS_Store differ diff --git a/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/A.meta b/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/A.meta new file mode 100644 index 0000000..19a1cb8 --- /dev/null +++ b/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/A.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: be6a0fc31d8e942149e6291afbff18d8 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/A/ErrorCode.cs b/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/A/ErrorCode.cs new file mode 100644 index 0000000..e0b5b7e --- /dev/null +++ b/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/A/ErrorCode.cs @@ -0,0 +1,10 @@ +namespace Fantasy +{ + public partial class ErrorCode + { + public static string GetText(uint errorCode) + { + return ErrorCodeData.Instance.Get(errorCode).Text; + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/A/ErrorCode.cs.meta b/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/A/ErrorCode.cs.meta new file mode 100644 index 0000000..eeeb476 --- /dev/null +++ b/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/A/ErrorCode.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a6cd7984eec694f5ca83080cbed1da95 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/ConfigTable.meta b/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/ConfigTable.meta new file mode 100644 index 0000000..00c9573 --- /dev/null +++ b/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/ConfigTable.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: f4598fcac010243349354de5df0a6c60 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/ConfigTable/A.meta b/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/ConfigTable/A.meta new file mode 100644 index 0000000..f54c365 --- /dev/null +++ b/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/ConfigTable/A.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 4d9f327360a24d41b52855d149c87578 +timeCreated: 1742971118 \ No newline at end of file diff --git a/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/ConfigTable/A/LevelConfig.cs b/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/ConfigTable/A/LevelConfig.cs new file mode 100644 index 0000000..6b4b0c0 --- /dev/null +++ b/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/ConfigTable/A/LevelConfig.cs @@ -0,0 +1,11 @@ +namespace Fantasy +{ + public partial class LevelConfig + { + public bool IsGroup1; + public override void EndInit() + { + IsGroup1 = Group == 1; + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/ConfigTable/A/LevelConfig.cs.meta b/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/ConfigTable/A/LevelConfig.cs.meta new file mode 100644 index 0000000..cac6326 --- /dev/null +++ b/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/ConfigTable/A/LevelConfig.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 9dd377279fae44f4850cacc93b7010ed +timeCreated: 1742971691 \ No newline at end of file diff --git a/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/ConfigTable/A/LevelConfigData.cs b/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/ConfigTable/A/LevelConfigData.cs new file mode 100644 index 0000000..b92374b --- /dev/null +++ b/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/ConfigTable/A/LevelConfigData.cs @@ -0,0 +1,26 @@ +using System.Collections.Generic; +using Fantasy.DataStructure.Collection; + +namespace Fantasy +{ + public partial class LevelConfigData + { + private readonly OneToManyList _levelConfigsByGroup = new OneToManyList(); + public override void EndInit() + { + foreach (var levelConfig in List) + { + _levelConfigsByGroup.Add(levelConfig.Group, levelConfig); + } + } + public List GetLevelConfigByGroup(uint group) + { + return _levelConfigsByGroup[group]; + } + + public bool TryGetLevelConfigByGroup(uint group, out List levelConfig) + { + return _levelConfigsByGroup.TryGetValue(group, out levelConfig); + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/ConfigTable/A/LevelConfigData.cs.meta b/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/ConfigTable/A/LevelConfigData.cs.meta new file mode 100644 index 0000000..6f41171 --- /dev/null +++ b/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/ConfigTable/A/LevelConfigData.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: bc1dd9007e40493cb31de31aabdf1a8c +timeCreated: 1742971129 \ No newline at end of file diff --git a/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/ConfigTable/Entity.meta b/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/ConfigTable/Entity.meta new file mode 100644 index 0000000..96c3e8b --- /dev/null +++ b/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/ConfigTable/Entity.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 80b620ba3ea924f0dad7d8f27e24e912 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/ConfigTable/Entity/ContainerConfig.cs b/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/ConfigTable/Entity/ContainerConfig.cs new file mode 100644 index 0000000..a144717 --- /dev/null +++ b/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/ConfigTable/Entity/ContainerConfig.cs @@ -0,0 +1,105 @@ +using System; +using ProtoBuf; +using Fantasy; +using System.Linq; +using System.Reflection; +using System.Collections.Generic; +using System.Collections.Concurrent; +using Fantasy.ConfigTable; +using Fantasy.Serialize; +// ReSharper disable CollectionNeverUpdated.Global +// ReSharper disable UnusedAutoPropertyAccessor.Global +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member +#pragma warning disable CS0169 +#pragma warning disable CS8618 +#pragma warning disable CS8625 +#pragma warning disable CS8603 + +namespace Fantasy +{ + [ProtoContract] + public sealed partial class ContainerConfigData : ASerialize, IConfigTable, IProto + { + [ProtoMember(1)] + public List List { get; set; } = new List(); +#if FANTASY_NET + [ProtoIgnore] + private readonly ConcurrentDictionary _configs = new ConcurrentDictionary(); +#else + [ProtoIgnore] + private readonly Dictionary _configs = new Dictionary(); +#endif + private static ContainerConfigData _instance = null; + + public static ContainerConfigData Instance + { + get { return _instance ??= ConfigTableHelper.Load(); } + private set => _instance = value; + } + + public ContainerConfig Get(uint id, bool check = true) + { + if (_configs.ContainsKey(id)) + { + return _configs[id]; + } + + if (check) + { + throw new Exception($"ContainerConfig not find {id} Id"); + } + + return null; + } + public bool TryGet(uint id, out ContainerConfig config) + { + config = null; + + if (!_configs.ContainsKey(id)) + { + return false; + } + + config = _configs[id]; + return true; + } + public override void AfterDeserialization() + { + foreach (var config in List) + { +#if FANTASY_NET + _configs.TryAdd(config.Id, config); +#else + _configs.Add(config.Id, config); +#endif + config.AfterDeserialization(); + } + + EndInit(); + } + + public override void Dispose() + { + Instance = null; + } + } + + [ProtoContract] + public sealed partial class ContainerConfig : ASerialize, IProto + { + [ProtoMember(1)] + public uint Id { get; set; } // Id + [ProtoMember(2)] + public string Name { get; set; } // 名字 + [ProtoMember(3)] + public int Type { get; set; } // 容器类型 + [ProtoMember(4)] + public int CellCountMax { get; set; } // 容器最大的格子数 + [ProtoMember(5)] + public int CellCount { get; set; } // 初始解锁格子 + [ProtoMember(6)] + public bool CanSort { get; set; } // 是否可以整理 + [ProtoMember(7)] + public int SortCD { get; set; } // 是否可以整理 + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/ConfigTable/Entity/ContainerConfig.cs.meta b/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/ConfigTable/Entity/ContainerConfig.cs.meta new file mode 100644 index 0000000..9f02887 --- /dev/null +++ b/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/ConfigTable/Entity/ContainerConfig.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d7274baf613e94a51998deb754d756cb +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/ConfigTable/Entity/EquipAffixConfig.cs b/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/ConfigTable/Entity/EquipAffixConfig.cs new file mode 100644 index 0000000..c771054 --- /dev/null +++ b/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/ConfigTable/Entity/EquipAffixConfig.cs @@ -0,0 +1,97 @@ +using System; +using ProtoBuf; +using Fantasy; +using System.Linq; +using System.Reflection; +using System.Collections.Generic; +using System.Collections.Concurrent; +using Fantasy.ConfigTable; +using Fantasy.Serialize; +// ReSharper disable CollectionNeverUpdated.Global +// ReSharper disable UnusedAutoPropertyAccessor.Global +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member +#pragma warning disable CS0169 +#pragma warning disable CS8618 +#pragma warning disable CS8625 +#pragma warning disable CS8603 + +namespace Fantasy +{ + [ProtoContract] + public sealed partial class EquipAffixConfigData : ASerialize, IConfigTable, IProto + { + [ProtoMember(1)] + public List List { get; set; } = new List(); +#if FANTASY_NET + [ProtoIgnore] + private readonly ConcurrentDictionary _configs = new ConcurrentDictionary(); +#else + [ProtoIgnore] + private readonly Dictionary _configs = new Dictionary(); +#endif + private static EquipAffixConfigData _instance = null; + + public static EquipAffixConfigData Instance + { + get { return _instance ??= ConfigTableHelper.Load(); } + private set => _instance = value; + } + + public EquipAffixConfig Get(uint id, bool check = true) + { + if (_configs.ContainsKey(id)) + { + return _configs[id]; + } + + if (check) + { + throw new Exception($"EquipAffixConfig not find {id} Id"); + } + + return null; + } + public bool TryGet(uint id, out EquipAffixConfig config) + { + config = null; + + if (!_configs.ContainsKey(id)) + { + return false; + } + + config = _configs[id]; + return true; + } + public override void AfterDeserialization() + { + foreach (var config in List) + { +#if FANTASY_NET + _configs.TryAdd(config.Id, config); +#else + _configs.Add(config.Id, config); +#endif + config.AfterDeserialization(); + } + + EndInit(); + } + + public override void Dispose() + { + Instance = null; + } + } + + [ProtoContract] + public sealed partial class EquipAffixConfig : ASerialize, IProto + { + [ProtoMember(1)] + public uint Id { get; set; } // Id + [ProtoMember(2)] + public uint BuffConfigId { get; set; } // 触发的Buff + [ProtoMember(3)] + public string Descride { get; set; } // 介绍 + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/ConfigTable/Entity/EquipAffixConfig.cs.meta b/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/ConfigTable/Entity/EquipAffixConfig.cs.meta new file mode 100644 index 0000000..a826761 --- /dev/null +++ b/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/ConfigTable/Entity/EquipAffixConfig.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: cea9d23e4b03b4979918c5daa31f09d2 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/ConfigTable/Entity/EquipEntryConfig.cs b/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/ConfigTable/Entity/EquipEntryConfig.cs new file mode 100644 index 0000000..bd2c1cd --- /dev/null +++ b/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/ConfigTable/Entity/EquipEntryConfig.cs @@ -0,0 +1,105 @@ +using System; +using ProtoBuf; +using Fantasy; +using System.Linq; +using System.Reflection; +using System.Collections.Generic; +using System.Collections.Concurrent; +using Fantasy.ConfigTable; +using Fantasy.Serialize; +// ReSharper disable CollectionNeverUpdated.Global +// ReSharper disable UnusedAutoPropertyAccessor.Global +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member +#pragma warning disable CS0169 +#pragma warning disable CS8618 +#pragma warning disable CS8625 +#pragma warning disable CS8603 + +namespace Fantasy +{ + [ProtoContract] + public sealed partial class EquipEntryConfigData : ASerialize, IConfigTable, IProto + { + [ProtoMember(1)] + public List List { get; set; } = new List(); +#if FANTASY_NET + [ProtoIgnore] + private readonly ConcurrentDictionary _configs = new ConcurrentDictionary(); +#else + [ProtoIgnore] + private readonly Dictionary _configs = new Dictionary(); +#endif + private static EquipEntryConfigData _instance = null; + + public static EquipEntryConfigData Instance + { + get { return _instance ??= ConfigTableHelper.Load(); } + private set => _instance = value; + } + + public EquipEntryConfig Get(uint id, bool check = true) + { + if (_configs.ContainsKey(id)) + { + return _configs[id]; + } + + if (check) + { + throw new Exception($"EquipEntryConfig not find {id} Id"); + } + + return null; + } + public bool TryGet(uint id, out EquipEntryConfig config) + { + config = null; + + if (!_configs.ContainsKey(id)) + { + return false; + } + + config = _configs[id]; + return true; + } + public override void AfterDeserialization() + { + foreach (var config in List) + { +#if FANTASY_NET + _configs.TryAdd(config.Id, config); +#else + _configs.Add(config.Id, config); +#endif + config.AfterDeserialization(); + } + + EndInit(); + } + + public override void Dispose() + { + Instance = null; + } + } + + [ProtoContract] + public sealed partial class EquipEntryConfig : ASerialize, IProto + { + [ProtoMember(1)] + public uint Id { get; set; } // Id + [ProtoMember(2)] + public int Min { get; set; } // 词条最小数 + [ProtoMember(3)] + public int Max { get; set; } // 词条最大数 + [ProtoMember(4)] + public int AffixMin { get; set; } // 词缀最小数 + [ProtoMember(5)] + public int AffixMax { get; set; } // 词缀最大数 + [ProtoMember(6)] + public uint[] Affix { get; set; } = Array.Empty(); // 词缀列表 + [ProtoMember(7)] + public int[] Attrs { get; set; } = Array.Empty(); // 属性数组 + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/ConfigTable/Entity/EquipEntryConfig.cs.meta b/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/ConfigTable/Entity/EquipEntryConfig.cs.meta new file mode 100644 index 0000000..d93d1a5 --- /dev/null +++ b/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/ConfigTable/Entity/EquipEntryConfig.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 785516e0f77da4618a0ed9dd3face3b2 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/ConfigTable/Entity/EquipValueConfig.cs b/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/ConfigTable/Entity/EquipValueConfig.cs new file mode 100644 index 0000000..e8d5112 --- /dev/null +++ b/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/ConfigTable/Entity/EquipValueConfig.cs @@ -0,0 +1,101 @@ +using System; +using ProtoBuf; +using Fantasy; +using System.Linq; +using System.Reflection; +using System.Collections.Generic; +using System.Collections.Concurrent; +using Fantasy.ConfigTable; +using Fantasy.Serialize; +// ReSharper disable CollectionNeverUpdated.Global +// ReSharper disable UnusedAutoPropertyAccessor.Global +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member +#pragma warning disable CS0169 +#pragma warning disable CS8618 +#pragma warning disable CS8625 +#pragma warning disable CS8603 + +namespace Fantasy +{ + [ProtoContract] + public sealed partial class EquipValueConfigData : ASerialize, IConfigTable, IProto + { + [ProtoMember(1)] + public List List { get; set; } = new List(); +#if FANTASY_NET + [ProtoIgnore] + private readonly ConcurrentDictionary _configs = new ConcurrentDictionary(); +#else + [ProtoIgnore] + private readonly Dictionary _configs = new Dictionary(); +#endif + private static EquipValueConfigData _instance = null; + + public static EquipValueConfigData Instance + { + get { return _instance ??= ConfigTableHelper.Load(); } + private set => _instance = value; + } + + public EquipValueConfig Get(uint id, bool check = true) + { + if (_configs.ContainsKey(id)) + { + return _configs[id]; + } + + if (check) + { + throw new Exception($"EquipValueConfig not find {id} Id"); + } + + return null; + } + public bool TryGet(uint id, out EquipValueConfig config) + { + config = null; + + if (!_configs.ContainsKey(id)) + { + return false; + } + + config = _configs[id]; + return true; + } + public override void AfterDeserialization() + { + foreach (var config in List) + { +#if FANTASY_NET + _configs.TryAdd(config.Id, config); +#else + _configs.Add(config.Id, config); +#endif + config.AfterDeserialization(); + } + + EndInit(); + } + + public override void Dispose() + { + Instance = null; + } + } + + [ProtoContract] + public sealed partial class EquipValueConfig : ASerialize, IProto + { + [ProtoMember(1)] + public uint Id { get; set; } // Id + [ProtoMember(2)] + public uint ItemConfigId { get; set; } // ItemConfigId + [ProtoMember(3)] + public uint EquipEntryConfigId { get; set; } // EquipEntryConfigId + [ProtoMember(4)] + public int Quality { get; set; } // 品质 + [ProtoMember(5)] + public IntDictionaryConfig MainAttrs { get; set; } // 法术强度 + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/ConfigTable/Entity/EquipValueConfig.cs.meta b/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/ConfigTable/Entity/EquipValueConfig.cs.meta new file mode 100644 index 0000000..5cd4146 --- /dev/null +++ b/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/ConfigTable/Entity/EquipValueConfig.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e843d1e93bb2d480e9b504817c8752c3 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/ConfigTable/Entity/ErrorCode.cs b/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/ConfigTable/Entity/ErrorCode.cs new file mode 100644 index 0000000..22c5440 --- /dev/null +++ b/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/ConfigTable/Entity/ErrorCode.cs @@ -0,0 +1,97 @@ +using System; +using ProtoBuf; +using Fantasy; +using System.Linq; +using System.Reflection; +using System.Collections.Generic; +using System.Collections.Concurrent; +using Fantasy.ConfigTable; +using Fantasy.Serialize; +// ReSharper disable CollectionNeverUpdated.Global +// ReSharper disable UnusedAutoPropertyAccessor.Global +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member +#pragma warning disable CS0169 +#pragma warning disable CS8618 +#pragma warning disable CS8625 +#pragma warning disable CS8603 + +namespace Fantasy +{ + [ProtoContract] + public sealed partial class ErrorCodeData : ASerialize, IConfigTable, IProto + { + [ProtoMember(1)] + public List List { get; set; } = new List(); +#if FANTASY_NET + [ProtoIgnore] + private readonly ConcurrentDictionary _configs = new ConcurrentDictionary(); +#else + [ProtoIgnore] + private readonly Dictionary _configs = new Dictionary(); +#endif + private static ErrorCodeData _instance = null; + + public static ErrorCodeData Instance + { + get { return _instance ??= ConfigTableHelper.Load(); } + private set => _instance = value; + } + + public ErrorCode Get(uint id, bool check = true) + { + if (_configs.ContainsKey(id)) + { + return _configs[id]; + } + + if (check) + { + throw new Exception($"ErrorCode not find {id} Id"); + } + + return null; + } + public bool TryGet(uint id, out ErrorCode config) + { + config = null; + + if (!_configs.ContainsKey(id)) + { + return false; + } + + config = _configs[id]; + return true; + } + public override void AfterDeserialization() + { + foreach (var config in List) + { +#if FANTASY_NET + _configs.TryAdd(config.Id, config); +#else + _configs.Add(config.Id, config); +#endif + config.AfterDeserialization(); + } + + EndInit(); + } + + public override void Dispose() + { + Instance = null; + } + } + + [ProtoContract] + public sealed partial class ErrorCode : ASerialize, IProto + { + [ProtoMember(1)] + public uint Id { get; set; } // Id + [ProtoMember(2)] + public string Name { get; set; } // 名称 + [ProtoMember(3)] + public string Text { get; set; } // 文本内容 + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/ConfigTable/Entity/ErrorCode.cs.meta b/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/ConfigTable/Entity/ErrorCode.cs.meta new file mode 100644 index 0000000..fe17b58 --- /dev/null +++ b/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/ConfigTable/Entity/ErrorCode.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 93c9bbffbdcf24e4da780112640c17ba +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/ConfigTable/Entity/ItemConfig.cs b/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/ConfigTable/Entity/ItemConfig.cs new file mode 100644 index 0000000..f7f6e27 --- /dev/null +++ b/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/ConfigTable/Entity/ItemConfig.cs @@ -0,0 +1,123 @@ +using System; +using ProtoBuf; +using Fantasy; +using System.Linq; +using System.Reflection; +using System.Collections.Generic; +using System.Collections.Concurrent; +using Fantasy.ConfigTable; +using Fantasy.Serialize; +// ReSharper disable CollectionNeverUpdated.Global +// ReSharper disable UnusedAutoPropertyAccessor.Global +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member +#pragma warning disable CS0169 +#pragma warning disable CS8618 +#pragma warning disable CS8625 +#pragma warning disable CS8603 + +namespace Fantasy +{ + [ProtoContract] + public sealed partial class ItemConfigData : ASerialize, IConfigTable, IProto + { + [ProtoMember(1)] + public List List { get; set; } = new List(); +#if FANTASY_NET + [ProtoIgnore] + private readonly ConcurrentDictionary _configs = new ConcurrentDictionary(); +#else + [ProtoIgnore] + private readonly Dictionary _configs = new Dictionary(); +#endif + private static ItemConfigData _instance = null; + + public static ItemConfigData Instance + { + get { return _instance ??= ConfigTableHelper.Load(); } + private set => _instance = value; + } + + public ItemConfig Get(uint id, bool check = true) + { + if (_configs.ContainsKey(id)) + { + return _configs[id]; + } + + if (check) + { + throw new Exception($"ItemConfig not find {id} Id"); + } + + return null; + } + public bool TryGet(uint id, out ItemConfig config) + { + config = null; + + if (!_configs.ContainsKey(id)) + { + return false; + } + + config = _configs[id]; + return true; + } + public override void AfterDeserialization() + { + foreach (var config in List) + { +#if FANTASY_NET + _configs.TryAdd(config.Id, config); +#else + _configs.Add(config.Id, config); +#endif + config.AfterDeserialization(); + } + + EndInit(); + } + + public override void Dispose() + { + Instance = null; + } + } + + [ProtoContract] + public sealed partial class ItemConfig : ASerialize, IProto + { + [ProtoMember(1)] + public uint Id { get; set; } // Id + [ProtoMember(2)] + public string Name { get; set; } // 名称 + [ProtoMember(3)] + public string Descride { get; set; } // 描述 + [ProtoMember(4)] + public int Weight { get; set; } // 排序权重 + [ProtoMember(5)] + public string Model2D { get; set; } // 对应模型 + [ProtoMember(6)] + public bool Superposed { get; set; } // 是否可以叠加 + [ProtoMember(7)] + public uint SuperposedMax { get; set; } // 叠加 + [ProtoMember(8)] + public uint Type { get; set; } // 类型 + [ProtoMember(9)] + public bool IsDeal { get; set; } // 是否可以交易 + [ProtoMember(10)] + public bool IsSell { get; set; } // 是否可以出售 + [ProtoMember(11)] + public int[] Sell { get; set; } = Array.Empty(); // 出售价格 + [ProtoMember(12)] + public int Effect { get; set; } // 使用效果 + [ProtoMember(13)] + public string[] Params { get; set; } = Array.Empty(); // 效果参数 + [ProtoMember(14)] + public int Durable { get; set; } // 耐久度 + [ProtoMember(15)] + public int Quality { get; set; } // 品质 + [ProtoMember(16)] + public int Position { get; set; } // 装备位置 + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/ConfigTable/Entity/ItemConfig.cs.meta b/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/ConfigTable/Entity/ItemConfig.cs.meta new file mode 100644 index 0000000..31b66df --- /dev/null +++ b/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/ConfigTable/Entity/ItemConfig.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 736d7304df10e40e4b20fcce1ec0cf51 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/ConfigTable/Entity/LevelConfig.cs b/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/ConfigTable/Entity/LevelConfig.cs new file mode 100644 index 0000000..e3cb9f6 --- /dev/null +++ b/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/ConfigTable/Entity/LevelConfig.cs @@ -0,0 +1,99 @@ +using System; +using ProtoBuf; +using Fantasy; +using System.Linq; +using System.Reflection; +using System.Collections.Generic; +using System.Collections.Concurrent; +using Fantasy.ConfigTable; +using Fantasy.Serialize; +// ReSharper disable CollectionNeverUpdated.Global +// ReSharper disable UnusedAutoPropertyAccessor.Global +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member +#pragma warning disable CS0169 +#pragma warning disable CS8618 +#pragma warning disable CS8625 +#pragma warning disable CS8603 + +namespace Fantasy +{ + [ProtoContract] + public sealed partial class LevelConfigData : ASerialize, IConfigTable, IProto + { + [ProtoMember(1)] + public List List { get; set; } = new List(); +#if FANTASY_NET + [ProtoIgnore] + private readonly ConcurrentDictionary _configs = new ConcurrentDictionary(); +#else + [ProtoIgnore] + private readonly Dictionary _configs = new Dictionary(); +#endif + private static LevelConfigData _instance = null; + + public static LevelConfigData Instance + { + get { return _instance ??= ConfigTableHelper.Load(); } + private set => _instance = value; + } + + public LevelConfig Get(uint id, bool check = true) + { + if (_configs.ContainsKey(id)) + { + return _configs[id]; + } + + if (check) + { + throw new Exception($"LevelConfig not find {id} Id"); + } + + return null; + } + public bool TryGet(uint id, out LevelConfig config) + { + config = null; + + if (!_configs.ContainsKey(id)) + { + return false; + } + + config = _configs[id]; + return true; + } + public override void AfterDeserialization() + { + foreach (var config in List) + { +#if FANTASY_NET + _configs.TryAdd(config.Id, config); +#else + _configs.Add(config.Id, config); +#endif + config.AfterDeserialization(); + } + + EndInit(); + } + + public override void Dispose() + { + Instance = null; + } + } + + [ProtoContract] + public sealed partial class LevelConfig : ASerialize, IProto + { + [ProtoMember(1)] + public uint Id { get; set; } // Id + [ProtoMember(2)] + public string Name { get; set; } // 名称 + [ProtoMember(3)] + public string Model { get; set; } // 数据库类型 + [ProtoMember(4)] + public uint Group { get; set; } // 分组 + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/ConfigTable/Entity/LevelConfig.cs.meta b/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/ConfigTable/Entity/LevelConfig.cs.meta new file mode 100644 index 0000000..6377a05 --- /dev/null +++ b/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/ConfigTable/Entity/LevelConfig.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 60ae3251840bf48c7b8bb30a059c02a8 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/ConfigTable/Entity/UnitConfig.cs b/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/ConfigTable/Entity/UnitConfig.cs new file mode 100644 index 0000000..cf00156 --- /dev/null +++ b/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/ConfigTable/Entity/UnitConfig.cs @@ -0,0 +1,105 @@ +using System; +using ProtoBuf; +using Fantasy; +using System.Linq; +using System.Reflection; +using System.Collections.Generic; +using System.Collections.Concurrent; +using Fantasy.ConfigTable; +using Fantasy.Serialize; +// ReSharper disable CollectionNeverUpdated.Global +// ReSharper disable UnusedAutoPropertyAccessor.Global +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member +#pragma warning disable CS0169 +#pragma warning disable CS8618 +#pragma warning disable CS8625 +#pragma warning disable CS8603 + +namespace Fantasy +{ + [ProtoContract] + public sealed partial class UnitConfigData : ASerialize, IConfigTable, IProto + { + [ProtoMember(1)] + public List List { get; set; } = new List(); +#if FANTASY_NET + [ProtoIgnore] + private readonly ConcurrentDictionary _configs = new ConcurrentDictionary(); +#else + [ProtoIgnore] + private readonly Dictionary _configs = new Dictionary(); +#endif + private static UnitConfigData _instance = null; + + public static UnitConfigData Instance + { + get { return _instance ??= ConfigTableHelper.Load(); } + private set => _instance = value; + } + + public UnitConfig Get(uint id, bool check = true) + { + if (_configs.ContainsKey(id)) + { + return _configs[id]; + } + + if (check) + { + throw new Exception($"UnitConfig not find {id} Id"); + } + + return null; + } + public bool TryGet(uint id, out UnitConfig config) + { + config = null; + + if (!_configs.ContainsKey(id)) + { + return false; + } + + config = _configs[id]; + return true; + } + public override void AfterDeserialization() + { + foreach (var config in List) + { +#if FANTASY_NET + _configs.TryAdd(config.Id, config); +#else + _configs.Add(config.Id, config); +#endif + config.AfterDeserialization(); + } + + EndInit(); + } + + public override void Dispose() + { + Instance = null; + } + } + + [ProtoContract] + public sealed partial class UnitConfig : ASerialize, IProto + { + [ProtoMember(1)] + public uint Id { get; set; } // Id + [ProtoMember(2)] + public string Name { get; set; } // 名称 + [ProtoMember(3)] + public string Model { get; set; } // 数据库类型 + [ProtoMember(4)] + public uint Type { get; set; } // 类型 + [ProtoMember(5)] + public uint MonsterPRange { get; set; } // 怪物追击范围 + [ProtoMember(6)] + public uint TalkConfigId { get; set; } // NPC对话列表Id + [ProtoMember(7)] + public uint Camp { get; set; } // 玩家阵营 + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/ConfigTable/Entity/UnitConfig.cs.meta b/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/ConfigTable/Entity/UnitConfig.cs.meta new file mode 100644 index 0000000..9269e1c --- /dev/null +++ b/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/ConfigTable/Entity/UnitConfig.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7ba8eb1bdd9f740659c67a32dba1eba2 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/CustomExport.meta b/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/CustomExport.meta new file mode 100644 index 0000000..f0792a7 --- /dev/null +++ b/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/CustomExport.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: a2673f292fb01410492068cbd15e2341 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/CustomExport/ConstValue.cs b/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/CustomExport/ConstValue.cs new file mode 100644 index 0000000..8c080e4 --- /dev/null +++ b/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/CustomExport/ConstValue.cs @@ -0,0 +1,27 @@ +namespace Fantasy +{ + // 生成器自动生成,请不要手动编辑,修改请在#ConstValue.xsl里。 + public partial class ConstValue + { + /// + /// 游戏版本 + /// + public const string Version = "v202501"; + /// + /// 可以创建角色的最大数量 + /// + public const int CreateRoleMax = 5; + /// + /// 客户端使用的网络类型 + /// + public const string Network = "KCP"; + /// + /// 客户端发送心跳的时间(毫秒单位) + /// + public const int Heartbeat = 2000; + /// + /// 服务器最大容纳玩家人数 + /// + public const int PlayerCount = 5000; + } +} diff --git a/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/CustomExport/ConstValue.cs.meta b/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/CustomExport/ConstValue.cs.meta new file mode 100644 index 0000000..7a9874e --- /dev/null +++ b/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/CustomExport/ConstValue.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 78d090fa7aa79473fba4f9156b162664 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/CustomExport/ContainerType.cs b/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/CustomExport/ContainerType.cs new file mode 100644 index 0000000..63102b2 --- /dev/null +++ b/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/CustomExport/ContainerType.cs @@ -0,0 +1,16 @@ +using System; + +namespace Fantasy +{ + // 生成器自动生成,请不要手动编辑,修改请在ContainerConfig.xsl里。 + [Flags] + public enum ContainerType : byte + { + None = 0, + Bag = 1,// 背包 + Equip = 2,// 装备栏 + Trade = 4,// 交易 + Cell = Equip | Trade,// 按格子存储的容器 + Normal = Bag,// 正常的容器 + } +} diff --git a/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/CustomExport/ContainerType.cs.meta b/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/CustomExport/ContainerType.cs.meta new file mode 100644 index 0000000..4977540 --- /dev/null +++ b/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/CustomExport/ContainerType.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 41386197615e84f64a03fec1523194a0 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/CustomExport/ErrorCode.cs b/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/CustomExport/ErrorCode.cs new file mode 100644 index 0000000..7029507 --- /dev/null +++ b/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/CustomExport/ErrorCode.cs @@ -0,0 +1,15 @@ +namespace Fantasy +{ + // 生成器自动生成,请不要手动编辑,修改请在ErrorCode.xsl里。 + public partial class ErrorCode + { + /// + /// 登陆失败 + /// + public const uint LoingError = 1; + /// + /// 角色登陆失败 + /// + public const uint LoginRoleError = 2; + } +} diff --git a/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/CustomExport/ErrorCode.cs.meta b/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/CustomExport/ErrorCode.cs.meta new file mode 100644 index 0000000..b93c4d2 --- /dev/null +++ b/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/CustomExport/ErrorCode.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 52e540e7dcf8241aeb76ce3ace622a06 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/CustomExport/ItemType.cs b/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/CustomExport/ItemType.cs new file mode 100644 index 0000000..32a7fe7 --- /dev/null +++ b/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/CustomExport/ItemType.cs @@ -0,0 +1,12 @@ +namespace Fantasy +{ + // 生成器自动生成,请不要手动编辑,修改请在#ItemType.xsl里。 + public enum ItemType + { + None = 0, + Drug = 1,// 药品 + Equip = 2,// 装备 + Prop = 3,// 道具 + Garbage = 4,// 垃圾 + } +} diff --git a/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/CustomExport/ItemType.cs.meta b/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/CustomExport/ItemType.cs.meta new file mode 100644 index 0000000..93c9d7e --- /dev/null +++ b/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/CustomExport/ItemType.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d2dacd15b6b61438eba3c56686b2f7cf +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/CustomExport/ItemUseEffect.cs b/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/CustomExport/ItemUseEffect.cs new file mode 100644 index 0000000..cbcc3c0 --- /dev/null +++ b/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/CustomExport/ItemUseEffect.cs @@ -0,0 +1,12 @@ +namespace Fantasy +{ + // 生成器自动生成,请不要手动编辑,修改请在#ItemUseEffect.xsl里。 + public enum ItemUseEffect + { + None = 0, + Equip = 1,// 装备到身上 + UnEquip = 2,// 从身上卸下 + AddAttr = 3,// 增加属性 + CutAttr = 4,// 减少属性 + } +} diff --git a/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/CustomExport/ItemUseEffect.cs.meta b/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/CustomExport/ItemUseEffect.cs.meta new file mode 100644 index 0000000..15cea12 --- /dev/null +++ b/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/CustomExport/ItemUseEffect.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2cc1f02b07b064cb6a3540aced600b52 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/NetworkProtocol.meta b/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/NetworkProtocol.meta new file mode 100644 index 0000000..ffaf0b0 --- /dev/null +++ b/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/NetworkProtocol.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 6f6f4ef09be2d4afb85592aaf63045e8 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/NetworkProtocol/OuterMessage.cs b/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/NetworkProtocol/OuterMessage.cs new file mode 100644 index 0000000..a8a078e --- /dev/null +++ b/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/NetworkProtocol/OuterMessage.cs @@ -0,0 +1,341 @@ +using ProtoBuf; + +using System.Collections.Generic; +using Fantasy; +using Fantasy.Network.Interface; +using Fantasy.Serialize; +#pragma warning disable CS8618 + +namespace Fantasy +{ + /// + /// 客户端登陆到服务器 + /// + [ProtoContract] + public partial class C2G_LoginRequest : AMessage, IRequest, IProto + { + public static C2G_LoginRequest Create(Scene scene) + { + return scene.MessagePoolComponent.Rent(); + } + public override void Dispose() + { + UserName = default; + PassWord = default; +#if FANTASY_NET || FANTASY_UNITY + GetScene().MessagePoolComponent.Return(this); +#endif + } + [ProtoIgnore] + public G2C_LoginResponse ResponseType { get; set; } + public uint OpCode() { return OuterOpcode.C2G_LoginRequest; } + [ProtoMember(1)] + public string UserName { get; set; } + [ProtoMember(2)] + public string PassWord { get; set; } + } + /// + /// 服务器返回登陆状态给客户端 + /// + [ProtoContract] + public partial class G2C_LoginResponse : AMessage, IResponse, IProto + { + public static G2C_LoginResponse Create(Scene scene) + { + return scene.MessagePoolComponent.Rent(); + } + public override void Dispose() + { + ErrorCode = default; +#if FANTASY_NET || FANTASY_UNITY + GetScene().MessagePoolComponent.Return(this); +#endif + } + public uint OpCode() { return OuterOpcode.G2C_LoginResponse; } + [ProtoMember(1)] + public uint ErrorCode { get; set; } + } + /// + /// 客户端请求服务器使用物品 + /// + [ProtoContract] + public partial class C2G_UseItemRequest : AMessage, IRequest, IProto + { + public static C2G_UseItemRequest Create(Scene scene) + { + return scene.MessagePoolComponent.Rent(); + } + public override void Dispose() + { + ItemId = default; + Count = default; + ContainerType = default; +#if FANTASY_NET || FANTASY_UNITY + GetScene().MessagePoolComponent.Return(this); +#endif + } + [ProtoIgnore] + public G2C_UseItemResponse ResponseType { get; set; } + public uint OpCode() { return OuterOpcode.C2G_UseItemRequest; } + [ProtoMember(1)] + public long ItemId { get; set; } + [ProtoMember(2)] + public int Count { get; set; } + [ProtoMember(3)] + public int ContainerType { get; set; } + } + [ProtoContract] + public partial class G2C_UseItemResponse : AMessage, IResponse, IProto + { + public static G2C_UseItemResponse Create(Scene scene) + { + return scene.MessagePoolComponent.Rent(); + } + public override void Dispose() + { + ErrorCode = default; +#if FANTASY_NET || FANTASY_UNITY + GetScene().MessagePoolComponent.Return(this); +#endif + } + public uint OpCode() { return OuterOpcode.G2C_UseItemResponse; } + [ProtoMember(1)] + public uint ErrorCode { get; set; } + } + /// + /// 装备基础信息类 + /// + [ProtoContract] + public partial class EquipInfo : AMessage, IProto + { + public static EquipInfo Create(Scene scene) + { + return scene.MessagePoolComponent.Rent(); + } + public override void Dispose() + { + Durable = default; + DurableMax = default; + MainKeys.Clear(); + EquipAttrKeys.Clear(); + EquipAttrValues.Clear(); + EquipAttrSValues.Clear(); +#if FANTASY_NET || FANTASY_UNITY + GetScene().MessagePoolComponent.Return(this); +#endif + } + [ProtoMember(1)] + public int Durable { get; set; } + [ProtoMember(2)] + public int DurableMax { get; set; } + [ProtoMember(3)] + public List MainKeys = new List(); + [ProtoMember(4)] + public List EquipAttrKeys = new List(); + [ProtoMember(5)] + public List EquipAttrValues = new List(); + [ProtoMember(6)] + public List EquipAttrSValues = new List(); + /// + /// 比如强化等级,副属性,词缀等。都可以在这里添加 + /// + } + /// + /// 物品基础信息类 + /// + [ProtoContract] + public partial class ItemInfo : AMessage, IProto + { + public static ItemInfo Create(Scene scene) + { + return scene.MessagePoolComponent.Rent(); + } + public override void Dispose() + { + ItemId = default; + Container = default; + ConfigId = default; + CellId = default; + Count = default; + IsBind = default; + EquipInfo = default; +#if FANTASY_NET || FANTASY_UNITY + GetScene().MessagePoolComponent.Return(this); +#endif + } + [ProtoMember(1)] + public long ItemId { get; set; } + [ProtoMember(2)] + public int Container { get; set; } + [ProtoMember(3)] + public int ConfigId { get; set; } + [ProtoMember(4)] + public long CellId { get; set; } + [ProtoMember(5)] + public int Count { get; set; } + [ProtoMember(6)] + public bool IsBind { get; set; } + [ProtoMember(7)] + public EquipInfo EquipInfo { get; set; } + /// + /// 后面可能会有装备词条 也会在这里定义的,现在没有所以就是先不管了 + /// + } + /// + /// 容器信息类 + /// + [ProtoContract] + public partial class ContainerInfo : AMessage, IProto + { + public static ContainerInfo Create(Scene scene) + { + return scene.MessagePoolComponent.Rent(); + } + public override void Dispose() + { + CurrentCellCount = default; + ConfigId = default; + Items.Clear(); +#if FANTASY_NET || FANTASY_UNITY + GetScene().MessagePoolComponent.Return(this); +#endif + } + [ProtoMember(1)] + public int CurrentCellCount { get; set; } + [ProtoMember(2)] + public int ConfigId { get; set; } + [ProtoMember(3)] + public List Items = new List(); + } + /// + /// 物品变更协议(服务器推送给客户端) + /// + [ProtoContract] + public partial class G2C_UpdateItems : AMessage, IMessage, IProto + { + public static G2C_UpdateItems Create(Scene scene) + { + return scene.MessagePoolComponent.Rent(); + } + public override void Dispose() + { + ItemReason = default; + Items.Clear(); +#if FANTASY_NET || FANTASY_UNITY + GetScene().MessagePoolComponent.Return(this); +#endif + } + public uint OpCode() { return OuterOpcode.G2C_UpdateItems; } + [ProtoMember(1)] + public int ItemReason { get; set; } + [ProtoMember(2)] + public List Items = new List(); + } + /// + /// 通知服务器客户端初始化完成 + /// + [ProtoContract] + public partial class C2G_GameInitCompleteRequest : AMessage, IRequest, IProto + { + public static C2G_GameInitCompleteRequest Create(Scene scene) + { + return scene.MessagePoolComponent.Rent(); + } + public override void Dispose() + { + PushContainer = default; + PushUnitInfo = default; + Aoi = default; +#if FANTASY_NET || FANTASY_UNITY + GetScene().MessagePoolComponent.Return(this); +#endif + } + [ProtoIgnore] + public G2C_GameInitCompleteResponse ResponseType { get; set; } + public uint OpCode() { return OuterOpcode.C2G_GameInitCompleteRequest; } + [ProtoMember(1)] + public bool PushContainer { get; set; } + [ProtoMember(2)] + public bool PushUnitInfo { get; set; } + [ProtoMember(3)] + public bool Aoi { get; set; } + } + [ProtoContract] + public partial class G2C_GameInitCompleteResponse : AMessage, IResponse, IProto + { + public static G2C_GameInitCompleteResponse Create(Scene scene) + { + return scene.MessagePoolComponent.Rent(); + } + public override void Dispose() + { + ErrorCode = default; +#if FANTASY_NET || FANTASY_UNITY + GetScene().MessagePoolComponent.Return(this); +#endif + } + public uint OpCode() { return OuterOpcode.G2C_GameInitCompleteResponse; } + [ProtoMember(1)] + public uint ErrorCode { get; set; } + } + /// + /// 推送所有容器数据给客户端 + /// + [ProtoContract] + public partial class G2C_PushAllContainerInfo : AMessage, IMessage, IProto + { + public static G2C_PushAllContainerInfo Create(Scene scene) + { + return scene.MessagePoolComponent.Rent(); + } + public override void Dispose() + { + Containers.Clear(); +#if FANTASY_NET || FANTASY_UNITY + GetScene().MessagePoolComponent.Return(this); +#endif + } + public uint OpCode() { return OuterOpcode.G2C_PushAllContainerInfo; } + [ProtoMember(1)] + public List Containers = new List(); + } + /// + /// 推送单个的容器数据给客户端 + /// + [ProtoContract] + public partial class G2C_PushContainerInfo : AMessage, IMessage, IProto + { + public static G2C_PushContainerInfo Create(Scene scene) + { + return scene.MessagePoolComponent.Rent(); + } + public override void Dispose() + { + Container = default; +#if FANTASY_NET || FANTASY_UNITY + GetScene().MessagePoolComponent.Return(this); +#endif + } + public uint OpCode() { return OuterOpcode.G2C_PushContainerInfo; } + [ProtoMember(1)] + public ContainerInfo Container { get; set; } + } + /// + /// 通知服务器创建一个物品到背包容器中。 + /// + [ProtoContract] + public partial class C2G_StartCreateItem : AMessage, IMessage, IProto + { + public static C2G_StartCreateItem Create(Scene scene) + { + return scene.MessagePoolComponent.Rent(); + } + public override void Dispose() + { +#if FANTASY_NET || FANTASY_UNITY + GetScene().MessagePoolComponent.Return(this); +#endif + } + public uint OpCode() { return OuterOpcode.C2G_StartCreateItem; } + } +} diff --git a/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/NetworkProtocol/OuterMessage.cs.meta b/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/NetworkProtocol/OuterMessage.cs.meta new file mode 100644 index 0000000..c624f24 --- /dev/null +++ b/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/NetworkProtocol/OuterMessage.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c24653a7e44534a69812243fb639e44b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/NetworkProtocol/OuterOpcode.cs b/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/NetworkProtocol/OuterOpcode.cs new file mode 100644 index 0000000..913f8a0 --- /dev/null +++ b/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/NetworkProtocol/OuterOpcode.cs @@ -0,0 +1,16 @@ +namespace Fantasy +{ + public static partial class OuterOpcode + { + public const uint C2G_LoginRequest = 268445457; + public const uint G2C_LoginResponse = 402663185; + public const uint C2G_UseItemRequest = 268445458; + public const uint G2C_UseItemResponse = 402663186; + public const uint G2C_UpdateItems = 134227729; + public const uint C2G_GameInitCompleteRequest = 268445459; + public const uint G2C_GameInitCompleteResponse = 402663187; + public const uint G2C_PushAllContainerInfo = 134227730; + public const uint G2C_PushContainerInfo = 134227731; + public const uint C2G_StartCreateItem = 134227732; + } +} diff --git a/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/NetworkProtocol/OuterOpcode.cs.meta b/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/NetworkProtocol/OuterOpcode.cs.meta new file mode 100644 index 0000000..ae389ad --- /dev/null +++ b/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/NetworkProtocol/OuterOpcode.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f7a4d22b54bb447b79f6b2e64c015560 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/NetworkProtocol/RouteType.cs b/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/NetworkProtocol/RouteType.cs new file mode 100644 index 0000000..cdd0df0 --- /dev/null +++ b/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/NetworkProtocol/RouteType.cs @@ -0,0 +1,9 @@ +namespace Fantasy +{ + // Route协议定义(需要定义1000以上、因为1000以内的框架预留) + public static class RouteType + { + public const int GateRoute = 1001; // Gate + public const int ChatRoute = 1002; // Chat + } +} diff --git a/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/NetworkProtocol/RouteType.cs.meta b/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/NetworkProtocol/RouteType.cs.meta new file mode 100644 index 0000000..bdf2d86 --- /dev/null +++ b/物品和背包的完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/NetworkProtocol/RouteType.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 51588b3c7353f43a7b77d55ca78e0cae +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Client/Unity/Fantasy.ConfigTable.csproj b/物品和背包的完整代码/Client/Unity/Fantasy.ConfigTable.csproj new file mode 100644 index 0000000..ff949d2 --- /dev/null +++ b/物品和背包的完整代码/Client/Unity/Fantasy.ConfigTable.csproj @@ -0,0 +1,757 @@ + + + + 9.0 + <_TargetFrameworkDirectories>non_empty_path_generated_by_unity.rider.package + <_FullFrameworkReferenceAssemblyPaths>non_empty_path_generated_by_unity.rider.package + true + + + Debug + AnyCPU + 10.0.20506 + 2.0 + + {8eb45200-d3be-6efd-d01e-a23e2721ecc7} + {E097FAD1-6243-4DAD-9C02-E9B9EFC3FFC1};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + Library + Properties + Fantasy.ConfigTable + v4.7.1 + 512 + . + + + true + full + false + Temp\Bin\Debug\Fantasy.ConfigTable\ + UNITY_2021_3_14;UNITY_2021_3;UNITY_2021;UNITY_5_3_OR_NEWER;UNITY_5_4_OR_NEWER;UNITY_5_5_OR_NEWER;UNITY_5_6_OR_NEWER;UNITY_2017_1_OR_NEWER;UNITY_2017_2_OR_NEWER;UNITY_2017_3_OR_NEWER;UNITY_2017_4_OR_NEWER;UNITY_2018_1_OR_NEWER;UNITY_2018_2_OR_NEWER;UNITY_2018_3_OR_NEWER;UNITY_2018_4_OR_NEWER;UNITY_2019_1_OR_NEWER;UNITY_2019_2_OR_NEWER;UNITY_2019_3_OR_NEWER;UNITY_2019_4_OR_NEWER;UNITY_2020_1_OR_NEWER;UNITY_2020_2_OR_NEWER;UNITY_2020_3_OR_NEWER;UNITY_2021_1_OR_NEWER;UNITY_2021_2_OR_NEWER;UNITY_2021_3_OR_NEWER;PLATFORM_ARCH_64;UNITY_64;UNITY_INCLUDE_TESTS;USE_SEARCH_ENGINE_API;USE_SEARCH_TABLE;USE_SEARCH_MODULE;USE_PROPERTY_DATABASE;USE_SEARCH_EXTENSION_API;ENABLE_AR;ENABLE_AUDIO;ENABLE_CACHING;ENABLE_CLOTH;ENABLE_MICROPHONE;ENABLE_MULTIPLE_DISPLAYS;ENABLE_PHYSICS;ENABLE_TEXTURE_STREAMING;ENABLE_VIRTUALTEXTURING;ENABLE_UNET;ENABLE_LZMA;ENABLE_UNITYEVENTS;ENABLE_VR;ENABLE_WEBCAM;ENABLE_UNITYWEBREQUEST;ENABLE_WWW;ENABLE_CLOUD_SERVICES;ENABLE_CLOUD_SERVICES_COLLAB;ENABLE_CLOUD_SERVICES_COLLAB_SOFTLOCKS;ENABLE_CLOUD_SERVICES_ADS;ENABLE_CLOUD_SERVICES_USE_WEBREQUEST;ENABLE_CLOUD_SERVICES_CRASH_REPORTING;ENABLE_CLOUD_SERVICES_NATIVE_CRASH_REPORTING;ENABLE_CLOUD_SERVICES_PURCHASING;ENABLE_CLOUD_SERVICES_ANALYTICS;ENABLE_CLOUD_SERVICES_UNET;ENABLE_CLOUD_SERVICES_BUILD;ENABLE_CLOUD_LICENSE;ENABLE_EDITOR_HUB_LICENSE;ENABLE_WEBSOCKET_CLIENT;ENABLE_DIRECTOR_AUDIO;ENABLE_DIRECTOR_TEXTURE;ENABLE_MANAGED_JOBS;ENABLE_MANAGED_TRANSFORM_JOBS;ENABLE_MANAGED_ANIMATION_JOBS;ENABLE_MANAGED_AUDIO_JOBS;ENABLE_MANAGED_UNITYTLS;INCLUDE_DYNAMIC_GI;ENABLE_SCRIPTING_GC_WBARRIERS;PLATFORM_SUPPORTS_MONO;RENDER_SOFTWARE_CURSOR;ENABLE_VIDEO;ENABLE_ACCELERATOR_CLIENT_DEBUGGING;PLATFORM_STANDALONE;TEXTCORE_1_0_OR_NEWER;PLATFORM_STANDALONE_OSX;UNITY_STANDALONE_OSX;UNITY_STANDALONE;ENABLE_GAMECENTER;ENABLE_RUNTIME_GI;ENABLE_MOVIES;ENABLE_NETWORK;ENABLE_CRUNCH_TEXTURE_COMPRESSION;ENABLE_UNITY_GAME_SERVICES_ANALYTICS_SUPPORT;ENABLE_CLUSTER_SYNC;ENABLE_CLUSTERINPUT;ENABLE_SPATIALTRACKING;PLATFORM_UPDATES_TIME_OUTSIDE_OF_PLAYER_LOOP;ENABLE_WEBSOCKET_HOST;ENABLE_MONO;NET_STANDARD_2_0;NET_STANDARD;NET_STANDARD_2_1;NETSTANDARD;NETSTANDARD2_1;ENABLE_PROFILER;DEBUG;TRACE;UNITY_ASSERTIONS;UNITY_EDITOR;UNITY_EDITOR_64;UNITY_EDITOR_OSX;ENABLE_UNITY_COLLECTIONS_CHECKS;ENABLE_BURST_AOT;UNITY_TEAM_LICENSE;ENABLE_CUSTOM_RENDER_TEXTURE;ENABLE_DIRECTOR;ENABLE_LOCALIZATION;ENABLE_SPRITES;ENABLE_TERRAIN;ENABLE_TILEMAP;ENABLE_TIMELINE;ENABLE_LEGACY_INPUT_MANAGER;CSHARP_7_OR_LATER;CSHARP_7_3_OR_NEWER + prompt + 4 + 0169,0649 + False + False + + + true + true + false + false + false + + + + + + + + + + + + + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.AIModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.ARModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.AccessibilityModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.AndroidJNIModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.AnimationModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.AssetBundleModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.AudioModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.ClothModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.ClusterInputModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.ClusterRendererModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.CoreModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.CrashReportingModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.DSPGraphModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.DirectorModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.GIModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.GameCenterModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.GridModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.HotReloadModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.IMGUIModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.ImageConversionModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.InputModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.InputLegacyModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.JSONSerializeModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.LocalizationModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.ParticleSystemModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.PerformanceReportingModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.PhysicsModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.Physics2DModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.ProfilerModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.RuntimeInitializeOnLoadManagerInitializerModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.ScreenCaptureModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.SharedInternalsModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.SpriteMaskModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.SpriteShapeModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.StreamingModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.SubstanceModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.SubsystemsModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.TLSModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.TerrainModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.TerrainPhysicsModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.TextCoreFontEngineModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.TextCoreTextEngineModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.TextRenderingModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.TilemapModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.UIModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.UIElementsModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.UIElementsNativeModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.UNETModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.UmbraModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.UnityAnalyticsModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.UnityAnalyticsCommonModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.UnityConnectModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.UnityCurlModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.UnityTestProtocolModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.UnityWebRequestModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.UnityWebRequestAssetBundleModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.UnityWebRequestAudioModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.UnityWebRequestTextureModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.UnityWebRequestWWWModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.VFXModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.VRModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.VehiclesModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.VideoModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.VirtualTexturingModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.WindModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.XRModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEditor.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEditor.CoreModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEditor.DeviceSimulatorModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEditor.DiagnosticsModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEditor.GraphViewModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEditor.PackageManagerUIModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEditor.QuickSearchModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEditor.SceneTemplateModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEditor.TextCoreFontEngineModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEditor.TextCoreTextEngineModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEditor.UIBuilderModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEditor.UIElementsModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEditor.UIElementsSamplesModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEditor.UIServiceModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEditor.UnityConnectModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEditor.Graphs.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/PlaybackEngines/WebGLSupport/UnityEditor.WebGL.Extensions.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/PlaybackEngines/MacStandaloneSupport/UnityEditor.OSXStandalone.Extensions.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/PlaybackEngines/AndroidPlayer/UnityEditor.Android.Extensions.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/PlaybackEngines/iOSSupport/UnityEditor.iOS.Extensions.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/PlaybackEngines/WindowsStandaloneSupport/UnityEditor.WindowsStandalone.Extensions.dll + + + /Users/fantasy/Movies/物品背包开发之旅/B/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Other/System.Collections.Immutable.dll + + + /Users/fantasy/Movies/物品背包开发之旅/B/Client/Unity/Library/PackageCache/com.unity.collab-proxy@1.17.6/Lib/Editor/PlasticSCM/Unity.Plastic.Newtonsoft.Json.dll + + + /Users/fantasy/Movies/物品背包开发之旅/B/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Other/System.IO.Pipelines.dll + + + /Users/fantasy/Movies/物品背包开发之旅/B/Client/Unity/Library/PackageCache/com.unity.collab-proxy@1.17.6/Lib/Editor/PlasticSCM/Unity.Plastic.Antlr3.Runtime.dll + + + /Users/fantasy/Movies/物品背包开发之旅/B/Client/Unity/Library/PackageCache/com.unity.visualscripting@1.7.8/Editor/VisualScripting.Core/Dependencies/YamlDotNet/Unity.VisualScripting.YamlDotNet.dll + + + /Users/fantasy/Movies/物品背包开发之旅/B/Client/Unity/Library/PackageCache/com.unity.visualscripting@1.7.8/Editor/VisualScripting.Core/EditorAssetResources/Unity.VisualScripting.TextureAssets.dll + + + /Users/fantasy/Movies/物品背包开发之旅/B/Client/Unity/Library/PackageCache/com.unity.visualscripting@1.7.8/Editor/VisualScripting.Core/Dependencies/DotNetZip/Unity.VisualScripting.IonicZip.dll + + + /Users/fantasy/Movies/物品背包开发之旅/B/Client/Unity/Library/PackageCache/com.unity.collab-proxy@1.17.6/Lib/Editor/PlasticSCM/unityplastic.dll + + + /Users/fantasy/Movies/物品背包开发之旅/B/Client/Unity/Library/PackageCache/com.unity.collab-proxy@1.17.6/Lib/Editor/PlasticSCM/log4netPlastic.dll + + + /Users/fantasy/Movies/物品背包开发之旅/B/Client/Unity/Library/PackageCache/com.unity.visualscripting@1.7.8/Runtime/VisualScripting.Flow/Dependencies/NCalc/Unity.VisualScripting.Antlr3.Runtime.dll + + + /Users/fantasy/Movies/物品背包开发之旅/B/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Other/System.Runtime.CompilerServices.Unsafe.dll + + + /Users/fantasy/Movies/物品背包开发之旅/B/Client/Unity/Library/PackageCache/com.unity.testtools.codecoverage@1.0.1/lib/ReportGenerator/ReportGeneratorMerged.dll + + + /Users/fantasy/Movies/物品背包开发之旅/B/Client/Unity/Library/PackageCache/com.unity.nuget.newtonsoft-json@3.2.1/Runtime/Newtonsoft.Json.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/PlaybackEngines/iOSSupport/UnityEditor.iOS.Extensions.Xcode.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/PlaybackEngines/iOSSupport/UnityEditor.iOS.Extensions.Common.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/PlaybackEngines/AndroidPlayer/Unity.Android.Types.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/PlaybackEngines/AndroidPlayer/Unity.Android.Gradle.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/ref/2.1.0/netstandard.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/Microsoft.Win32.Primitives.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.AppContext.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Buffers.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Collections.Concurrent.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Collections.NonGeneric.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Collections.Specialized.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Collections.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.ComponentModel.EventBasedAsync.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.ComponentModel.Primitives.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.ComponentModel.TypeConverter.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.ComponentModel.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Console.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Data.Common.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Diagnostics.Contracts.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Diagnostics.Debug.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Diagnostics.FileVersionInfo.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Diagnostics.Process.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Diagnostics.StackTrace.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Diagnostics.TextWriterTraceListener.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Diagnostics.Tools.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Diagnostics.TraceSource.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Diagnostics.Tracing.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Drawing.Primitives.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Dynamic.Runtime.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Globalization.Calendars.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Globalization.Extensions.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Globalization.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.IO.Compression.ZipFile.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.IO.Compression.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.IO.FileSystem.DriveInfo.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.IO.FileSystem.Primitives.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.IO.FileSystem.Watcher.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.IO.FileSystem.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.IO.IsolatedStorage.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.IO.MemoryMappedFiles.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.IO.Pipes.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.IO.UnmanagedMemoryStream.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.IO.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Linq.Expressions.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Linq.Parallel.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Linq.Queryable.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Linq.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Memory.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Net.Http.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Net.NameResolution.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Net.NetworkInformation.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Net.Ping.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Net.Primitives.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Net.Requests.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Net.Security.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Net.Sockets.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Net.WebHeaderCollection.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Net.WebSockets.Client.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Net.WebSockets.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Numerics.Vectors.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.ObjectModel.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Reflection.DispatchProxy.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Reflection.Emit.ILGeneration.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Reflection.Emit.Lightweight.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Reflection.Emit.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Reflection.Extensions.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Reflection.Primitives.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Reflection.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Resources.Reader.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Resources.ResourceManager.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Resources.Writer.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Runtime.CompilerServices.VisualC.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Runtime.Extensions.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Runtime.Handles.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Runtime.InteropServices.RuntimeInformation.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Runtime.InteropServices.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Runtime.Numerics.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Runtime.Serialization.Formatters.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Runtime.Serialization.Json.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Runtime.Serialization.Primitives.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Runtime.Serialization.Xml.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Runtime.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Security.Claims.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Security.Cryptography.Algorithms.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Security.Cryptography.Csp.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Security.Cryptography.Encoding.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Security.Cryptography.Primitives.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Security.Cryptography.X509Certificates.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Security.Principal.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Security.SecureString.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Text.Encoding.Extensions.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Text.Encoding.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Text.RegularExpressions.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Threading.Overlapped.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Threading.Tasks.Extensions.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Threading.Tasks.Parallel.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Threading.Tasks.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Threading.Thread.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Threading.ThreadPool.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Threading.Timer.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Threading.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.ValueTuple.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Xml.ReaderWriter.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Xml.XDocument.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Xml.XPath.XDocument.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Xml.XPath.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Xml.XmlDocument.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Xml.XmlSerializer.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/Extensions/2.0.0/System.Runtime.InteropServices.WindowsRuntime.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netfx/System.ComponentModel.Composition.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netfx/System.Core.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netfx/System.Data.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netfx/System.Drawing.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netfx/System.IO.Compression.FileSystem.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netfx/System.Net.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netfx/System.Numerics.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netfx/System.Runtime.Serialization.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netfx/System.ServiceModel.Web.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netfx/System.Transactions.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netfx/System.Web.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netfx/System.Windows.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netfx/System.Xml.Linq.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netfx/System.Xml.Serialization.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netfx/System.Xml.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netfx/System.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netfx/mscorlib.dll + + + /Users/fantasy/Movies/物品背包开发之旅/B/Client/Unity/Library/ScriptAssemblies/UnityEditor.UI.dll + + + /Users/fantasy/Movies/物品背包开发之旅/B/Client/Unity/Library/ScriptAssemblies/UnityEngine.UI.dll + + + + + {d85fa58b-aca9-8bf0-e827-074457206988} + Fantasy.Unity + + + + + diff --git a/物品和背包的完整代码/Client/Unity/Fantasy.Editor.csproj b/物品和背包的完整代码/Client/Unity/Fantasy.Editor.csproj new file mode 100644 index 0000000..274456a --- /dev/null +++ b/物品和背包的完整代码/Client/Unity/Fantasy.Editor.csproj @@ -0,0 +1,779 @@ + + + + 9.0 + <_TargetFrameworkDirectories>non_empty_path_generated_by_unity.rider.package + <_FullFrameworkReferenceAssemblyPaths>non_empty_path_generated_by_unity.rider.package + true + + + Debug + AnyCPU + 10.0.20506 + 2.0 + + {f09e7d37-0f11-85f5-9f5a-ea60c1261f78} + {E097FAD1-6243-4DAD-9C02-E9B9EFC3FFC1};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + Library + Properties + Fantasy.Editor + v4.7.1 + 512 + . + + + true + full + false + Temp\Bin\Debug\Fantasy.Editor\ + UNITY_2021_3_14;UNITY_2021_3;UNITY_2021;UNITY_5_3_OR_NEWER;UNITY_5_4_OR_NEWER;UNITY_5_5_OR_NEWER;UNITY_5_6_OR_NEWER;UNITY_2017_1_OR_NEWER;UNITY_2017_2_OR_NEWER;UNITY_2017_3_OR_NEWER;UNITY_2017_4_OR_NEWER;UNITY_2018_1_OR_NEWER;UNITY_2018_2_OR_NEWER;UNITY_2018_3_OR_NEWER;UNITY_2018_4_OR_NEWER;UNITY_2019_1_OR_NEWER;UNITY_2019_2_OR_NEWER;UNITY_2019_3_OR_NEWER;UNITY_2019_4_OR_NEWER;UNITY_2020_1_OR_NEWER;UNITY_2020_2_OR_NEWER;UNITY_2020_3_OR_NEWER;UNITY_2021_1_OR_NEWER;UNITY_2021_2_OR_NEWER;UNITY_2021_3_OR_NEWER;PLATFORM_ARCH_64;UNITY_64;UNITY_INCLUDE_TESTS;USE_SEARCH_ENGINE_API;USE_SEARCH_TABLE;USE_SEARCH_MODULE;USE_PROPERTY_DATABASE;USE_SEARCH_EXTENSION_API;ENABLE_AR;ENABLE_AUDIO;ENABLE_CACHING;ENABLE_CLOTH;ENABLE_MICROPHONE;ENABLE_MULTIPLE_DISPLAYS;ENABLE_PHYSICS;ENABLE_TEXTURE_STREAMING;ENABLE_VIRTUALTEXTURING;ENABLE_UNET;ENABLE_LZMA;ENABLE_UNITYEVENTS;ENABLE_VR;ENABLE_WEBCAM;ENABLE_UNITYWEBREQUEST;ENABLE_WWW;ENABLE_CLOUD_SERVICES;ENABLE_CLOUD_SERVICES_COLLAB;ENABLE_CLOUD_SERVICES_COLLAB_SOFTLOCKS;ENABLE_CLOUD_SERVICES_ADS;ENABLE_CLOUD_SERVICES_USE_WEBREQUEST;ENABLE_CLOUD_SERVICES_CRASH_REPORTING;ENABLE_CLOUD_SERVICES_NATIVE_CRASH_REPORTING;ENABLE_CLOUD_SERVICES_PURCHASING;ENABLE_CLOUD_SERVICES_ANALYTICS;ENABLE_CLOUD_SERVICES_UNET;ENABLE_CLOUD_SERVICES_BUILD;ENABLE_CLOUD_LICENSE;ENABLE_EDITOR_HUB_LICENSE;ENABLE_WEBSOCKET_CLIENT;ENABLE_DIRECTOR_AUDIO;ENABLE_DIRECTOR_TEXTURE;ENABLE_MANAGED_JOBS;ENABLE_MANAGED_TRANSFORM_JOBS;ENABLE_MANAGED_ANIMATION_JOBS;ENABLE_MANAGED_AUDIO_JOBS;ENABLE_MANAGED_UNITYTLS;INCLUDE_DYNAMIC_GI;ENABLE_SCRIPTING_GC_WBARRIERS;PLATFORM_SUPPORTS_MONO;RENDER_SOFTWARE_CURSOR;ENABLE_VIDEO;ENABLE_ACCELERATOR_CLIENT_DEBUGGING;PLATFORM_STANDALONE;TEXTCORE_1_0_OR_NEWER;PLATFORM_STANDALONE_OSX;UNITY_STANDALONE_OSX;UNITY_STANDALONE;ENABLE_GAMECENTER;ENABLE_RUNTIME_GI;ENABLE_MOVIES;ENABLE_NETWORK;ENABLE_CRUNCH_TEXTURE_COMPRESSION;ENABLE_UNITY_GAME_SERVICES_ANALYTICS_SUPPORT;ENABLE_CLUSTER_SYNC;ENABLE_CLUSTERINPUT;ENABLE_SPATIALTRACKING;PLATFORM_UPDATES_TIME_OUTSIDE_OF_PLAYER_LOOP;ENABLE_WEBSOCKET_HOST;ENABLE_MONO;NET_4_6;NET_UNITY_4_8;ENABLE_PROFILER;DEBUG;TRACE;UNITY_ASSERTIONS;UNITY_EDITOR;UNITY_EDITOR_64;UNITY_EDITOR_OSX;ENABLE_UNITY_COLLECTIONS_CHECKS;ENABLE_BURST_AOT;UNITY_TEAM_LICENSE;ENABLE_CUSTOM_RENDER_TEXTURE;ENABLE_DIRECTOR;ENABLE_LOCALIZATION;ENABLE_SPRITES;ENABLE_TERRAIN;ENABLE_TILEMAP;ENABLE_TIMELINE;ENABLE_LEGACY_INPUT_MANAGER;CSHARP_7_OR_LATER;CSHARP_7_3_OR_NEWER + prompt + 4 + 0169,0649 + False + False + + + true + true + false + false + false + + + + + + + + + + + + + + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.AIModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.ARModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.AccessibilityModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.AndroidJNIModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.AnimationModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.AssetBundleModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.AudioModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.ClothModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.ClusterInputModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.ClusterRendererModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.CoreModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.CrashReportingModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.DSPGraphModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.DirectorModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.GIModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.GameCenterModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.GridModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.HotReloadModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.IMGUIModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.ImageConversionModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.InputModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.InputLegacyModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.JSONSerializeModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.LocalizationModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.NVIDIAModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.ParticleSystemModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.PerformanceReportingModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.PhysicsModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.Physics2DModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.ProfilerModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.RuntimeInitializeOnLoadManagerInitializerModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.ScreenCaptureModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.SharedInternalsModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.SpriteMaskModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.SpriteShapeModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.StreamingModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.SubstanceModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.SubsystemsModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.TLSModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.TerrainModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.TerrainPhysicsModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.TextCoreFontEngineModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.TextCoreTextEngineModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.TextRenderingModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.TilemapModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.UIModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.UIElementsModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.UIElementsNativeModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.UNETModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.UmbraModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.UnityAnalyticsModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.UnityAnalyticsCommonModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.UnityConnectModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.UnityCurlModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.UnityTestProtocolModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.UnityWebRequestModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.UnityWebRequestAssetBundleModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.UnityWebRequestAudioModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.UnityWebRequestTextureModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.UnityWebRequestWWWModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.VFXModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.VRModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.VehiclesModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.VideoModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.VirtualTexturingModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.WindModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.XRModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEditor.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEditor.CoreModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEditor.DeviceSimulatorModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEditor.DiagnosticsModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEditor.GraphViewModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEditor.PackageManagerUIModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEditor.QuickSearchModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEditor.SceneTemplateModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEditor.TextCoreFontEngineModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEditor.TextCoreTextEngineModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEditor.UIBuilderModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEditor.UIElementsModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEditor.UIElementsSamplesModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEditor.UIServiceModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEditor.UnityConnectModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEditor.Graphs.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/PlaybackEngines/WebGLSupport/UnityEditor.WebGL.Extensions.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/PlaybackEngines/MacStandaloneSupport/UnityEditor.OSXStandalone.Extensions.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/PlaybackEngines/AndroidPlayer/UnityEditor.Android.Extensions.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/PlaybackEngines/iOSSupport/UnityEditor.iOS.Extensions.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/PlaybackEngines/WindowsStandaloneSupport/UnityEditor.WindowsStandalone.Extensions.dll + + + /Users/fantasy/Movies/物品背包开发之旅/B/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Other/System.Collections.Immutable.dll + + + /Users/fantasy/Movies/物品背包开发之旅/B/Client/Unity/Library/PackageCache/com.unity.collab-proxy@1.17.6/Lib/Editor/PlasticSCM/Unity.Plastic.Newtonsoft.Json.dll + + + /Users/fantasy/Movies/物品背包开发之旅/B/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Other/System.IO.Pipelines.dll + + + /Users/fantasy/Movies/物品背包开发之旅/B/Client/Unity/Library/PackageCache/com.unity.collab-proxy@1.17.6/Lib/Editor/PlasticSCM/Unity.Plastic.Antlr3.Runtime.dll + + + /Users/fantasy/Movies/物品背包开发之旅/B/Client/Unity/Library/PackageCache/com.unity.visualscripting@1.7.8/Editor/VisualScripting.Core/Dependencies/YamlDotNet/Unity.VisualScripting.YamlDotNet.dll + + + /Users/fantasy/Movies/物品背包开发之旅/B/Client/Unity/Library/PackageCache/com.unity.visualscripting@1.7.8/Editor/VisualScripting.Core/EditorAssetResources/Unity.VisualScripting.TextureAssets.dll + + + /Users/fantasy/Movies/物品背包开发之旅/B/Client/Unity/Library/PackageCache/com.unity.visualscripting@1.7.8/Editor/VisualScripting.Core/Dependencies/DotNetZip/Unity.VisualScripting.IonicZip.dll + + + /Users/fantasy/Movies/物品背包开发之旅/B/Client/Unity/Library/PackageCache/com.unity.collab-proxy@1.17.6/Lib/Editor/PlasticSCM/unityplastic.dll + + + /Users/fantasy/Movies/物品背包开发之旅/B/Client/Unity/Library/PackageCache/com.unity.collab-proxy@1.17.6/Lib/Editor/PlasticSCM/log4netPlastic.dll + + + /Users/fantasy/Movies/物品背包开发之旅/B/Client/Unity/Library/PackageCache/com.unity.visualscripting@1.7.8/Runtime/VisualScripting.Flow/Dependencies/NCalc/Unity.VisualScripting.Antlr3.Runtime.dll + + + /Users/fantasy/Movies/物品背包开发之旅/B/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Other/System.Runtime.CompilerServices.Unsafe.dll + + + /Users/fantasy/Movies/物品背包开发之旅/B/Client/Unity/Library/PackageCache/com.unity.testtools.codecoverage@1.0.1/lib/ReportGenerator/ReportGeneratorMerged.dll + + + /Users/fantasy/Movies/物品背包开发之旅/B/Client/Unity/Library/PackageCache/com.unity.nuget.newtonsoft-json@3.2.1/Runtime/Newtonsoft.Json.dll + + + /Users/fantasy/Movies/物品背包开发之旅/B/Client/Unity/Library/PackageCache/com.unity.ext.nunit@1.0.6/net35/unity-custom/nunit.framework.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/PlaybackEngines/iOSSupport/UnityEditor.iOS.Extensions.Xcode.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/PlaybackEngines/iOSSupport/UnityEditor.iOS.Extensions.Common.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/PlaybackEngines/AndroidPlayer/Unity.Android.Types.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/PlaybackEngines/AndroidPlayer/Unity.Android.Gradle.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/mscorlib.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/System.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/System.Core.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/System.Runtime.Serialization.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/System.Xml.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/System.Xml.Linq.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/System.Numerics.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/System.Numerics.Vectors.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/System.Net.Http.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/System.IO.Compression.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Microsoft.CSharp.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/System.Data.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/System.Data.DataSetExtensions.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/System.Drawing.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/System.IO.Compression.FileSystem.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/System.ComponentModel.Composition.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/System.Transactions.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/Microsoft.Win32.Primitives.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.AppContext.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Buffers.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Collections.Concurrent.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Collections.NonGeneric.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Collections.Specialized.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Collections.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.ComponentModel.Annotations.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.ComponentModel.EventBasedAsync.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.ComponentModel.Primitives.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.ComponentModel.TypeConverter.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.ComponentModel.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Console.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Data.Common.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Diagnostics.Contracts.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Diagnostics.Debug.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Diagnostics.FileVersionInfo.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Diagnostics.Process.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Diagnostics.StackTrace.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Diagnostics.TextWriterTraceListener.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Diagnostics.Tools.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Diagnostics.TraceSource.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Drawing.Primitives.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Dynamic.Runtime.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Globalization.Calendars.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Globalization.Extensions.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Globalization.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.IO.Compression.ZipFile.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.IO.FileSystem.DriveInfo.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.IO.FileSystem.Primitives.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.IO.FileSystem.Watcher.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.IO.FileSystem.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.IO.IsolatedStorage.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.IO.MemoryMappedFiles.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.IO.Pipes.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.IO.UnmanagedMemoryStream.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.IO.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Linq.Expressions.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Linq.Parallel.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Linq.Queryable.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Linq.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Memory.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Net.Http.Rtc.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Net.NameResolution.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Net.NetworkInformation.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Net.Ping.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Net.Primitives.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Net.Requests.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Net.Security.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Net.Sockets.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Net.WebHeaderCollection.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Net.WebSockets.Client.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Net.WebSockets.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.ObjectModel.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Reflection.DispatchProxy.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Reflection.Emit.ILGeneration.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Reflection.Emit.Lightweight.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Reflection.Emit.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Reflection.Extensions.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Reflection.Primitives.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Reflection.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Resources.Reader.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Resources.ResourceManager.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Resources.Writer.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Runtime.CompilerServices.VisualC.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Runtime.Extensions.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Runtime.Handles.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Runtime.InteropServices.RuntimeInformation.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Runtime.InteropServices.WindowsRuntime.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Runtime.InteropServices.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Runtime.Numerics.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Runtime.Serialization.Formatters.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Runtime.Serialization.Json.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Runtime.Serialization.Primitives.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Runtime.Serialization.Xml.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Runtime.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Security.Claims.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Security.Cryptography.Algorithms.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Security.Cryptography.Csp.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Security.Cryptography.Encoding.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Security.Cryptography.Primitives.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Security.Cryptography.X509Certificates.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Security.Principal.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Security.SecureString.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.ServiceModel.Duplex.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.ServiceModel.Http.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.ServiceModel.NetTcp.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.ServiceModel.Primitives.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.ServiceModel.Security.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Text.Encoding.Extensions.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Text.Encoding.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Text.RegularExpressions.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Threading.Overlapped.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Threading.Tasks.Extensions.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Threading.Tasks.Parallel.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Threading.Tasks.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Threading.Thread.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Threading.ThreadPool.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Threading.Timer.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Threading.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.ValueTuple.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Xml.ReaderWriter.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Xml.XDocument.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Xml.XPath.XDocument.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Xml.XPath.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Xml.XmlDocument.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/System.Xml.XmlSerializer.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/UnityReferenceAssemblies/unity-4.8-api/Facades/netstandard.dll + + + /Users/fantasy/Movies/物品背包开发之旅/B/Client/Unity/Library/ScriptAssemblies/UnityEditor.UI.dll + + + /Users/fantasy/Movies/物品背包开发之旅/B/Client/Unity/Library/ScriptAssemblies/UnityEngine.UI.dll + + + /Users/fantasy/Movies/物品背包开发之旅/B/Client/Unity/Library/ScriptAssemblies/UnityEngine.TestRunner.dll + + + /Users/fantasy/Movies/物品背包开发之旅/B/Client/Unity/Library/ScriptAssemblies/UnityEditor.TestRunner.dll + + + + + {d85fa58b-aca9-8bf0-e827-074457206988} + Fantasy.Unity + + + + + diff --git a/物品和背包的完整代码/Client/Unity/Fantasy.Unity.csproj b/物品和背包的完整代码/Client/Unity/Fantasy.Unity.csproj new file mode 100644 index 0000000..177e08f --- /dev/null +++ b/物品和背包的完整代码/Client/Unity/Fantasy.Unity.csproj @@ -0,0 +1,1215 @@ + + + + 9.0 + <_TargetFrameworkDirectories>non_empty_path_generated_by_unity.rider.package + <_FullFrameworkReferenceAssemblyPaths>non_empty_path_generated_by_unity.rider.package + true + + + Debug + AnyCPU + 10.0.20506 + 2.0 + + {d85fa58b-aca9-8bf0-e827-074457206988} + {E097FAD1-6243-4DAD-9C02-E9B9EFC3FFC1};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + Library + Properties + Fantasy.Unity + v4.7.1 + 512 + . + + + true + full + false + Temp\Bin\Debug\Fantasy.Unity\ + UNITY_2021_3_14;UNITY_2021_3;UNITY_2021;UNITY_5_3_OR_NEWER;UNITY_5_4_OR_NEWER;UNITY_5_5_OR_NEWER;UNITY_5_6_OR_NEWER;UNITY_2017_1_OR_NEWER;UNITY_2017_2_OR_NEWER;UNITY_2017_3_OR_NEWER;UNITY_2017_4_OR_NEWER;UNITY_2018_1_OR_NEWER;UNITY_2018_2_OR_NEWER;UNITY_2018_3_OR_NEWER;UNITY_2018_4_OR_NEWER;UNITY_2019_1_OR_NEWER;UNITY_2019_2_OR_NEWER;UNITY_2019_3_OR_NEWER;UNITY_2019_4_OR_NEWER;UNITY_2020_1_OR_NEWER;UNITY_2020_2_OR_NEWER;UNITY_2020_3_OR_NEWER;UNITY_2021_1_OR_NEWER;UNITY_2021_2_OR_NEWER;UNITY_2021_3_OR_NEWER;PLATFORM_ARCH_64;UNITY_64;UNITY_INCLUDE_TESTS;USE_SEARCH_ENGINE_API;USE_SEARCH_TABLE;USE_SEARCH_MODULE;USE_PROPERTY_DATABASE;USE_SEARCH_EXTENSION_API;ENABLE_AR;ENABLE_AUDIO;ENABLE_CACHING;ENABLE_CLOTH;ENABLE_MICROPHONE;ENABLE_MULTIPLE_DISPLAYS;ENABLE_PHYSICS;ENABLE_TEXTURE_STREAMING;ENABLE_VIRTUALTEXTURING;ENABLE_UNET;ENABLE_LZMA;ENABLE_UNITYEVENTS;ENABLE_VR;ENABLE_WEBCAM;ENABLE_UNITYWEBREQUEST;ENABLE_WWW;ENABLE_CLOUD_SERVICES;ENABLE_CLOUD_SERVICES_COLLAB;ENABLE_CLOUD_SERVICES_COLLAB_SOFTLOCKS;ENABLE_CLOUD_SERVICES_ADS;ENABLE_CLOUD_SERVICES_USE_WEBREQUEST;ENABLE_CLOUD_SERVICES_CRASH_REPORTING;ENABLE_CLOUD_SERVICES_NATIVE_CRASH_REPORTING;ENABLE_CLOUD_SERVICES_PURCHASING;ENABLE_CLOUD_SERVICES_ANALYTICS;ENABLE_CLOUD_SERVICES_UNET;ENABLE_CLOUD_SERVICES_BUILD;ENABLE_CLOUD_LICENSE;ENABLE_EDITOR_HUB_LICENSE;ENABLE_WEBSOCKET_CLIENT;ENABLE_DIRECTOR_AUDIO;ENABLE_DIRECTOR_TEXTURE;ENABLE_MANAGED_JOBS;ENABLE_MANAGED_TRANSFORM_JOBS;ENABLE_MANAGED_ANIMATION_JOBS;ENABLE_MANAGED_AUDIO_JOBS;ENABLE_MANAGED_UNITYTLS;INCLUDE_DYNAMIC_GI;ENABLE_SCRIPTING_GC_WBARRIERS;PLATFORM_SUPPORTS_MONO;RENDER_SOFTWARE_CURSOR;ENABLE_VIDEO;ENABLE_ACCELERATOR_CLIENT_DEBUGGING;PLATFORM_STANDALONE;TEXTCORE_1_0_OR_NEWER;PLATFORM_STANDALONE_OSX;UNITY_STANDALONE_OSX;UNITY_STANDALONE;ENABLE_GAMECENTER;ENABLE_RUNTIME_GI;ENABLE_MOVIES;ENABLE_NETWORK;ENABLE_CRUNCH_TEXTURE_COMPRESSION;ENABLE_UNITY_GAME_SERVICES_ANALYTICS_SUPPORT;ENABLE_CLUSTER_SYNC;ENABLE_CLUSTERINPUT;ENABLE_SPATIALTRACKING;PLATFORM_UPDATES_TIME_OUTSIDE_OF_PLAYER_LOOP;ENABLE_WEBSOCKET_HOST;ENABLE_MONO;NET_STANDARD_2_0;NET_STANDARD;NET_STANDARD_2_1;NETSTANDARD;NETSTANDARD2_1;ENABLE_PROFILER;DEBUG;TRACE;UNITY_ASSERTIONS;UNITY_EDITOR;UNITY_EDITOR_64;UNITY_EDITOR_OSX;ENABLE_UNITY_COLLECTIONS_CHECKS;ENABLE_BURST_AOT;UNITY_TEAM_LICENSE;ENABLE_CUSTOM_RENDER_TEXTURE;ENABLE_DIRECTOR;ENABLE_LOCALIZATION;ENABLE_SPRITES;ENABLE_TERRAIN;ENABLE_TILEMAP;ENABLE_TIMELINE;ENABLE_LEGACY_INPUT_MANAGER;CSHARP_7_OR_LATER;CSHARP_7_3_OR_NEWER;FANTASY_UNITY + prompt + 4 + 0169,0649 + True + False + + + true + true + false + false + false + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.AIModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.ARModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.AccessibilityModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.AndroidJNIModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.AnimationModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.AssetBundleModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.AudioModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.ClothModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.ClusterInputModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.ClusterRendererModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.CoreModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.CrashReportingModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.DSPGraphModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.DirectorModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.GIModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.GameCenterModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.GridModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.HotReloadModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.IMGUIModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.ImageConversionModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.InputModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.InputLegacyModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.JSONSerializeModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.LocalizationModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.ParticleSystemModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.PerformanceReportingModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.PhysicsModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.Physics2DModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.ProfilerModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.RuntimeInitializeOnLoadManagerInitializerModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.ScreenCaptureModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.SharedInternalsModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.SpriteMaskModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.SpriteShapeModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.StreamingModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.SubstanceModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.SubsystemsModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.TLSModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.TerrainModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.TerrainPhysicsModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.TextCoreFontEngineModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.TextCoreTextEngineModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.TextRenderingModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.TilemapModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.UIModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.UIElementsModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.UIElementsNativeModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.UNETModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.UmbraModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.UnityAnalyticsModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.UnityAnalyticsCommonModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.UnityConnectModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.UnityCurlModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.UnityTestProtocolModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.UnityWebRequestModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.UnityWebRequestAssetBundleModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.UnityWebRequestAudioModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.UnityWebRequestTextureModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.UnityWebRequestWWWModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.VFXModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.VRModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.VehiclesModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.VideoModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.VirtualTexturingModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.WindModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.XRModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEditor.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEditor.CoreModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEditor.DeviceSimulatorModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEditor.DiagnosticsModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEditor.GraphViewModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEditor.PackageManagerUIModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEditor.QuickSearchModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEditor.SceneTemplateModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEditor.TextCoreFontEngineModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEditor.TextCoreTextEngineModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEditor.UIBuilderModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEditor.UIElementsModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEditor.UIElementsSamplesModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEditor.UIServiceModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEditor.UnityConnectModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEditor.Graphs.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/PlaybackEngines/WebGLSupport/UnityEditor.WebGL.Extensions.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/PlaybackEngines/MacStandaloneSupport/UnityEditor.OSXStandalone.Extensions.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/PlaybackEngines/AndroidPlayer/UnityEditor.Android.Extensions.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/PlaybackEngines/iOSSupport/UnityEditor.iOS.Extensions.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/PlaybackEngines/WindowsStandaloneSupport/UnityEditor.WindowsStandalone.Extensions.dll + + + /Users/fantasy/Movies/物品背包开发之旅/B/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Other/System.Collections.Immutable.dll + + + /Users/fantasy/Movies/物品背包开发之旅/B/Client/Unity/Library/PackageCache/com.unity.collab-proxy@1.17.6/Lib/Editor/PlasticSCM/Unity.Plastic.Newtonsoft.Json.dll + + + /Users/fantasy/Movies/物品背包开发之旅/B/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Other/System.IO.Pipelines.dll + + + /Users/fantasy/Movies/物品背包开发之旅/B/Client/Unity/Library/PackageCache/com.unity.collab-proxy@1.17.6/Lib/Editor/PlasticSCM/Unity.Plastic.Antlr3.Runtime.dll + + + /Users/fantasy/Movies/物品背包开发之旅/B/Client/Unity/Library/PackageCache/com.unity.visualscripting@1.7.8/Editor/VisualScripting.Core/Dependencies/YamlDotNet/Unity.VisualScripting.YamlDotNet.dll + + + /Users/fantasy/Movies/物品背包开发之旅/B/Client/Unity/Library/PackageCache/com.unity.visualscripting@1.7.8/Editor/VisualScripting.Core/EditorAssetResources/Unity.VisualScripting.TextureAssets.dll + + + /Users/fantasy/Movies/物品背包开发之旅/B/Client/Unity/Library/PackageCache/com.unity.visualscripting@1.7.8/Editor/VisualScripting.Core/Dependencies/DotNetZip/Unity.VisualScripting.IonicZip.dll + + + /Users/fantasy/Movies/物品背包开发之旅/B/Client/Unity/Library/PackageCache/com.unity.collab-proxy@1.17.6/Lib/Editor/PlasticSCM/unityplastic.dll + + + /Users/fantasy/Movies/物品背包开发之旅/B/Client/Unity/Library/PackageCache/com.unity.collab-proxy@1.17.6/Lib/Editor/PlasticSCM/log4netPlastic.dll + + + /Users/fantasy/Movies/物品背包开发之旅/B/Client/Unity/Library/PackageCache/com.unity.visualscripting@1.7.8/Runtime/VisualScripting.Flow/Dependencies/NCalc/Unity.VisualScripting.Antlr3.Runtime.dll + + + /Users/fantasy/Movies/物品背包开发之旅/B/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Other/System.Runtime.CompilerServices.Unsafe.dll + + + /Users/fantasy/Movies/物品背包开发之旅/B/Client/Unity/Library/PackageCache/com.unity.testtools.codecoverage@1.0.1/lib/ReportGenerator/ReportGeneratorMerged.dll + + + /Users/fantasy/Movies/物品背包开发之旅/B/Client/Unity/Library/PackageCache/com.unity.nuget.newtonsoft-json@3.2.1/Runtime/Newtonsoft.Json.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/PlaybackEngines/iOSSupport/UnityEditor.iOS.Extensions.Xcode.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/PlaybackEngines/iOSSupport/UnityEditor.iOS.Extensions.Common.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/PlaybackEngines/AndroidPlayer/Unity.Android.Types.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/PlaybackEngines/AndroidPlayer/Unity.Android.Gradle.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/ref/2.1.0/netstandard.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/Microsoft.Win32.Primitives.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.AppContext.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Buffers.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Collections.Concurrent.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Collections.NonGeneric.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Collections.Specialized.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Collections.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.ComponentModel.EventBasedAsync.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.ComponentModel.Primitives.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.ComponentModel.TypeConverter.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.ComponentModel.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Console.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Data.Common.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Diagnostics.Contracts.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Diagnostics.Debug.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Diagnostics.FileVersionInfo.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Diagnostics.Process.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Diagnostics.StackTrace.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Diagnostics.TextWriterTraceListener.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Diagnostics.Tools.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Diagnostics.TraceSource.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Diagnostics.Tracing.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Drawing.Primitives.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Dynamic.Runtime.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Globalization.Calendars.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Globalization.Extensions.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Globalization.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.IO.Compression.ZipFile.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.IO.Compression.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.IO.FileSystem.DriveInfo.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.IO.FileSystem.Primitives.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.IO.FileSystem.Watcher.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.IO.FileSystem.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.IO.IsolatedStorage.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.IO.MemoryMappedFiles.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.IO.Pipes.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.IO.UnmanagedMemoryStream.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.IO.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Linq.Expressions.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Linq.Parallel.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Linq.Queryable.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Linq.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Memory.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Net.Http.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Net.NameResolution.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Net.NetworkInformation.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Net.Ping.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Net.Primitives.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Net.Requests.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Net.Security.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Net.Sockets.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Net.WebHeaderCollection.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Net.WebSockets.Client.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Net.WebSockets.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Numerics.Vectors.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.ObjectModel.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Reflection.DispatchProxy.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Reflection.Emit.ILGeneration.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Reflection.Emit.Lightweight.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Reflection.Emit.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Reflection.Extensions.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Reflection.Primitives.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Reflection.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Resources.Reader.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Resources.ResourceManager.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Resources.Writer.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Runtime.CompilerServices.VisualC.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Runtime.Extensions.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Runtime.Handles.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Runtime.InteropServices.RuntimeInformation.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Runtime.InteropServices.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Runtime.Numerics.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Runtime.Serialization.Formatters.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Runtime.Serialization.Json.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Runtime.Serialization.Primitives.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Runtime.Serialization.Xml.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Runtime.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Security.Claims.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Security.Cryptography.Algorithms.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Security.Cryptography.Csp.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Security.Cryptography.Encoding.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Security.Cryptography.Primitives.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Security.Cryptography.X509Certificates.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Security.Principal.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Security.SecureString.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Text.Encoding.Extensions.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Text.Encoding.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Text.RegularExpressions.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Threading.Overlapped.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Threading.Tasks.Extensions.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Threading.Tasks.Parallel.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Threading.Tasks.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Threading.Thread.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Threading.ThreadPool.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Threading.Timer.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Threading.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.ValueTuple.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Xml.ReaderWriter.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Xml.XDocument.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Xml.XPath.XDocument.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Xml.XPath.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Xml.XmlDocument.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Xml.XmlSerializer.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/Extensions/2.0.0/System.Runtime.InteropServices.WindowsRuntime.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netfx/System.ComponentModel.Composition.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netfx/System.Core.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netfx/System.Data.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netfx/System.Drawing.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netfx/System.IO.Compression.FileSystem.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netfx/System.Net.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netfx/System.Numerics.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netfx/System.Runtime.Serialization.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netfx/System.ServiceModel.Web.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netfx/System.Transactions.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netfx/System.Web.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netfx/System.Windows.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netfx/System.Xml.Linq.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netfx/System.Xml.Serialization.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netfx/System.Xml.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netfx/System.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netfx/mscorlib.dll + + + /Users/fantasy/Movies/物品背包开发之旅/B/Client/Unity/Library/ScriptAssemblies/UnityEditor.UI.dll + + + /Users/fantasy/Movies/物品背包开发之旅/B/Client/Unity/Library/ScriptAssemblies/UnityEngine.UI.dll + + + + + + + diff --git a/物品和背包的完整代码/Client/Unity/Packages/manifest.json b/物品和背包的完整代码/Client/Unity/Packages/manifest.json new file mode 100644 index 0000000..c13f8ac --- /dev/null +++ b/物品和背包的完整代码/Client/Unity/Packages/manifest.json @@ -0,0 +1,47 @@ +{ + "dependencies": { + "com.fantasy.configtable": "file:../../../Packages/Fantasy/Fantasy.Packages/Fantasy.ConfigTable/Unity", + "com.fantasy.unity": "file:../../../Packages/Fantasy/Fantasy.Unity/Fantasy.Unity", + "com.unity.collab-proxy": "1.17.6", + "com.unity.feature.development": "1.0.1", + "com.unity.ide.rider": "3.0.16", + "com.unity.ide.visualstudio": "2.0.16", + "com.unity.ide.vscode": "1.2.5", + "com.unity.test-framework": "1.1.31", + "com.unity.textmeshpro": "3.0.6", + "com.unity.timeline": "1.6.4", + "com.unity.ugui": "1.0.0", + "com.unity.visualscripting": "1.7.8", + "com.unity.modules.ai": "1.0.0", + "com.unity.modules.androidjni": "1.0.0", + "com.unity.modules.animation": "1.0.0", + "com.unity.modules.assetbundle": "1.0.0", + "com.unity.modules.audio": "1.0.0", + "com.unity.modules.cloth": "1.0.0", + "com.unity.modules.director": "1.0.0", + "com.unity.modules.imageconversion": "1.0.0", + "com.unity.modules.imgui": "1.0.0", + "com.unity.modules.jsonserialize": "1.0.0", + "com.unity.modules.particlesystem": "1.0.0", + "com.unity.modules.physics": "1.0.0", + "com.unity.modules.physics2d": "1.0.0", + "com.unity.modules.screencapture": "1.0.0", + "com.unity.modules.terrain": "1.0.0", + "com.unity.modules.terrainphysics": "1.0.0", + "com.unity.modules.tilemap": "1.0.0", + "com.unity.modules.ui": "1.0.0", + "com.unity.modules.uielements": "1.0.0", + "com.unity.modules.umbra": "1.0.0", + "com.unity.modules.unityanalytics": "1.0.0", + "com.unity.modules.unitywebrequest": "1.0.0", + "com.unity.modules.unitywebrequestassetbundle": "1.0.0", + "com.unity.modules.unitywebrequestaudio": "1.0.0", + "com.unity.modules.unitywebrequesttexture": "1.0.0", + "com.unity.modules.unitywebrequestwww": "1.0.0", + "com.unity.modules.vehicles": "1.0.0", + "com.unity.modules.video": "1.0.0", + "com.unity.modules.vr": "1.0.0", + "com.unity.modules.wind": "1.0.0", + "com.unity.modules.xr": "1.0.0" + } +} diff --git a/物品和背包的完整代码/Client/Unity/Packages/packages-lock.json b/物品和背包的完整代码/Client/Unity/Packages/packages-lock.json new file mode 100644 index 0000000..0d2d15b --- /dev/null +++ b/物品和背包的完整代码/Client/Unity/Packages/packages-lock.json @@ -0,0 +1,427 @@ +{ + "dependencies": { + "com.fantasy.configtable": { + "version": "file:../../../Packages/Fantasy/Fantasy.Packages/Fantasy.ConfigTable/Unity", + "depth": 0, + "source": "local", + "dependencies": {} + }, + "com.fantasy.unity": { + "version": "file:../../../Packages/Fantasy/Fantasy.Unity/Fantasy.Unity", + "depth": 0, + "source": "local", + "dependencies": { + "com.unity.nuget.newtonsoft-json": "3.2.1" + } + }, + "com.unity.collab-proxy": { + "version": "1.17.6", + "depth": 0, + "source": "registry", + "dependencies": { + "com.unity.services.core": "1.0.1" + }, + "url": "https://packages.unity.com" + }, + "com.unity.editorcoroutines": { + "version": "1.0.0", + "depth": 1, + "source": "registry", + "dependencies": {}, + "url": "https://packages.unity.com" + }, + "com.unity.ext.nunit": { + "version": "1.0.6", + "depth": 1, + "source": "registry", + "dependencies": {}, + "url": "https://packages.unity.com" + }, + "com.unity.feature.development": { + "version": "1.0.1", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.ide.visualstudio": "2.0.16", + "com.unity.ide.rider": "3.0.16", + "com.unity.ide.vscode": "1.2.5", + "com.unity.editorcoroutines": "1.0.0", + "com.unity.performance.profile-analyzer": "1.1.1", + "com.unity.test-framework": "1.1.31", + "com.unity.testtools.codecoverage": "1.0.1" + } + }, + "com.unity.ide.rider": { + "version": "3.0.16", + "depth": 0, + "source": "registry", + "dependencies": { + "com.unity.ext.nunit": "1.0.6" + }, + "url": "https://packages.unity.com" + }, + "com.unity.ide.visualstudio": { + "version": "2.0.16", + "depth": 0, + "source": "registry", + "dependencies": { + "com.unity.test-framework": "1.1.9" + }, + "url": "https://packages.unity.com" + }, + "com.unity.ide.vscode": { + "version": "1.2.5", + "depth": 0, + "source": "registry", + "dependencies": {}, + "url": "https://packages.unity.com" + }, + "com.unity.nuget.newtonsoft-json": { + "version": "3.2.1", + "depth": 1, + "source": "registry", + "dependencies": {}, + "url": "https://packages.unity.com" + }, + "com.unity.performance.profile-analyzer": { + "version": "1.1.1", + "depth": 1, + "source": "registry", + "dependencies": {}, + "url": "https://packages.unity.com" + }, + "com.unity.services.core": { + "version": "1.6.0", + "depth": 1, + "source": "registry", + "dependencies": { + "com.unity.modules.androidjni": "1.0.0", + "com.unity.nuget.newtonsoft-json": "3.0.2", + "com.unity.modules.unitywebrequest": "1.0.0" + }, + "url": "https://packages.unity.com" + }, + "com.unity.settings-manager": { + "version": "1.0.3", + "depth": 2, + "source": "registry", + "dependencies": {}, + "url": "https://packages.unity.com" + }, + "com.unity.test-framework": { + "version": "1.1.31", + "depth": 0, + "source": "registry", + "dependencies": { + "com.unity.ext.nunit": "1.0.6", + "com.unity.modules.imgui": "1.0.0", + "com.unity.modules.jsonserialize": "1.0.0" + }, + "url": "https://packages.unity.com" + }, + "com.unity.testtools.codecoverage": { + "version": "1.0.1", + "depth": 1, + "source": "registry", + "dependencies": { + "com.unity.test-framework": "1.0.16", + "com.unity.settings-manager": "1.0.1" + }, + "url": "https://packages.unity.com" + }, + "com.unity.textmeshpro": { + "version": "3.0.6", + "depth": 0, + "source": "registry", + "dependencies": { + "com.unity.ugui": "1.0.0" + }, + "url": "https://packages.unity.com" + }, + "com.unity.timeline": { + "version": "1.6.4", + "depth": 0, + "source": "registry", + "dependencies": { + "com.unity.modules.audio": "1.0.0", + "com.unity.modules.director": "1.0.0", + "com.unity.modules.animation": "1.0.0", + "com.unity.modules.particlesystem": "1.0.0" + }, + "url": "https://packages.unity.com" + }, + "com.unity.ugui": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.ui": "1.0.0", + "com.unity.modules.imgui": "1.0.0" + } + }, + "com.unity.visualscripting": { + "version": "1.7.8", + "depth": 0, + "source": "registry", + "dependencies": { + "com.unity.ugui": "1.0.0", + "com.unity.modules.jsonserialize": "1.0.0" + }, + "url": "https://packages.unity.com" + }, + "com.unity.modules.ai": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.androidjni": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.animation": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.assetbundle": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.audio": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.cloth": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.physics": "1.0.0" + } + }, + "com.unity.modules.director": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.audio": "1.0.0", + "com.unity.modules.animation": "1.0.0" + } + }, + "com.unity.modules.imageconversion": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.imgui": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.jsonserialize": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.particlesystem": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.physics": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.physics2d": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.screencapture": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.imageconversion": "1.0.0" + } + }, + "com.unity.modules.subsystems": { + "version": "1.0.0", + "depth": 1, + "source": "builtin", + "dependencies": { + "com.unity.modules.jsonserialize": "1.0.0" + } + }, + "com.unity.modules.terrain": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.terrainphysics": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.physics": "1.0.0", + "com.unity.modules.terrain": "1.0.0" + } + }, + "com.unity.modules.tilemap": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.physics2d": "1.0.0" + } + }, + "com.unity.modules.ui": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.uielements": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.ui": "1.0.0", + "com.unity.modules.imgui": "1.0.0", + "com.unity.modules.jsonserialize": "1.0.0", + "com.unity.modules.uielementsnative": "1.0.0" + } + }, + "com.unity.modules.uielementsnative": { + "version": "1.0.0", + "depth": 1, + "source": "builtin", + "dependencies": { + "com.unity.modules.ui": "1.0.0", + "com.unity.modules.imgui": "1.0.0", + "com.unity.modules.jsonserialize": "1.0.0" + } + }, + "com.unity.modules.umbra": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.unityanalytics": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.unitywebrequest": "1.0.0", + "com.unity.modules.jsonserialize": "1.0.0" + } + }, + "com.unity.modules.unitywebrequest": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.unitywebrequestassetbundle": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.assetbundle": "1.0.0", + "com.unity.modules.unitywebrequest": "1.0.0" + } + }, + "com.unity.modules.unitywebrequestaudio": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.unitywebrequest": "1.0.0", + "com.unity.modules.audio": "1.0.0" + } + }, + "com.unity.modules.unitywebrequesttexture": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.unitywebrequest": "1.0.0", + "com.unity.modules.imageconversion": "1.0.0" + } + }, + "com.unity.modules.unitywebrequestwww": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.unitywebrequest": "1.0.0", + "com.unity.modules.unitywebrequestassetbundle": "1.0.0", + "com.unity.modules.unitywebrequestaudio": "1.0.0", + "com.unity.modules.audio": "1.0.0", + "com.unity.modules.assetbundle": "1.0.0", + "com.unity.modules.imageconversion": "1.0.0" + } + }, + "com.unity.modules.vehicles": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.physics": "1.0.0" + } + }, + "com.unity.modules.video": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.audio": "1.0.0", + "com.unity.modules.ui": "1.0.0", + "com.unity.modules.unitywebrequest": "1.0.0" + } + }, + "com.unity.modules.vr": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.jsonserialize": "1.0.0", + "com.unity.modules.physics": "1.0.0", + "com.unity.modules.xr": "1.0.0" + } + }, + "com.unity.modules.wind": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.xr": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.physics": "1.0.0", + "com.unity.modules.jsonserialize": "1.0.0", + "com.unity.modules.subsystems": "1.0.0" + } + } + } +} diff --git a/物品和背包的完整代码/Client/Unity/ProjectSettings/AudioManager.asset b/物品和背包的完整代码/Client/Unity/ProjectSettings/AudioManager.asset new file mode 100644 index 0000000..07ebfb0 --- /dev/null +++ b/物品和背包的完整代码/Client/Unity/ProjectSettings/AudioManager.asset @@ -0,0 +1,19 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!11 &1 +AudioManager: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Volume: 1 + Rolloff Scale: 1 + Doppler Factor: 1 + Default Speaker Mode: 2 + m_SampleRate: 0 + m_DSPBufferSize: 1024 + m_VirtualVoiceCount: 512 + m_RealVoiceCount: 32 + m_SpatializerPlugin: + m_AmbisonicDecoderPlugin: + m_DisableAudio: 0 + m_VirtualizeEffects: 1 + m_RequestedDSPBufferSize: 1024 diff --git a/物品和背包的完整代码/Client/Unity/ProjectSettings/ClusterInputManager.asset b/物品和背包的完整代码/Client/Unity/ProjectSettings/ClusterInputManager.asset new file mode 100644 index 0000000..e7886b2 --- /dev/null +++ b/物品和背包的完整代码/Client/Unity/ProjectSettings/ClusterInputManager.asset @@ -0,0 +1,6 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!236 &1 +ClusterInputManager: + m_ObjectHideFlags: 0 + m_Inputs: [] diff --git a/物品和背包的完整代码/Client/Unity/ProjectSettings/DynamicsManager.asset b/物品和背包的完整代码/Client/Unity/ProjectSettings/DynamicsManager.asset new file mode 100644 index 0000000..cdc1f3e --- /dev/null +++ b/物品和背包的完整代码/Client/Unity/ProjectSettings/DynamicsManager.asset @@ -0,0 +1,34 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!55 &1 +PhysicsManager: + m_ObjectHideFlags: 0 + serializedVersion: 11 + m_Gravity: {x: 0, y: -9.81, z: 0} + m_DefaultMaterial: {fileID: 0} + m_BounceThreshold: 2 + m_SleepThreshold: 0.005 + m_DefaultContactOffset: 0.01 + m_DefaultSolverIterations: 6 + m_DefaultSolverVelocityIterations: 1 + m_QueriesHitBackfaces: 0 + m_QueriesHitTriggers: 1 + m_EnableAdaptiveForce: 0 + m_ClothInterCollisionDistance: 0 + m_ClothInterCollisionStiffness: 0 + m_ContactsGeneration: 1 + m_LayerCollisionMatrix: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff + m_AutoSimulation: 1 + m_AutoSyncTransforms: 0 + m_ReuseCollisionCallbacks: 1 + m_ClothInterCollisionSettingsToggle: 0 + m_ContactPairsMode: 0 + m_BroadphaseType: 0 + m_WorldBounds: + m_Center: {x: 0, y: 0, z: 0} + m_Extent: {x: 250, y: 250, z: 250} + m_WorldSubdivisions: 8 + m_FrictionType: 0 + m_EnableEnhancedDeterminism: 0 + m_EnableUnifiedHeightmaps: 1 + m_DefaultMaxAngluarSpeed: 7 diff --git a/物品和背包的完整代码/Client/Unity/ProjectSettings/EditorBuildSettings.asset b/物品和背包的完整代码/Client/Unity/ProjectSettings/EditorBuildSettings.asset new file mode 100644 index 0000000..0147887 --- /dev/null +++ b/物品和背包的完整代码/Client/Unity/ProjectSettings/EditorBuildSettings.asset @@ -0,0 +1,8 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1045 &1 +EditorBuildSettings: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Scenes: [] + m_configObjects: {} diff --git a/物品和背包的完整代码/Client/Unity/ProjectSettings/EditorSettings.asset b/物品和背包的完整代码/Client/Unity/ProjectSettings/EditorSettings.asset new file mode 100644 index 0000000..1e44a0a --- /dev/null +++ b/物品和背包的完整代码/Client/Unity/ProjectSettings/EditorSettings.asset @@ -0,0 +1,30 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!159 &1 +EditorSettings: + m_ObjectHideFlags: 0 + serializedVersion: 11 + m_ExternalVersionControlSupport: Visible Meta Files + m_SerializationMode: 2 + m_LineEndingsForNewScripts: 0 + m_DefaultBehaviorMode: 0 + m_PrefabRegularEnvironment: {fileID: 0} + m_PrefabUIEnvironment: {fileID: 0} + m_SpritePackerMode: 0 + m_SpritePackerPaddingPower: 1 + m_EtcTextureCompressorBehavior: 1 + m_EtcTextureFastCompressor: 1 + m_EtcTextureNormalCompressor: 2 + m_EtcTextureBestCompressor: 4 + m_ProjectGenerationIncludedExtensions: txt;xml;fnt;cd;asmdef;rsp;asmref + m_ProjectGenerationRootNamespace: + m_CollabEditorSettings: + inProgressEnabled: 1 + m_EnableTextureStreamingInEditMode: 1 + m_EnableTextureStreamingInPlayMode: 1 + m_AsyncShaderCompilation: 1 + m_EnterPlayModeOptionsEnabled: 0 + m_EnterPlayModeOptions: 3 + m_ShowLightmapResolutionOverlay: 1 + m_UseLegacyProbeSampleCount: 0 + m_SerializeInlineMappingsOnOneLine: 1 diff --git a/物品和背包的完整代码/Client/Unity/ProjectSettings/GraphicsSettings.asset b/物品和背包的完整代码/Client/Unity/ProjectSettings/GraphicsSettings.asset new file mode 100644 index 0000000..43369e3 --- /dev/null +++ b/物品和背包的完整代码/Client/Unity/ProjectSettings/GraphicsSettings.asset @@ -0,0 +1,63 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!30 &1 +GraphicsSettings: + m_ObjectHideFlags: 0 + serializedVersion: 13 + m_Deferred: + m_Mode: 1 + m_Shader: {fileID: 69, guid: 0000000000000000f000000000000000, type: 0} + m_DeferredReflections: + m_Mode: 1 + m_Shader: {fileID: 74, guid: 0000000000000000f000000000000000, type: 0} + m_ScreenSpaceShadows: + m_Mode: 1 + m_Shader: {fileID: 64, guid: 0000000000000000f000000000000000, type: 0} + m_LegacyDeferred: + m_Mode: 1 + m_Shader: {fileID: 63, guid: 0000000000000000f000000000000000, type: 0} + m_DepthNormals: + m_Mode: 1 + m_Shader: {fileID: 62, guid: 0000000000000000f000000000000000, type: 0} + m_MotionVectors: + m_Mode: 1 + m_Shader: {fileID: 75, guid: 0000000000000000f000000000000000, type: 0} + m_LightHalo: + m_Mode: 1 + m_Shader: {fileID: 105, guid: 0000000000000000f000000000000000, type: 0} + m_LensFlare: + m_Mode: 1 + m_Shader: {fileID: 102, guid: 0000000000000000f000000000000000, type: 0} + m_AlwaysIncludedShaders: + - {fileID: 7, guid: 0000000000000000f000000000000000, type: 0} + - {fileID: 15104, guid: 0000000000000000f000000000000000, type: 0} + - {fileID: 15105, guid: 0000000000000000f000000000000000, type: 0} + - {fileID: 15106, guid: 0000000000000000f000000000000000, type: 0} + - {fileID: 10753, guid: 0000000000000000f000000000000000, type: 0} + - {fileID: 10770, guid: 0000000000000000f000000000000000, type: 0} + m_PreloadedShaders: [] + m_SpritesDefaultMaterial: {fileID: 10754, guid: 0000000000000000f000000000000000, + type: 0} + m_CustomRenderPipeline: {fileID: 0} + m_TransparencySortMode: 0 + m_TransparencySortAxis: {x: 0, y: 0, z: 1} + m_DefaultRenderingPath: 1 + m_DefaultMobileRenderingPath: 1 + m_TierSettings: [] + m_LightmapStripping: 0 + m_FogStripping: 0 + m_InstancingStripping: 0 + m_LightmapKeepPlain: 1 + m_LightmapKeepDirCombined: 1 + m_LightmapKeepDynamicPlain: 1 + m_LightmapKeepDynamicDirCombined: 1 + m_LightmapKeepShadowMask: 1 + m_LightmapKeepSubtractive: 1 + m_FogKeepLinear: 1 + m_FogKeepExp: 1 + m_FogKeepExp2: 1 + m_AlbedoSwatchInfos: [] + m_LightsUseLinearIntensity: 0 + m_LightsUseColorTemperature: 0 + m_LogWhenShaderIsCompiled: 0 + m_AllowEnlightenSupportForUpgradedProject: 0 diff --git a/物品和背包的完整代码/Client/Unity/ProjectSettings/InputManager.asset b/物品和背包的完整代码/Client/Unity/ProjectSettings/InputManager.asset new file mode 100644 index 0000000..17c8f53 --- /dev/null +++ b/物品和背包的完整代码/Client/Unity/ProjectSettings/InputManager.asset @@ -0,0 +1,295 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!13 &1 +InputManager: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Axes: + - serializedVersion: 3 + m_Name: Horizontal + descriptiveName: + descriptiveNegativeName: + negativeButton: left + positiveButton: right + altNegativeButton: a + altPositiveButton: d + gravity: 3 + dead: 0.001 + sensitivity: 3 + snap: 1 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Vertical + descriptiveName: + descriptiveNegativeName: + negativeButton: down + positiveButton: up + altNegativeButton: s + altPositiveButton: w + gravity: 3 + dead: 0.001 + sensitivity: 3 + snap: 1 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Fire1 + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: left ctrl + altNegativeButton: + altPositiveButton: mouse 0 + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Fire2 + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: left alt + altNegativeButton: + altPositiveButton: mouse 1 + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Fire3 + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: left shift + altNegativeButton: + altPositiveButton: mouse 2 + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Jump + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: space + altNegativeButton: + altPositiveButton: + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Mouse X + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: + altNegativeButton: + altPositiveButton: + gravity: 0 + dead: 0 + sensitivity: 0.1 + snap: 0 + invert: 0 + type: 1 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Mouse Y + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: + altNegativeButton: + altPositiveButton: + gravity: 0 + dead: 0 + sensitivity: 0.1 + snap: 0 + invert: 0 + type: 1 + axis: 1 + joyNum: 0 + - serializedVersion: 3 + m_Name: Mouse ScrollWheel + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: + altNegativeButton: + altPositiveButton: + gravity: 0 + dead: 0 + sensitivity: 0.1 + snap: 0 + invert: 0 + type: 1 + axis: 2 + joyNum: 0 + - serializedVersion: 3 + m_Name: Horizontal + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: + altNegativeButton: + altPositiveButton: + gravity: 0 + dead: 0.19 + sensitivity: 1 + snap: 0 + invert: 0 + type: 2 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Vertical + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: + altNegativeButton: + altPositiveButton: + gravity: 0 + dead: 0.19 + sensitivity: 1 + snap: 0 + invert: 1 + type: 2 + axis: 1 + joyNum: 0 + - serializedVersion: 3 + m_Name: Fire1 + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: joystick button 0 + altNegativeButton: + altPositiveButton: + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Fire2 + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: joystick button 1 + altNegativeButton: + altPositiveButton: + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Fire3 + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: joystick button 2 + altNegativeButton: + altPositiveButton: + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Jump + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: joystick button 3 + altNegativeButton: + altPositiveButton: + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Submit + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: return + altNegativeButton: + altPositiveButton: joystick button 0 + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Submit + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: enter + altNegativeButton: + altPositiveButton: space + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Cancel + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: escape + altNegativeButton: + altPositiveButton: joystick button 1 + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 diff --git a/物品和背包的完整代码/Client/Unity/ProjectSettings/MemorySettings.asset b/物品和背包的完整代码/Client/Unity/ProjectSettings/MemorySettings.asset new file mode 100644 index 0000000..5b5face --- /dev/null +++ b/物品和背包的完整代码/Client/Unity/ProjectSettings/MemorySettings.asset @@ -0,0 +1,35 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!387306366 &1 +MemorySettings: + m_ObjectHideFlags: 0 + m_EditorMemorySettings: + m_MainAllocatorBlockSize: -1 + m_ThreadAllocatorBlockSize: -1 + m_MainGfxBlockSize: -1 + m_ThreadGfxBlockSize: -1 + m_CacheBlockSize: -1 + m_TypetreeBlockSize: -1 + m_ProfilerBlockSize: -1 + m_ProfilerEditorBlockSize: -1 + m_BucketAllocatorGranularity: -1 + m_BucketAllocatorBucketsCount: -1 + m_BucketAllocatorBlockSize: -1 + m_BucketAllocatorBlockCount: -1 + m_ProfilerBucketAllocatorGranularity: -1 + m_ProfilerBucketAllocatorBucketsCount: -1 + m_ProfilerBucketAllocatorBlockSize: -1 + m_ProfilerBucketAllocatorBlockCount: -1 + m_TempAllocatorSizeMain: -1 + m_JobTempAllocatorBlockSize: -1 + m_BackgroundJobTempAllocatorBlockSize: -1 + m_JobTempAllocatorReducedBlockSize: -1 + m_TempAllocatorSizeGIBakingWorker: -1 + m_TempAllocatorSizeNavMeshWorker: -1 + m_TempAllocatorSizeAudioWorker: -1 + m_TempAllocatorSizeCloudWorker: -1 + m_TempAllocatorSizeGfx: -1 + m_TempAllocatorSizeJobWorker: -1 + m_TempAllocatorSizeBackgroundWorker: -1 + m_TempAllocatorSizePreloadManager: -1 + m_PlatformMemorySettings: {} diff --git a/物品和背包的完整代码/Client/Unity/ProjectSettings/NavMeshAreas.asset b/物品和背包的完整代码/Client/Unity/ProjectSettings/NavMeshAreas.asset new file mode 100644 index 0000000..3b0b7c3 --- /dev/null +++ b/物品和背包的完整代码/Client/Unity/ProjectSettings/NavMeshAreas.asset @@ -0,0 +1,91 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!126 &1 +NavMeshProjectSettings: + m_ObjectHideFlags: 0 + serializedVersion: 2 + areas: + - name: Walkable + cost: 1 + - name: Not Walkable + cost: 1 + - name: Jump + cost: 2 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + m_LastAgentTypeID: -887442657 + m_Settings: + - serializedVersion: 2 + agentTypeID: 0 + agentRadius: 0.5 + agentHeight: 2 + agentSlope: 45 + agentClimb: 0.75 + ledgeDropHeight: 0 + maxJumpAcrossDistance: 0 + minRegionArea: 2 + manualCellSize: 0 + cellSize: 0.16666667 + manualTileSize: 0 + tileSize: 256 + accuratePlacement: 0 + debug: + m_Flags: 0 + m_SettingNames: + - Humanoid diff --git a/物品和背包的完整代码/Client/Unity/ProjectSettings/PackageManagerSettings.asset b/物品和背包的完整代码/Client/Unity/ProjectSettings/PackageManagerSettings.asset new file mode 100644 index 0000000..112a053 --- /dev/null +++ b/物品和背包的完整代码/Client/Unity/ProjectSettings/PackageManagerSettings.asset @@ -0,0 +1,35 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &1 +MonoBehaviour: + m_ObjectHideFlags: 61 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 13964, guid: 0000000000000000e000000000000000, type: 0} + m_Name: + m_EditorClassIdentifier: + m_EnablePreReleasePackages: 0 + m_EnablePackageDependencies: 0 + m_AdvancedSettingsExpanded: 1 + m_ScopedRegistriesSettingsExpanded: 1 + m_SeeAllPackageVersions: 0 + oneTimeWarningShown: 0 + m_Registries: + - m_Id: main + m_Name: + m_Url: https://packages.unity.com + m_Scopes: [] + m_IsDefault: 1 + m_Capabilities: 7 + m_UserSelectedRegistryName: + m_UserAddingNewScopedRegistry: 0 + m_RegistryInfoDraft: + m_Modified: 0 + m_ErrorMessage: + m_UserModificationsInstanceId: -830 + m_OriginalInstanceId: -832 + m_LoadAssets: 0 diff --git a/物品和背包的完整代码/Client/Unity/ProjectSettings/Packages/com.unity.testtools.codecoverage/Settings.json b/物品和背包的完整代码/Client/Unity/ProjectSettings/Packages/com.unity.testtools.codecoverage/Settings.json new file mode 100644 index 0000000..ad11087 --- /dev/null +++ b/物品和背包的完整代码/Client/Unity/ProjectSettings/Packages/com.unity.testtools.codecoverage/Settings.json @@ -0,0 +1,7 @@ +{ + "m_Name": "Settings", + "m_Path": "ProjectSettings/Packages/com.unity.testtools.codecoverage/Settings.json", + "m_Dictionary": { + "m_DictionaryValues": [] + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Client/Unity/ProjectSettings/Physics2DSettings.asset b/物品和背包的完整代码/Client/Unity/ProjectSettings/Physics2DSettings.asset new file mode 100644 index 0000000..47880b1 --- /dev/null +++ b/物品和背包的完整代码/Client/Unity/ProjectSettings/Physics2DSettings.asset @@ -0,0 +1,56 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!19 &1 +Physics2DSettings: + m_ObjectHideFlags: 0 + serializedVersion: 4 + m_Gravity: {x: 0, y: -9.81} + m_DefaultMaterial: {fileID: 0} + m_VelocityIterations: 8 + m_PositionIterations: 3 + m_VelocityThreshold: 1 + m_MaxLinearCorrection: 0.2 + m_MaxAngularCorrection: 8 + m_MaxTranslationSpeed: 100 + m_MaxRotationSpeed: 360 + m_BaumgarteScale: 0.2 + m_BaumgarteTimeOfImpactScale: 0.75 + m_TimeToSleep: 0.5 + m_LinearSleepTolerance: 0.01 + m_AngularSleepTolerance: 2 + m_DefaultContactOffset: 0.01 + m_JobOptions: + serializedVersion: 2 + useMultithreading: 0 + useConsistencySorting: 0 + m_InterpolationPosesPerJob: 100 + m_NewContactsPerJob: 30 + m_CollideContactsPerJob: 100 + m_ClearFlagsPerJob: 200 + m_ClearBodyForcesPerJob: 200 + m_SyncDiscreteFixturesPerJob: 50 + m_SyncContinuousFixturesPerJob: 50 + m_FindNearestContactsPerJob: 100 + m_UpdateTriggerContactsPerJob: 100 + m_IslandSolverCostThreshold: 100 + m_IslandSolverBodyCostScale: 1 + m_IslandSolverContactCostScale: 10 + m_IslandSolverJointCostScale: 10 + m_IslandSolverBodiesPerJob: 50 + m_IslandSolverContactsPerJob: 50 + m_AutoSimulation: 1 + m_QueriesHitTriggers: 1 + m_QueriesStartInColliders: 1 + m_CallbacksOnDisable: 1 + m_ReuseCollisionCallbacks: 1 + m_AutoSyncTransforms: 0 + m_AlwaysShowColliders: 0 + m_ShowColliderSleep: 1 + m_ShowColliderContacts: 0 + m_ShowColliderAABB: 0 + m_ContactArrowScale: 0.2 + m_ColliderAwakeColor: {r: 0.5686275, g: 0.95686275, b: 0.54509807, a: 0.7529412} + m_ColliderAsleepColor: {r: 0.5686275, g: 0.95686275, b: 0.54509807, a: 0.36078432} + m_ColliderContactColor: {r: 1, g: 0, b: 1, a: 0.6862745} + m_ColliderAABBColor: {r: 1, g: 1, b: 0, a: 0.2509804} + m_LayerCollisionMatrix: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff diff --git a/物品和背包的完整代码/Client/Unity/ProjectSettings/PresetManager.asset b/物品和背包的完整代码/Client/Unity/ProjectSettings/PresetManager.asset new file mode 100644 index 0000000..67a94da --- /dev/null +++ b/物品和背包的完整代码/Client/Unity/ProjectSettings/PresetManager.asset @@ -0,0 +1,7 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1386491679 &1 +PresetManager: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_DefaultPresets: {} diff --git a/物品和背包的完整代码/Client/Unity/ProjectSettings/ProjectSettings.asset b/物品和背包的完整代码/Client/Unity/ProjectSettings/ProjectSettings.asset new file mode 100644 index 0000000..614ab2d --- /dev/null +++ b/物品和背包的完整代码/Client/Unity/ProjectSettings/ProjectSettings.asset @@ -0,0 +1,907 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!129 &1 +PlayerSettings: + m_ObjectHideFlags: 0 + serializedVersion: 23 + productGUID: b9c3a61a72a7f4f85b1e249abd3b6037 + AndroidProfiler: 0 + AndroidFilterTouchesWhenObscured: 0 + AndroidEnableSustainedPerformanceMode: 0 + defaultScreenOrientation: 4 + targetDevice: 2 + useOnDemandResources: 0 + accelerometerFrequency: 60 + companyName: DefaultCompany + productName: Unity + defaultCursor: {fileID: 0} + cursorHotspot: {x: 0, y: 0} + m_SplashScreenBackgroundColor: {r: 0.13725491, g: 0.12156863, b: 0.1254902, a: 1} + m_ShowUnitySplashScreen: 1 + m_ShowUnitySplashLogo: 1 + m_SplashScreenOverlayOpacity: 1 + m_SplashScreenAnimation: 1 + m_SplashScreenLogoStyle: 1 + m_SplashScreenDrawMode: 0 + m_SplashScreenBackgroundAnimationZoom: 1 + m_SplashScreenLogoAnimationZoom: 1 + m_SplashScreenBackgroundLandscapeAspect: 1 + m_SplashScreenBackgroundPortraitAspect: 1 + m_SplashScreenBackgroundLandscapeUvs: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 + m_SplashScreenBackgroundPortraitUvs: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 + m_SplashScreenLogos: [] + m_VirtualRealitySplashScreen: {fileID: 0} + m_HolographicTrackingLossScreen: {fileID: 0} + defaultScreenWidth: 1920 + defaultScreenHeight: 1080 + defaultScreenWidthWeb: 960 + defaultScreenHeightWeb: 600 + m_StereoRenderingPath: 0 + m_ActiveColorSpace: 1 + m_MTRendering: 1 + mipStripping: 0 + numberOfMipsStripped: 0 + m_StackTraceTypes: 010000000100000001000000010000000100000001000000 + iosShowActivityIndicatorOnLoading: -1 + androidShowActivityIndicatorOnLoading: -1 + iosUseCustomAppBackgroundBehavior: 0 + iosAllowHTTPDownload: 1 + allowedAutorotateToPortrait: 1 + allowedAutorotateToPortraitUpsideDown: 1 + allowedAutorotateToLandscapeRight: 1 + allowedAutorotateToLandscapeLeft: 1 + useOSAutorotation: 1 + use32BitDisplayBuffer: 1 + preserveFramebufferAlpha: 0 + disableDepthAndStencilBuffers: 0 + androidStartInFullscreen: 1 + androidRenderOutsideSafeArea: 1 + androidUseSwappy: 1 + androidBlitType: 0 + androidResizableWindow: 0 + androidDefaultWindowWidth: 1920 + androidDefaultWindowHeight: 1080 + androidMinimumWindowWidth: 400 + androidMinimumWindowHeight: 300 + androidFullscreenMode: 1 + defaultIsNativeResolution: 1 + macRetinaSupport: 1 + runInBackground: 1 + captureSingleScreen: 0 + muteOtherAudioSources: 0 + Prepare IOS For Recording: 0 + Force IOS Speakers When Recording: 0 + deferSystemGesturesMode: 0 + hideHomeButton: 0 + submitAnalytics: 1 + usePlayerLog: 1 + bakeCollisionMeshes: 0 + forceSingleInstance: 0 + useFlipModelSwapchain: 1 + resizableWindow: 0 + useMacAppStoreValidation: 0 + macAppStoreCategory: public.app-category.games + gpuSkinning: 1 + xboxPIXTextureCapture: 0 + xboxEnableAvatar: 0 + xboxEnableKinect: 0 + xboxEnableKinectAutoTracking: 0 + xboxEnableFitness: 0 + visibleInBackground: 1 + allowFullscreenSwitch: 1 + fullscreenMode: 1 + xboxSpeechDB: 0 + xboxEnableHeadOrientation: 0 + xboxEnableGuest: 0 + xboxEnablePIXSampling: 0 + metalFramebufferOnly: 0 + xboxOneResolution: 0 + xboxOneSResolution: 0 + xboxOneXResolution: 3 + xboxOneMonoLoggingLevel: 0 + xboxOneLoggingLevel: 1 + xboxOneDisableEsram: 0 + xboxOneEnableTypeOptimization: 0 + xboxOnePresentImmediateThreshold: 0 + switchQueueCommandMemory: 0 + switchQueueControlMemory: 16384 + switchQueueComputeMemory: 262144 + switchNVNShaderPoolsGranularity: 33554432 + switchNVNDefaultPoolsGranularity: 16777216 + switchNVNOtherPoolsGranularity: 16777216 + switchNVNMaxPublicTextureIDCount: 0 + switchNVNMaxPublicSamplerIDCount: 0 + stadiaPresentMode: 0 + stadiaTargetFramerate: 0 + vulkanNumSwapchainBuffers: 3 + vulkanEnableSetSRGBWrite: 0 + vulkanEnablePreTransform: 1 + vulkanEnableLateAcquireNextImage: 0 + vulkanEnableCommandBufferRecycling: 1 + m_SupportedAspectRatios: + 4:3: 1 + 5:4: 1 + 16:10: 1 + 16:9: 1 + Others: 1 + bundleVersion: 0.1 + preloadedAssets: [] + metroInputSource: 0 + wsaTransparentSwapchain: 0 + m_HolographicPauseOnTrackingLoss: 1 + xboxOneDisableKinectGpuReservation: 1 + xboxOneEnable7thCore: 1 + vrSettings: + enable360StereoCapture: 0 + isWsaHolographicRemotingEnabled: 0 + enableFrameTimingStats: 0 + enableOpenGLProfilerGPURecorders: 1 + useHDRDisplay: 0 + D3DHDRBitDepth: 0 + m_ColorGamuts: 00000000 + targetPixelDensity: 30 + resolutionScalingMode: 0 + resetResolutionOnWindowResize: 0 + androidSupportedAspectRatio: 1 + androidMaxAspectRatio: 2.1 + applicationIdentifier: {} + buildNumber: + Standalone: 0 + iPhone: 0 + tvOS: 0 + overrideDefaultApplicationIdentifier: 0 + AndroidBundleVersionCode: 1 + AndroidMinSdkVersion: 22 + AndroidTargetSdkVersion: 0 + AndroidPreferredInstallLocation: 1 + aotOptions: + stripEngineCode: 1 + iPhoneStrippingLevel: 0 + iPhoneScriptCallOptimization: 0 + ForceInternetPermission: 0 + ForceSDCardPermission: 0 + CreateWallpaper: 0 + APKExpansionFiles: 0 + keepLoadedShadersAlive: 0 + StripUnusedMeshComponents: 1 + VertexChannelCompressionMask: 4054 + iPhoneSdkVersion: 988 + iOSTargetOSVersionString: 11.0 + tvOSSdkVersion: 0 + tvOSRequireExtendedGameController: 0 + tvOSTargetOSVersionString: 11.0 + uIPrerenderedIcon: 0 + uIRequiresPersistentWiFi: 0 + uIRequiresFullScreen: 1 + uIStatusBarHidden: 1 + uIExitOnSuspend: 0 + uIStatusBarStyle: 0 + appleTVSplashScreen: {fileID: 0} + appleTVSplashScreen2x: {fileID: 0} + tvOSSmallIconLayers: [] + tvOSSmallIconLayers2x: [] + tvOSLargeIconLayers: [] + tvOSLargeIconLayers2x: [] + tvOSTopShelfImageLayers: [] + tvOSTopShelfImageLayers2x: [] + tvOSTopShelfImageWideLayers: [] + tvOSTopShelfImageWideLayers2x: [] + iOSLaunchScreenType: 0 + iOSLaunchScreenPortrait: {fileID: 0} + iOSLaunchScreenLandscape: {fileID: 0} + iOSLaunchScreenBackgroundColor: + serializedVersion: 2 + rgba: 0 + iOSLaunchScreenFillPct: 100 + iOSLaunchScreenSize: 100 + iOSLaunchScreenCustomXibPath: + iOSLaunchScreeniPadType: 0 + iOSLaunchScreeniPadImage: {fileID: 0} + iOSLaunchScreeniPadBackgroundColor: + serializedVersion: 2 + rgba: 0 + iOSLaunchScreeniPadFillPct: 100 + iOSLaunchScreeniPadSize: 100 + iOSLaunchScreeniPadCustomXibPath: + iOSLaunchScreenCustomStoryboardPath: + iOSLaunchScreeniPadCustomStoryboardPath: + iOSDeviceRequirements: [] + iOSURLSchemes: [] + macOSURLSchemes: [] + iOSBackgroundModes: 0 + iOSMetalForceHardShadows: 0 + metalEditorSupport: 1 + metalAPIValidation: 1 + iOSRenderExtraFrameOnPause: 0 + iosCopyPluginsCodeInsteadOfSymlink: 0 + appleDeveloperTeamID: + iOSManualSigningProvisioningProfileID: + tvOSManualSigningProvisioningProfileID: + iOSManualSigningProvisioningProfileType: 0 + tvOSManualSigningProvisioningProfileType: 0 + appleEnableAutomaticSigning: 0 + iOSRequireARKit: 0 + iOSAutomaticallyDetectAndAddCapabilities: 1 + appleEnableProMotion: 0 + shaderPrecisionModel: 0 + clonedFromGUID: c0afd0d1d80e3634a9dac47e8a0426ea + templatePackageId: com.unity.template.3d@8.1.3 + templateDefaultScene: Assets/Scenes/SampleScene.unity + useCustomMainManifest: 0 + useCustomLauncherManifest: 0 + useCustomMainGradleTemplate: 0 + useCustomLauncherGradleManifest: 0 + useCustomBaseGradleTemplate: 0 + useCustomGradlePropertiesTemplate: 0 + useCustomProguardFile: 0 + AndroidTargetArchitectures: 1 + AndroidTargetDevices: 0 + AndroidSplashScreenScale: 0 + androidSplashScreen: {fileID: 0} + AndroidKeystoreName: + AndroidKeyaliasName: + AndroidBuildApkPerCpuArchitecture: 0 + AndroidTVCompatibility: 0 + AndroidIsGame: 1 + AndroidEnableTango: 0 + androidEnableBanner: 1 + androidUseLowAccuracyLocation: 0 + androidUseCustomKeystore: 0 + m_AndroidBanners: + - width: 320 + height: 180 + banner: {fileID: 0} + androidGamepadSupportLevel: 0 + chromeosInputEmulation: 1 + AndroidMinifyWithR8: 0 + AndroidMinifyRelease: 0 + AndroidMinifyDebug: 0 + AndroidValidateAppBundleSize: 1 + AndroidAppBundleSizeToValidate: 150 + m_BuildTargetIcons: [] + m_BuildTargetPlatformIcons: + - m_BuildTarget: iPhone + m_Icons: + - m_Textures: [] + m_Width: 180 + m_Height: 180 + m_Kind: 0 + m_SubKind: iPhone + - m_Textures: [] + m_Width: 120 + m_Height: 120 + m_Kind: 0 + m_SubKind: iPhone + - m_Textures: [] + m_Width: 167 + m_Height: 167 + m_Kind: 0 + m_SubKind: iPad + - m_Textures: [] + m_Width: 152 + m_Height: 152 + m_Kind: 0 + m_SubKind: iPad + - m_Textures: [] + m_Width: 76 + m_Height: 76 + m_Kind: 0 + m_SubKind: iPad + - m_Textures: [] + m_Width: 120 + m_Height: 120 + m_Kind: 3 + m_SubKind: iPhone + - m_Textures: [] + m_Width: 80 + m_Height: 80 + m_Kind: 3 + m_SubKind: iPhone + - m_Textures: [] + m_Width: 80 + m_Height: 80 + m_Kind: 3 + m_SubKind: iPad + - m_Textures: [] + m_Width: 40 + m_Height: 40 + m_Kind: 3 + m_SubKind: iPad + - m_Textures: [] + m_Width: 87 + m_Height: 87 + m_Kind: 1 + m_SubKind: iPhone + - m_Textures: [] + m_Width: 58 + m_Height: 58 + m_Kind: 1 + m_SubKind: iPhone + - m_Textures: [] + m_Width: 29 + m_Height: 29 + m_Kind: 1 + m_SubKind: iPhone + - m_Textures: [] + m_Width: 58 + m_Height: 58 + m_Kind: 1 + m_SubKind: iPad + - m_Textures: [] + m_Width: 29 + m_Height: 29 + m_Kind: 1 + m_SubKind: iPad + - m_Textures: [] + m_Width: 60 + m_Height: 60 + m_Kind: 2 + m_SubKind: iPhone + - m_Textures: [] + m_Width: 40 + m_Height: 40 + m_Kind: 2 + m_SubKind: iPhone + - m_Textures: [] + m_Width: 40 + m_Height: 40 + m_Kind: 2 + m_SubKind: iPad + - m_Textures: [] + m_Width: 20 + m_Height: 20 + m_Kind: 2 + m_SubKind: iPad + - m_Textures: [] + m_Width: 1024 + m_Height: 1024 + m_Kind: 4 + m_SubKind: App Store + - m_BuildTarget: Android + m_Icons: + - m_Textures: [] + m_Width: 432 + m_Height: 432 + m_Kind: 2 + m_SubKind: + - m_Textures: [] + m_Width: 324 + m_Height: 324 + m_Kind: 2 + m_SubKind: + - m_Textures: [] + m_Width: 216 + m_Height: 216 + m_Kind: 2 + m_SubKind: + - m_Textures: [] + m_Width: 162 + m_Height: 162 + m_Kind: 2 + m_SubKind: + - m_Textures: [] + m_Width: 108 + m_Height: 108 + m_Kind: 2 + m_SubKind: + - m_Textures: [] + m_Width: 81 + m_Height: 81 + m_Kind: 2 + m_SubKind: + - m_Textures: [] + m_Width: 192 + m_Height: 192 + m_Kind: 1 + m_SubKind: + - m_Textures: [] + m_Width: 144 + m_Height: 144 + m_Kind: 1 + m_SubKind: + - m_Textures: [] + m_Width: 96 + m_Height: 96 + m_Kind: 1 + m_SubKind: + - m_Textures: [] + m_Width: 72 + m_Height: 72 + m_Kind: 1 + m_SubKind: + - m_Textures: [] + m_Width: 48 + m_Height: 48 + m_Kind: 1 + m_SubKind: + - m_Textures: [] + m_Width: 36 + m_Height: 36 + m_Kind: 1 + m_SubKind: + - m_Textures: [] + m_Width: 192 + m_Height: 192 + m_Kind: 0 + m_SubKind: + - m_Textures: [] + m_Width: 144 + m_Height: 144 + m_Kind: 0 + m_SubKind: + - m_Textures: [] + m_Width: 96 + m_Height: 96 + m_Kind: 0 + m_SubKind: + - m_Textures: [] + m_Width: 72 + m_Height: 72 + m_Kind: 0 + m_SubKind: + - m_Textures: [] + m_Width: 48 + m_Height: 48 + m_Kind: 0 + m_SubKind: + - m_Textures: [] + m_Width: 36 + m_Height: 36 + m_Kind: 0 + m_SubKind: + m_BuildTargetBatching: + - m_BuildTarget: Standalone + m_StaticBatching: 1 + m_DynamicBatching: 0 + - m_BuildTarget: tvOS + m_StaticBatching: 1 + m_DynamicBatching: 0 + - m_BuildTarget: Android + m_StaticBatching: 1 + m_DynamicBatching: 0 + - m_BuildTarget: iPhone + m_StaticBatching: 1 + m_DynamicBatching: 0 + - m_BuildTarget: WebGL + m_StaticBatching: 0 + m_DynamicBatching: 0 + m_BuildTargetShaderSettings: [] + m_BuildTargetGraphicsJobs: + - m_BuildTarget: MacStandaloneSupport + m_GraphicsJobs: 0 + - m_BuildTarget: Switch + m_GraphicsJobs: 1 + - m_BuildTarget: MetroSupport + m_GraphicsJobs: 1 + - m_BuildTarget: AppleTVSupport + m_GraphicsJobs: 0 + - m_BuildTarget: BJMSupport + m_GraphicsJobs: 1 + - m_BuildTarget: LinuxStandaloneSupport + m_GraphicsJobs: 1 + - m_BuildTarget: PS4Player + m_GraphicsJobs: 1 + - m_BuildTarget: iOSSupport + m_GraphicsJobs: 0 + - m_BuildTarget: WindowsStandaloneSupport + m_GraphicsJobs: 1 + - m_BuildTarget: XboxOnePlayer + m_GraphicsJobs: 1 + - m_BuildTarget: LuminSupport + m_GraphicsJobs: 0 + - m_BuildTarget: AndroidPlayer + m_GraphicsJobs: 0 + - m_BuildTarget: WebGLSupport + m_GraphicsJobs: 0 + m_BuildTargetGraphicsJobMode: + - m_BuildTarget: PS4Player + m_GraphicsJobMode: 0 + - m_BuildTarget: XboxOnePlayer + m_GraphicsJobMode: 0 + m_BuildTargetGraphicsAPIs: + - m_BuildTarget: AndroidPlayer + m_APIs: 150000000b000000 + m_Automatic: 1 + - m_BuildTarget: iOSSupport + m_APIs: 10000000 + m_Automatic: 1 + - m_BuildTarget: AppleTVSupport + m_APIs: 10000000 + m_Automatic: 1 + - m_BuildTarget: WebGLSupport + m_APIs: 0b000000 + m_Automatic: 1 + m_BuildTargetVRSettings: + - m_BuildTarget: Standalone + m_Enabled: 0 + m_Devices: + - Oculus + - OpenVR + m_DefaultShaderChunkSizeInMB: 16 + m_DefaultShaderChunkCount: 0 + openGLRequireES31: 0 + openGLRequireES31AEP: 0 + openGLRequireES32: 0 + m_TemplateCustomTags: {} + mobileMTRendering: + Android: 1 + iPhone: 1 + tvOS: 1 + m_BuildTargetGroupLightmapEncodingQuality: + - m_BuildTarget: Android + m_EncodingQuality: 1 + - m_BuildTarget: iPhone + m_EncodingQuality: 1 + - m_BuildTarget: tvOS + m_EncodingQuality: 1 + m_BuildTargetGroupLightmapSettings: [] + m_BuildTargetNormalMapEncoding: + - m_BuildTarget: Android + m_Encoding: 1 + - m_BuildTarget: iPhone + m_Encoding: 1 + - m_BuildTarget: tvOS + m_Encoding: 1 + m_BuildTargetDefaultTextureCompressionFormat: + - m_BuildTarget: Android + m_Format: 3 + playModeTestRunnerEnabled: 0 + runPlayModeTestAsEditModeTest: 0 + actionOnDotNetUnhandledException: 1 + enableInternalProfiler: 0 + logObjCUncaughtExceptions: 1 + enableCrashReportAPI: 0 + cameraUsageDescription: + locationUsageDescription: + microphoneUsageDescription: + bluetoothUsageDescription: + switchNMETAOverride: + switchNetLibKey: + switchSocketMemoryPoolSize: 6144 + switchSocketAllocatorPoolSize: 128 + switchSocketConcurrencyLimit: 14 + switchScreenResolutionBehavior: 2 + switchUseCPUProfiler: 0 + switchUseGOLDLinker: 0 + switchLTOSetting: 0 + switchApplicationID: 0x01004b9000490000 + switchNSODependencies: + switchTitleNames_0: + switchTitleNames_1: + switchTitleNames_2: + switchTitleNames_3: + switchTitleNames_4: + switchTitleNames_5: + switchTitleNames_6: + switchTitleNames_7: + switchTitleNames_8: + switchTitleNames_9: + switchTitleNames_10: + switchTitleNames_11: + switchTitleNames_12: + switchTitleNames_13: + switchTitleNames_14: + switchTitleNames_15: + switchPublisherNames_0: + switchPublisherNames_1: + switchPublisherNames_2: + switchPublisherNames_3: + switchPublisherNames_4: + switchPublisherNames_5: + switchPublisherNames_6: + switchPublisherNames_7: + switchPublisherNames_8: + switchPublisherNames_9: + switchPublisherNames_10: + switchPublisherNames_11: + switchPublisherNames_12: + switchPublisherNames_13: + switchPublisherNames_14: + switchPublisherNames_15: + switchIcons_0: {fileID: 0} + switchIcons_1: {fileID: 0} + switchIcons_2: {fileID: 0} + switchIcons_3: {fileID: 0} + switchIcons_4: {fileID: 0} + switchIcons_5: {fileID: 0} + switchIcons_6: {fileID: 0} + switchIcons_7: {fileID: 0} + switchIcons_8: {fileID: 0} + switchIcons_9: {fileID: 0} + switchIcons_10: {fileID: 0} + switchIcons_11: {fileID: 0} + switchIcons_12: {fileID: 0} + switchIcons_13: {fileID: 0} + switchIcons_14: {fileID: 0} + switchIcons_15: {fileID: 0} + switchSmallIcons_0: {fileID: 0} + switchSmallIcons_1: {fileID: 0} + switchSmallIcons_2: {fileID: 0} + switchSmallIcons_3: {fileID: 0} + switchSmallIcons_4: {fileID: 0} + switchSmallIcons_5: {fileID: 0} + switchSmallIcons_6: {fileID: 0} + switchSmallIcons_7: {fileID: 0} + switchSmallIcons_8: {fileID: 0} + switchSmallIcons_9: {fileID: 0} + switchSmallIcons_10: {fileID: 0} + switchSmallIcons_11: {fileID: 0} + switchSmallIcons_12: {fileID: 0} + switchSmallIcons_13: {fileID: 0} + switchSmallIcons_14: {fileID: 0} + switchSmallIcons_15: {fileID: 0} + switchManualHTML: + switchAccessibleURLs: + switchLegalInformation: + switchMainThreadStackSize: 1048576 + switchPresenceGroupId: + switchLogoHandling: 0 + switchReleaseVersion: 0 + switchDisplayVersion: 1.0.0 + switchStartupUserAccount: 0 + switchTouchScreenUsage: 0 + switchSupportedLanguagesMask: 0 + switchLogoType: 0 + switchApplicationErrorCodeCategory: + switchUserAccountSaveDataSize: 0 + switchUserAccountSaveDataJournalSize: 0 + switchApplicationAttribute: 0 + switchCardSpecSize: -1 + switchCardSpecClock: -1 + switchRatingsMask: 0 + switchRatingsInt_0: 0 + switchRatingsInt_1: 0 + switchRatingsInt_2: 0 + switchRatingsInt_3: 0 + switchRatingsInt_4: 0 + switchRatingsInt_5: 0 + switchRatingsInt_6: 0 + switchRatingsInt_7: 0 + switchRatingsInt_8: 0 + switchRatingsInt_9: 0 + switchRatingsInt_10: 0 + switchRatingsInt_11: 0 + switchRatingsInt_12: 0 + switchLocalCommunicationIds_0: + switchLocalCommunicationIds_1: + switchLocalCommunicationIds_2: + switchLocalCommunicationIds_3: + switchLocalCommunicationIds_4: + switchLocalCommunicationIds_5: + switchLocalCommunicationIds_6: + switchLocalCommunicationIds_7: + switchParentalControl: 0 + switchAllowsScreenshot: 1 + switchAllowsVideoCapturing: 1 + switchAllowsRuntimeAddOnContentInstall: 0 + switchDataLossConfirmation: 0 + switchUserAccountLockEnabled: 0 + switchSystemResourceMemory: 16777216 + switchSupportedNpadStyles: 22 + switchNativeFsCacheSize: 32 + switchIsHoldTypeHorizontal: 0 + switchSupportedNpadCount: 8 + switchSocketConfigEnabled: 0 + switchTcpInitialSendBufferSize: 32 + switchTcpInitialReceiveBufferSize: 64 + switchTcpAutoSendBufferSizeMax: 256 + switchTcpAutoReceiveBufferSizeMax: 256 + switchUdpSendBufferSize: 9 + switchUdpReceiveBufferSize: 42 + switchSocketBufferEfficiency: 4 + switchSocketInitializeEnabled: 1 + switchNetworkInterfaceManagerInitializeEnabled: 1 + switchPlayerConnectionEnabled: 1 + switchUseNewStyleFilepaths: 0 + switchUseMicroSleepForYield: 1 + switchEnableRamDiskSupport: 0 + switchMicroSleepForYieldTime: 25 + switchRamDiskSpaceSize: 12 + ps4NPAgeRating: 12 + ps4NPTitleSecret: + ps4NPTrophyPackPath: + ps4ParentalLevel: 11 + ps4ContentID: ED1633-NPXX51362_00-0000000000000000 + ps4Category: 0 + ps4MasterVersion: 01.00 + ps4AppVersion: 01.00 + ps4AppType: 0 + ps4ParamSfxPath: + ps4VideoOutPixelFormat: 0 + ps4VideoOutInitialWidth: 1920 + ps4VideoOutBaseModeInitialWidth: 1920 + ps4VideoOutReprojectionRate: 60 + ps4PronunciationXMLPath: + ps4PronunciationSIGPath: + ps4BackgroundImagePath: + ps4StartupImagePath: + ps4StartupImagesFolder: + ps4IconImagesFolder: + ps4SaveDataImagePath: + ps4SdkOverride: + ps4BGMPath: + ps4ShareFilePath: + ps4ShareOverlayImagePath: + ps4PrivacyGuardImagePath: + ps4ExtraSceSysFile: + ps4NPtitleDatPath: + ps4RemotePlayKeyAssignment: -1 + ps4RemotePlayKeyMappingDir: + ps4PlayTogetherPlayerCount: 0 + ps4EnterButtonAssignment: 1 + ps4ApplicationParam1: 0 + ps4ApplicationParam2: 0 + ps4ApplicationParam3: 0 + ps4ApplicationParam4: 0 + ps4DownloadDataSize: 0 + ps4GarlicHeapSize: 2048 + ps4ProGarlicHeapSize: 2560 + playerPrefsMaxSize: 32768 + ps4Passcode: frAQBc8Wsa1xVPfvJcrgRYwTiizs2trQ + ps4pnSessions: 1 + ps4pnPresence: 1 + ps4pnFriends: 1 + ps4pnGameCustomData: 1 + playerPrefsSupport: 0 + enableApplicationExit: 0 + resetTempFolder: 1 + restrictedAudioUsageRights: 0 + ps4UseResolutionFallback: 0 + ps4ReprojectionSupport: 0 + ps4UseAudio3dBackend: 0 + ps4UseLowGarlicFragmentationMode: 1 + ps4SocialScreenEnabled: 0 + ps4ScriptOptimizationLevel: 0 + ps4Audio3dVirtualSpeakerCount: 14 + ps4attribCpuUsage: 0 + ps4PatchPkgPath: + ps4PatchLatestPkgPath: + ps4PatchChangeinfoPath: + ps4PatchDayOne: 0 + ps4attribUserManagement: 0 + ps4attribMoveSupport: 0 + ps4attrib3DSupport: 0 + ps4attribShareSupport: 0 + ps4attribExclusiveVR: 0 + ps4disableAutoHideSplash: 0 + ps4videoRecordingFeaturesUsed: 0 + ps4contentSearchFeaturesUsed: 0 + ps4CompatibilityPS5: 0 + ps4AllowPS5Detection: 0 + ps4GPU800MHz: 1 + ps4attribEyeToEyeDistanceSettingVR: 0 + ps4IncludedModules: [] + ps4attribVROutputEnabled: 0 + monoEnv: + splashScreenBackgroundSourceLandscape: {fileID: 0} + splashScreenBackgroundSourcePortrait: {fileID: 0} + blurSplashScreenBackground: 1 + spritePackerPolicy: + webGLMemorySize: 16 + webGLExceptionSupport: 1 + webGLNameFilesAsHashes: 0 + webGLDataCaching: 1 + webGLDebugSymbols: 0 + webGLEmscriptenArgs: + webGLModulesDirectory: + webGLTemplate: APPLICATION:Default + webGLAnalyzeBuildSize: 0 + webGLUseEmbeddedResources: 0 + webGLCompressionFormat: 1 + webGLWasmArithmeticExceptions: 0 + webGLLinkerTarget: 1 + webGLThreadsSupport: 0 + webGLDecompressionFallback: 0 + webGLPowerPreference: 2 + scriptingDefineSymbols: {} + additionalCompilerArguments: {} + platformArchitecture: {} + scriptingBackend: {} + il2cppCompilerConfiguration: {} + managedStrippingLevel: {} + incrementalIl2cppBuild: {} + suppressCommonWarnings: 1 + allowUnsafeCode: 0 + useDeterministicCompilation: 1 + enableRoslynAnalyzers: 1 + selectedPlatform: 0 + additionalIl2CppArgs: + scriptingRuntimeVersion: 1 + gcIncremental: 1 + assemblyVersionValidation: 1 + gcWBarrierValidation: 0 + apiCompatibilityLevelPerPlatform: {} + m_RenderingPath: 1 + m_MobileRenderingPath: 1 + metroPackageName: Template_3D + metroPackageVersion: + metroCertificatePath: + metroCertificatePassword: + metroCertificateSubject: + metroCertificateIssuer: + metroCertificateNotAfter: 0000000000000000 + metroApplicationDescription: Template_3D + wsaImages: {} + metroTileShortName: + metroTileShowName: 0 + metroMediumTileShowName: 0 + metroLargeTileShowName: 0 + metroWideTileShowName: 0 + metroSupportStreamingInstall: 0 + metroLastRequiredScene: 0 + metroDefaultTileSize: 1 + metroTileForegroundText: 2 + metroTileBackgroundColor: {r: 0.13333334, g: 0.17254902, b: 0.21568628, a: 0} + metroSplashScreenBackgroundColor: {r: 0.12941177, g: 0.17254902, b: 0.21568628, a: 1} + metroSplashScreenUseBackgroundColor: 0 + platformCapabilities: {} + metroTargetDeviceFamilies: {} + metroFTAName: + metroFTAFileTypes: [] + metroProtocolName: + vcxProjDefaultLanguage: + XboxOneProductId: + XboxOneUpdateKey: + XboxOneSandboxId: + XboxOneContentId: + XboxOneTitleId: + XboxOneSCId: + XboxOneGameOsOverridePath: + XboxOnePackagingOverridePath: + XboxOneAppManifestOverridePath: + XboxOneVersion: 1.0.0.0 + XboxOnePackageEncryption: 0 + XboxOnePackageUpdateGranularity: 2 + XboxOneDescription: + XboxOneLanguage: + - enus + XboxOneCapability: [] + XboxOneGameRating: {} + XboxOneIsContentPackage: 0 + XboxOneEnhancedXboxCompatibilityMode: 0 + XboxOneEnableGPUVariability: 1 + XboxOneSockets: {} + XboxOneSplashScreen: {fileID: 0} + XboxOneAllowedProductIds: [] + XboxOnePersistentLocalStorageSize: 0 + XboxOneXTitleMemory: 8 + XboxOneOverrideIdentityName: + XboxOneOverrideIdentityPublisher: + vrEditorSettings: {} + cloudServicesEnabled: + Collab: 1 + UNet: 1 + luminIcon: + m_Name: + m_ModelFolderPath: + m_PortalFolderPath: + luminCert: + m_CertPath: + m_SignPackage: 1 + luminIsChannelApp: 0 + luminVersion: + m_VersionCode: 1 + m_VersionName: + apiCompatibilityLevel: 6 + activeInputHandler: 0 + windowsGamepadBackendHint: 0 + cloudProjectId: + framebufferDepthMemorylessMode: 0 + qualitySettingsNames: [] + projectName: + organizationId: + cloudEnabled: 0 + legacyClampBlendShapeWeights: 0 + playerDataPath: + forceSRGBBlit: 1 + virtualTexturingSupportEnabled: 0 diff --git a/物品和背包的完整代码/Client/Unity/ProjectSettings/ProjectVersion.txt b/物品和背包的完整代码/Client/Unity/ProjectSettings/ProjectVersion.txt new file mode 100644 index 0000000..6a95707 --- /dev/null +++ b/物品和背包的完整代码/Client/Unity/ProjectSettings/ProjectVersion.txt @@ -0,0 +1,2 @@ +m_EditorVersion: 2021.3.14f1 +m_EditorVersionWithRevision: 2021.3.14f1 (eee1884e7226) diff --git a/物品和背包的完整代码/Client/Unity/ProjectSettings/QualitySettings.asset b/物品和背包的完整代码/Client/Unity/ProjectSettings/QualitySettings.asset new file mode 100644 index 0000000..36c0dad --- /dev/null +++ b/物品和背包的完整代码/Client/Unity/ProjectSettings/QualitySettings.asset @@ -0,0 +1,234 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!47 &1 +QualitySettings: + m_ObjectHideFlags: 0 + serializedVersion: 5 + m_CurrentQuality: 5 + m_QualitySettings: + - serializedVersion: 2 + name: Very Low + pixelLightCount: 0 + shadows: 0 + shadowResolution: 0 + shadowProjection: 1 + shadowCascades: 1 + shadowDistance: 15 + shadowNearPlaneOffset: 3 + shadowCascade2Split: 0.33333334 + shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} + shadowmaskMode: 0 + blendWeights: 1 + textureQuality: 1 + anisotropicTextures: 0 + antiAliasing: 0 + softParticles: 0 + softVegetation: 0 + realtimeReflectionProbes: 0 + billboardsFaceCameraPosition: 0 + vSyncCount: 0 + lodBias: 0.3 + maximumLODLevel: 0 + streamingMipmapsActive: 0 + streamingMipmapsAddAllCameras: 1 + streamingMipmapsMemoryBudget: 512 + streamingMipmapsRenderersPerFrame: 512 + streamingMipmapsMaxLevelReduction: 2 + streamingMipmapsMaxFileIORequests: 1024 + particleRaycastBudget: 4 + asyncUploadTimeSlice: 2 + asyncUploadBufferSize: 16 + asyncUploadPersistentBuffer: 1 + resolutionScalingFixedDPIFactor: 1 + excludedTargetPlatforms: [] + - serializedVersion: 2 + name: Low + pixelLightCount: 0 + shadows: 0 + shadowResolution: 0 + shadowProjection: 1 + shadowCascades: 1 + shadowDistance: 20 + shadowNearPlaneOffset: 3 + shadowCascade2Split: 0.33333334 + shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} + shadowmaskMode: 0 + blendWeights: 2 + textureQuality: 0 + anisotropicTextures: 0 + antiAliasing: 0 + softParticles: 0 + softVegetation: 0 + realtimeReflectionProbes: 0 + billboardsFaceCameraPosition: 0 + vSyncCount: 0 + lodBias: 0.4 + maximumLODLevel: 0 + streamingMipmapsActive: 0 + streamingMipmapsAddAllCameras: 1 + streamingMipmapsMemoryBudget: 512 + streamingMipmapsRenderersPerFrame: 512 + streamingMipmapsMaxLevelReduction: 2 + streamingMipmapsMaxFileIORequests: 1024 + particleRaycastBudget: 16 + asyncUploadTimeSlice: 2 + asyncUploadBufferSize: 16 + asyncUploadPersistentBuffer: 1 + resolutionScalingFixedDPIFactor: 1 + excludedTargetPlatforms: [] + - serializedVersion: 2 + name: Medium + pixelLightCount: 1 + shadows: 1 + shadowResolution: 0 + shadowProjection: 1 + shadowCascades: 1 + shadowDistance: 20 + shadowNearPlaneOffset: 3 + shadowCascade2Split: 0.33333334 + shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} + shadowmaskMode: 0 + blendWeights: 2 + textureQuality: 0 + anisotropicTextures: 1 + antiAliasing: 0 + softParticles: 0 + softVegetation: 0 + realtimeReflectionProbes: 0 + billboardsFaceCameraPosition: 0 + vSyncCount: 1 + lodBias: 0.7 + maximumLODLevel: 0 + streamingMipmapsActive: 0 + streamingMipmapsAddAllCameras: 1 + streamingMipmapsMemoryBudget: 512 + streamingMipmapsRenderersPerFrame: 512 + streamingMipmapsMaxLevelReduction: 2 + streamingMipmapsMaxFileIORequests: 1024 + particleRaycastBudget: 64 + asyncUploadTimeSlice: 2 + asyncUploadBufferSize: 16 + asyncUploadPersistentBuffer: 1 + resolutionScalingFixedDPIFactor: 1 + excludedTargetPlatforms: [] + - serializedVersion: 2 + name: High + pixelLightCount: 2 + shadows: 2 + shadowResolution: 1 + shadowProjection: 1 + shadowCascades: 2 + shadowDistance: 40 + shadowNearPlaneOffset: 3 + shadowCascade2Split: 0.33333334 + shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} + shadowmaskMode: 1 + blendWeights: 2 + textureQuality: 0 + anisotropicTextures: 1 + antiAliasing: 0 + softParticles: 0 + softVegetation: 1 + realtimeReflectionProbes: 1 + billboardsFaceCameraPosition: 1 + vSyncCount: 1 + lodBias: 1 + maximumLODLevel: 0 + streamingMipmapsActive: 0 + streamingMipmapsAddAllCameras: 1 + streamingMipmapsMemoryBudget: 512 + streamingMipmapsRenderersPerFrame: 512 + streamingMipmapsMaxLevelReduction: 2 + streamingMipmapsMaxFileIORequests: 1024 + particleRaycastBudget: 256 + asyncUploadTimeSlice: 2 + asyncUploadBufferSize: 16 + asyncUploadPersistentBuffer: 1 + resolutionScalingFixedDPIFactor: 1 + excludedTargetPlatforms: [] + - serializedVersion: 2 + name: Very High + pixelLightCount: 3 + shadows: 2 + shadowResolution: 2 + shadowProjection: 1 + shadowCascades: 2 + shadowDistance: 70 + shadowNearPlaneOffset: 3 + shadowCascade2Split: 0.33333334 + shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} + shadowmaskMode: 1 + blendWeights: 4 + textureQuality: 0 + anisotropicTextures: 2 + antiAliasing: 2 + softParticles: 1 + softVegetation: 1 + realtimeReflectionProbes: 1 + billboardsFaceCameraPosition: 1 + vSyncCount: 1 + lodBias: 1.5 + maximumLODLevel: 0 + streamingMipmapsActive: 0 + streamingMipmapsAddAllCameras: 1 + streamingMipmapsMemoryBudget: 512 + streamingMipmapsRenderersPerFrame: 512 + streamingMipmapsMaxLevelReduction: 2 + streamingMipmapsMaxFileIORequests: 1024 + particleRaycastBudget: 1024 + asyncUploadTimeSlice: 2 + asyncUploadBufferSize: 16 + asyncUploadPersistentBuffer: 1 + resolutionScalingFixedDPIFactor: 1 + excludedTargetPlatforms: [] + - serializedVersion: 2 + name: Ultra + pixelLightCount: 4 + shadows: 2 + shadowResolution: 2 + shadowProjection: 1 + shadowCascades: 4 + shadowDistance: 150 + shadowNearPlaneOffset: 3 + shadowCascade2Split: 0.33333334 + shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} + shadowmaskMode: 1 + blendWeights: 4 + textureQuality: 0 + anisotropicTextures: 2 + antiAliasing: 2 + softParticles: 1 + softVegetation: 1 + realtimeReflectionProbes: 1 + billboardsFaceCameraPosition: 1 + vSyncCount: 1 + lodBias: 2 + maximumLODLevel: 0 + streamingMipmapsActive: 0 + streamingMipmapsAddAllCameras: 1 + streamingMipmapsMemoryBudget: 512 + streamingMipmapsRenderersPerFrame: 512 + streamingMipmapsMaxLevelReduction: 2 + streamingMipmapsMaxFileIORequests: 1024 + particleRaycastBudget: 4096 + asyncUploadTimeSlice: 2 + asyncUploadBufferSize: 16 + asyncUploadPersistentBuffer: 1 + resolutionScalingFixedDPIFactor: 1 + excludedTargetPlatforms: [] + m_PerPlatformDefaultQuality: + Android: 2 + Lumin: 5 + GameCoreScarlett: 5 + GameCoreXboxOne: 5 + Nintendo 3DS: 5 + Nintendo Switch: 5 + PS4: 5 + PS5: 5 + Stadia: 5 + Standalone: 5 + WebGL: 3 + Windows Store Apps: 5 + XboxOne: 5 + iPhone: 2 + tvOS: 2 diff --git a/物品和背包的完整代码/Client/Unity/ProjectSettings/SceneTemplateSettings.json b/物品和背包的完整代码/Client/Unity/ProjectSettings/SceneTemplateSettings.json new file mode 100644 index 0000000..6f3e60f --- /dev/null +++ b/物品和背包的完整代码/Client/Unity/ProjectSettings/SceneTemplateSettings.json @@ -0,0 +1,167 @@ +{ + "templatePinStates": [], + "dependencyTypeInfos": [ + { + "userAdded": false, + "type": "UnityEngine.AnimationClip", + "ignore": false, + "defaultInstantiationMode": 0, + "supportsModification": true + }, + { + "userAdded": false, + "type": "UnityEditor.Animations.AnimatorController", + "ignore": false, + "defaultInstantiationMode": 0, + "supportsModification": true + }, + { + "userAdded": false, + "type": "UnityEngine.AnimatorOverrideController", + "ignore": false, + "defaultInstantiationMode": 0, + "supportsModification": true + }, + { + "userAdded": false, + "type": "UnityEditor.Audio.AudioMixerController", + "ignore": false, + "defaultInstantiationMode": 0, + "supportsModification": true + }, + { + "userAdded": false, + "type": "UnityEngine.ComputeShader", + "ignore": true, + "defaultInstantiationMode": 1, + "supportsModification": true + }, + { + "userAdded": false, + "type": "UnityEngine.Cubemap", + "ignore": false, + "defaultInstantiationMode": 0, + "supportsModification": true + }, + { + "userAdded": false, + "type": "UnityEngine.GameObject", + "ignore": false, + "defaultInstantiationMode": 0, + "supportsModification": true + }, + { + "userAdded": false, + "type": "UnityEditor.LightingDataAsset", + "ignore": false, + "defaultInstantiationMode": 0, + "supportsModification": false + }, + { + "userAdded": false, + "type": "UnityEngine.LightingSettings", + "ignore": false, + "defaultInstantiationMode": 0, + "supportsModification": true + }, + { + "userAdded": false, + "type": "UnityEngine.Material", + "ignore": false, + "defaultInstantiationMode": 0, + "supportsModification": true + }, + { + "userAdded": false, + "type": "UnityEditor.MonoScript", + "ignore": true, + "defaultInstantiationMode": 1, + "supportsModification": true + }, + { + "userAdded": false, + "type": "UnityEngine.PhysicMaterial", + "ignore": false, + "defaultInstantiationMode": 0, + "supportsModification": true + }, + { + "userAdded": false, + "type": "UnityEngine.PhysicsMaterial2D", + "ignore": false, + "defaultInstantiationMode": 0, + "supportsModification": true + }, + { + "userAdded": false, + "type": "UnityEngine.Rendering.PostProcessing.PostProcessProfile", + "ignore": false, + "defaultInstantiationMode": 0, + "supportsModification": true + }, + { + "userAdded": false, + "type": "UnityEngine.Rendering.PostProcessing.PostProcessResources", + "ignore": false, + "defaultInstantiationMode": 0, + "supportsModification": true + }, + { + "userAdded": false, + "type": "UnityEngine.Rendering.VolumeProfile", + "ignore": false, + "defaultInstantiationMode": 0, + "supportsModification": true + }, + { + "userAdded": false, + "type": "UnityEditor.SceneAsset", + "ignore": false, + "defaultInstantiationMode": 0, + "supportsModification": false + }, + { + "userAdded": false, + "type": "UnityEngine.Shader", + "ignore": true, + "defaultInstantiationMode": 1, + "supportsModification": true + }, + { + "userAdded": false, + "type": "UnityEngine.ShaderVariantCollection", + "ignore": true, + "defaultInstantiationMode": 1, + "supportsModification": true + }, + { + "userAdded": false, + "type": "UnityEngine.Texture", + "ignore": false, + "defaultInstantiationMode": 0, + "supportsModification": true + }, + { + "userAdded": false, + "type": "UnityEngine.Texture2D", + "ignore": false, + "defaultInstantiationMode": 0, + "supportsModification": true + }, + { + "userAdded": false, + "type": "UnityEngine.Timeline.TimelineAsset", + "ignore": false, + "defaultInstantiationMode": 0, + "supportsModification": true + } + ], + "defaultDependencyTypeInfo": { + "userAdded": false, + "type": "", + "ignore": false, + "defaultInstantiationMode": 1, + "supportsModification": true + }, + "newSceneOverride": 0 +} \ No newline at end of file diff --git a/物品和背包的完整代码/Client/Unity/ProjectSettings/TagManager.asset b/物品和背包的完整代码/Client/Unity/ProjectSettings/TagManager.asset new file mode 100644 index 0000000..1c92a78 --- /dev/null +++ b/物品和背包的完整代码/Client/Unity/ProjectSettings/TagManager.asset @@ -0,0 +1,43 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!78 &1 +TagManager: + serializedVersion: 2 + tags: [] + layers: + - Default + - TransparentFX + - Ignore Raycast + - + - Water + - UI + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + m_SortingLayers: + - name: Default + uniqueID: 0 + locked: 0 diff --git a/物品和背包的完整代码/Client/Unity/ProjectSettings/TimeManager.asset b/物品和背包的完整代码/Client/Unity/ProjectSettings/TimeManager.asset new file mode 100644 index 0000000..558a017 --- /dev/null +++ b/物品和背包的完整代码/Client/Unity/ProjectSettings/TimeManager.asset @@ -0,0 +1,9 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!5 &1 +TimeManager: + m_ObjectHideFlags: 0 + Fixed Timestep: 0.02 + Maximum Allowed Timestep: 0.33333334 + m_TimeScale: 1 + Maximum Particle Timestep: 0.03 diff --git a/物品和背包的完整代码/Client/Unity/ProjectSettings/UnityConnectSettings.asset b/物品和背包的完整代码/Client/Unity/ProjectSettings/UnityConnectSettings.asset new file mode 100644 index 0000000..a88bee0 --- /dev/null +++ b/物品和背包的完整代码/Client/Unity/ProjectSettings/UnityConnectSettings.asset @@ -0,0 +1,36 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!310 &1 +UnityConnectSettings: + m_ObjectHideFlags: 0 + serializedVersion: 1 + m_Enabled: 0 + m_TestMode: 0 + m_EventOldUrl: https://api.uca.cloud.unity3d.com/v1/events + m_EventUrl: https://cdp.cloud.unity3d.com/v1/events + m_ConfigUrl: https://config.uca.cloud.unity3d.com + m_DashboardUrl: https://dashboard.unity3d.com + m_TestInitMode: 0 + CrashReportingSettings: + m_EventUrl: https://perf-events.cloud.unity3d.com + m_Enabled: 0 + m_LogBufferSize: 10 + m_CaptureEditorExceptions: 1 + UnityPurchasingSettings: + m_Enabled: 0 + m_TestMode: 0 + UnityAnalyticsSettings: + m_Enabled: 0 + m_TestMode: 0 + m_InitializeOnStartup: 1 + m_PackageRequiringCoreStatsPresent: 0 + UnityAdsSettings: + m_Enabled: 0 + m_InitializeOnStartup: 1 + m_TestMode: 0 + m_IosGameId: + m_AndroidGameId: + m_GameIds: {} + m_GameId: + PerformanceReportingSettings: + m_Enabled: 0 diff --git a/物品和背包的完整代码/Client/Unity/ProjectSettings/VFXManager.asset b/物品和背包的完整代码/Client/Unity/ProjectSettings/VFXManager.asset new file mode 100644 index 0000000..3a95c98 --- /dev/null +++ b/物品和背包的完整代码/Client/Unity/ProjectSettings/VFXManager.asset @@ -0,0 +1,12 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!937362698 &1 +VFXManager: + m_ObjectHideFlags: 0 + m_IndirectShader: {fileID: 0} + m_CopyBufferShader: {fileID: 0} + m_SortShader: {fileID: 0} + m_StripUpdateShader: {fileID: 0} + m_RenderPipeSettingsPath: + m_FixedTimeStep: 0.016666668 + m_MaxDeltaTime: 0.05 diff --git a/物品和背包的完整代码/Client/Unity/ProjectSettings/VersionControlSettings.asset b/物品和背包的完整代码/Client/Unity/ProjectSettings/VersionControlSettings.asset new file mode 100644 index 0000000..dca2881 --- /dev/null +++ b/物品和背包的完整代码/Client/Unity/ProjectSettings/VersionControlSettings.asset @@ -0,0 +1,8 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!890905787 &1 +VersionControlSettings: + m_ObjectHideFlags: 0 + m_Mode: Visible Meta Files + m_CollabEditorSettings: + inProgressEnabled: 1 diff --git a/物品和背包的完整代码/Client/Unity/ProjectSettings/XRSettings.asset b/物品和背包的完整代码/Client/Unity/ProjectSettings/XRSettings.asset new file mode 100644 index 0000000..482590c --- /dev/null +++ b/物品和背包的完整代码/Client/Unity/ProjectSettings/XRSettings.asset @@ -0,0 +1,10 @@ +{ + "m_SettingKeys": [ + "VR Device Disabled", + "VR Device User Alert" + ], + "m_SettingValues": [ + "False", + "False" + ] +} \ No newline at end of file diff --git a/物品和背包的完整代码/Client/Unity/ProjectSettings/boot.config b/物品和背包的完整代码/Client/Unity/ProjectSettings/boot.config new file mode 100644 index 0000000..e69de29 diff --git a/物品和背包的完整代码/Client/Unity/Unity.sln b/物品和背包的完整代码/Client/Unity/Unity.sln new file mode 100644 index 0000000..2cfa71b --- /dev/null +++ b/物品和背包的完整代码/Client/Unity/Unity.sln @@ -0,0 +1,29 @@ + +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Fantasy.Unity", "Fantasy.Unity.csproj", "{d85fa58b-aca9-8bf0-e827-074457206988}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Fantasy.ConfigTable", "Fantasy.ConfigTable.csproj", "{8eb45200-d3be-6efd-d01e-a23e2721ecc7}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Assembly-CSharp", "Assembly-CSharp.csproj", "{03938ccd-4b40-8dfb-6b9b-21988d5cac0a}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Fantasy.Editor", "Fantasy.Editor.csproj", "{f09e7d37-0f11-85f5-9f5a-ea60c1261f78}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {d85fa58b-aca9-8bf0-e827-074457206988}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {d85fa58b-aca9-8bf0-e827-074457206988}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8eb45200-d3be-6efd-d01e-a23e2721ecc7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8eb45200-d3be-6efd-d01e-a23e2721ecc7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {03938ccd-4b40-8dfb-6b9b-21988d5cac0a}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {03938ccd-4b40-8dfb-6b9b-21988d5cac0a}.Debug|Any CPU.Build.0 = Debug|Any CPU + {f09e7d37-0f11-85f5-9f5a-ea60c1261f78}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {f09e7d37-0f11-85f5-9f5a-ea60c1261f78}.Debug|Any CPU.Build.0 = Debug|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/物品和背包的完整代码/Client/Unity/UserSettings/EditorUserSettings.asset b/物品和背包的完整代码/Client/Unity/UserSettings/EditorUserSettings.asset new file mode 100644 index 0000000..6a96f1e --- /dev/null +++ b/物品和背包的完整代码/Client/Unity/UserSettings/EditorUserSettings.asset @@ -0,0 +1,31 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!162 &1 +EditorUserSettings: + m_ObjectHideFlags: 0 + serializedVersion: 4 + m_ConfigSettings: + RecentlyUsedSceneGuid-0: + value: 5a5757560101590a5d0c0e24427b5d44434e4c7a7b7a23677f2b4565b7b5353a + flags: 0 + RecentlyUsedSceneGuid-1: + value: 5b035207510c0f0b0e5a582714775d4943164d287e2a7333287b1835e3e23669 + flags: 0 + vcSharedLogLevel: + value: 0d5e400f0650 + flags: 0 + m_VCAutomaticAdd: 1 + m_VCDebugCom: 0 + m_VCDebugCmd: 0 + m_VCDebugOut: 0 + m_SemanticMergeMode: 2 + m_DesiredImportWorkerCount: 4 + m_StandbyImportWorkerCount: 2 + m_IdleImportWorkerShutdownDelay: 60000 + m_VCShowFailedCheckout: 1 + m_VCOverwriteFailedCheckoutAssets: 1 + m_VCProjectOverlayIcons: 1 + m_VCHierarchyOverlayIcons: 1 + m_VCOtherOverlayIcons: 1 + m_VCAllowAsyncUpdate: 1 + m_ArtifactGarbageCollection: 1 diff --git a/物品和背包的完整代码/Client/Unity/UserSettings/Layouts/default-2021.dwlt b/物品和背包的完整代码/Client/Unity/UserSettings/Layouts/default-2021.dwlt new file mode 100644 index 0000000..f6a8354 --- /dev/null +++ b/物品和背包的完整代码/Client/Unity/UserSettings/Layouts/default-2021.dwlt @@ -0,0 +1,950 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &1 +MonoBehaviour: + m_ObjectHideFlags: 52 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 1 + m_Script: {fileID: 12004, guid: 0000000000000000e000000000000000, type: 0} + m_Name: + m_EditorClassIdentifier: + m_PixelRect: + serializedVersion: 2 + x: -1920 + y: 53 + width: 1920 + height: 1027 + m_ShowMode: 4 + m_Title: Scene + m_RootView: {fileID: 2} + m_MinSize: {x: 875, y: 542} + m_MaxSize: {x: 10000, y: 10000} + m_Maximized: 1 +--- !u!114 &2 +MonoBehaviour: + m_ObjectHideFlags: 52 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 1 + m_Script: {fileID: 12008, guid: 0000000000000000e000000000000000, type: 0} + m_Name: + m_EditorClassIdentifier: + m_Children: + - {fileID: 3} + - {fileID: 4} + - {fileID: 5} + m_Position: + serializedVersion: 2 + x: 0 + y: 0 + width: 1920 + height: 1027 + m_MinSize: {x: 875, y: 300} + m_MaxSize: {x: 10000, y: 10000} + m_UseTopView: 1 + m_TopViewHeight: 30 + m_UseBottomView: 1 + m_BottomViewHeight: 20 +--- !u!114 &3 +MonoBehaviour: + m_ObjectHideFlags: 52 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 1 + m_Script: {fileID: 12011, guid: 0000000000000000e000000000000000, type: 0} + m_Name: + m_EditorClassIdentifier: + m_Children: [] + m_Position: + serializedVersion: 2 + x: 0 + y: 0 + width: 1920 + height: 30 + m_MinSize: {x: 0, y: 0} + m_MaxSize: {x: 0, y: 0} + m_LastLoadedLayoutName: +--- !u!114 &4 +MonoBehaviour: + m_ObjectHideFlags: 52 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 1 + m_Script: {fileID: 12010, guid: 0000000000000000e000000000000000, type: 0} + m_Name: + m_EditorClassIdentifier: + m_Children: + - {fileID: 6} + - {fileID: 7} + - {fileID: 8} + m_Position: + serializedVersion: 2 + x: 0 + y: 30 + width: 1920 + height: 977 + m_MinSize: {x: 300, y: 200} + m_MaxSize: {x: 24288, y: 16192} + vertical: 0 + controlID: 60 +--- !u!114 &5 +MonoBehaviour: + m_ObjectHideFlags: 52 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 1 + m_Script: {fileID: 12042, guid: 0000000000000000e000000000000000, type: 0} + m_Name: + m_EditorClassIdentifier: + m_Children: [] + m_Position: + serializedVersion: 2 + x: 0 + y: 1007 + width: 1920 + height: 20 + m_MinSize: {x: 0, y: 0} + m_MaxSize: {x: 0, y: 0} +--- !u!114 &6 +MonoBehaviour: + m_ObjectHideFlags: 52 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 1 + m_Script: {fileID: 12006, guid: 0000000000000000e000000000000000, type: 0} + m_Name: SceneView + m_EditorClassIdentifier: + m_Children: [] + m_Position: + serializedVersion: 2 + x: 0 + y: 0 + width: 980.5 + height: 977 + m_MinSize: {x: 201, y: 221} + m_MaxSize: {x: 4001, y: 4021} + m_ActualView: {fileID: 15} + m_Panes: + - {fileID: 15} + - {fileID: 14} + m_Selected: 0 + m_LastSelected: 1 +--- !u!114 &7 +MonoBehaviour: + m_ObjectHideFlags: 52 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 1 + m_Script: {fileID: 12010, guid: 0000000000000000e000000000000000, type: 0} + m_Name: + m_EditorClassIdentifier: + m_Children: + - {fileID: 9} + - {fileID: 10} + m_Position: + serializedVersion: 2 + x: 980.5 + y: 0 + width: 517 + height: 977 + m_MinSize: {x: 100, y: 200} + m_MaxSize: {x: 8096, y: 16192} + vertical: 1 + controlID: 71 +--- !u!114 &8 +MonoBehaviour: + m_ObjectHideFlags: 52 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 1 + m_Script: {fileID: 12006, guid: 0000000000000000e000000000000000, type: 0} + m_Name: + m_EditorClassIdentifier: + m_Children: [] + m_Position: + serializedVersion: 2 + x: 1497.5 + y: 0 + width: 422.5 + height: 977 + m_MinSize: {x: 275, y: 50} + m_MaxSize: {x: 4000, y: 4000} + m_ActualView: {fileID: 12} + m_Panes: + - {fileID: 12} + m_Selected: 0 + m_LastSelected: 0 +--- !u!114 &9 +MonoBehaviour: + m_ObjectHideFlags: 52 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 1 + m_Script: {fileID: 12006, guid: 0000000000000000e000000000000000, type: 0} + m_Name: + m_EditorClassIdentifier: + m_Children: [] + m_Position: + serializedVersion: 2 + x: 0 + y: 0 + width: 517 + height: 426.5 + m_MinSize: {x: 200, y: 200} + m_MaxSize: {x: 4000, y: 4000} + m_ActualView: {fileID: 16} + m_Panes: + - {fileID: 16} + m_Selected: 0 + m_LastSelected: 0 +--- !u!114 &10 +MonoBehaviour: + m_ObjectHideFlags: 52 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 1 + m_Script: {fileID: 12006, guid: 0000000000000000e000000000000000, type: 0} + m_Name: ConsoleWindow + m_EditorClassIdentifier: + m_Children: [] + m_Position: + serializedVersion: 2 + x: 0 + y: 426.5 + width: 517 + height: 550.5 + m_MinSize: {x: 100, y: 100} + m_MaxSize: {x: 4000, y: 4000} + m_ActualView: {fileID: 11} + m_Panes: + - {fileID: 13} + - {fileID: 11} + m_Selected: 1 + m_LastSelected: 0 +--- !u!114 &11 +MonoBehaviour: + m_ObjectHideFlags: 52 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 12003, guid: 0000000000000000e000000000000000, type: 0} + m_Name: + m_EditorClassIdentifier: + m_MinSize: {x: 100, y: 100} + m_MaxSize: {x: 4000, y: 4000} + m_TitleContent: + m_Text: Console + m_Image: {fileID: -4950941429401207979, guid: 0000000000000000d000000000000000, type: 0} + m_Tooltip: + m_Pos: + serializedVersion: 2 + x: -939.5 + y: 509.5 + width: 515 + height: 529.5 + m_ViewDataDictionary: {fileID: 0} + m_OverlayCanvas: + m_LastAppliedPresetName: Default + m_SaveData: [] +--- !u!114 &12 +MonoBehaviour: + m_ObjectHideFlags: 52 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 1 + m_Script: {fileID: 12019, guid: 0000000000000000e000000000000000, type: 0} + m_Name: + m_EditorClassIdentifier: + m_MinSize: {x: 275, y: 50} + m_MaxSize: {x: 4000, y: 4000} + m_TitleContent: + m_Text: Inspector + m_Image: {fileID: -440750813802333266, guid: 0000000000000000d000000000000000, type: 0} + m_Tooltip: + m_Pos: + serializedVersion: 2 + x: -422.5 + y: 83 + width: 421.5 + height: 956 + m_ViewDataDictionary: {fileID: 0} + m_OverlayCanvas: + m_LastAppliedPresetName: Default + m_SaveData: [] + m_ObjectsLockedBeforeSerialization: [] + m_InstanceIDsLockedBeforeSerialization: + m_PreviewResizer: + m_CachedPref: 160 + m_ControlHash: -371814159 + m_PrefName: Preview_InspectorPreview + m_LastInspectedObjectInstanceID: -1 + m_LastVerticalScrollValue: 0 + m_GlobalObjectId: + m_InspectorMode: 0 + m_LockTracker: + m_IsLocked: 0 + m_PreviewWindow: {fileID: 0} +--- !u!114 &13 +MonoBehaviour: + m_ObjectHideFlags: 52 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 1 + m_Script: {fileID: 12014, guid: 0000000000000000e000000000000000, type: 0} + m_Name: + m_EditorClassIdentifier: + m_MinSize: {x: 230, y: 250} + m_MaxSize: {x: 10000, y: 10000} + m_TitleContent: + m_Text: Project + m_Image: {fileID: -5179483145760003458, guid: 0000000000000000d000000000000000, type: 0} + m_Tooltip: + m_Pos: + serializedVersion: 2 + x: -937 + y: 512 + width: 514 + height: 527 + m_ViewDataDictionary: {fileID: 0} + m_OverlayCanvas: + m_LastAppliedPresetName: Default + m_SaveData: [] + m_SearchFilter: + m_NameFilter: + m_ClassNames: [] + m_AssetLabels: [] + m_AssetBundleNames: [] + m_VersionControlStates: [] + m_SoftLockControlStates: [] + m_ReferencingInstanceIDs: + m_SceneHandles: + m_ShowAllHits: 0 + m_SkipHidden: 0 + m_SearchArea: 1 + m_Folders: + - Assets/Scenes + m_Globs: [] + m_OriginalText: + m_ViewMode: 0 + m_StartGridSize: 64 + m_LastFolders: + - Assets + m_LastFoldersGridSize: -1 + m_LastProjectPath: "/Users/fantasy/Movies/\u7269\u54C1\u80CC\u5305\u5F00\u53D1\u4E4B\u65C5/B/Client/Unity" + m_LockTracker: + m_IsLocked: 0 + m_FolderTreeState: + scrollPos: {x: 0, y: 0} + m_SelectedIDs: 105d0000 + m_LastClickedID: 23824 + m_ExpandedIDs: 00000000b05d0000b25d0000 + m_RenameOverlay: + m_UserAcceptedRename: 0 + m_Name: + m_OriginalName: + m_EditFieldRect: + serializedVersion: 2 + x: 0 + y: 0 + width: 0 + height: 0 + m_UserData: 0 + m_IsWaitingForDelay: 0 + m_IsRenaming: 0 + m_OriginalEventType: 11 + m_IsRenamingFilename: 1 + m_ClientGUIView: {fileID: 0} + m_SearchString: + m_CreateAssetUtility: + m_EndAction: {fileID: 0} + m_InstanceID: 0 + m_Path: + m_Icon: {fileID: 0} + m_ResourceFile: + m_AssetTreeState: + scrollPos: {x: 0, y: 0} + m_SelectedIDs: 5e5d0000 + m_LastClickedID: 23902 + m_ExpandedIDs: 00000000b05d0000b25d0000 + m_RenameOverlay: + m_UserAcceptedRename: 0 + m_Name: + m_OriginalName: + m_EditFieldRect: + serializedVersion: 2 + x: 0 + y: 0 + width: 0 + height: 0 + m_UserData: 0 + m_IsWaitingForDelay: 0 + m_IsRenaming: 0 + m_OriginalEventType: 11 + m_IsRenamingFilename: 1 + m_ClientGUIView: {fileID: 10} + m_SearchString: + m_CreateAssetUtility: + m_EndAction: {fileID: 0} + m_InstanceID: 0 + m_Path: + m_Icon: {fileID: 0} + m_ResourceFile: + m_ListAreaState: + m_SelectedInstanceIDs: 5e5d0000 + m_LastClickedInstanceID: 23902 + m_HadKeyboardFocusLastEvent: 0 + m_ExpandedInstanceIDs: c6230000 + m_RenameOverlay: + m_UserAcceptedRename: 0 + m_Name: + m_OriginalName: + m_EditFieldRect: + serializedVersion: 2 + x: 0 + y: 0 + width: 0 + height: 0 + m_UserData: 0 + m_IsWaitingForDelay: 0 + m_IsRenaming: 0 + m_OriginalEventType: 11 + m_IsRenamingFilename: 1 + m_ClientGUIView: {fileID: 0} + m_CreateAssetUtility: + m_EndAction: {fileID: 0} + m_InstanceID: 0 + m_Path: + m_Icon: {fileID: 0} + m_ResourceFile: + m_NewAssetIndexInList: -1 + m_ScrollPosition: {x: 0, y: 0} + m_GridSize: 64 + m_SkipHiddenPackages: 0 + m_DirectoriesAreaWidth: 115 +--- !u!114 &14 +MonoBehaviour: + m_ObjectHideFlags: 52 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 1 + m_Script: {fileID: 12015, guid: 0000000000000000e000000000000000, type: 0} + m_Name: + m_EditorClassIdentifier: + m_MinSize: {x: 200, y: 200} + m_MaxSize: {x: 4000, y: 4000} + m_TitleContent: + m_Text: Game + m_Image: {fileID: 4621777727084837110, guid: 0000000000000000d000000000000000, type: 0} + m_Tooltip: + m_Pos: + serializedVersion: 2 + x: -1920 + y: 83 + width: 979.5 + height: 956 + m_ViewDataDictionary: {fileID: 0} + m_OverlayCanvas: + m_LastAppliedPresetName: Default + m_SaveData: [] + m_SerializedViewNames: [] + m_SerializedViewValues: [] + m_PlayModeViewName: GameView + m_ShowGizmos: 0 + m_TargetDisplay: 0 + m_ClearColor: {r: 0, g: 0, b: 0, a: 0} + m_TargetSize: {x: 1959, y: 1870} + m_TextureFilterMode: 0 + m_TextureHideFlags: 61 + m_RenderIMGUI: 1 + m_EnterPlayModeBehavior: 0 + m_UseMipMap: 0 + m_VSyncEnabled: 0 + m_Gizmos: 0 + m_Stats: 0 + m_SelectedSizes: 00000000000000000000000000000000000000000000000000000000000000000000000000000000 + m_ZoomArea: + m_HRangeLocked: 0 + m_VRangeLocked: 0 + hZoomLockedByDefault: 0 + vZoomLockedByDefault: 0 + m_HBaseRangeMin: -489.75 + m_HBaseRangeMax: 489.75 + m_VBaseRangeMin: -467.5 + m_VBaseRangeMax: 467.5 + m_HAllowExceedBaseRangeMin: 1 + m_HAllowExceedBaseRangeMax: 1 + m_VAllowExceedBaseRangeMin: 1 + m_VAllowExceedBaseRangeMax: 1 + m_ScaleWithWindow: 0 + m_HSlider: 0 + m_VSlider: 0 + m_IgnoreScrollWheelUntilClicked: 0 + m_EnableMouseInput: 0 + m_EnableSliderZoomHorizontal: 0 + m_EnableSliderZoomVertical: 0 + m_UniformScale: 1 + m_UpDirection: 1 + m_DrawArea: + serializedVersion: 2 + x: 0 + y: 21 + width: 979.5 + height: 935 + m_Scale: {x: 1, y: 1} + m_Translation: {x: 489.75, y: 467.5} + m_MarginLeft: 0 + m_MarginRight: 0 + m_MarginTop: 0 + m_MarginBottom: 0 + m_LastShownAreaInsideMargins: + serializedVersion: 2 + x: -489.75 + y: -467.5 + width: 979.5 + height: 935 + m_MinimalGUI: 1 + m_defaultScale: 1 + m_LastWindowPixelSize: {x: 1959, y: 1912} + m_ClearInEditMode: 1 + m_NoCameraWarning: 1 + m_LowResolutionForAspectRatios: 00000000000000000000 + m_XRRenderMode: 0 + m_RenderTexture: {fileID: 0} +--- !u!114 &15 +MonoBehaviour: + m_ObjectHideFlags: 52 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 1 + m_Script: {fileID: 12013, guid: 0000000000000000e000000000000000, type: 0} + m_Name: + m_EditorClassIdentifier: + m_MinSize: {x: 200, y: 200} + m_MaxSize: {x: 4000, y: 4000} + m_TitleContent: + m_Text: Scene + m_Image: {fileID: 8634526014445323508, guid: 0000000000000000d000000000000000, type: 0} + m_Tooltip: + m_Pos: + serializedVersion: 2 + x: -1920 + y: 83 + width: 979.5 + height: 956 + m_ViewDataDictionary: {fileID: 0} + m_OverlayCanvas: + m_LastAppliedPresetName: Default + m_SaveData: + - dockPosition: 0 + containerId: overlay-toolbar__top + floating: 0 + collapsed: 0 + displayed: 1 + snapOffset: {x: -101, y: -26} + snapOffsetDelta: {x: 0, y: 0} + snapCorner: 3 + id: Tool Settings + index: 0 + layout: 1 + - dockPosition: 0 + containerId: overlay-toolbar__top + floating: 0 + collapsed: 0 + displayed: 1 + snapOffset: {x: -141, y: 149} + snapOffsetDelta: {x: 0, y: 0} + snapCorner: 1 + id: unity-grid-and-snap-toolbar + index: 1 + layout: 1 + - dockPosition: 1 + containerId: overlay-toolbar__top + floating: 0 + collapsed: 0 + displayed: 1 + snapOffset: {x: 0, y: 0} + snapOffsetDelta: {x: 0, y: 0} + snapCorner: 0 + id: unity-scene-view-toolbar + index: 0 + layout: 1 + - dockPosition: 1 + containerId: overlay-toolbar__top + floating: 0 + collapsed: 0 + displayed: 0 + snapOffset: {x: 0, y: 0} + snapOffsetDelta: {x: 0, y: 0} + snapCorner: 1 + id: unity-search-toolbar + index: 1 + layout: 1 + - dockPosition: 0 + containerId: overlay-container--left + floating: 0 + collapsed: 0 + displayed: 1 + snapOffset: {x: 0, y: 0} + snapOffsetDelta: {x: 0, y: 0} + snapCorner: 0 + id: unity-transform-toolbar + index: 0 + layout: 2 + - dockPosition: 0 + containerId: overlay-container--left + floating: 0 + collapsed: 0 + displayed: 1 + snapOffset: {x: 0, y: 197} + snapOffsetDelta: {x: 0, y: 0} + snapCorner: 0 + id: unity-component-tools + index: 1 + layout: 2 + - dockPosition: 0 + containerId: overlay-container--right + floating: 0 + collapsed: 0 + displayed: 1 + snapOffset: {x: 67.5, y: 86} + snapOffsetDelta: {x: 0, y: 0} + snapCorner: 0 + id: Orientation + index: 0 + layout: 4 + - dockPosition: 1 + containerId: overlay-container--right + floating: 0 + collapsed: 0 + displayed: 0 + snapOffset: {x: 0, y: 0} + snapOffsetDelta: {x: 0, y: 0} + snapCorner: 0 + id: Scene View/Light Settings + index: 0 + layout: 4 + - dockPosition: 1 + containerId: overlay-container--right + floating: 0 + collapsed: 0 + displayed: 0 + snapOffset: {x: 0, y: 0} + snapOffsetDelta: {x: 0, y: 0} + snapCorner: 0 + id: Scene View/Camera + index: 1 + layout: 4 + - dockPosition: 1 + containerId: overlay-container--right + floating: 0 + collapsed: 0 + displayed: 0 + snapOffset: {x: 0, y: 0} + snapOffsetDelta: {x: 0, y: 0} + snapCorner: 0 + id: Scene View/Cloth Constraints + index: 2 + layout: 4 + - dockPosition: 1 + containerId: overlay-container--right + floating: 0 + collapsed: 0 + displayed: 0 + snapOffset: {x: 0, y: 0} + snapOffsetDelta: {x: 0, y: 0} + snapCorner: 0 + id: Scene View/Cloth Collisions + index: 3 + layout: 4 + - dockPosition: 1 + containerId: overlay-container--right + floating: 0 + collapsed: 0 + displayed: 0 + snapOffset: {x: 0, y: 0} + snapOffsetDelta: {x: 0, y: 0} + snapCorner: 0 + id: Scene View/Navmesh Display + index: 4 + layout: 4 + - dockPosition: 1 + containerId: overlay-container--right + floating: 0 + collapsed: 0 + displayed: 0 + snapOffset: {x: 0, y: 0} + snapOffsetDelta: {x: 0, y: 0} + snapCorner: 0 + id: Scene View/Agent Display + index: 5 + layout: 4 + - dockPosition: 1 + containerId: overlay-container--right + floating: 0 + collapsed: 0 + displayed: 0 + snapOffset: {x: 0, y: 0} + snapOffsetDelta: {x: 0, y: 0} + snapCorner: 0 + id: Scene View/Obstacle Display + index: 6 + layout: 4 + - dockPosition: 1 + containerId: overlay-container--right + floating: 0 + collapsed: 0 + displayed: 0 + snapOffset: {x: 0, y: 0} + snapOffsetDelta: {x: 0, y: 0} + snapCorner: 0 + id: Scene View/Occlusion Culling + index: 7 + layout: 4 + - dockPosition: 1 + containerId: overlay-container--right + floating: 0 + collapsed: 0 + displayed: 0 + snapOffset: {x: 0, y: 0} + snapOffsetDelta: {x: 0, y: 0} + snapCorner: 0 + id: Scene View/Physics Debugger + index: 8 + layout: 4 + - dockPosition: 1 + containerId: overlay-container--right + floating: 0 + collapsed: 0 + displayed: 0 + snapOffset: {x: 0, y: 0} + snapOffsetDelta: {x: 0, y: 0} + snapCorner: 0 + id: Scene View/Scene Visibility + index: 9 + layout: 4 + - dockPosition: 1 + containerId: overlay-container--right + floating: 0 + collapsed: 0 + displayed: 0 + snapOffset: {x: 0, y: 0} + snapOffsetDelta: {x: 0, y: 0} + snapCorner: 0 + id: Scene View/Particles + index: 10 + layout: 4 + - dockPosition: 1 + containerId: overlay-container--right + floating: 0 + collapsed: 0 + displayed: 0 + snapOffset: {x: 0, y: 0} + snapOffsetDelta: {x: 0, y: 0} + snapCorner: 0 + id: Scene View/Tilemap + index: 11 + layout: 4 + - dockPosition: 1 + containerId: overlay-container--right + floating: 0 + collapsed: 0 + displayed: 0 + snapOffset: {x: 0, y: 0} + snapOffsetDelta: {x: 0, y: 0} + snapCorner: 0 + id: Scene View/Tilemap Palette Helper + index: 12 + layout: 4 + m_WindowGUID: 7baa9ba73fc4e4f3a914569e791b8341 + m_Gizmos: 1 + m_OverrideSceneCullingMask: 6917529027641081856 + m_SceneIsLit: 1 + m_SceneLighting: 1 + m_2DMode: 1 + m_isRotationLocked: 0 + m_PlayAudio: 0 + m_AudioPlay: 0 + m_Position: + m_Target: {x: 982, y: 935, z: 0} + speed: 2 + m_Value: {x: 982, y: 935, z: 0} + m_RenderMode: 0 + m_CameraMode: + drawMode: 0 + name: Shaded + section: Shading Mode + m_ValidateTrueMetals: 0 + m_DoValidateTrueMetals: 0 + m_ExposureSliderValue: 0 + m_SceneViewState: + m_AlwaysRefresh: 0 + showFog: 1 + showSkybox: 1 + showFlares: 1 + showImageEffects: 1 + showParticleSystems: 1 + showVisualEffectGraphs: 1 + m_FxEnabled: 1 + m_Grid: + xGrid: + m_Fade: + m_Target: 0 + speed: 2 + m_Value: 0 + m_Color: {r: 0.5, g: 0.5, b: 0.5, a: 0.4} + m_Pivot: {x: 0, y: 0, z: 0} + m_Size: {x: 0, y: 0} + yGrid: + m_Fade: + m_Target: 0 + speed: 2 + m_Value: 0 + m_Color: {r: 0.5, g: 0.5, b: 0.5, a: 0.4} + m_Pivot: {x: 0, y: 0, z: 0} + m_Size: {x: 1, y: 1} + zGrid: + m_Fade: + m_Target: 1 + speed: 2 + m_Value: 1 + m_Color: {r: 0.5, g: 0.5, b: 0.5, a: 0.4} + m_Pivot: {x: 0, y: 0, z: 0} + m_Size: {x: 1, y: 1} + m_ShowGrid: 1 + m_GridAxis: 1 + m_gridOpacity: 0.5 + m_Rotation: + m_Target: {x: 0, y: 0, z: 0, w: 1} + speed: 2 + m_Value: {x: 0, y: 0, z: 0, w: 1} + m_Size: + m_Target: 1355.931 + speed: 2 + m_Value: 1355.931 + m_Ortho: + m_Target: 1 + speed: 2 + m_Value: 1 + m_CameraSettings: + m_Speed: 1 + m_SpeedNormalized: 0.5 + m_SpeedMin: 0.01 + m_SpeedMax: 2 + m_EasingEnabled: 1 + m_EasingDuration: 0.4 + m_AccelerationEnabled: 1 + m_FieldOfViewHorizontalOrVertical: 60 + m_NearClip: 0.03 + m_FarClip: 10000 + m_DynamicClip: 1 + m_OcclusionCulling: 0 + m_LastSceneViewRotation: {x: -0.08717229, y: 0.89959055, z: -0.21045254, w: -0.3726226} + m_LastSceneViewOrtho: 0 + m_ReplacementShader: {fileID: 0} + m_ReplacementString: + m_SceneVisActive: 1 + m_LastLockedObject: {fileID: 0} + m_ViewIsLockedToObject: 0 +--- !u!114 &16 +MonoBehaviour: + m_ObjectHideFlags: 52 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 1 + m_Script: {fileID: 12061, guid: 0000000000000000e000000000000000, type: 0} + m_Name: + m_EditorClassIdentifier: + m_MinSize: {x: 200, y: 200} + m_MaxSize: {x: 4000, y: 4000} + m_TitleContent: + m_Text: Hierarchy + m_Image: {fileID: -3734745235275155857, guid: 0000000000000000d000000000000000, type: 0} + m_Tooltip: + m_Pos: + serializedVersion: 2 + x: -939.5 + y: 83 + width: 515 + height: 405.5 + m_ViewDataDictionary: {fileID: 0} + m_OverlayCanvas: + m_LastAppliedPresetName: Default + m_SaveData: [] + m_SceneHierarchy: + m_TreeViewState: + scrollPos: {x: 0, y: 0} + m_SelectedIDs: + m_LastClickedID: 0 + m_ExpandedIDs: 22fbffff + m_RenameOverlay: + m_UserAcceptedRename: 0 + m_Name: + m_OriginalName: + m_EditFieldRect: + serializedVersion: 2 + x: 0 + y: 0 + width: 0 + height: 0 + m_UserData: 0 + m_IsWaitingForDelay: 0 + m_IsRenaming: 0 + m_OriginalEventType: 11 + m_IsRenamingFilename: 0 + m_ClientGUIView: {fileID: 9} + m_SearchString: + m_ExpandedScenes: [] + m_CurrenRootInstanceID: 0 + m_LockTracker: + m_IsLocked: 0 + m_CurrentSortingName: TransformSorting + m_WindowGUID: 46c36a87d2c1d4c8dbff6c717cb3ee59 diff --git a/物品和背包的完整代码/Config/.DS_Store b/物品和背包的完整代码/Config/.DS_Store new file mode 100644 index 0000000..8eb2220 Binary files /dev/null and b/物品和背包的完整代码/Config/.DS_Store differ diff --git a/物品和背包的完整代码/Config/Binary/ContainerConfigData.bytes b/物品和背包的完整代码/Config/Binary/ContainerConfigData.bytes new file mode 100644 index 0000000..5f74585 --- /dev/null +++ b/物品和背包的完整代码/Config/Binary/ContainerConfigData.bytes @@ -0,0 +1,10 @@ + +Bag +( +08 +Equip +( +08 +Trade +( +08 \ No newline at end of file diff --git a/物品和背包的完整代码/Config/Binary/EquipAffixConfigData.bytes b/物品和背包的完整代码/Config/Binary/EquipAffixConfigData.bytes new file mode 100644 index 0000000..94dc7ae --- /dev/null +++ b/物品和背包的完整代码/Config/Binary/EquipAffixConfigData.bytes @@ -0,0 +1,4 @@ + +$ 装备上每秒恢复5点血 +Gš ?装备上每次攻击增加6点攻击力,最高增加了30点 +&Ú 装备上增加100点法力值 \ No newline at end of file diff --git a/物品和背包的完整代码/Config/Binary/EquipEntryConfigData.bytes b/物品和背包的完整代码/Config/Binary/EquipEntryConfigData.bytes new file mode 100644 index 0000000..3d97c10 --- /dev/null +++ b/物品和背包的完整代码/Config/Binary/EquipEntryConfigData.bytes @@ -0,0 +1,9 @@ + +( (0008 88 8š 88 +8Ú 88 +( (0008 88 +8š 88 +8Ú 88 +( (0008 88 +8š 88 +8Ú 88 \ No newline at end of file diff --git a/物品和背包的完整代码/Config/Binary/EquipValueConfigData.bytes b/物品和背包的完整代码/Config/Binary/EquipValueConfigData.bytes new file mode 100644 index 0000000..99900bc --- /dev/null +++ b/物品和背包的完整代码/Config/Binary/EquipValueConfigData.bytes @@ -0,0 +1,13 @@ + +$= * +  +š  +Ú  +$„= * +  +š  +Ú  +$Ä= * +  +š  +Ú  \ No newline at end of file diff --git a/物品和背包的完整代码/Config/Binary/ErrorCodeData.bytes b/物品和背包的完整代码/Config/Binary/ErrorCodeData.bytes new file mode 100644 index 0000000..f32d886 --- /dev/null +++ b/物品和背包的完整代码/Config/Binary/ErrorCodeData.bytes @@ -0,0 +1,4 @@ + + +LoingError 登陆失败 +&LoginRoleError角色登陆失败 \ No newline at end of file diff --git a/物品和背包的完整代码/Config/Binary/ItemConfigData.bytes b/物品和背包的完整代码/Config/Binary/ItemConfigData.bytes new file mode 100644 index 0000000..a4a68cd --- /dev/null +++ b/物品和背包的完整代码/Config/Binary/ItemConfigData.bytes @@ -0,0 +1,13 @@ + +\ 恢复药剂A!使用后,会提升体力200点 *Item_0108 +@HPXX`j10000j200 +\ 恢复药剂B!使用后,会提升体力400点 *Item_0108 +@HPXX`j10001j400 +} 恢复药剂C6使用后,会提升体力400点,提升法力值300 *Item_0108 +@HPXX`j10000j400j10001j300 +P= 幻想大剑这个是介绍 *Item_018@HPXX`j10000j200pdx +P„= 幻想头盔这个是介绍 *Item_028@HPXX`j10000j200pdx +PÄ= 幻想衣服这个是介绍 *Item_038@HPXX`j10000j200pdx +PĄ= 幻想护腿这个是介绍 *Item_048@HPXX`j10000j200pdx +Pń= 幻想护腕这个是介绍 *Item_058@HPXX`j10000j200pdx +PƄ= 幻想鞋子这个是介绍 *Item_068@HPXX`j10000j200pdx \ No newline at end of file diff --git a/物品和背包的完整代码/Config/Binary/LevelConfigData.bytes b/物品和背包的完整代码/Config/Binary/LevelConfigData.bytes new file mode 100644 index 0000000..25b9f15 --- /dev/null +++ b/物品和背包的完整代码/Config/Binary/LevelConfigData.bytes @@ -0,0 +1,5 @@ + +Unit01Unit01  +Unit02Unit02  +Unit03Unit03  +Unit04Unit04  \ No newline at end of file diff --git a/物品和背包的完整代码/Config/Binary/MachineConfigData.bytes b/物品和背包的完整代码/Config/Binary/MachineConfigData.bytes new file mode 100644 index 0000000..d4ebe57 --- /dev/null +++ b/物品和背包的完整代码/Config/Binary/MachineConfigData.bytes @@ -0,0 +1,2 @@ + +# 127.0.0.1 127.0.0.1" 127.0.0.1 \ No newline at end of file diff --git a/物品和背包的完整代码/Config/Binary/ProcessConfigData.bytes b/物品和背包的完整代码/Config/Binary/ProcessConfigData.bytes new file mode 100644 index 0000000..b9c2dfd --- /dev/null +++ b/物品和背包的完整代码/Config/Binary/ProcessConfigData.bytes @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/物品和背包的完整代码/Config/Binary/SceneConfigData.bytes b/物品和背包的完整代码/Config/Binary/SceneConfigData.bytes new file mode 100644 index 0000000..be1408a --- /dev/null +++ b/物品和背包的完整代码/Config/Binary/SceneConfigData.bytes @@ -0,0 +1,3 @@ + +&" MultiThread* Addressable@UH +(" MultiThread*Gate2KCP8@UH \ No newline at end of file diff --git a/物品和背包的完整代码/Config/Binary/UnitConfigData.bytes b/物品和背包的完整代码/Config/Binary/UnitConfigData.bytes new file mode 100644 index 0000000..cb491ec --- /dev/null +++ b/物品和背包的完整代码/Config/Binary/UnitConfigData.bytes @@ -0,0 +1,4 @@ + +(地精投资公司职员Unit03 ( ++希尔瓦娜斯·风行者Unit02 0N +/ 牛头人Unit01 8@@HHHHHHHHH \ No newline at end of file diff --git a/物品和背包的完整代码/Config/Binary/WorldConfigData.bytes b/物品和背包的完整代码/Config/Binary/WorldConfigData.bytes new file mode 100644 index 0000000..3940725 --- /dev/null +++ b/物品和背包的完整代码/Config/Binary/WorldConfigData.bytes @@ -0,0 +1,2 @@ + +> 测试服mongodb://192.168.31.100" fantasy_main*MongoDB \ No newline at end of file diff --git a/物品和背包的完整代码/Config/Excel/#ConstValue.xlsx b/物品和背包的完整代码/Config/Excel/#ConstValue.xlsx new file mode 100644 index 0000000..abea141 Binary files /dev/null and b/物品和背包的完整代码/Config/Excel/#ConstValue.xlsx differ diff --git a/物品和背包的完整代码/Config/Excel/.DS_Store b/物品和背包的完整代码/Config/Excel/.DS_Store new file mode 100644 index 0000000..bcff88e Binary files /dev/null and b/物品和背包的完整代码/Config/Excel/.DS_Store differ diff --git a/物品和背包的完整代码/Config/Excel/ContainerConfig.xlsx b/物品和背包的完整代码/Config/Excel/ContainerConfig.xlsx new file mode 100644 index 0000000..de1fab2 Binary files /dev/null and b/物品和背包的完整代码/Config/Excel/ContainerConfig.xlsx differ diff --git a/物品和背包的完整代码/Config/Excel/Custom.txt b/物品和背包的完整代码/Config/Excel/Custom.txt new file mode 100644 index 0000000..78ed5a6 --- /dev/null +++ b/物品和背包的完整代码/Config/Excel/Custom.txt @@ -0,0 +1,6 @@ +// 自定义导出配置文件,用于配置自定义导出自定义程序的路径,每行一个路径,路径是导表应用的相对路径。如:../../Config/Custom/1.cs +../../Config/Excel/Custom/ErrorCodeToConst.cs +../../Config/Excel/Custom/ConstValueToConst.cs +../../Config/Excel/Custom/ItemTypeToEnum.cs +../../Config/Excel/Custom/ItemUseEffectToEnum.cs +../../Config/Excel/Custom/ContainerConfigToEnum.cs \ No newline at end of file diff --git a/物品和背包的完整代码/Config/Excel/Custom/ConstValueToConst.cs b/物品和背包的完整代码/Config/Excel/Custom/ConstValueToConst.cs new file mode 100644 index 0000000..890ccb7 --- /dev/null +++ b/物品和背包的完整代码/Config/Excel/Custom/ConstValueToConst.cs @@ -0,0 +1,148 @@ +using System; +using System.Text; +using Fantasy.Exporter; +using Fantasy.Tools.ConfigTable; +using System.Collections.Generic; + +namespace Exporter; + +public class ConstValueToConst : ACustomExport +{ + private class ConstValueInfo + { + public string Name; + public string Type; + public string Value; + public string Remark; + } + [Flags] + private enum ExportType + { + None = 0, + Server = 1, + Client = 1 << 1, + All = Server | Client + } + public override void Run() + { + if (!ExcelExporter.IgnoreTable.TryGetValue("#ConstValue", out var constValuePath)) + { + Log.Error("ConstValue is null"); + return; + } + + var serverDic = new List(); + var clientDic = new List(); + var excelWorksheet = ExcelExporter.LoadExcel(constValuePath, false); + + for (int row = 2; row <= excelWorksheet.Dimension.Rows; row++) + { + var exportType = ExportType.All; + var exportTypeStr = excelWorksheet.GetCellValue(row, 1); + + if (!string.IsNullOrEmpty(exportTypeStr)) + { + exportType = ExportType.None; + exportTypeStr = exportTypeStr.ToUpper(); + + if (exportTypeStr.Contains("S")) + { + exportType |= ExportType.Server; + } + + if (exportTypeStr.Contains("C")) + { + exportType |= ExportType.Client; + } + } + + var constValueInfo = new ConstValueInfo() + { + Name = excelWorksheet.GetCellValue(row, 2), + Type = excelWorksheet.GetCellValue(row, 3), + Value = excelWorksheet.GetCellValue(row, 4), + Remark = excelWorksheet.GetCellValue(row, 5) + }; + + if (exportType.HasFlag(ExportType.Server)) + { + serverDic.Add(constValueInfo); + } + + if (exportType.HasFlag(ExportType.Client)) + { + clientDic.Add(constValueInfo); + } + } + + if (serverDic.Count > 0) + { + Write(serverDic, CustomExportType.Server); + } + + if (clientDic.Count > 0) + { + Write(clientDic, CustomExportType.Client); + } + } + + private void Write(List dic, CustomExportType customExportType) + { + var strBuilder = new StringBuilder(); + strBuilder.AppendLine("namespace Fantasy\n{"); + strBuilder.AppendLine("\t// 生成器自动生成,请不要手动编辑,修改请在#ConstValue.xsl里。"); + strBuilder.AppendLine("\tpublic partial class ConstValue\n\t{"); + foreach (var constValueInfo in dic) + { + var remark = string.IsNullOrEmpty(constValueInfo.Remark) ? constValueInfo.Name : constValueInfo.Remark; + strBuilder.AppendLine($"\t\t/// \n\t\t/// {remark}\n\t\t/// "); + strBuilder.AppendLine( + $"\t\tpublic const {constValueInfo.Type} {constValueInfo.Name} = {DefaultValue(constValueInfo.Type, constValueInfo.Value)};"); + } + strBuilder.AppendLine("\t}\n}"); + Write("ConstValue.cs", strBuilder.ToString(), customExportType); + } + + private static string DefaultValue(string type, string value) + { + switch (type) + { + case "byte[]": + case "int[]": + case "long[]": + case "string[]": + case "double[]": + case "float[]": + return $"new {type} {{{value}}}"; + case "byte[,]": + case "int[,]": + case "long[,]": + case "string[,]": + case "float[,]": + case "double[,]": + return $"new {type} {{{value}}}"; + case "int": + case "bool": + case "uint": + case "long": + case "double": + return $"{value}"; + case "float": + return value[^1] == 'f' ? value : $"{value}f"; + case "string": + return $"\"{value}\""; + case "Vector2": + { + var strings = value.Split(',', StringSplitOptions.TrimEntries); + return $"new Vector2({strings[0]},{strings[1]})"; + } + case "Vector3": + { + var strings = value.Split(',', StringSplitOptions.TrimEntries); + return $"new Vector3({strings[0]},{strings[1]},{strings[2]})"; + } + default: + throw new Exception($"不支持此类型: {type}"); + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Config/Excel/Custom/ContainerConfigToEnum.cs b/物品和背包的完整代码/Config/Excel/Custom/ContainerConfigToEnum.cs new file mode 100644 index 0000000..4d733fb --- /dev/null +++ b/物品和背包的完整代码/Config/Excel/Custom/ContainerConfigToEnum.cs @@ -0,0 +1,62 @@ +using System.Text; +using Fantasy.Exporter; +using Fantasy.Tools.ConfigTable; +using System.Collections.Generic; + +namespace Exporter; + +public class ContainerConfigToEnum : ACustomExport +{ + private class ContainerConfigInfo + { + public int Type; + public string Name; + public string Descride; + } + public override void Run() + { + if (!Worksheets.TryGetValue("ContainerConfig", out var containerConfig)) + { + Log.Info("ContainerConfig is null"); + return; + } + + var dic = new List(); + + for (int row = 7; row <= containerConfig.Dimension.Rows; row++) + { + var containerName = containerConfig.GetCellValue(row, 4); + var containerType = containerConfig.GetCellValue(row, 6); + var containerDes = containerConfig.GetCellValue(row, 5); + + dic.Add(new ContainerConfigInfo() + { + Type = int.Parse(containerType), + Name = containerName, + Descride = containerDes, + }); + } + + Write(dic, CustomExportType.Server); + Write(dic, CustomExportType.Client); + } + + private void Write(List dic, CustomExportType customExportType) + { + var strBuilder = new StringBuilder(); + strBuilder.AppendLine("using System;\n"); + strBuilder.AppendLine("namespace Fantasy\n{"); + strBuilder.AppendLine("\t// 生成器自动生成,请不要手动编辑,修改请在ContainerConfig.xsl里。"); + strBuilder.AppendLine("\t[Flags]"); + strBuilder.AppendLine("\tpublic enum ContainerType : byte\n\t{"); + strBuilder.AppendLine("\t\tNone = 0,"); + foreach (var constValueInfo in dic) + { + strBuilder.AppendLine($"\t\t{constValueInfo.Name} = {constValueInfo.Type},// {constValueInfo.Descride}"); + } + strBuilder.AppendLine("\t\tCell = Equip | Trade,// 按格子存储的容器"); + strBuilder.AppendLine("\t\tNormal = Bag,// 正常的容器"); + strBuilder.AppendLine("\t}\n}"); + Write("ContainerType.cs", strBuilder.ToString(), customExportType); + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Config/Excel/Custom/ErrorCodeToConst.cs b/物品和背包的完整代码/Config/Excel/Custom/ErrorCodeToConst.cs new file mode 100644 index 0000000..57e6511 --- /dev/null +++ b/物品和背包的完整代码/Config/Excel/Custom/ErrorCodeToConst.cs @@ -0,0 +1,56 @@ +using System.Text; +using Fantasy.Exporter; +using Fantasy.Tools.ConfigTable; +using System.Collections.Generic; + +namespace Exporter; + +public class ErrorCodeToConst : ACustomExport +{ + private class ErrorCodeInfo + { + public uint Id; + public string Name; + public string Text; + } + public override void Run() + { + if (!Worksheets.TryGetValue("ErrorCode", out var errorCodeConfig)) + { + Log.Info("ErrorCode is null"); + return; + } + + var dic = new List(); + for (var row = 7; row <= errorCodeConfig.Dimension.Rows; row++) + { + var errorCodeInfo = new ErrorCodeInfo() + { + Id = uint.Parse( errorCodeConfig.GetCellValue(row, 3)), + Name = errorCodeConfig.GetCellValue(row, 4), + Text = errorCodeConfig.GetCellValue(row, 5) + }; + dic.Add(errorCodeInfo); + } + + Write(dic, CustomExportType.Server); + Write(dic, CustomExportType.Client); + } + + private void Write(List dic, CustomExportType customExportType) + { + var strBuilder = new StringBuilder(); + strBuilder.AppendLine("namespace Fantasy\n{"); + strBuilder.AppendLine("\t// 生成器自动生成,请不要手动编辑,修改请在ErrorCode.xsl里。"); + strBuilder.AppendLine("\tpublic partial class ErrorCode\n\t{"); + + foreach (var errorCodeInfo in dic) + { + strBuilder.AppendLine($"\t\t/// \n\t\t/// {errorCodeInfo.Text}\n\t\t/// "); + strBuilder.AppendLine($"\t\tpublic const uint {errorCodeInfo.Name} = {errorCodeInfo.Id};"); + } + + strBuilder.AppendLine("\t}\n}"); + Write("ErrorCode.cs", strBuilder.ToString(), customExportType); + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Config/Excel/Custom/ItemTypeToEnum.cs b/物品和背包的完整代码/Config/Excel/Custom/ItemTypeToEnum.cs new file mode 100644 index 0000000..231b04d --- /dev/null +++ b/物品和背包的完整代码/Config/Excel/Custom/ItemTypeToEnum.cs @@ -0,0 +1,60 @@ +using System.Text; +using System.Collections.Generic; +using Fantasy.Exporter; +using Fantasy.Tools.ConfigTable; + +namespace Exporter; + +public sealed class ItemTypeToEnum : ACustomExport +{ + private class ItemTypeInfo + { + public int Index; + public string Name; + public string Descride; + } + public override void Run() + { + if (!ExcelExporter.IgnoreTable.TryGetValue("#ItemType", out var itemTypePath)) + { + Log.Error("#ItemType is null"); + return; + } + + var dic = new List(); + var excelWorksheet = ExcelExporter.LoadExcel(itemTypePath, false); + for (int row = 2; row <= excelWorksheet.Dimension.Rows; row++) + { + var exportIndex = excelWorksheet.GetCellValue(row, 1); + if (string.IsNullOrEmpty(exportIndex)) + { + continue; + } + + dic.Add(new ItemTypeInfo() + { + Index = int.Parse(exportIndex), + Name = excelWorksheet.GetCellValue(row, 2), + Descride = excelWorksheet.GetCellValue(row, 3), + }); + } + + Write(dic, CustomExportType.Server); + Write(dic, CustomExportType.Client); + } + + private void Write(List dic, CustomExportType customExportType) + { + var strBuilder = new StringBuilder(); + strBuilder.AppendLine("namespace Fantasy\n{"); + strBuilder.AppendLine("\t// 生成器自动生成,请不要手动编辑,修改请在#ItemType.xsl里。"); + strBuilder.AppendLine("\tpublic enum ItemType\n\t{"); + strBuilder.AppendLine("\t\tNone = 0,"); + foreach (var constValueInfo in dic) + { + strBuilder.AppendLine($"\t\t{constValueInfo.Name} = {constValueInfo.Index},// {constValueInfo.Descride}"); + } + strBuilder.AppendLine("\t}\n}"); + Write("ItemType.cs", strBuilder.ToString(), customExportType); + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Config/Excel/Custom/ItemUseEffectToEnum.cs b/物品和背包的完整代码/Config/Excel/Custom/ItemUseEffectToEnum.cs new file mode 100644 index 0000000..e0f6e8f --- /dev/null +++ b/物品和背包的完整代码/Config/Excel/Custom/ItemUseEffectToEnum.cs @@ -0,0 +1,60 @@ +using System.Text; +using System.Collections.Generic; +using Fantasy.Exporter; +using Fantasy.Tools.ConfigTable; + +namespace Exporter; + +public sealed class ItemUseEffectToEnum : ACustomExport +{ + private class ItemUseEffectInfo + { + public int Index; + public string Name; + public string Descride; + } + public override void Run() + { + if (!ExcelExporter.IgnoreTable.TryGetValue("#ItemUseEffect", out var itemTypePath)) + { + Log.Error("ItemUseEffect is null"); + return; + } + + var dic = new List(); + var excelWorksheet = ExcelExporter.LoadExcel(itemTypePath, false); + for (int row = 2; row <= excelWorksheet.Dimension.Rows; row++) + { + var exportIndex = excelWorksheet.GetCellValue(row, 1); + if (string.IsNullOrEmpty(exportIndex)) + { + continue; + } + + dic.Add(new ItemUseEffectInfo() + { + Index = int.Parse(exportIndex), + Name = excelWorksheet.GetCellValue(row, 2), + Descride = excelWorksheet.GetCellValue(row, 3), + }); + } + + Write(dic, CustomExportType.Server); + Write(dic, CustomExportType.Client); + } + + private void Write(List dic, CustomExportType customExportType) + { + var strBuilder = new StringBuilder(); + strBuilder.AppendLine("namespace Fantasy\n{"); + strBuilder.AppendLine("\t// 生成器自动生成,请不要手动编辑,修改请在#ItemUseEffect.xsl里。"); + strBuilder.AppendLine("\tpublic enum ItemUseEffect\n\t{"); + strBuilder.AppendLine("\t\tNone = 0,"); + foreach (var constValueInfo in dic) + { + strBuilder.AppendLine($"\t\t{constValueInfo.Name} = {constValueInfo.Index},// {constValueInfo.Descride}"); + } + strBuilder.AppendLine("\t}\n}"); + Write("ItemUseEffect.cs", strBuilder.ToString(), customExportType); + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Config/Excel/ErrorCode.xlsx b/物品和背包的完整代码/Config/Excel/ErrorCode.xlsx new file mode 100644 index 0000000..3b16563 Binary files /dev/null and b/物品和背包的完整代码/Config/Excel/ErrorCode.xlsx differ diff --git a/物品和背包的完整代码/Config/Excel/Item/#ItemType.xlsx b/物品和背包的完整代码/Config/Excel/Item/#ItemType.xlsx new file mode 100644 index 0000000..7ee1ee4 Binary files /dev/null and b/物品和背包的完整代码/Config/Excel/Item/#ItemType.xlsx differ diff --git a/物品和背包的完整代码/Config/Excel/Item/#ItemUseEffect.xlsx b/物品和背包的完整代码/Config/Excel/Item/#ItemUseEffect.xlsx new file mode 100644 index 0000000..6468897 Binary files /dev/null and b/物品和背包的完整代码/Config/Excel/Item/#ItemUseEffect.xlsx differ diff --git a/物品和背包的完整代码/Config/Excel/Item/.DS_Store b/物品和背包的完整代码/Config/Excel/Item/.DS_Store new file mode 100644 index 0000000..8b05ea1 Binary files /dev/null and b/物品和背包的完整代码/Config/Excel/Item/.DS_Store differ diff --git a/物品和背包的完整代码/Config/Excel/Item/Equip/.DS_Store b/物品和背包的完整代码/Config/Excel/Item/Equip/.DS_Store new file mode 100644 index 0000000..6c30d34 Binary files /dev/null and b/物品和背包的完整代码/Config/Excel/Item/Equip/.DS_Store differ diff --git a/物品和背包的完整代码/Config/Excel/Item/Equip/EquipAffixConfig.xlsm b/物品和背包的完整代码/Config/Excel/Item/Equip/EquipAffixConfig.xlsm new file mode 100644 index 0000000..dfe35d2 Binary files /dev/null and b/物品和背包的完整代码/Config/Excel/Item/Equip/EquipAffixConfig.xlsm differ diff --git a/物品和背包的完整代码/Config/Excel/Item/Equip/EquipEntryConfig.xlsm b/物品和背包的完整代码/Config/Excel/Item/Equip/EquipEntryConfig.xlsm new file mode 100644 index 0000000..49188d0 Binary files /dev/null and b/物品和背包的完整代码/Config/Excel/Item/Equip/EquipEntryConfig.xlsm differ diff --git a/物品和背包的完整代码/Config/Excel/Item/Equip/EquipValueConfig.xlsm b/物品和背包的完整代码/Config/Excel/Item/Equip/EquipValueConfig.xlsm new file mode 100644 index 0000000..2f4d467 Binary files /dev/null and b/物品和背包的完整代码/Config/Excel/Item/Equip/EquipValueConfig.xlsm differ diff --git a/物品和背包的完整代码/Config/Excel/Item/ItemConfig_Drug.xlsx b/物品和背包的完整代码/Config/Excel/Item/ItemConfig_Drug.xlsx new file mode 100644 index 0000000..10b1df3 Binary files /dev/null and b/物品和背包的完整代码/Config/Excel/Item/ItemConfig_Drug.xlsx differ diff --git a/物品和背包的完整代码/Config/Excel/Item/ItemConfig_Equip.xlsx b/物品和背包的完整代码/Config/Excel/Item/ItemConfig_Equip.xlsx new file mode 100644 index 0000000..16346b2 Binary files /dev/null and b/物品和背包的完整代码/Config/Excel/Item/ItemConfig_Equip.xlsx differ diff --git a/物品和背包的完整代码/Config/Excel/LevelConfig.xlsx b/物品和背包的完整代码/Config/Excel/LevelConfig.xlsx new file mode 100644 index 0000000..3872602 Binary files /dev/null and b/物品和背包的完整代码/Config/Excel/LevelConfig.xlsx differ diff --git a/物品和背包的完整代码/Config/Excel/Server/MachineConfig.xlsx b/物品和背包的完整代码/Config/Excel/Server/MachineConfig.xlsx new file mode 100644 index 0000000..195d88d Binary files /dev/null and b/物品和背包的完整代码/Config/Excel/Server/MachineConfig.xlsx differ diff --git a/物品和背包的完整代码/Config/Excel/Server/ProcessConfig.xlsx b/物品和背包的完整代码/Config/Excel/Server/ProcessConfig.xlsx new file mode 100644 index 0000000..ae71a9b Binary files /dev/null and b/物品和背包的完整代码/Config/Excel/Server/ProcessConfig.xlsx differ diff --git a/物品和背包的完整代码/Config/Excel/Server/SceneConfig.xlsx b/物品和背包的完整代码/Config/Excel/Server/SceneConfig.xlsx new file mode 100644 index 0000000..02eeb40 Binary files /dev/null and b/物品和背包的完整代码/Config/Excel/Server/SceneConfig.xlsx differ diff --git a/物品和背包的完整代码/Config/Excel/Server/WorldConfig.xlsx b/物品和背包的完整代码/Config/Excel/Server/WorldConfig.xlsx new file mode 100644 index 0000000..0573b79 Binary files /dev/null and b/物品和背包的完整代码/Config/Excel/Server/WorldConfig.xlsx differ diff --git a/物品和背包的完整代码/Config/Excel/Unit/.DS_Store b/物品和背包的完整代码/Config/Excel/Unit/.DS_Store new file mode 100644 index 0000000..0d86a3f Binary files /dev/null and b/物品和背包的完整代码/Config/Excel/Unit/.DS_Store differ diff --git a/物品和背包的完整代码/Config/Excel/Unit/UnitConfig_Monster.xlsx b/物品和背包的完整代码/Config/Excel/Unit/UnitConfig_Monster.xlsx new file mode 100644 index 0000000..e98f3b1 Binary files /dev/null and b/物品和背包的完整代码/Config/Excel/Unit/UnitConfig_Monster.xlsx differ diff --git a/物品和背包的完整代码/Config/Excel/Unit/UnitConfig_NPC.xlsx b/物品和背包的完整代码/Config/Excel/Unit/UnitConfig_NPC.xlsx new file mode 100644 index 0000000..bf8fefc Binary files /dev/null and b/物品和背包的完整代码/Config/Excel/Unit/UnitConfig_NPC.xlsx differ diff --git a/物品和背包的完整代码/Config/Excel/Unit/UnitConfig_Player.xlsx b/物品和背包的完整代码/Config/Excel/Unit/UnitConfig_Player.xlsx new file mode 100644 index 0000000..c046443 Binary files /dev/null and b/物品和背包的完整代码/Config/Excel/Unit/UnitConfig_Player.xlsx differ diff --git a/物品和背包的完整代码/Config/Excel/Version.txt b/物品和背包的完整代码/Config/Excel/Version.txt new file mode 100644 index 0000000..676d92c --- /dev/null +++ b/物品和背包的完整代码/Config/Excel/Version.txt @@ -0,0 +1 @@ +{"WorksheetNames":["LevelConfig","ContainerConfig","EquipAffixConfig","MachineConfig","ProcessConfig","ErrorCode","ItemConfig_Drug","UnitConfig_Monster","WorldConfig","UnitConfig_NPC","ItemConfig_Equip","UnitConfig_Player","EquipValueConfig","EquipEntryConfig","SceneConfig","SceneTypeConfig"],"Tables":{"ErrorCode":1743067797553,"LevelConfig":1743003386521,"ContainerConfig":1745421515852,"UnitConfig_NPC":1742985157502,"UnitConfig_Player":1745918312114,"UnitConfig_Monster":1742985381203,"MachineConfig":1742224599000,"SceneConfig":1743618691132,"WorldConfig":1743413221256,"ProcessConfig":1742224599000,"ItemConfig_Drug":1745943712301,"ItemConfig_Equip":1747148981281,"EquipAffixConfig":1747129966512,"EquipValueConfig":1746993412781,"EquipEntryConfig":1747129308542}} \ No newline at end of file diff --git a/物品和背包的完整代码/Config/Json/.DS_Store b/物品和背包的完整代码/Config/Json/.DS_Store new file mode 100644 index 0000000..6eb7e74 Binary files /dev/null and b/物品和背包的完整代码/Config/Json/.DS_Store differ diff --git a/物品和背包的完整代码/Config/Json/Client/ContainerConfigData.Json b/物品和背包的完整代码/Config/Json/Client/ContainerConfigData.Json new file mode 100644 index 0000000..090ecc1 --- /dev/null +++ b/物品和背包的完整代码/Config/Json/Client/ContainerConfigData.Json @@ -0,0 +1,5 @@ +{"List":[ +{"Id":1,"Name":"Bag","Type":1,"CellCountMax":10,"CellCount":10,"CanSort":true,"SortCD":1000}, +{"Id":2,"Name":"Equip","Type":2,"CellCountMax":10,"CellCount":10,"CanSort":true,"SortCD":1000}, +{"Id":3,"Name":"Trade","Type":4,"CellCountMax":10,"CellCount":10,"CanSort":true,"SortCD":1000} +]} diff --git a/物品和背包的完整代码/Config/Json/Client/EquipAffixConfigData.Json b/物品和背包的完整代码/Config/Json/Client/EquipAffixConfigData.Json new file mode 100644 index 0000000..cbacb44 --- /dev/null +++ b/物品和背包的完整代码/Config/Json/Client/EquipAffixConfigData.Json @@ -0,0 +1,5 @@ +{"List":[ +{"Id":1,"BuffConfigId":200001,"Descride":"装备上每秒恢复5点血"}, +{"Id":2,"BuffConfigId":200002,"Descride":"装备上每次攻击增加6点攻击力,最高增加了30点"}, +{"Id":3,"BuffConfigId":200003,"Descride":"装备上增加100点法力值"} +]} diff --git a/物品和背包的完整代码/Config/Json/Client/EquipEntryConfigData.Json b/物品和背包的完整代码/Config/Json/Client/EquipEntryConfigData.Json new file mode 100644 index 0000000..171a442 --- /dev/null +++ b/物品和背包的完整代码/Config/Json/Client/EquipEntryConfigData.Json @@ -0,0 +1,5 @@ +{"List":[ +{"Id":1,"Min":1,"Max":1,"AffixMin":1,"AffixMax":1,"Affix":[1,2,3],"Attrs":[200001,1,12,200002,1,10,200003,2,20]}, +{"Id":2,"Min":2,"Max":2,"AffixMin":2,"AffixMax":2,"Affix":[1,2,3],"Attrs":[200001,2,10,200002,2,10,200003,2,20]}, +{"Id":3,"Min":3,"Max":3,"AffixMin":3,"AffixMax":3,"Affix":[1,2,3],"Attrs":[200001,3,10,200002,3,10,200003,3,20]} +]} diff --git a/物品和背包的完整代码/Config/Json/Client/EquipValueConfigData.Json b/物品和背包的完整代码/Config/Json/Client/EquipValueConfigData.Json new file mode 100644 index 0000000..c529124 --- /dev/null +++ b/物品和背包的完整代码/Config/Json/Client/EquipValueConfigData.Json @@ -0,0 +1,5 @@ +{"List":[ +{"Id":1,"ItemConfigId":1000001,"EquipEntryConfigId":1,"Quality":1,"MainAttrs":{"Dic":{"200001":1,"200002":1,"200003":2}}}, +{"Id":2,"ItemConfigId":1000002,"EquipEntryConfigId":2,"Quality":2,"MainAttrs":{"Dic":{"200001":2,"200002":2,"200003":2}}}, +{"Id":3,"ItemConfigId":1000003,"EquipEntryConfigId":3,"Quality":3,"MainAttrs":{"Dic":{"200001":3,"200002":3,"200003":3}}} +]} diff --git a/物品和背包的完整代码/Config/Json/Client/ErrorCodeData.Json b/物品和背包的完整代码/Config/Json/Client/ErrorCodeData.Json new file mode 100644 index 0000000..f44a03c --- /dev/null +++ b/物品和背包的完整代码/Config/Json/Client/ErrorCodeData.Json @@ -0,0 +1,4 @@ +{"List":[ +{"Id":1,"Name":"LoingError","Text":"登陆失败"}, +{"Id":2,"Name":"LoginRoleError","Text":"角色登陆失败"} +]} diff --git a/物品和背包的完整代码/Config/Json/Client/ItemConfigData.Json b/物品和背包的完整代码/Config/Json/Client/ItemConfigData.Json new file mode 100644 index 0000000..af254e9 --- /dev/null +++ b/物品和背包的完整代码/Config/Json/Client/ItemConfigData.Json @@ -0,0 +1,11 @@ +{"List":[ +{"Id":1,"Name":"恢复药剂A","Descride":"使用后,会提升体力200点","Weight":1,"Model2D":"Item_01","Superposed":true,"SuperposedMax":10,"Type":1,"IsDeal":true,"IsSell":true,"Sell":[1,1000],"Effect":3,"Params":["10000","200"],"Durable":0,"Quality":0,"Position":0}, +{"Id":2,"Name":"恢复药剂B","Descride":"使用后,会提升体力400点","Weight":1,"Model2D":"Item_01","Superposed":true,"SuperposedMax":10,"Type":1,"IsDeal":true,"IsSell":true,"Sell":[1,1000],"Effect":3,"Params":["10001","400"],"Durable":0,"Quality":0,"Position":0}, +{"Id":3,"Name":"恢复药剂C","Descride":"使用后,会提升体力400点,提升法力值300","Weight":3,"Model2D":"Item_01","Superposed":true,"SuperposedMax":10,"Type":1,"IsDeal":true,"IsSell":true,"Sell":[1,1000],"Effect":3,"Params":["10000","400","10001","300"],"Durable":0,"Quality":0,"Position":0}, +{"Id":1000001,"Name":"幻想大剑","Descride":"这个是介绍","Weight":1,"Model2D":"Item_01","Superposed":false,"SuperposedMax":1,"Type":2,"IsDeal":true,"IsSell":true,"Sell":[1,1000],"Effect":3,"Params":["10000","200"],"Durable":100,"Quality":1,"Position":1}, +{"Id":1000002,"Name":"幻想头盔","Descride":"这个是介绍","Weight":1,"Model2D":"Item_02","Superposed":false,"SuperposedMax":1,"Type":2,"IsDeal":true,"IsSell":true,"Sell":[1,1000],"Effect":3,"Params":["10000","200"],"Durable":100,"Quality":1,"Position":2}, +{"Id":1000003,"Name":"幻想衣服","Descride":"这个是介绍","Weight":1,"Model2D":"Item_03","Superposed":false,"SuperposedMax":1,"Type":2,"IsDeal":true,"IsSell":true,"Sell":[1,1000],"Effect":3,"Params":["10000","200"],"Durable":100,"Quality":1,"Position":3}, +{"Id":1000004,"Name":"幻想护腿","Descride":"这个是介绍","Weight":1,"Model2D":"Item_04","Superposed":false,"SuperposedMax":1,"Type":2,"IsDeal":true,"IsSell":true,"Sell":[1,1000],"Effect":3,"Params":["10000","200"],"Durable":100,"Quality":1,"Position":4}, +{"Id":1000005,"Name":"幻想护腕","Descride":"这个是介绍","Weight":1,"Model2D":"Item_05","Superposed":false,"SuperposedMax":1,"Type":2,"IsDeal":true,"IsSell":true,"Sell":[1,1000],"Effect":3,"Params":["10000","200"],"Durable":100,"Quality":1,"Position":5}, +{"Id":1000006,"Name":"幻想鞋子","Descride":"这个是介绍","Weight":1,"Model2D":"Item_06","Superposed":false,"SuperposedMax":1,"Type":2,"IsDeal":true,"IsSell":true,"Sell":[1,1000],"Effect":3,"Params":["10000","200"],"Durable":100,"Quality":1,"Position":6} +]} diff --git a/物品和背包的完整代码/Config/Json/Client/LevelConfigData.Json b/物品和背包的完整代码/Config/Json/Client/LevelConfigData.Json new file mode 100644 index 0000000..970edd0 --- /dev/null +++ b/物品和背包的完整代码/Config/Json/Client/LevelConfigData.Json @@ -0,0 +1,6 @@ +{"List":[ +{"Id":1,"Name":"Unit01","Model":"Unit01","Group":1}, +{"Id":2,"Name":"Unit02","Model":"Unit02","Group":1}, +{"Id":3,"Name":"Unit03","Model":"Unit03","Group":2}, +{"Id":4,"Name":"Unit04","Model":"Unit04","Group":2} +]} diff --git a/物品和背包的完整代码/Config/Json/Client/UnitConfigData.Json b/物品和背包的完整代码/Config/Json/Client/UnitConfigData.Json new file mode 100644 index 0000000..4f4fe72 --- /dev/null +++ b/物品和背包的完整代码/Config/Json/Client/UnitConfigData.Json @@ -0,0 +1,5 @@ +{"List":[ +{"Id":3,"Name":"地精投资公司职员","Model":"Unit03","Type":3,"MonsterPRange":1,"TalkConfigId":0,"Camp":0}, +{"Id":2,"Name":"希尔瓦娜斯·风行者","Model":"Unit02","Type":2,"MonsterPRange":0,"TalkConfigId":10012,"Camp":0}, +{"Id":1,"Name":"牛头人","Model":"Unit01","Type":1,"MonsterPRange":0,"TalkConfigId":0,"Camp":1} +]} diff --git a/物品和背包的完整代码/Config/Json/Server/.DS_Store b/物品和背包的完整代码/Config/Json/Server/.DS_Store new file mode 100644 index 0000000..3701309 Binary files /dev/null and b/物品和背包的完整代码/Config/Json/Server/.DS_Store differ diff --git a/物品和背包的完整代码/Config/Json/Server/ContainerConfigData.Json b/物品和背包的完整代码/Config/Json/Server/ContainerConfigData.Json new file mode 100644 index 0000000..090ecc1 --- /dev/null +++ b/物品和背包的完整代码/Config/Json/Server/ContainerConfigData.Json @@ -0,0 +1,5 @@ +{"List":[ +{"Id":1,"Name":"Bag","Type":1,"CellCountMax":10,"CellCount":10,"CanSort":true,"SortCD":1000}, +{"Id":2,"Name":"Equip","Type":2,"CellCountMax":10,"CellCount":10,"CanSort":true,"SortCD":1000}, +{"Id":3,"Name":"Trade","Type":4,"CellCountMax":10,"CellCount":10,"CanSort":true,"SortCD":1000} +]} diff --git a/物品和背包的完整代码/Config/Json/Server/EquipAffixConfigData.Json b/物品和背包的完整代码/Config/Json/Server/EquipAffixConfigData.Json new file mode 100644 index 0000000..cbacb44 --- /dev/null +++ b/物品和背包的完整代码/Config/Json/Server/EquipAffixConfigData.Json @@ -0,0 +1,5 @@ +{"List":[ +{"Id":1,"BuffConfigId":200001,"Descride":"装备上每秒恢复5点血"}, +{"Id":2,"BuffConfigId":200002,"Descride":"装备上每次攻击增加6点攻击力,最高增加了30点"}, +{"Id":3,"BuffConfigId":200003,"Descride":"装备上增加100点法力值"} +]} diff --git a/物品和背包的完整代码/Config/Json/Server/EquipEntryConfigData.Json b/物品和背包的完整代码/Config/Json/Server/EquipEntryConfigData.Json new file mode 100644 index 0000000..171a442 --- /dev/null +++ b/物品和背包的完整代码/Config/Json/Server/EquipEntryConfigData.Json @@ -0,0 +1,5 @@ +{"List":[ +{"Id":1,"Min":1,"Max":1,"AffixMin":1,"AffixMax":1,"Affix":[1,2,3],"Attrs":[200001,1,12,200002,1,10,200003,2,20]}, +{"Id":2,"Min":2,"Max":2,"AffixMin":2,"AffixMax":2,"Affix":[1,2,3],"Attrs":[200001,2,10,200002,2,10,200003,2,20]}, +{"Id":3,"Min":3,"Max":3,"AffixMin":3,"AffixMax":3,"Affix":[1,2,3],"Attrs":[200001,3,10,200002,3,10,200003,3,20]} +]} diff --git a/物品和背包的完整代码/Config/Json/Server/EquipValueConfigData.Json b/物品和背包的完整代码/Config/Json/Server/EquipValueConfigData.Json new file mode 100644 index 0000000..c529124 --- /dev/null +++ b/物品和背包的完整代码/Config/Json/Server/EquipValueConfigData.Json @@ -0,0 +1,5 @@ +{"List":[ +{"Id":1,"ItemConfigId":1000001,"EquipEntryConfigId":1,"Quality":1,"MainAttrs":{"Dic":{"200001":1,"200002":1,"200003":2}}}, +{"Id":2,"ItemConfigId":1000002,"EquipEntryConfigId":2,"Quality":2,"MainAttrs":{"Dic":{"200001":2,"200002":2,"200003":2}}}, +{"Id":3,"ItemConfigId":1000003,"EquipEntryConfigId":3,"Quality":3,"MainAttrs":{"Dic":{"200001":3,"200002":3,"200003":3}}} +]} diff --git a/物品和背包的完整代码/Config/Json/Server/ErrorCodeData.Json b/物品和背包的完整代码/Config/Json/Server/ErrorCodeData.Json new file mode 100644 index 0000000..f44a03c --- /dev/null +++ b/物品和背包的完整代码/Config/Json/Server/ErrorCodeData.Json @@ -0,0 +1,4 @@ +{"List":[ +{"Id":1,"Name":"LoingError","Text":"登陆失败"}, +{"Id":2,"Name":"LoginRoleError","Text":"角色登陆失败"} +]} diff --git a/物品和背包的完整代码/Config/Json/Server/ItemConfigData.Json b/物品和背包的完整代码/Config/Json/Server/ItemConfigData.Json new file mode 100644 index 0000000..af254e9 --- /dev/null +++ b/物品和背包的完整代码/Config/Json/Server/ItemConfigData.Json @@ -0,0 +1,11 @@ +{"List":[ +{"Id":1,"Name":"恢复药剂A","Descride":"使用后,会提升体力200点","Weight":1,"Model2D":"Item_01","Superposed":true,"SuperposedMax":10,"Type":1,"IsDeal":true,"IsSell":true,"Sell":[1,1000],"Effect":3,"Params":["10000","200"],"Durable":0,"Quality":0,"Position":0}, +{"Id":2,"Name":"恢复药剂B","Descride":"使用后,会提升体力400点","Weight":1,"Model2D":"Item_01","Superposed":true,"SuperposedMax":10,"Type":1,"IsDeal":true,"IsSell":true,"Sell":[1,1000],"Effect":3,"Params":["10001","400"],"Durable":0,"Quality":0,"Position":0}, +{"Id":3,"Name":"恢复药剂C","Descride":"使用后,会提升体力400点,提升法力值300","Weight":3,"Model2D":"Item_01","Superposed":true,"SuperposedMax":10,"Type":1,"IsDeal":true,"IsSell":true,"Sell":[1,1000],"Effect":3,"Params":["10000","400","10001","300"],"Durable":0,"Quality":0,"Position":0}, +{"Id":1000001,"Name":"幻想大剑","Descride":"这个是介绍","Weight":1,"Model2D":"Item_01","Superposed":false,"SuperposedMax":1,"Type":2,"IsDeal":true,"IsSell":true,"Sell":[1,1000],"Effect":3,"Params":["10000","200"],"Durable":100,"Quality":1,"Position":1}, +{"Id":1000002,"Name":"幻想头盔","Descride":"这个是介绍","Weight":1,"Model2D":"Item_02","Superposed":false,"SuperposedMax":1,"Type":2,"IsDeal":true,"IsSell":true,"Sell":[1,1000],"Effect":3,"Params":["10000","200"],"Durable":100,"Quality":1,"Position":2}, +{"Id":1000003,"Name":"幻想衣服","Descride":"这个是介绍","Weight":1,"Model2D":"Item_03","Superposed":false,"SuperposedMax":1,"Type":2,"IsDeal":true,"IsSell":true,"Sell":[1,1000],"Effect":3,"Params":["10000","200"],"Durable":100,"Quality":1,"Position":3}, +{"Id":1000004,"Name":"幻想护腿","Descride":"这个是介绍","Weight":1,"Model2D":"Item_04","Superposed":false,"SuperposedMax":1,"Type":2,"IsDeal":true,"IsSell":true,"Sell":[1,1000],"Effect":3,"Params":["10000","200"],"Durable":100,"Quality":1,"Position":4}, +{"Id":1000005,"Name":"幻想护腕","Descride":"这个是介绍","Weight":1,"Model2D":"Item_05","Superposed":false,"SuperposedMax":1,"Type":2,"IsDeal":true,"IsSell":true,"Sell":[1,1000],"Effect":3,"Params":["10000","200"],"Durable":100,"Quality":1,"Position":5}, +{"Id":1000006,"Name":"幻想鞋子","Descride":"这个是介绍","Weight":1,"Model2D":"Item_06","Superposed":false,"SuperposedMax":1,"Type":2,"IsDeal":true,"IsSell":true,"Sell":[1,1000],"Effect":3,"Params":["10000","200"],"Durable":100,"Quality":1,"Position":6} +]} diff --git a/物品和背包的完整代码/Config/Json/Server/LevelConfigData.Json b/物品和背包的完整代码/Config/Json/Server/LevelConfigData.Json new file mode 100644 index 0000000..970edd0 --- /dev/null +++ b/物品和背包的完整代码/Config/Json/Server/LevelConfigData.Json @@ -0,0 +1,6 @@ +{"List":[ +{"Id":1,"Name":"Unit01","Model":"Unit01","Group":1}, +{"Id":2,"Name":"Unit02","Model":"Unit02","Group":1}, +{"Id":3,"Name":"Unit03","Model":"Unit03","Group":2}, +{"Id":4,"Name":"Unit04","Model":"Unit04","Group":2} +]} diff --git a/物品和背包的完整代码/Config/Json/Server/MachineConfigData.Json b/物品和背包的完整代码/Config/Json/Server/MachineConfigData.Json new file mode 100644 index 0000000..f56f98e --- /dev/null +++ b/物品和背包的完整代码/Config/Json/Server/MachineConfigData.Json @@ -0,0 +1,3 @@ +{"List":[ +{"Id":1,"OuterIP":"127.0.0.1","OuterBindIP":"127.0.0.1","InnerBindIP":"127.0.0.1"} +]} diff --git a/物品和背包的完整代码/Config/Json/Server/ProcessConfigData.Json b/物品和背包的完整代码/Config/Json/Server/ProcessConfigData.Json new file mode 100644 index 0000000..a05a13c --- /dev/null +++ b/物品和背包的完整代码/Config/Json/Server/ProcessConfigData.Json @@ -0,0 +1,3 @@ +{"List":[ +{"Id":1,"MachineId":1,"StartupGroup":0} +]} diff --git a/物品和背包的完整代码/Config/Json/Server/SceneConfigData.Json b/物品和背包的完整代码/Config/Json/Server/SceneConfigData.Json new file mode 100644 index 0000000..df1c4aa --- /dev/null +++ b/物品和背包的完整代码/Config/Json/Server/SceneConfigData.Json @@ -0,0 +1,4 @@ +{"List":[ +{"Id":1001,"ProcessConfigId":1,"WorldConfigId":1,"SceneRuntimeType":"MultiThread","SceneTypeString":"Addressable","NetworkProtocol":null,"OuterPort":0,"InnerPort":11001,"SceneType":2}, +{"Id":1002,"ProcessConfigId":1,"WorldConfigId":1,"SceneRuntimeType":"MultiThread","SceneTypeString":"Gate","NetworkProtocol":"KCP","OuterPort":20000,"InnerPort":11002,"SceneType":3} +]} diff --git a/物品和背包的完整代码/Config/Json/Server/UnitConfigData.Json b/物品和背包的完整代码/Config/Json/Server/UnitConfigData.Json new file mode 100644 index 0000000..8f7ca1c --- /dev/null +++ b/物品和背包的完整代码/Config/Json/Server/UnitConfigData.Json @@ -0,0 +1,5 @@ +{"List":[ +{"Id":3,"Name":"地精投资公司职员","Model":"Unit03","Type":3,"MonsterPRange":1,"TalkConfigId":0,"Camp":0,"MountContainer":[],"Items":[]}, +{"Id":2,"Name":"希尔瓦娜斯·风行者","Model":"Unit02","Type":2,"MonsterPRange":0,"TalkConfigId":10012,"Camp":0,"MountContainer":[],"Items":[]}, +{"Id":1,"Name":"牛头人","Model":"Unit01","Type":1,"MonsterPRange":0,"TalkConfigId":0,"Camp":1,"MountContainer":[1,2],"Items":[1,1,3,1,2,5,1,3,1]} +]} diff --git a/物品和背包的完整代码/Config/Json/Server/WorldConfigData.Json b/物品和背包的完整代码/Config/Json/Server/WorldConfigData.Json new file mode 100644 index 0000000..006c92f --- /dev/null +++ b/物品和背包的完整代码/Config/Json/Server/WorldConfigData.Json @@ -0,0 +1,3 @@ +{"List":[ +{"Id":1,"WorldName":"测试服","DbConnection":"mongodb://192.168.31.100","DbName":"fantasy_main","DbType":"MongoDB"} +]} diff --git a/物品和背包的完整代码/Config/NetworkProtocol/.DS_Store b/物品和背包的完整代码/Config/NetworkProtocol/.DS_Store new file mode 100644 index 0000000..db26c12 Binary files /dev/null and b/物品和背包的完整代码/Config/NetworkProtocol/.DS_Store differ diff --git a/物品和背包的完整代码/Config/NetworkProtocol/Inner/InnerMessage.proto b/物品和背包的完整代码/Config/NetworkProtocol/Inner/InnerMessage.proto new file mode 100644 index 0000000..bc46436 --- /dev/null +++ b/物品和背包的完整代码/Config/NetworkProtocol/Inner/InnerMessage.proto @@ -0,0 +1,14 @@ +syntax = "proto3"; +package Sining.Message; +message G2A_TestMessage // IRouteMessage +{ + string Tag = 1; +} +message G2A_TestRequest // IRouteRequest,G2A_TestResponse +{ + +} +message G2A_TestResponse // IRouteResponse +{ + +} diff --git a/物品和背包的完整代码/Config/NetworkProtocol/OpCode.Cache b/物品和背包的完整代码/Config/NetworkProtocol/OpCode.Cache new file mode 100644 index 0000000..9e26dfe --- /dev/null +++ b/物品和背包的完整代码/Config/NetworkProtocol/OpCode.Cache @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/物品和背包的完整代码/Config/NetworkProtocol/Outer/OuterMessage.proto b/物品和背包的完整代码/Config/NetworkProtocol/Outer/OuterMessage.proto new file mode 100644 index 0000000..d5921c8 --- /dev/null +++ b/物品和背包的完整代码/Config/NetworkProtocol/Outer/OuterMessage.proto @@ -0,0 +1,114 @@ +syntax = "proto3"; +package Fantasy.Network.Message; +// 协议分为: +// ProtoBuf:可以在Outer和Inner文件里使用。 +// MemoryPack:可以在Outer和Inner文件里使用。 +// Bson:仅支持在Inner文件里使用。 +// 使用方式: +// 在message协议上方添加// Protocol+空格+协议名字 +// 例如:// Protocol ProtoBuf 或 // Protocol MemoryPack +/// 客户端登陆到服务器 +message C2G_LoginRequest // IRequest,G2C_LoginResponse +{ + string UserName = 1; + string PassWord = 2; +} +/// 服务器返回登陆状态给客户端 +message G2C_LoginResponse // IResponse +{ + +} +/// 客户端请求服务器使用物品 +message C2G_UseItemRequest // IRequest,G2C_UseItemResponse +{ + int64 ItemId = 1; + int32 Count = 2; + int32 ContainerType = 3; // ContainerType +} +message G2C_UseItemResponse // IResponse +{ + +} +/// 装备基础信息类 +message EquipInfo +{ + int32 Durable = 1; // 当前耐久度 + int32 DurableMax = 2; // 最大耐久度 + repeated int32 MainKeys = 3; // 主属性的Key + repeated int32 EquipAttrKeys = 4; // 主属性改变属性Key + repeated int32 EquipAttrValues = 5; // 主属性的对应数值 + repeated int32 EquipAttrSValues = 6; // 主属性的附加数值 + // 比如强化等级,副属性,词缀等。都可以在这里添加 +} +/// 物品基础信息类 +message ItemInfo +{ + int64 ItemId = 1; // 物品Id + int32 Container = 2; // 属于容器的类型 + int32 ConfigId = 3; // 配置表Id + int64 CellId = 4; // 格子的Id + int32 Count = 5; // 物品的数量 + bool IsBind = 6; // 是否是绑定 + EquipInfo EquipInfo = 7; // 装备信息 + // 后面可能会有装备词条 也会在这里定义的,现在没有所以就是先不管了 +} +/// 容器信息类 +message ContainerInfo +{ + int32 CurrentCellCount = 1; // 容器当前可用的格子数量 + int32 ConfigId = 2; // 容器的配置表Id + repeated ItemInfo Items = 3; // 容器内的物品列表 +} +/// 物品变更协议(服务器推送给客户端) +message G2C_UpdateItems // IMessage +{ + int32 ItemReason = 1; // 物品的操作原因,具体可以看代码的ItemReason.cs。 + repeated ItemInfo Items = 2; // 变更物品列表 +} +/// 通知服务器客户端初始化完成 +message C2G_GameInitCompleteRequest // IRequest,G2C_GameInitCompleteResponse +{ + bool PushContainer = 1; // 是否推送容器数据到客户端 + bool PushUnitInfo = 2; // 是否推送角色的数据 + bool Aoi = 3; // 是否推送周围玩家和单位的数据 +} +message G2C_GameInitCompleteResponse // IResponse +{ + +} +/// 推送所有容器数据给客户端 +message G2C_PushAllContainerInfo // IMessage +{ + repeated ContainerInfo Containers = 1; // 容器的数据列表 +} +/// 推送单个的容器数据给客户端 +message G2C_PushContainerInfo // IMessage +{ + ContainerInfo Container = 1; // 容器的数据 +} +/// 通知服务器创建一个物品到背包容器中。 +message C2G_StartCreateItem // IMessage +{ + +} + + + + + + + + + + + + + + + + + + + + + diff --git a/物品和背包的完整代码/Config/NetworkProtocol/RouteType.Config b/物品和背包的完整代码/Config/NetworkProtocol/RouteType.Config new file mode 100644 index 0000000..66082cf --- /dev/null +++ b/物品和背包的完整代码/Config/NetworkProtocol/RouteType.Config @@ -0,0 +1,3 @@ +// Route协议定义(需要定义1000以上、因为1000以内的框架预留) +GateRoute = 1001 // Gate +ChatRoute = 1002 // Chat \ No newline at end of file diff --git a/物品和背包的完整代码/Item.sln b/物品和背包的完整代码/Item.sln new file mode 100644 index 0000000..58b3e92 --- /dev/null +++ b/物品和背包的完整代码/Item.sln @@ -0,0 +1,95 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Main", "Server\Main\Main.csproj", "{61639E0F-9679-4896-99D6-F61F708EDBBF}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Entity", "Server\Entity\Entity.csproj", "{7AAC7EC0-BD68-4A71-BBD2-B5E96EFC9B6B}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Hotfix", "Server\Hotfix\Hotfix.csproj", "{DE4E83AD-D0DD-4990-9388-60328F9C3FE9}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Client", "Client", "{2D3C8EF2-FFCD-40A5-97F1-A5012AFC9A12}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Packages", "Packages", "{1E22CE01-0CD9-45D8-801A-8CE5A38F16B5}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Server", "Server", "{508808CA-E5CC-4C8D-BBCF-9C027A0C25A7}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Fantasy.Net", "Packages\Fantasy\Fantasy.Net\Fantasy.Net\Fantasy.Net.csproj", "{F1AD6E49-CA6C-4463-AC5E-8DD1D71CF977}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Fantasy.NLog", "Packages\Fantasy\Fantasy.Packages\Fantasy.NLog\Fantasy.NLog.csproj", "{909112FB-F857-48BC-8C37-20F93316879D}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Assembly-CSharp", "Client\Unity\Assembly-CSharp.csproj", "{03938CCD-4B40-8DFB-6B9B-21988D5CAC0A}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Fantasy.Editor", "Client\Unity\Fantasy.Editor.csproj", "{F09E7D37-0F11-85F5-9F5A-EA60C1261F78}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Fantasy.Unity", "Client\Unity\Fantasy.Unity.csproj", "{D85FA58B-ACA9-8BF0-E827-074457206988}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Fantasy.ConfigTable", "Client\Unity\Fantasy.ConfigTable.csproj", "{8EB45200-D3BE-6EFD-D01E-A23E2721ECC7}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Fantasy.ConfigTable", "Packages\Fantasy\Fantasy.Packages\Fantasy.ConfigTable\Net\Fantasy.ConfigTable.csproj", "{37E3A440-42B3-4607-A68A-1E77338A425A}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Fantasy.Tools.ConfigTable", "Packages\Fantasy\Tools\SourceCode\Fantasy.Tools.ConfigTable\Fantasy.Tools.ConfigTable.csproj", "{432BD90D-F426-469C-9261-42CD50C0B8A9}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {61639E0F-9679-4896-99D6-F61F708EDBBF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {61639E0F-9679-4896-99D6-F61F708EDBBF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {61639E0F-9679-4896-99D6-F61F708EDBBF}.Release|Any CPU.ActiveCfg = Release|Any CPU + {61639E0F-9679-4896-99D6-F61F708EDBBF}.Release|Any CPU.Build.0 = Release|Any CPU + {7AAC7EC0-BD68-4A71-BBD2-B5E96EFC9B6B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7AAC7EC0-BD68-4A71-BBD2-B5E96EFC9B6B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7AAC7EC0-BD68-4A71-BBD2-B5E96EFC9B6B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7AAC7EC0-BD68-4A71-BBD2-B5E96EFC9B6B}.Release|Any CPU.Build.0 = Release|Any CPU + {DE4E83AD-D0DD-4990-9388-60328F9C3FE9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DE4E83AD-D0DD-4990-9388-60328F9C3FE9}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DE4E83AD-D0DD-4990-9388-60328F9C3FE9}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DE4E83AD-D0DD-4990-9388-60328F9C3FE9}.Release|Any CPU.Build.0 = Release|Any CPU + {F1AD6E49-CA6C-4463-AC5E-8DD1D71CF977}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F1AD6E49-CA6C-4463-AC5E-8DD1D71CF977}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F1AD6E49-CA6C-4463-AC5E-8DD1D71CF977}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F1AD6E49-CA6C-4463-AC5E-8DD1D71CF977}.Release|Any CPU.Build.0 = Release|Any CPU + {909112FB-F857-48BC-8C37-20F93316879D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {909112FB-F857-48BC-8C37-20F93316879D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {909112FB-F857-48BC-8C37-20F93316879D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {909112FB-F857-48BC-8C37-20F93316879D}.Release|Any CPU.Build.0 = Release|Any CPU + {03938CCD-4B40-8DFB-6B9B-21988D5CAC0A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {03938CCD-4B40-8DFB-6B9B-21988D5CAC0A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {03938CCD-4B40-8DFB-6B9B-21988D5CAC0A}.Release|Any CPU.ActiveCfg = Debug|Any CPU + {03938CCD-4B40-8DFB-6B9B-21988D5CAC0A}.Release|Any CPU.Build.0 = Debug|Any CPU + {F09E7D37-0F11-85F5-9F5A-EA60C1261F78}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F09E7D37-0F11-85F5-9F5A-EA60C1261F78}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F09E7D37-0F11-85F5-9F5A-EA60C1261F78}.Release|Any CPU.ActiveCfg = Debug|Any CPU + {F09E7D37-0F11-85F5-9F5A-EA60C1261F78}.Release|Any CPU.Build.0 = Debug|Any CPU + {D85FA58B-ACA9-8BF0-E827-074457206988}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D85FA58B-ACA9-8BF0-E827-074457206988}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D85FA58B-ACA9-8BF0-E827-074457206988}.Release|Any CPU.ActiveCfg = Debug|Any CPU + {D85FA58B-ACA9-8BF0-E827-074457206988}.Release|Any CPU.Build.0 = Debug|Any CPU + {8EB45200-D3BE-6EFD-D01E-A23E2721ECC7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8EB45200-D3BE-6EFD-D01E-A23E2721ECC7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8EB45200-D3BE-6EFD-D01E-A23E2721ECC7}.Release|Any CPU.ActiveCfg = Debug|Any CPU + {8EB45200-D3BE-6EFD-D01E-A23E2721ECC7}.Release|Any CPU.Build.0 = Debug|Any CPU + {37E3A440-42B3-4607-A68A-1E77338A425A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {37E3A440-42B3-4607-A68A-1E77338A425A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {37E3A440-42B3-4607-A68A-1E77338A425A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {37E3A440-42B3-4607-A68A-1E77338A425A}.Release|Any CPU.Build.0 = Release|Any CPU + {432BD90D-F426-469C-9261-42CD50C0B8A9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {432BD90D-F426-469C-9261-42CD50C0B8A9}.Debug|Any CPU.Build.0 = Debug|Any CPU + {432BD90D-F426-469C-9261-42CD50C0B8A9}.Release|Any CPU.ActiveCfg = Release|Any CPU + {432BD90D-F426-469C-9261-42CD50C0B8A9}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {7AAC7EC0-BD68-4A71-BBD2-B5E96EFC9B6B} = {508808CA-E5CC-4C8D-BBCF-9C027A0C25A7} + {DE4E83AD-D0DD-4990-9388-60328F9C3FE9} = {508808CA-E5CC-4C8D-BBCF-9C027A0C25A7} + {61639E0F-9679-4896-99D6-F61F708EDBBF} = {508808CA-E5CC-4C8D-BBCF-9C027A0C25A7} + {F1AD6E49-CA6C-4463-AC5E-8DD1D71CF977} = {1E22CE01-0CD9-45D8-801A-8CE5A38F16B5} + {909112FB-F857-48BC-8C37-20F93316879D} = {1E22CE01-0CD9-45D8-801A-8CE5A38F16B5} + {03938CCD-4B40-8DFB-6B9B-21988D5CAC0A} = {2D3C8EF2-FFCD-40A5-97F1-A5012AFC9A12} + {F09E7D37-0F11-85F5-9F5A-EA60C1261F78} = {2D3C8EF2-FFCD-40A5-97F1-A5012AFC9A12} + {D85FA58B-ACA9-8BF0-E827-074457206988} = {2D3C8EF2-FFCD-40A5-97F1-A5012AFC9A12} + {8EB45200-D3BE-6EFD-D01E-A23E2721ECC7} = {2D3C8EF2-FFCD-40A5-97F1-A5012AFC9A12} + {37E3A440-42B3-4607-A68A-1E77338A425A} = {1E22CE01-0CD9-45D8-801A-8CE5A38F16B5} + {432BD90D-F426-469C-9261-42CD50C0B8A9} = {1E22CE01-0CD9-45D8-801A-8CE5A38F16B5} + EndGlobalSection +EndGlobal diff --git a/物品和背包的完整代码/Item.sln.DotSettings.user b/物品和背包的完整代码/Item.sln.DotSettings.user new file mode 100644 index 0000000..1d3e627 --- /dev/null +++ b/物品和背包的完整代码/Item.sln.DotSettings.user @@ -0,0 +1,10 @@ + + ForceIncluded + ForceIncluded + ForceIncluded + ForceIncluded + ForceIncluded + ForceIncluded + <AssemblyExplorer> + <Assembly Path="/Users/fantasy/.nuget/packages/snappier/1.0.0/lib/net5.0/Snappier.dll" /> +</AssemblyExplorer> \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/.DS_Store b/物品和背包的完整代码/Packages/.DS_Store new file mode 100644 index 0000000..7cc5d15 Binary files /dev/null and b/物品和背包的完整代码/Packages/.DS_Store differ diff --git a/物品和背包的完整代码/Packages/Fantasy/.gitattributes b/物品和背包的完整代码/Packages/Fantasy/.gitattributes new file mode 100644 index 0000000..291159c --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/.gitattributes @@ -0,0 +1,64 @@ +############################################################################### +# Set default behavior to automatically normalize line endings. +############################################################################### +* text=auto + +############################################################################### +# Set default behavior for command prompt diff. +# +# This is need for earlier builds of msysgit that does not have it on by +# default for csharp files. +# Note: This is only used by command line +############################################################################### +#*.cs diff=csharp + +############################################################################### +# Set the merge driver for project and solution files +# +# Merging from the command prompt will add diff markers to the files if there +# are conflicts (Merging from VS is not affected by the settings below, in VS +# the diff markers are never inserted). Diff markers may cause the following +# file extensions to fail to load in VS. An alternative would be to treat +# these files as binary and thus will always conflict and require user +# intervention with every merge. To do so, just uncomment the entries below +############################################################################### +#*.sln merge=binary +#*.csproj merge=binary +#*.vbproj merge=binary +#*.vcxproj merge=binary +#*.vcproj merge=binary +#*.dbproj merge=binary +#*.fsproj merge=binary +#*.lsproj merge=binary +#*.wixproj merge=binary +#*.modelproj merge=binary +#*.sqlproj merge=binary +#*.wwaproj merge=binary + +############################################################################### +# behavior for image files +# +# image files are treated as binary by default. +############################################################################### +#*.jpg binary +#*.png binary +#*.gif binary + +############################################################################### +# diff behavior for common document formats +# +# Convert binary document formats to text before diffing them. This feature +# is only available from the command line. Turn it on by uncommenting the +# entries below. +############################################################################### +#*.doc diff=astextplain +#*.DOC diff=astextplain +#*.docx diff=astextplain +#*.DOCX diff=astextplain +#*.dot diff=astextplain +#*.DOT diff=astextplain +#*.pdf diff=astextplain +#*.PDF diff=astextplain +#*.rtf diff=astextplain +#*.RTF diff=astextplain + diff --git a/物品和背包的完整代码/Packages/Fantasy/.gitignore b/物品和背包的完整代码/Packages/Fantasy/.gitignore new file mode 100644 index 0000000..d9b4e5d --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/.gitignore @@ -0,0 +1,35 @@ +# Specify filepatterns you want git to ignore. +obj/ +Bin/ +bin/ +Temp/ +Library/ +Logs/ +temp/ +DocFx/ +global.json + +# 项目素材 +ResLibrary/ +# Unity项目文件 +examples/**/Unity/*.sln +examples/**/Unity/*.csproj +examples/**/Unity/.vsconfig + +# Client-Unity +HybridCLRData/ +AssetBundles/ +UserSettings/ +# 忽略Packages.Unity包下的.meta +Packages.Unity/**/*.meta + + +# Other +.idea +.vs +.vscode +*.DS_Store +# 不排除示例项目的.vscode +!examples/**/.vscode +!Tools/**/.vscode +examples/**/Unity/.vscode diff --git a/物品和背包的完整代码/Packages/Fantasy/Fanatsy.sln b/物品和背包的完整代码/Packages/Fantasy/Fanatsy.sln new file mode 100644 index 0000000..d8ecc28 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fanatsy.sln @@ -0,0 +1,83 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "NuGet", "NuGet", "{83FB151F-5881-4757-9505-8B70B8C38AA3}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Fantasy.Config", "Fantasy.Packages\Fantasy.Config\Fantasy.Config.csproj", "{BAB58713-49A4-4F34-AE69-333AA1F19DC9}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Fantasy.ConfigTable", "Fantasy.Packages\Fantasy.ConfigTable\Net\Fantasy.ConfigTable.csproj", "{B7383D00-BCF9-4F1B-A79A-6C11DB324237}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Fantasy.NLog", "Fantasy.Packages\Fantasy.NLog\Fantasy.NLog.csproj", "{138EF56B-7154-4656-B55C-30429A68DCC8}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Fantasy.Tools.ExporterConfigTable", "Tools\NuGet\Fantasy.Tools.ExporterConfigTable\Fantasy.Tools.ExporterConfigTable.csproj", "{0BC5E44D-A515-4776-B42D-4872E40194B7}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Fantasy.Tools.ExporterNetworkProtocol", "Tools\NuGet\Fantasy.Tools.ExporterNetworkProtocol\Fantasy.Tools.ExporterNetworkProtocol.csproj", "{5D780C1D-0505-4CF0-925C-1373DCFCBA58}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Fantasy.Net", "Fantasy.Net\Fantasy.Net\Fantasy.Net.csproj", "{4782A7D1-2B43-48DD-AF50-EDC773436E20}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Fantasy.Console", "Fantays.Console\Fantasy.Console.csproj", "{4E463740-00D2-4B4F-AC5B-A09B24487D35}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tools", "Tools", "{0CEB6A4D-8CE9-4EA7-A918-61FA62D6F6F0}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Fantasy.Tools.ConfigTable", "Tools\SourceCode\Fantasy.Tools.ConfigTable\Fantasy.Tools.ConfigTable.csproj", "{A93DFC08-E57F-4BBF-BAAA-18FDB458D515}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Fantasy.Tools.NetworkProtocol", "Tools\SourceCode\Fantasy.Tools.NetworkProtocol\Fantasy.Tools.NetworkProtocol.csproj", "{1951BC8A-0B3E-42F8-950B-DC142988B225}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Fantasy.Benchmark", "Fantasy.Benchmark\Fantasy.Benchmark.csproj", "{C228C5CC-81B9-4323-B4BD-F3C1FB129676}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {BAB58713-49A4-4F34-AE69-333AA1F19DC9} = {83FB151F-5881-4757-9505-8B70B8C38AA3} + {B7383D00-BCF9-4F1B-A79A-6C11DB324237} = {83FB151F-5881-4757-9505-8B70B8C38AA3} + {138EF56B-7154-4656-B55C-30429A68DCC8} = {83FB151F-5881-4757-9505-8B70B8C38AA3} + {0BC5E44D-A515-4776-B42D-4872E40194B7} = {83FB151F-5881-4757-9505-8B70B8C38AA3} + {5D780C1D-0505-4CF0-925C-1373DCFCBA58} = {83FB151F-5881-4757-9505-8B70B8C38AA3} + {A93DFC08-E57F-4BBF-BAAA-18FDB458D515} = {0CEB6A4D-8CE9-4EA7-A918-61FA62D6F6F0} + {1951BC8A-0B3E-42F8-950B-DC142988B225} = {0CEB6A4D-8CE9-4EA7-A918-61FA62D6F6F0} + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {BAB58713-49A4-4F34-AE69-333AA1F19DC9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {BAB58713-49A4-4F34-AE69-333AA1F19DC9}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BAB58713-49A4-4F34-AE69-333AA1F19DC9}.Release|Any CPU.ActiveCfg = Release|Any CPU + {BAB58713-49A4-4F34-AE69-333AA1F19DC9}.Release|Any CPU.Build.0 = Release|Any CPU + {B7383D00-BCF9-4F1B-A79A-6C11DB324237}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B7383D00-BCF9-4F1B-A79A-6C11DB324237}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B7383D00-BCF9-4F1B-A79A-6C11DB324237}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B7383D00-BCF9-4F1B-A79A-6C11DB324237}.Release|Any CPU.Build.0 = Release|Any CPU + {138EF56B-7154-4656-B55C-30429A68DCC8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {138EF56B-7154-4656-B55C-30429A68DCC8}.Debug|Any CPU.Build.0 = Debug|Any CPU + {138EF56B-7154-4656-B55C-30429A68DCC8}.Release|Any CPU.ActiveCfg = Release|Any CPU + {138EF56B-7154-4656-B55C-30429A68DCC8}.Release|Any CPU.Build.0 = Release|Any CPU + {0BC5E44D-A515-4776-B42D-4872E40194B7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0BC5E44D-A515-4776-B42D-4872E40194B7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0BC5E44D-A515-4776-B42D-4872E40194B7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0BC5E44D-A515-4776-B42D-4872E40194B7}.Release|Any CPU.Build.0 = Release|Any CPU + {5D780C1D-0505-4CF0-925C-1373DCFCBA58}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5D780C1D-0505-4CF0-925C-1373DCFCBA58}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5D780C1D-0505-4CF0-925C-1373DCFCBA58}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5D780C1D-0505-4CF0-925C-1373DCFCBA58}.Release|Any CPU.Build.0 = Release|Any CPU + {4782A7D1-2B43-48DD-AF50-EDC773436E20}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4782A7D1-2B43-48DD-AF50-EDC773436E20}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4782A7D1-2B43-48DD-AF50-EDC773436E20}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4782A7D1-2B43-48DD-AF50-EDC773436E20}.Release|Any CPU.Build.0 = Release|Any CPU + {4E463740-00D2-4B4F-AC5B-A09B24487D35}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4E463740-00D2-4B4F-AC5B-A09B24487D35}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4E463740-00D2-4B4F-AC5B-A09B24487D35}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4E463740-00D2-4B4F-AC5B-A09B24487D35}.Release|Any CPU.Build.0 = Release|Any CPU + {A93DFC08-E57F-4BBF-BAAA-18FDB458D515}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A93DFC08-E57F-4BBF-BAAA-18FDB458D515}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A93DFC08-E57F-4BBF-BAAA-18FDB458D515}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A93DFC08-E57F-4BBF-BAAA-18FDB458D515}.Release|Any CPU.Build.0 = Release|Any CPU + {1951BC8A-0B3E-42F8-950B-DC142988B225}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1951BC8A-0B3E-42F8-950B-DC142988B225}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1951BC8A-0B3E-42F8-950B-DC142988B225}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1951BC8A-0B3E-42F8-950B-DC142988B225}.Release|Any CPU.Build.0 = Release|Any CPU + {C228C5CC-81B9-4323-B4BD-F3C1FB129676}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C228C5CC-81B9-4323-B4BD-F3C1FB129676}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C228C5CC-81B9-4323-B4BD-F3C1FB129676}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C228C5CC-81B9-4323-B4BD-F3C1FB129676}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection +EndGlobal diff --git a/物品和背包的完整代码/Packages/Fantasy/Fanatsy.sln.DotSettings.user b/物品和背包的完整代码/Packages/Fantasy/Fanatsy.sln.DotSettings.user new file mode 100644 index 0000000..cfad639 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fanatsy.sln.DotSettings.user @@ -0,0 +1,4 @@ + + ForceIncluded + ForceIncluded + ForceIncluded \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net.sln b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net.sln new file mode 100644 index 0000000..1abdc06 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net.sln @@ -0,0 +1,16 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Fantasy.Net", "Fantasy.Net\Fantasy.Net.csproj", "{636FBF87-A6D2-4A31-86FF-F4157F558C95}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {636FBF87-A6D2-4A31-86FF-F4157F558C95}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {636FBF87-A6D2-4A31-86FF-F4157F558C95}.Debug|Any CPU.Build.0 = Debug|Any CPU + {636FBF87-A6D2-4A31-86FF-F4157F558C95}.Release|Any CPU.ActiveCfg = Release|Any CPU + {636FBF87-A6D2-4A31-86FF-F4157F558C95}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection +EndGlobal diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Fantasy-Net.targets b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Fantasy-Net.targets new file mode 100644 index 0000000..5426ed6 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Fantasy-Net.targets @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Fantasy.Net.csproj b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Fantasy.Net.csproj new file mode 100644 index 0000000..3d42988 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Fantasy.Net.csproj @@ -0,0 +1,59 @@ + + + + Fantasy-Net + 2024.2.24 + Fantasy-Net + qq362946 + qq362946 + ../../nupkg + false + + Fantasy is a high-performance network development framework based on .NET, supporting mainstream protocols. It is designed for development teams or individuals needing a quick start, scalability, and a distributed, cross-platform solution at the commercial level. Fantasy aims to provide easy-to-use tools while ensuring high system performance and scalability. + Copyright 2026 qq362946 + LICENSE + README.md + https://www.code-fantasy.com/ + https://github.com/qq362946/Fantasy + git + Net, c#, Server, Game, GameServer, Fantasy , Network + icon.png + enable + enable + Fantasy-Net + net8.0;net9.0 + + + + TRACE;FANTASY_NET + true + true + bin\Debug\net8.0\Fantasy.Net.xml + + + + TRACE;FANTASY_NET + true + + + + + + + + + + + + + + + + + + + + + + + diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/LICENSE b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/LICENSE new file mode 100644 index 0000000..24a69b2 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/LICENSE @@ -0,0 +1,14 @@ +MIT License + +Copyright (c) 2023 qq362946 + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +However, the following entity is explicitly prohibited from using, copying, modifying, or distributing the Software or any of its portions: + +泰课在线(https://www.taikr.com/) +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/README.md b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/README.md new file mode 100644 index 0000000..582e668 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/README.md @@ -0,0 +1,34 @@ +# Fantasy +#### 框架支持TCP\KCP\WebSocket\http(支持Unity发布成H5)三种网络协议,采用的Protobuf/MemoryPack/Bson做为消息的序列化方案。 +#### Fantasy是基于.NET的高性能网络开发框架,支持主流协议,前后端分离,适合需要快速上手、可扩展、分布式全平台商业级解决方案的开发团队或个人。它旨在提供易用工具,同时保证系统的高性能和扩展性。 +## 导航 +* [Fantasy介绍网站](https://www.code-fantasy.com/) +* [Fantasy的API文档](https://www.code-fantasy.com/doc/api/Fantasy.html) +* [入门视频观看地址](https://space.bilibili.com/382126312) +## 快速上手 +* 01.快速入门 + * [1.1.获得Fantasy](https://www.code-fantasy.com/top/download-fantasy/) + * [1.2.安装Fantasy](https://www.code-fantasy.com/top/creating-your-app/) + * [1.3.Fantasy的网络](https://www.code-fantasy.com/top/use-network/) + * [1.4.Fantasy的配置文件](https://www.code-fantasy.com/top/config-file/) + * [1.5.Fantasy的命令行参数](https://www.code-fantasy.com/top/command-line-parameter/) + * [1.6.Fantasy的导表工具](https://www.code-fantasy.com/top/guidance/) + * [1.7.如何升级到最新版](https://www.code-fantasy.com/top/upgrade/) +* 02.网络通信 + * [2.1.客户端服务器之间发送消息](https://www.code-fantasy.com/network/session/) + * [2.2.服务器之间发送消息](https://www.code-fantasy.com/network/networkmessagingomponent/) + * [2.3.定义通信协议](https://www.code-fantasy.com/network/network-protocols/) + * [2.4.Route通信协议](https://www.code-fantasy.com/network/network-route/) + * [2.5.Addressable通信协议](https://www.code-fantasy.com/network/network-addressable/) +* 03.系统组件 + * [3.1.ECS系统](https://www.code-fantasy.com/core/ecs/) + * [3.2.事件系统](https://www.code-fantasy.com/core/event/) + * [3.3.任务系统](https://www.code-fantasy.com/core/task/) + * [3.4.异步协程锁](https://www.code-fantasy.com/core/lock/) + * [3.5.数据库](https://www.code-fantasy.com/core/db/) +* [更新日志](https://www.code-fantasy.com/changelog/) +* [API文档](https://www.code-fantasy.com/doc/api/Fantasy.html) +* [常见问题](https://www.code-fantasy.com/question/) + +## 交流与讨论: +__讨论QQ群 : Fantasy服务器开发交流群 569888673 __ \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Assembly/AssemblyInfo.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Assembly/AssemblyInfo.cs new file mode 100644 index 0000000..3957539 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Assembly/AssemblyInfo.cs @@ -0,0 +1,89 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using Fantasy.DataStructure.Collection; + +// ReSharper disable CollectionNeverQueried.Global +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. + +namespace Fantasy.Assembly +{ + /// + /// AssemblyInfo提供有关程序集和类型的信息 + /// + public sealed class AssemblyInfo + { + /// + /// 唯一标识 + /// + public readonly long AssemblyIdentity; + /// + /// 获取或设置与此程序集相关联的 实例。 + /// + public System.Reflection.Assembly Assembly { get; private set; } + /// + /// 程序集类型集合,获取一个列表,包含从程序集加载的所有类型。 + /// + public readonly List AssemblyTypeList = new List(); + /// + /// 程序集类型分组集合,获取一个分组列表,将接口类型映射到实现这些接口的类型。 + /// + public readonly OneToManyList AssemblyTypeGroupList = new OneToManyList(); + + /// + /// 初始化 类的新实例。 + /// + /// + public AssemblyInfo(long assemblyIdentity) + { + AssemblyIdentity = assemblyIdentity; + } + + /// + /// 从指定的程序集加载类型信息并进行分类。 + /// + /// 要加载信息的程序集。 + public void Load(System.Reflection.Assembly assembly) + { + Assembly = assembly; + var assemblyTypes = assembly.GetTypes().ToList(); + + foreach (var type in assemblyTypes) + { + if (type.IsAbstract || type.IsInterface) + { + continue; + } + + var interfaces = type.GetInterfaces(); + + foreach (var interfaceType in interfaces) + { + AssemblyTypeGroupList.Add(interfaceType, type); + } + } + + AssemblyTypeList.AddRange(assemblyTypes); + } + + /// + /// 重新加载程序集的类型信息。 + /// + /// + public void ReLoad(System.Reflection.Assembly assembly) + { + Unload(); + Load(assembly); + } + + /// + /// 卸载程序集的类型信息。 + /// + public void Unload() + { + AssemblyTypeList.Clear(); + AssemblyTypeGroupList.Clear(); + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Assembly/AssemblySystem.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Assembly/AssemblySystem.cs new file mode 100644 index 0000000..2014429 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Assembly/AssemblySystem.cs @@ -0,0 +1,276 @@ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Security.Cryptography; +using System.Text; +using Fantasy.Async; +using Fantasy.Helper; +#pragma warning disable CS8604 // Possible null reference argument. +#pragma warning disable CS8602 // Dereference of a possibly null reference. +#pragma warning disable CS8603 +#pragma warning disable CS8618 +namespace Fantasy.Assembly +{ + /// + /// 管理程序集加载和卸载的帮助类。 + /// + public static class AssemblySystem + { +#if FANTASY_WEBGL + private static readonly List AssemblySystems = new List(); + private static readonly Dictionary AssemblyList = new Dictionary(); +#else + private static readonly ConcurrentBag AssemblySystems = new ConcurrentBag(); + private static readonly ConcurrentDictionary AssemblyList = new ConcurrentDictionary(); +#endif + /// + /// 初始化 AssemblySystem。(仅限内部) + /// + /// + internal static async FTask InnerInitialize(params System.Reflection.Assembly[] assemblies) + { + await LoadAssembly(typeof(AssemblySystem).Assembly); + foreach (var assembly in assemblies) + { + await LoadAssembly(assembly); + } + } + + /// + /// 加载指定的程序集,并触发相应的事件。 + /// + /// 要加载的程序集。 + /// 如果当前Domain中已经存在同名的Assembly,使用Domain中的程序集。 + public static async FTask LoadAssembly(System.Reflection.Assembly assembly, bool isCurrentDomain = true) + { + if (isCurrentDomain) + { + var currentDomainAssemblies = System.AppDomain.CurrentDomain.GetAssemblies(); + var currentAssembly = currentDomainAssemblies.FirstOrDefault(d => d.GetName().Name == assembly.GetName().Name); + if (currentAssembly != null) + { + assembly = currentAssembly; + } + } + + var assemblyIdentity = AssemblyIdentity(assembly); + + if (AssemblyList.TryGetValue(assemblyIdentity, out var assemblyInfo)) + { + assemblyInfo.ReLoad(assembly); + foreach (var assemblySystem in AssemblySystems) + { + await assemblySystem.ReLoad(assemblyIdentity); + } + } + else + { + assemblyInfo = new AssemblyInfo(assemblyIdentity); + assemblyInfo.Load(assembly); + AssemblyList.TryAdd(assemblyIdentity, assemblyInfo); + foreach (var assemblySystem in AssemblySystems) + { + await assemblySystem.Load(assemblyIdentity); + } + } + } + + /// + /// 卸载程序集 + /// + /// + public static async FTask UnLoadAssembly(System.Reflection.Assembly assembly) + { + var assemblyIdentity = AssemblyIdentity(assembly); + + if (!AssemblyList.Remove(assemblyIdentity, out var assemblyInfo)) + { + return; + } + + assemblyInfo.Unload(); + foreach (var assemblySystem in AssemblySystems) + { + await assemblySystem.OnUnLoad(assemblyIdentity); + } + } + + /// + /// 将AssemblySystem接口的object注册到程序集管理中心 + /// + /// + public static async FTask Register(object obj) + { + if (obj is not IAssembly assemblySystem) + { + return; + } + + AssemblySystems.Add(assemblySystem); + + foreach (var (assemblyIdentity, _) in AssemblyList) + { + await assemblySystem.Load(assemblyIdentity); + } + } + + /// + /// 程序集管理中心卸载注册的Load、ReLoad、UnLoad的接口 + /// + /// + public static void UnRegister(object obj) + { + if (obj is not IAssembly assemblySystem) + { + return; + } +#if FANTASY_WEBGL + AssemblySystems.Remove(assemblySystem); +#else + while (AssemblySystems.TryTake(out var removeAssemblySystem)) + { + if (removeAssemblySystem == assemblySystem) + { + continue; + } + + AssemblySystems.Add(removeAssemblySystem); + } +#endif + } + + /// + /// 获取所有已加载程序集中的所有类型。 + /// + /// 所有已加载程序集中的类型。 + public static IEnumerable ForEach() + { + foreach (var (_, assemblyInfo) in AssemblyList) + { + foreach (var type in assemblyInfo.AssemblyTypeList) + { + yield return type; + } + } + } + + /// + /// 获取指定程序集中的所有类型。 + /// + /// 程序集唯一标识。 + /// 指定程序集中的类型。 + public static IEnumerable ForEach(long assemblyIdentity) + { + if (!AssemblyList.TryGetValue(assemblyIdentity, out var assemblyInfo)) + { + yield break; + } + + foreach (var type in assemblyInfo.AssemblyTypeList) + { + yield return type; + } + } + + /// + /// 获取所有已加载程序集中实现指定类型的所有类型。 + /// + /// 要查找的基类或接口类型。 + /// 所有已加载程序集中实现指定类型的类型。 + public static IEnumerable ForEach(Type findType) + { + foreach (var (_, assemblyInfo) in AssemblyList) + { + if (!assemblyInfo.AssemblyTypeGroupList.TryGetValue(findType, out var assemblyLoad)) + { + continue; + } + + foreach (var type in assemblyLoad) + { + yield return type; + } + } + } + + /// + /// 获取指定程序集中实现指定类型的所有类型。 + /// + /// 程序集唯一标识。 + /// 要查找的基类或接口类型。 + /// 指定程序集中实现指定类型的类型。 + public static IEnumerable ForEach(long assemblyIdentity, Type findType) + { + if (!AssemblyList.TryGetValue(assemblyIdentity, out var assemblyInfo)) + { + yield break; + } + + if (!assemblyInfo.AssemblyTypeGroupList.TryGetValue(findType, out var assemblyLoad)) + { + yield break; + } + + foreach (var type in assemblyLoad) + { + yield return type; + } + } + + /// + /// 获取指定程序集的实例。 + /// + /// 程序集名称。 + /// 指定程序集的实例,如果未加载则返回 null。 + public static System.Reflection.Assembly GetAssembly(long assemblyIdentity) + { + return !AssemblyList.TryGetValue(assemblyIdentity, out var assemblyInfo) ? null : assemblyInfo.Assembly; + } + + /// + /// 获取当前框架注册的Assembly + /// + /// + public static IEnumerable ForEachAssembly + { + get + { + foreach (var (_, assemblyInfo) in AssemblyList) + { + yield return assemblyInfo.Assembly; + } + } + } + + /// + /// 根据Assembly的强命名计算唯一标识。 + /// + /// + /// + private static long AssemblyIdentity(System.Reflection.Assembly assembly) + { + return HashCodeHelper.ComputeHash64(assembly.GetName().Name); + } + + /// + /// 释放资源,卸载所有加载的程序集。 + /// + public static void Dispose() + { + DisposeAsync().Coroutine(); + } + + private static async FTask DisposeAsync() + { + foreach (var (_, assemblyInfo) in AssemblyList.ToArray()) + { + await UnLoadAssembly(assemblyInfo.Assembly); + } + + AssemblyList.Clear(); + AssemblySystems.Clear(); + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Assembly/IAssembly.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Assembly/IAssembly.cs new file mode 100644 index 0000000..185e037 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Assembly/IAssembly.cs @@ -0,0 +1,27 @@ +using System; +using Fantasy.Async; + +namespace Fantasy.Assembly +{ + /// + /// 实现这个接口、会再程序集首次加载、卸载、重载的时候调用 + /// + public interface IAssembly : IDisposable + { + /// + /// 程序集加载时调用 + /// + /// 程序集标识 + public FTask Load(long assemblyIdentity); + /// + /// 程序集重新加载的时候调用 + /// + /// 程序集标识 + public FTask ReLoad(long assemblyIdentity); + /// + /// 卸载的时候调用 + /// + /// 程序集标识 + public FTask OnUnLoad(long assemblyIdentity); + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Benchmark/Handler/BenchmarkRequestHandler.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Benchmark/Handler/BenchmarkRequestHandler.cs new file mode 100644 index 0000000..8532547 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Benchmark/Handler/BenchmarkRequestHandler.cs @@ -0,0 +1,25 @@ +using Fantasy.Async; +using Fantasy.InnerMessage; +using Fantasy.Network.Interface; + +#if FANTASY_NET +namespace Fantasy.Network.Benchmark.Handler; + +/// +/// BenchmarkRequestHandler +/// +public sealed class BenchmarkRequestHandler : MessageRPC +{ + /// + /// Run方法 + /// + /// + /// + /// + /// + protected override async FTask Run(Session session, BenchmarkRequest request, BenchmarkResponse response, Action reply) + { + await FTask.CompletedTask; + } +} +#endif diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataBase/DataBaseType.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataBase/DataBaseType.cs new file mode 100644 index 0000000..2fb03ec --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataBase/DataBaseType.cs @@ -0,0 +1,20 @@ +// ReSharper disable CheckNamespace +// ReSharper disable InconsistentNaming +#if FANTASY_NET +namespace Fantasy.DataBase; + +/// +/// 数据库类型 +/// +public enum DataBaseType +{ + /// + /// 默认 + /// + None = 0, + /// + /// MongoDB + /// + MongoDB = 1 +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataBase/IDataBase.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataBase/IDataBase.cs new file mode 100644 index 0000000..b87e86d --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataBase/IDataBase.cs @@ -0,0 +1,205 @@ +#if FANTASY_NET +using System; +using System.Collections.Generic; +using System.Linq.Expressions; +using Fantasy.Async; +using Fantasy.Entitas; +using MongoDB.Driver; +// ReSharper disable InconsistentNaming +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring as nullable. + +#pragma warning disable CS8625 + +namespace Fantasy.DataBase +{ + /// + /// 数据库设置助手 + /// + public static class DataBaseSetting + { + /// + /// 初始化自定义委托,当设置了这个委托后,就不会自动创建MongoClient,需要自己在委托里创建MongoClient。 + /// + public static Func? MongoDBCustomInitialize; + } + + /// + /// MongoDB自定义连接参数 + /// + public sealed class DataBaseCustomConfig + { + /// + /// 当前Scene + /// + public Scene Scene; + /// + /// 连接字符串 + /// + public string ConnectionString; + /// + /// 数据库名字 + /// + public string DBName; + } + + /// + /// 表示用于执行各种数据库操作的数据库接口。 + /// + public interface IDataBase : IDisposable + { + /// + /// 获得当前数据的类型 + /// + public DataBaseType GetDataBaseType { get;} + /// + /// 初始化数据库连接。 + /// + IDataBase Initialize(Scene scene, string connectionString, string dbName); + /// + /// 在指定的集合中检索类型 的实体数量。 + /// + FTask Count(string collection = null) where T : Entity; + /// + /// 在指定的集合中检索满足给定筛选条件的类型 的实体数量。 + /// + FTask Count(Expression> filter, string collection = null) where T : Entity; + /// + /// 检查指定集合中是否存在类型 的实体。 + /// + FTask Exist(string collection = null) where T : Entity; + /// + /// 检查指定集合中是否存在满足给定筛选条件的类型 的实体。 + /// + FTask Exist(Expression> filter, string collection = null) where T : Entity; + /// + /// 从指定集合中检索指定 ID 的类型 的实体,不锁定。 + /// + FTask QueryNotLock(long id, bool isDeserialize = false, string collection = null) where T : Entity; + /// + /// 从指定集合中检索指定 ID 的类型 的实体。 + /// + FTask Query(long id, bool isDeserialize = false, string collection = null) where T : Entity; + /// + /// 按页查询满足给定筛选条件的类型 的实体数量和日期。 + /// + FTask<(int count, List dates)> QueryCountAndDatesByPage(Expression> filter, int pageIndex, int pageSize, bool isDeserialize = false, string collection = null) where T : Entity; + /// + /// 按页查询满足给定筛选条件的类型 的实体数量和日期。 + /// + FTask<(int count, List dates)> QueryCountAndDatesByPage(Expression> filter, int pageIndex, int pageSize, string[] cols, bool isDeserialize = false, string collection = null) where T : Entity; + /// + /// 分页查询指定集合中满足给定筛选条件的类型 的实体列表。 + /// + FTask> QueryByPage(Expression> filter, int pageIndex, int pageSize, bool isDeserialize = false, string collection = null) where T : Entity; + /// + /// 分页查询指定集合中满足给定筛选条件的类型 的实体列表,仅返回指定列的数据。 + /// + FTask> QueryByPage(Expression> filter, int pageIndex, int pageSize, string[] cols, bool isDeserialize = false, string collection = null) where T : Entity; + /// + /// 从指定集合中按页查询满足给定筛选条件的类型 的实体列表,按指定字段排序。 + /// + FTask> QueryByPageOrderBy(Expression> filter, int pageIndex, int pageSize, Expression> orderByExpression, bool isAsc = true, bool isDeserialize = false, string collection = null) where T : Entity; + /// + /// 检索满足给定筛选条件的类型 的第一个实体,从指定集合中。 + /// + FTask First(Expression> filter, bool isDeserialize = false, string collection = null) where T : Entity; + /// + /// 查询指定集合中满足给定 JSON 查询字符串的类型 的第一个实体,仅返回指定列的数据。 + /// + FTask First(string json, string[] cols, bool isDeserialize = false, string collection = null) where T : Entity; + /// + /// 从指定集合中按页查询满足给定筛选条件的类型 的实体列表,按指定字段排序。 + /// + FTask> QueryOrderBy(Expression> filter, Expression> orderByExpression, bool isAsc = true, bool isDeserialize = false, string collection = null) where T : Entity; + /// + /// 从指定集合中按页查询满足给定筛选条件的类型 的实体列表。 + /// + FTask> Query(Expression> filter, bool isDeserialize = false, string collection = null) where T : Entity; + /// + /// 查询指定集合中满足给定筛选条件的类型 实体列表,仅返回指定字段的数据。 + /// + FTask> Query(Expression> filter, Expression>[] cols, bool isDeserialize = false, string collection = null) where T : Entity; + /// + /// 查询指定 ID 的多个集合,将结果存储在给定的实体列表中。 + /// + FTask Query(long id, List collectionNames, List result, bool isDeserialize = false); + /// + /// 根据给定的 JSON 查询字符串查询指定集合中的类型 实体列表。 + /// + FTask> QueryJson(string json, bool isDeserialize = false, string collection = null) where T : Entity; + /// + /// 根据给定的 JSON 查询字符串查询指定集合中的类型 实体列表,仅返回指定列的数据。 + /// + FTask> QueryJson(string json, string[] cols, bool isDeserialize = false, string collection = null) where T : Entity; + /// + /// 根据给定的 JSON 查询字符串查询指定集合中的类型 实体列表,通过指定的任务 ID 进行标识。 + /// + FTask> QueryJson(long taskId, string json, bool isDeserialize = false, string collection = null) where T : Entity; + /// + /// 查询指定集合中满足给定筛选条件的类型 实体列表,仅返回指定列的数据。 + /// + FTask> Query(Expression> filter, string[] cols, bool isDeserialize = false, string collection = null) where T : Entity; + /// + /// 保存类型 实体到指定集合中,如果集合不存在将自动创建。 + /// + FTask Save(T entity, string collection = null) where T : Entity, new(); + /// + /// 保存一组实体到数据库中,根据实体列表的 ID 进行区分和存储。 + /// + FTask Save(long id, List entities); + /// + /// 通过事务会话将类型 实体保存到指定集合中,如果集合不存在将自动创建。 + /// + FTask Save(object transactionSession, T entity, string collection = null) where T : Entity; + /// + /// 向指定集合中插入一个类型 实体,如果集合不存在将自动创建。 + /// + FTask Insert(T entity, string collection = null) where T : Entity, new(); + /// + /// 批量插入一组类型 实体到指定集合中,如果集合不存在将自动创建。 + /// + FTask InsertBatch(IEnumerable list, string collection = null) where T : Entity, new(); + /// + /// 通过事务会话,批量插入一组类型 实体到指定集合中,如果集合不存在将自动创建。 + /// + FTask InsertBatch(object transactionSession, IEnumerable list, string collection = null) where T : Entity, new(); + /// + /// 通过事务会话,根据指定的 ID 从数据库中删除指定类型 实体。 + /// + FTask Remove(object transactionSession, long id, string collection = null) where T : Entity, new(); + /// + /// 根据指定的 ID 从数据库中删除指定类型 实体。 + /// + FTask Remove(long id, string collection = null) where T : Entity, new(); + /// + /// 通过事务会话,根据给定的筛选条件从数据库中删除指定类型 实体。 + /// + FTask Remove(long coroutineLockQueueKey, object transactionSession, Expression> filter, string collection = null) where T : Entity, new(); + /// + /// 根据给定的筛选条件从数据库中删除指定类型 实体。 + /// + FTask Remove(long coroutineLockQueueKey, Expression> filter, string collection = null) where T : Entity, new(); + /// + /// 根据给定的筛选条件计算指定集合中类型 实体某个属性的总和。 + /// + FTask Sum(Expression> filter, Expression> sumExpression, string collection = null) where T : Entity; + /// + /// 在指定的集合中创建索引,以提高类型 实体的查询性能。 + /// + FTask CreateIndex(string collection, params object[] keys) where T : Entity; + /// + /// 在默认集合中创建索引,以提高类型 实体的查询性能。 + /// + FTask CreateIndex(params object[] keys) where T : Entity; + /// + /// 创建指定类型 的数据库,用于存储实体。 + /// + FTask CreateDB() where T : Entity; + /// + /// 根据指定类型创建数据库,用于存储实体。 + /// + FTask CreateDB(Type type); + } +} + +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataBase/MongoDataBase.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataBase/MongoDataBase.cs new file mode 100644 index 0000000..a9be75a --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataBase/MongoDataBase.cs @@ -0,0 +1,1078 @@ +#if FANTASY_NET +using System.Linq.Expressions; +using Fantasy.Async; +using Fantasy.DataStructure.Collection; +using Fantasy.Entitas; +using Fantasy.Helper; +using Fantasy.Serialize; +using MongoDB.Bson; +using MongoDB.Driver; +#pragma warning disable CS8602 // Dereference of a possibly null reference. +#pragma warning disable CS8603 // Possible null reference return. +#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. + +namespace Fantasy.DataBase +{ + /// + /// 使用 MongoDB 数据库的实现。 + /// + public sealed class MongoDataBase : IDataBase + { + private const int DefaultTaskSize = 1024; + private Scene _scene; + private MongoClient _mongoClient; + private ISerialize _serializer; + private IMongoDatabase _mongoDatabase; + private CoroutineLock _dataBaseLock; + private readonly HashSet _collections = new HashSet(); + /// + /// 获得当前数据的类型 + /// + public DataBaseType GetDataBaseType { get; } = DataBaseType.MongoDB; + + /// + /// 初始化 MongoDB 数据库连接并记录所有集合名。 + /// + /// 场景对象。 + /// 数据库连接字符串。 + /// 数据库名称。 + /// 初始化后的数据库实例。 + public IDataBase Initialize(Scene scene, string connectionString, string dbName) + { + _scene = scene; + _mongoClient = DataBaseSetting.MongoDBCustomInitialize != null + ? DataBaseSetting.MongoDBCustomInitialize(new DataBaseCustomConfig() + { + Scene = scene, ConnectionString = connectionString, DBName = dbName + }) + : new MongoClient(connectionString); + _mongoDatabase = _mongoClient.GetDatabase(dbName); + _dataBaseLock = scene.CoroutineLockComponent.Create(GetType().TypeHandle.Value.ToInt64()); + // 记录所有集合名 + _collections.UnionWith(_mongoDatabase.ListCollectionNames().ToList()); + _serializer = SerializerManager.GetSerializer(FantasySerializerType.Bson); + return this; + } + + /// + /// 销毁释放资源。 + /// + public void Dispose() + { + // 优先释放协程锁。 + _dataBaseLock.Dispose(); + // 清理资源。 + _scene = null; + _serializer = null; + _mongoDatabase = null; + _dataBaseLock = null; + _collections.Clear(); + _mongoClient.Dispose(); + } + + #region Other + + /// + /// 对满足条件的文档中的某个数值字段进行求和操作。 + /// + /// 实体类型。 + /// 用于筛选文档的表达式。 + /// 要对其进行求和的字段表达式。 + /// 集合名称,可选。如果未指定,将使用实体类型的名称。 + /// 满足条件的文档中指定字段的求和结果。 + public async FTask Sum(Expression> filter, Expression> sumExpression, string collection = null) where T : Entity + { + var member = (MemberExpression)((UnaryExpression)sumExpression.Body).Operand; + var projection = new BsonDocument("_id", "null").Add("Result", new BsonDocument("$sum", $"${member.Member.Name}")); + var data = await GetCollection(collection).Aggregate().Match(filter).Group(projection).FirstOrDefaultAsync(); + return data == null ? 0 : Convert.ToInt64(data["Result"]); + } + + #endregion + + #region GetCollection + + /// + /// 获取指定集合中的 MongoDB 文档的 IMongoCollection 对象。 + /// + /// 实体类型。 + /// 集合名称,可选。如果未指定,将使用实体类型的名称。 + /// IMongoCollection 对象。 + private IMongoCollection GetCollection(string collection = null) + { + return _mongoDatabase.GetCollection(collection ?? typeof(T).Name); + } + + /// + /// 获取指定集合中的 MongoDB 文档的 IMongoCollection 对象,其中实体类型为 Entity。 + /// + /// 集合名称。 + /// IMongoCollection 对象。 + private IMongoCollection GetCollection(string name) + { + return _mongoDatabase.GetCollection(name); + } + + #endregion + + #region Count + + /// + /// 统计指定集合中满足条件的文档数量。 + /// + /// 实体类型。 + /// 集合名称,可选。如果未指定,将使用实体类型的名称。 + /// 满足条件的文档数量。 + public async FTask Count(string collection = null) where T : Entity + { + return await GetCollection(collection).CountDocumentsAsync(d => true); + } + + /// + /// 统计指定集合中满足条件的文档数量。 + /// + /// 实体类型。 + /// 用于筛选文档的表达式。 + /// 集合名称,可选。如果未指定,将使用实体类型的名称。 + /// 满足条件的文档数量。 + public async FTask Count(Expression> filter, string collection = null) where T : Entity + { + return await GetCollection(collection).CountDocumentsAsync(filter); + } + + #endregion + + #region Exist + + /// + /// 判断指定集合中是否存在文档。 + /// + /// 实体类型。 + /// 集合名称,可选。如果未指定,将使用实体类型的名称。 + /// 如果存在文档则返回 true,否则返回 false。 + public async FTask Exist(string collection = null) where T : Entity + { + return await Count(collection) > 0; + } + + /// + /// 判断指定集合中是否存在满足条件的文档。 + /// + /// 实体类型。 + /// 用于筛选文档的表达式。 + /// 集合名称,可选。如果未指定,将使用实体类型的名称。 + /// 如果存在满足条件的文档则返回 true,否则返回 false。 + public async FTask Exist(Expression> filter, string collection = null) where T : Entity + { + return await Count(filter, collection) > 0; + } + + #endregion + + #region Query + + /// + /// 在不加数据库锁定的情况下,查询指定 ID 的文档。 + /// + /// 文档实体类型。 + /// 要查询的文档 ID。 + /// 是否在查询后反序列化,执行反序列化后会自动将实体注册到框架系统中,并且能正常使用组件相关功能。 + /// 集合名称。 + /// 查询到的文档。 + public async FTask QueryNotLock(long id, bool isDeserialize = false, string collection = null) where T : Entity + { + var cursor = await GetCollection(collection).FindAsync(d => d.Id == id); + var v = await cursor.FirstOrDefaultAsync(); + + if (isDeserialize && v != null) + { + v.Deserialize(_scene); + } + + return v; + } + + /// + /// 查询指定 ID 的文档,并加数据库锁定以确保数据一致性。 + /// + /// 文档实体类型。 + /// 要查询的文档 ID。 + /// 是否在查询后反序列化,执行反序列化后会自动将实体注册到框架系统中,并且能正常使用组件相关功能。 + /// 集合名称。 + /// 查询到的文档。 + public async FTask Query(long id, bool isDeserialize = false, string collection = null) where T : Entity + { + using (await _dataBaseLock.Wait(id)) + { + var cursor = await GetCollection(collection).FindAsync(d => d.Id == id); + var v = await cursor.FirstOrDefaultAsync(); + + if (isDeserialize && v != null) + { + v.Deserialize(_scene); + } + + return v; + } + } + + /// + /// 通过分页查询并返回满足条件的文档数量和日期列表(不加锁)。 + /// + /// 文档实体类型。 + /// 查询过滤条件。 + /// 页码。 + /// 每页大小。 + /// 是否在查询后反序列化,执行反序列化后会自动将实体注册到框架系统中,并且能正常使用组件相关功能。 + /// 集合名称。 + /// 满足条件的文档数量和日期列表。 + public async FTask<(int count, List dates)> QueryCountAndDatesByPage(Expression> filter, int pageIndex, int pageSize, bool isDeserialize = false, string collection = null) where T : Entity + { + using (await _dataBaseLock.Wait(RandomHelper.RandInt64() % DefaultTaskSize)) + { + var count = await Count(filter); + var dates = await QueryByPage(filter, pageIndex, pageSize, isDeserialize, collection); + return ((int)count, dates); + } + } + + /// + /// 通过分页查询并返回满足条件的文档数量和日期列表(加锁)。 + /// + /// 文档实体类型。 + /// 查询过滤条件。 + /// 页码。 + /// 每页大小。 + /// 要查询的列名称数组。 + /// 是否在查询后反序列化,执行反序列化后会自动将实体注册到框架系统中,并且能正常使用组件相关功能。 + /// 集合名称。 + /// 满足条件的文档数量和日期列表。 + public async FTask<(int count, List dates)> QueryCountAndDatesByPage(Expression> filter, int pageIndex, int pageSize, string[] cols, bool isDeserialize = false, string collection = null) where T : Entity + { + using (await _dataBaseLock.Wait(RandomHelper.RandInt64() % DefaultTaskSize)) + { + var count = await Count(filter); + var dates = await QueryByPage(filter, pageIndex, pageSize, cols, isDeserialize, collection); + return ((int)count, dates); + } + } + + /// + /// 通过分页查询并返回满足条件的文档列表(不加锁)。 + /// + /// 文档实体类型。 + /// 查询过滤条件。 + /// 页码。 + /// 每页大小。 + /// 是否在查询后反序列化,执行反序列化后会自动将实体注册到框架系统中,并且能正常使用组件相关功能。 + /// 集合名称。 + /// 满足条件的文档列表。 + public async FTask> QueryByPage(Expression> filter, int pageIndex, int pageSize, bool isDeserialize = false, string collection = null) where T : Entity + { + using (await _dataBaseLock.Wait(RandomHelper.RandInt64() % DefaultTaskSize)) + { + var list = await GetCollection(collection).Find(filter).Skip((pageIndex - 1) * pageSize) + .Limit(pageSize) + .ToListAsync(); + + if (!isDeserialize || list is not { Count: > 0 }) + { + return list; + } + + foreach (var entity in list) + { + entity.Deserialize(_scene); + } + + return list; + } + } + + /// + /// 通过分页查询并返回满足条件的文档列表(加锁)。 + /// + /// 文档实体类型。 + /// 查询过滤条件。 + /// 页码。 + /// 每页大小。 + /// 要查询的列名称数组。 + /// 是否在查询后反序列化,执行反序列化后会自动将实体注册到框架系统中,并且能正常使用组件相关功能。 + /// 集合名称。 + /// 满足条件的文档列表。 + public async FTask> QueryByPage(Expression> filter, int pageIndex, int pageSize, string[] cols, bool isDeserialize = false, string collection = null) where T : Entity + { + using (await _dataBaseLock.Wait(RandomHelper.RandInt64() % DefaultTaskSize)) + { + var projection = Builders.Projection.Include(""); + + foreach (var col in cols) + { + projection = projection.Include(col); + } + + var list = await GetCollection(collection).Find(filter).Project(projection) + .Skip((pageIndex - 1) * pageSize).Limit(pageSize).ToListAsync(); + + if (!isDeserialize || list is not { Count: > 0 }) + { + return list; + } + + foreach (var entity in list) + { + entity.Deserialize(_scene); + } + + return list; + } + } + + /// + /// 通过分页查询并返回满足条件的文档列表,并按指定表达式进行排序(加锁)。 + /// + /// 文档实体类型。 + /// 查询过滤条件。 + /// 页码。 + /// 每页大小。 + /// 排序表达式。 + /// 是否升序排序。 + /// 是否在查询后反序列化,执行反序列化后会自动将实体注册到框架系统中,并且能正常使用组件相关功能。 + /// 集合名称。 + /// 满足条件的文档列表。 + public async FTask> QueryByPageOrderBy(Expression> filter, int pageIndex, int pageSize, Expression> orderByExpression, bool isAsc = true, bool isDeserialize = false, string collection = null) where T : Entity + { + using (await _dataBaseLock.Wait(RandomHelper.RandInt64() % DefaultTaskSize)) + { + List list; + + if (isAsc) + { + list = await GetCollection(collection).Find(filter).SortBy(orderByExpression).Skip((pageIndex - 1) * pageSize).Limit(pageSize).ToListAsync(); + } + else + { + list = await GetCollection(collection).Find(filter).SortByDescending(orderByExpression).Skip((pageIndex - 1) * pageSize).Limit(pageSize).ToListAsync(); + } + + if (!isDeserialize || list is not { Count: > 0 }) + { + return list; + } + + foreach (var entity in list) + { + entity.Deserialize(_scene); + } + + return list; + } + } + + /// + /// 通过指定过滤条件查询并返回满足条件的第一个文档(加锁)。 + /// + /// 文档实体类型。 + /// 查询过滤条件。 + /// 是否在查询后反序列化,执行反序列化后会自动将实体注册到框架系统中,并且能正常使用组件相关功能。 + /// 集合名称。 + /// 满足条件的第一个文档,如果未找到则为 null。 + public async FTask First(Expression> filter, bool isDeserialize = false, string collection = null) where T : Entity + { + using (await _dataBaseLock.Wait(RandomHelper.RandInt64() % DefaultTaskSize)) + { + var cursor = await GetCollection(collection).FindAsync(filter); + var t = await cursor.FirstOrDefaultAsync(); + + if (isDeserialize && t != null) + { + t.Deserialize(_scene); + } + + return t; + } + } + + /// + /// 通过指定 JSON 格式查询并返回满足条件的第一个文档(加锁)。 + /// + /// 文档实体类型。 + /// JSON 查询条件。 + /// 要查询的列名称数组。 + /// 是否在查询后反序列化,执行反序列化后会自动将实体注册到框架系统中,并且能正常使用组件相关功能。 + /// 集合名称。 + /// 满足条件的第一个文档。 + public async FTask First(string json, string[] cols, bool isDeserialize = false, string collection = null) where T : Entity + { + using (await _dataBaseLock.Wait(RandomHelper.RandInt64() % DefaultTaskSize)) + { + var projection = Builders.Projection.Include(""); + + foreach (var col in cols) + { + projection = projection.Include(col); + } + + var options = new FindOptions { Projection = projection }; + + FilterDefinition filterDefinition = new JsonFilterDefinition(json); + + var cursor = await GetCollection(collection).FindAsync(filterDefinition, options); + var t = await cursor.FirstOrDefaultAsync(); + + if (isDeserialize && t != null) + { + t.Deserialize(_scene); + } + + return t; + } + } + + /// + /// 通过指定过滤条件查询并返回满足条件的文档列表,并按指定表达式进行排序(加锁)。 + /// + /// 文档实体类型。 + /// 查询过滤条件。 + /// 排序表达式。 + /// 是否升序排序。 + /// 是否在查询后反序列化,执行反序列化后会自动将实体注册到框架系统中,并且能正常使用组件相关功能。 + /// 集合名称。 + /// 满足条件的文档列表。 + public async FTask> QueryOrderBy(Expression> filter, Expression> orderByExpression, bool isAsc = true, bool isDeserialize = false, string collection = null) where T : Entity + { + using (await _dataBaseLock.Wait(RandomHelper.RandInt64() % DefaultTaskSize)) + { + List list; + + if (isAsc) + { + list = await GetCollection(collection).Find(filter).SortBy(orderByExpression).ToListAsync(); + } + else + { + list = await GetCollection(collection).Find(filter).SortByDescending(orderByExpression).ToListAsync(); + } + + if (!isDeserialize || list is not { Count: > 0 }) + { + return list; + } + + foreach (var entity in list) + { + entity.Deserialize(_scene); + } + + return list; + } + } + + /// + /// 通过指定过滤条件查询并返回满足条件的文档列表(加锁)。 + /// + /// 文档实体类型。 + /// 查询过滤条件。 + /// 是否在查询后反序列化,执行反序列化后会自动将实体注册到框架系统中,并且能正常使用组件相关功能。 + /// 集合名称。 + /// 满足条件的文档列表。 + public async FTask> Query(Expression> filter, bool isDeserialize = false, string collection = null) where T : Entity + { + using (await _dataBaseLock.Wait(RandomHelper.RandInt64() % DefaultTaskSize)) + { + var cursor = await GetCollection(collection).FindAsync(filter); + var list = await cursor.ToListAsync(); + + if (!isDeserialize || list is not { Count: > 0 }) + { + return list; + } + + foreach (var entity in list) + { + entity.Deserialize(_scene); + } + + return list; + } + } + + /// + /// 根据指定 ID 加锁查询多个集合中的文档。 + /// + /// 文档 ID。 + /// 要查询的集合名称列表。 + /// 查询结果存储列表。 + /// 是否在查询后反序列化,执行反序列化后会自动将实体注册到框架系统中,并且能正常使用组件相关功能。 + public async FTask Query(long id, List? collectionNames, List result, bool isDeserialize = false) + { + using (await _dataBaseLock.Wait(id)) + { + if (collectionNames == null || collectionNames.Count == 0) + { + return; + } + + foreach (var collectionName in collectionNames) + { + var cursor = await GetCollection(collectionName).FindAsync(d => d.Id == id); + + var e = await cursor.FirstOrDefaultAsync(); + + if (e == null) + { + continue; + } + + if (isDeserialize) + { + e.Deserialize(_scene); + } + + result.Add(e); + } + } + } + + /// + /// 根据指定的 JSON 查询条件查询并返回满足条件的文档列表(加锁)。 + /// + /// 文档实体类型。 + /// JSON 查询条件。 + /// 是否在查询后反序列化,执行反序列化后会自动将实体注册到框架系统中,并且能正常使用组件相关功能。 + /// 集合名称。 + /// 满足条件的文档列表。 + public async FTask> QueryJson(string json, bool isDeserialize = false, string collection = null) where T : Entity + { + using (await _dataBaseLock.Wait(RandomHelper.RandInt64() % DefaultTaskSize)) + { + FilterDefinition filterDefinition = new JsonFilterDefinition(json); + var cursor = await GetCollection(collection).FindAsync(filterDefinition); + var list = await cursor.ToListAsync(); + + if (!isDeserialize || list is not { Count: > 0 }) + { + return list; + } + + foreach (var entity in list) + { + entity.Deserialize(_scene); + } + + return list; + } + } + + /// + /// 根据指定的 JSON 查询条件查询并返回满足条件的文档列表,并选择指定的列(加锁)。 + /// + /// 文档实体类型。 + /// JSON 查询条件。 + /// 要查询的列名称数组。 + /// 是否在查询后反序列化,执行反序列化后会自动将实体注册到框架系统中,并且能正常使用组件相关功能。 + /// 集合名称。 + /// 满足条件的文档列表。 + public async FTask> QueryJson(string json, string[] cols, bool isDeserialize = false, string collection = null) where T : Entity + { + using (await _dataBaseLock.Wait(RandomHelper.RandInt64() % DefaultTaskSize)) + { + var projection = Builders.Projection.Include(""); + + foreach (var col in cols) + { + projection = projection.Include(col); + } + + var options = new FindOptions { Projection = projection }; + + FilterDefinition filterDefinition = new JsonFilterDefinition(json); + + var cursor = await GetCollection(collection).FindAsync(filterDefinition, options); + var list = await cursor.ToListAsync(); + + if (!isDeserialize || list is not { Count: > 0 }) + { + return list; + } + + foreach (var entity in list) + { + entity.Deserialize(_scene); + } + + return list; + } + } + + /// + /// 根据指定的 JSON 查询条件和任务 ID 查询并返回满足条件的文档列表(加锁)。 + /// + /// 文档实体类型。 + /// 任务 ID。 + /// JSON 查询条件。 + /// 是否在查询后反序列化,执行反序列化后会自动将实体注册到框架系统中,并且能正常使用组件相关功能。 + /// 集合名称。 + /// 满足条件的文档列表。 + public async FTask> QueryJson(long taskId, string json, bool isDeserialize = false, string collection = null) where T : Entity + { + using (await _dataBaseLock.Wait(taskId)) + { + FilterDefinition filterDefinition = new JsonFilterDefinition(json); + var cursor = await GetCollection(collection).FindAsync(filterDefinition); + var list = await cursor.ToListAsync(); + + if (!isDeserialize || list is not { Count: > 0 }) + { + return list; + } + + foreach (var entity in list) + { + entity.Deserialize(_scene); + } + + return list; + } + } + + /// + /// 根据指定过滤条件查询并返回满足条件的文档列表,选择指定的列(加锁)。 + /// + /// 文档实体类型。 + /// 查询过滤条件。 + /// 要查询的列名称数组。 + /// 是否在查询后反序列化,执行反序列化后会自动将实体注册到框架系统中,并且能正常使用组件相关功能。 + /// 集合名称。 + /// 满足条件的文档列表。 + public async FTask> Query(Expression> filter, string[] cols, bool isDeserialize = false, string collection = null) where T : Entity + { + using (await _dataBaseLock.Wait(RandomHelper.RandInt64() % DefaultTaskSize)) + { + var projection = Builders.Projection.Include("_id"); + + foreach (var t in cols) + { + projection = projection.Include(t); + } + + var list = await GetCollection(collection).Find(filter).Project(projection).ToListAsync(); + + if (!isDeserialize || list is not { Count: > 0 }) + { + return list; + } + + foreach (var entity in list) + { + entity.Deserialize(_scene); + } + + return list; + } + } + + /// + /// 根据指定过滤条件查询并返回满足条件的文档列表,选择指定的列(加锁)。 + /// + /// 文档实体类型。 + /// 查询过滤条件。 + /// 要查询的列名称数组。 + /// 是否在查询后反序列化,执行反序列化后会自动将实体注册到框架系统中,并且能正常使用组件相关功能。 + /// 集合名称。 + /// + public async FTask> Query(Expression> filter, Expression>[] cols, bool isDeserialize = false, string collection = null) where T : Entity + { + using (await _dataBaseLock.Wait(RandomHelper.RandInt64() % DefaultTaskSize)) + { + var projection = Builders.Projection.Include("_id"); + + foreach (var col in cols) + { + if (col.Body is not MemberExpression memberExpression) + { + throw new ArgumentException("Lambda expression must be a member access expression."); + } + + projection = projection.Include(memberExpression.Member.Name); + } + + var list = await GetCollection(collection).Find(filter).Project(projection).ToListAsync(); + + if (!isDeserialize || list is not { Count: > 0 }) + { + return list; + } + + foreach (var entity in list) + { + entity.Deserialize(_scene); + } + + return list; + } + } + + #endregion + + #region Save + + /// + /// 保存实体对象到数据库(加锁)。 + /// + /// 实体类型。 + /// 事务会话对象。 + /// 要保存的实体对象。 + /// 集合名称。 + public async FTask Save(object transactionSession, T? entity, string collection = null) where T : Entity + { + if (entity == null) + { + Log.Error($"save entity is null: {typeof(T).Name}"); + return; + } + + var clone = _serializer.Clone(entity); + + using (await _dataBaseLock.Wait(clone.Id)) + { + await GetCollection(collection).ReplaceOneAsync( + (IClientSessionHandle)transactionSession, d => d.Id == clone.Id, clone, + new ReplaceOptions { IsUpsert = true }); + } + } + + /// + /// 保存实体对象到数据库(加锁)。 + /// + /// 实体类型。 + /// 要保存的实体对象。 + /// 集合名称。 + public async FTask Save(T? entity, string collection = null) where T : Entity, new() + { + if (entity == null) + { + Log.Error($"save entity is null: {typeof(T).Name}"); + + return; + } + + var clone = _serializer.Clone(entity); + + using (await _dataBaseLock.Wait(clone.Id)) + { + await GetCollection(collection).ReplaceOneAsync(d => d.Id == clone.Id, clone, new ReplaceOptions { IsUpsert = true }); + } + } + + /// + /// 保存实体对象到数据库(加锁)。 + /// + /// 保存的条件表达式。 + /// 实体类型。 + /// 集合名称。 + /// + public async FTask Save(Expression> filter, T? entity, string collection = null) where T : Entity, new() + { + if (entity == null) + { + Log.Error($"save entity is null: {typeof(T).Name}"); + return; + } + + T clone = _serializer.Clone(entity); + + using (await _dataBaseLock.Wait(clone.Id)) + { + await GetCollection(collection).ReplaceOneAsync(filter, clone, new ReplaceOptions { IsUpsert = true }); + } + } + + /// + /// 保存多个实体对象到数据库(加锁)。 + /// + /// 文档 ID。 + /// 要保存的实体对象列表。 + public async FTask Save(long id, List? entities) + { + if (entities == null || entities.Count == 0) + { + Log.Error("save entity is null"); + return; + } + + using var listPool = ListPool.Create(); + + foreach (var entity in entities) + { + listPool.Add(_serializer.Clone(entity)); + } + + using (await _dataBaseLock.Wait(id)) + { + foreach (var clone in listPool) + { + try + { + await GetCollection(clone.GetType().Name).ReplaceOneAsync(d => d.Id == clone.Id, clone, new ReplaceOptions { IsUpsert = true }); + } + catch (Exception e) + { + Log.Error($"Save List Entity Error: {clone.GetType().Name} {clone}\n{e}"); + } + } + } + } + + #endregion + + #region Insert + + /// + /// 插入单个实体对象到数据库(加锁)。 + /// + /// 实体类型。 + /// 要插入的实体对象。 + /// 集合名称。 + public async FTask Insert(T? entity, string collection = null) where T : Entity, new() + { + if (entity == null) + { + Log.Error($"insert entity is null: {typeof(T).Name}"); + return; + } + + var clone = _serializer.Clone(entity); + + using (await _dataBaseLock.Wait(entity.Id)) + { + await GetCollection(collection).InsertOneAsync(clone); + } + } + + /// + /// 批量插入实体对象列表到数据库(加锁)。 + /// + /// 实体类型。 + /// 要插入的实体对象列表。 + /// 集合名称。 + public async FTask InsertBatch(IEnumerable list, string collection = null) where T : Entity, new() + { + using (await _dataBaseLock.Wait(RandomHelper.RandInt64() % DefaultTaskSize)) + { + await GetCollection(collection).InsertManyAsync(list); + } + } + + /// + /// 批量插入实体对象列表到数据库(加锁)。 + /// + /// 实体类型。 + /// 事务会话对象。 + /// 要插入的实体对象列表。 + /// 集合名称。 + public async FTask InsertBatch(object transactionSession, IEnumerable list, string collection = null) + where T : Entity, new() + { + using (await _dataBaseLock.Wait(RandomHelper.RandInt64() % DefaultTaskSize)) + { + await GetCollection(collection).InsertManyAsync((IClientSessionHandle)transactionSession, list); + } + } + + /// + /// 插入BsonDocument到数据库(加锁)。 + /// + /// + /// + /// + public async Task Insert(BsonDocument bsonDocument, long taskId) where T : Entity + { + using (await _dataBaseLock.Wait(taskId)) + { + await GetCollection(typeof(T).Name).InsertOneAsync(bsonDocument); + } + } + + #endregion + + #region Remove + + /// + /// 根据ID删除单个实体对象(加锁)。 + /// + /// 实体类型。 + /// 事务会话对象。 + /// 要删除的实体的ID。 + /// 集合名称。 + /// 删除的实体数量。 + public async FTask Remove(object transactionSession, long id, string collection = null) + where T : Entity, new() + { + using (await _dataBaseLock.Wait(id)) + { + var result = await GetCollection(collection) + .DeleteOneAsync((IClientSessionHandle)transactionSession, d => d.Id == id); + return result.DeletedCount; + } + } + + /// + /// 根据ID删除单个实体对象(加锁)。 + /// + /// 实体类型。 + /// 要删除的实体的ID。 + /// 集合名称。 + /// 删除的实体数量。 + public async FTask Remove(long id, string collection = null) where T : Entity, new() + { + using (await _dataBaseLock.Wait(id)) + { + var result = await GetCollection(collection).DeleteOneAsync(d => d.Id == id); + return result.DeletedCount; + } + } + + /// + /// 根据ID和筛选条件删除多个实体对象(加锁)。 + /// + /// 实体类型。 + /// 异步锁Id。 + /// 事务会话对象。 + /// 筛选条件。 + /// 集合名称。 + /// 删除的实体数量。 + public async FTask Remove(long coroutineLockQueueKey, object transactionSession, + Expression> filter, string collection = null) where T : Entity, new() + { + using (await _dataBaseLock.Wait(coroutineLockQueueKey)) + { + var result = await GetCollection(collection) + .DeleteManyAsync((IClientSessionHandle)transactionSession, filter); + return result.DeletedCount; + } + } + + /// + /// 根据ID和筛选条件删除多个实体对象(加锁)。 + /// + /// 实体类型。 + /// 异步锁Id。 + /// 筛选条件。 + /// 集合名称。 + /// 删除的实体数量。 + public async FTask Remove(long coroutineLockQueueKey, Expression> filter, + string collection = null) where T : Entity, new() + { + using (await _dataBaseLock.Wait(coroutineLockQueueKey)) + { + var result = await GetCollection(collection).DeleteManyAsync(filter); + return result.DeletedCount; + } + } + + #endregion + + #region Index + + /// + /// 创建数据库索引(加锁)。 + /// + /// + /// + /// + /// + /// 使用例子(可多个): + /// 1 : Builders.IndexKeys.Ascending(d=>d.Id) + /// 2 : Builders.IndexKeys.Descending(d=>d.Id).Ascending(d=>d.Name) + /// 3 : Builders.IndexKeys.Descending(d=>d.Id),Builders.IndexKeys.Descending(d=>d.Name) + /// + public async FTask CreateIndex(string collection, params object[]? keys) where T : Entity + { + if (keys == null || keys.Length <= 0) + { + return; + } + + var indexModels = new List>(); + + foreach (object key in keys) + { + IndexKeysDefinition indexKeysDefinition = (IndexKeysDefinition)key; + + indexModels.Add(new CreateIndexModel(indexKeysDefinition)); + } + + await GetCollection(collection).Indexes.CreateManyAsync(indexModels); + } + + /// + /// 创建数据库的索引(加锁)。 + /// + /// 实体类型。 + /// 索引键定义。 + public async FTask CreateIndex(params object[]? keys) where T : Entity + { + if (keys == null) + { + return; + } + + List> indexModels = new List>(); + + foreach (object key in keys) + { + IndexKeysDefinition indexKeysDefinition = (IndexKeysDefinition)key; + + indexModels.Add(new CreateIndexModel(indexKeysDefinition)); + } + + await GetCollection().Indexes.CreateManyAsync(indexModels); + } + + #endregion + + #region CreateDB + + /// + /// 创建数据库集合(如果不存在)。 + /// + /// 实体类型。 + public async FTask CreateDB() where T : Entity + { + // 已经存在数据库表 + string name = typeof(T).Name; + + if (_collections.Contains(name)) + { + return; + } + + await _mongoDatabase.CreateCollectionAsync(name); + + _collections.Add(name); + } + + /// + /// 创建数据库集合(如果不存在)。 + /// + /// 实体类型。 + public async FTask CreateDB(Type type) + { + string name = type.Name; + + if (_collections.Contains(name)) + { + return; + } + + await _mongoDatabase.CreateCollectionAsync(name); + + _collections.Add(name); + } + + #endregion + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataBase/World.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataBase/World.cs new file mode 100644 index 0000000..c53351f --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataBase/World.cs @@ -0,0 +1,77 @@ +#pragma warning disable CS8603 // Possible null reference return. +#if FANTASY_NET +using Fantasy.Platform.Net; + +namespace Fantasy.DataBase +{ + /// + /// 表示一个游戏世界。 + /// + public sealed class World : IDisposable + { + /// + /// 获取游戏世界的唯一标识。 + /// + public byte Id { get; private init; } + /// + /// 获取游戏世界的数据库接口。 + /// + public IDataBase DataBase { get; private init; } + /// + /// 获取游戏世界的配置信息。 + /// + public WorldConfig Config => WorldConfigData.Instance.Get(Id); + + /// + /// 使用指定的配置信息创建一个游戏世界实例。 + /// + /// + /// + private World(Scene scene, byte worldConfigId) + { + Id = worldConfigId; + var worldConfig = Config; + var dbType = worldConfig.DbType.ToLower(); + + switch (dbType) + { + case "mongodb": + { + DataBase = new MongoDataBase(); + DataBase.Initialize(scene, worldConfig.DbConnection, worldConfig.DbName); + break; + } + default: + { + throw new Exception("No supported database"); + } + } + } + + /// + /// 创建一个指定唯一标识的游戏世界实例。 + /// + /// + /// 游戏世界的唯一标识。 + /// 游戏世界实例。 + internal static World Create(Scene scene, byte id) + { + if (!WorldConfigData.Instance.TryGet(id, out var worldConfigData)) + { + return null; + } + + return string.IsNullOrEmpty(worldConfigData.DbConnection) ? null : new World(scene, id); + } + + /// + /// 释放游戏世界资源。 + /// + public void Dispose() + { + DataBase.Dispose(); + } + } +} + +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/Collection/CircularBuffer.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/Collection/CircularBuffer.cs new file mode 100644 index 0000000..d80ec55 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/Collection/CircularBuffer.cs @@ -0,0 +1,346 @@ +using System; +using System.Collections.Generic; +using System.IO; +#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. + +namespace Fantasy.DataStructure.Collection +{ + /// 环形缓存(自增式缓存,自动扩充、不会收缩缓存、所以不要用这个操作过大的IO流) + /// 1、环大小8192,溢出的会自动增加环的大小。 + /// 2、每个块都是一个环形缓存,当溢出的时候会自动添加到下一个环中。 + /// 3、当读取完成后用过的环会放在缓存中,不会销毁掉。 + /// + /// 自增式缓存类,继承自 Stream 和 IDisposable 接口。 + /// 环形缓存具有自动扩充的特性,但不会收缩,适用于操作不过大的 IO 流。 + /// + public sealed class CircularBuffer : Stream, IDisposable + { + private byte[] _lastBuffer; + /// + /// 环形缓存块的默认大小 + /// + public const int ChunkSize = 8192; + private readonly Queue _bufferCache = new Queue(); + private readonly Queue _bufferQueue = new Queue(); + /// + /// 获取或设置环形缓存的第一个索引位置 + /// + public int FirstIndex { get; set; } + /// + /// 获取或设置环形缓存的最后一个索引位置 + /// + public int LastIndex { get; set; } + /// + /// 获取环形缓存的总长度 + /// + public override long Length + { + get + { + if (_bufferQueue.Count == 0) + { + return 0; + } + + return (_bufferQueue.Count - 1) * ChunkSize + LastIndex - FirstIndex; + } + } + + /// + /// 获取环形缓存的第一个块 + /// + public byte[] First + { + get + { + if (_bufferQueue.Count == 0) + { + AddLast(); + } + + return _bufferQueue.Peek(); + } + } + + /// + /// 获取环形缓存的最后一个块 + /// + public byte[] Last + { + get + { + if (_bufferQueue.Count == 0) + { + AddLast(); + } + + return _lastBuffer; + } + } + /// + /// 向环形缓存中添加一个新的块 + /// + public void AddLast() + { + var buffer = _bufferCache.Count > 0 ? _bufferCache.Dequeue() : new byte[ChunkSize]; + _bufferQueue.Enqueue(buffer); + _lastBuffer = buffer; + } + /// + /// 从环形缓存中移除第一个块 + /// + public void RemoveFirst() + { + _bufferCache.Enqueue(_bufferQueue.Dequeue()); + } + + /// + /// 从流中读取指定数量的数据到缓存。 + /// + /// 源数据流。 + /// 要读取的字节数。 + public void Read(Stream stream, int count) + { + if (count > Length) + { + throw new Exception($"bufferList length < count, {Length} {count}"); + } + + var copyCount = 0; + while (copyCount < count) + { + var n = count - copyCount; + if (ChunkSize - FirstIndex > n) + { + stream.Write(First, FirstIndex, n); + FirstIndex += n; + copyCount += n; + } + else + { + stream.Write(First, FirstIndex, ChunkSize - FirstIndex); + copyCount += ChunkSize - FirstIndex; + FirstIndex = 0; + RemoveFirst(); + } + } + } + + /// + /// 从缓存中读取指定数量的数据到内存。 + /// + /// 目标内存。 + /// 要读取的字节数。 + public void Read(Memory memory, int count) + { + if (count > Length) + { + throw new Exception($"bufferList length < count, {Length} {count}"); + } + + var copyCount = 0; + while (copyCount < count) + { + var n = count - copyCount; + var asMemory = First.AsMemory(); + + if (ChunkSize - FirstIndex > n) + { + var slice = asMemory.Slice(FirstIndex, n); + slice.CopyTo(memory.Slice(copyCount, n)); + FirstIndex += n; + copyCount += n; + } + else + { + var length = ChunkSize - FirstIndex; + var slice = asMemory.Slice(FirstIndex, length); + slice.CopyTo(memory.Slice(copyCount, length)); + copyCount += ChunkSize - FirstIndex; + FirstIndex = 0; + RemoveFirst(); + } + } + } + + /// + /// 从自定义流中读取数据到指定的缓冲区。 + /// + /// 目标缓冲区,用于存储读取的数据。 + /// 目标缓冲区中的起始偏移量。 + /// 要读取的字节数。 + /// 实际读取的字节数。 + public override int Read(byte[] buffer, int offset, int count) + { + if (buffer.Length < offset + count) + { + throw new Exception($"buffer length < count, buffer length: {buffer.Length} {offset} {count}"); + } + + var length = Length; + if (length < count) + { + count = (int) length; + } + + var copyCount = 0; + + // 循环直到成功读取所需的字节数 + while (copyCount < count) + { + var copyLength = count - copyCount; + + if (ChunkSize - FirstIndex > copyLength) + { + // 将数据从当前块的缓冲区复制到目标缓冲区 + Array.Copy(First, FirstIndex, buffer, copyCount + offset, copyLength); + + FirstIndex += copyLength; + copyCount += copyLength; + continue; + } + + // 复制当前块中剩余的数据,并切换到下一个块 + Array.Copy(First, FirstIndex, buffer, copyCount + offset, ChunkSize - FirstIndex); + copyCount += ChunkSize - FirstIndex; + FirstIndex = 0; + + RemoveFirst(); + } + + return count; + } + + /// + /// 将数据从给定的字节数组写入流中。 + /// + /// 包含要写入的数据的字节数组。 + public void Write(byte[] buffer) + { + Write(buffer, 0, buffer.Length); + } + + /// + /// 将数据从给定的流写入流中。 + /// + /// 包含要写入的数据的流。 + public void Write(Stream stream) + { + var copyCount = 0; + var count = (int) (stream.Length - stream.Position); + + while (copyCount < count) + { + if (LastIndex == ChunkSize) + { + AddLast(); + LastIndex = 0; + } + + var n = count - copyCount; + + if (ChunkSize - LastIndex > n) + { + _ = stream.Read(Last, LastIndex, n); + LastIndex += count - copyCount; + copyCount += n; + } + else + { + _ = stream.Read(Last, LastIndex, ChunkSize - LastIndex); + copyCount += ChunkSize - LastIndex; + LastIndex = ChunkSize; + } + } + } + + /// + /// 将数据从给定的字节数组写入流中。 + /// + /// 包含要写入的数据的字节数组。 + /// 开始写入的缓冲区中的索引。 + /// 要写入的字节数。 + public override void Write(byte[] buffer, int offset, int count) + { + var copyCount = 0; + + while (copyCount < count) + { + if (ChunkSize == LastIndex) + { + AddLast(); + LastIndex = 0; + } + + var byteLength = count - copyCount; + + if (ChunkSize - LastIndex > byteLength) + { + Array.Copy(buffer, copyCount + offset, Last, LastIndex, byteLength); + LastIndex += byteLength; + copyCount += byteLength; + } + else + { + Array.Copy(buffer, copyCount + offset, Last, LastIndex, ChunkSize - LastIndex); + copyCount += ChunkSize - LastIndex; + LastIndex = ChunkSize; + } + } + } + + /// + /// 获取一个值,指示流是否支持读取操作。 + /// + public override bool CanRead { get; } = true; + /// + /// 获取一个值,指示流是否支持寻找操作。 + /// + public override bool CanSeek { get; } = false; + /// + /// 获取一个值,指示流是否支持写入操作。 + /// + public override bool CanWrite { get; } = true; + /// + /// 获取或设置流中的位置。 + /// + public override long Position { get; set; } + + /// + /// 刷新流(在此实现中引发未实现异常)。 + /// + public override void Flush() + { + throw new NotImplementedException(); + } + + /// + /// 在流中寻找特定位置(在此实现中引发未实现异常)。 + /// + public override long Seek(long offset, SeekOrigin origin) + { + throw new NotImplementedException(); + } + + /// + /// 设置流的长度(在此实现中引发未实现异常)。 + /// + public override void SetLength(long value) + { + throw new NotImplementedException(); + } + + /// + /// 释放 CustomStream 使用的所有资源。 + /// + public new void Dispose() + { + _bufferQueue.Clear(); + _lastBuffer = null; + FirstIndex = 0; + LastIndex = 0; + base.Dispose(); + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/Collection/ConcurrentOneToManyListPool.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/Collection/ConcurrentOneToManyListPool.cs new file mode 100644 index 0000000..e110a0b --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/Collection/ConcurrentOneToManyListPool.cs @@ -0,0 +1,197 @@ +#if !FANTASY_WEBGL +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Linq; +using Fantasy.Pool; + +#pragma warning disable CS8603 // Possible null reference return. + +namespace Fantasy.DataStructure.Collection +{ + /// + /// 并发的一对多列表池,用于维护具有相同键的多个值的关联关系,实现了 接口。 + /// + /// 关键字的类型,不能为空。 + /// 值的类型。 + public class ConcurrentOneToManyListPool : ConcurrentOneToManyList, IDisposable, IPool where TKey : notnull + { + private bool _isPool; + private bool _isDispose; + + /// + /// 创建一个 的实例。 + /// + /// 创建的实例。 + public static ConcurrentOneToManyListPool Create() + { + var a = MultiThreadPool.Rent>(); + a._isDispose = false; + a._isPool = true; + return a; + } + + /// + /// 释放实例占用的资源。 + /// + public void Dispose() + { + if (_isDispose) + { + return; + } + + _isDispose = true; + // 清空实例的数据 + Clear(); + // 将实例返回到池中以便重用 + MultiThreadPool.Return(this); + } + + /// + /// 获取一个值,该值指示当前实例是否为对象池中的实例。 + /// + /// + public bool IsPool() + { + return _isPool; + } + + /// + /// 设置一个值,该值指示当前实例是否为对象池中的实例。 + /// + /// + public void SetIsPool(bool isPool) + { + _isPool = isPool; + } + } + + /// + /// 并发的一对多列表,用于维护具有相同键的多个值的关联关系。 + /// + /// 关键字的类型,不能为空。 + /// 值的类型。 + public class ConcurrentOneToManyList : ConcurrentDictionary> where TKey : notnull + { + private readonly Queue> _queue = new Queue>(); + private readonly int _recyclingLimit = 120; + + /// + /// 初始化 类的新实例。 + /// + public ConcurrentOneToManyList() + { + } + + /// + /// 设置最大缓存数量 + /// + /// + /// 1:防止数据量过大、所以超过recyclingLimit的数据还是走GC. + /// 2:设置成0不控制数量,全部缓存 + /// + public ConcurrentOneToManyList(int recyclingLimit) + { + _recyclingLimit = recyclingLimit; + } + + /// + /// 判断指定键的列表是否包含指定值。 + /// + /// 要搜索的键。 + /// 要搜索的值。 + /// 如果列表包含值,则为 true;否则为 false。 + public bool Contains(TKey key, TValue value) + { + TryGetValue(key, out var list); + + return list != null && list.Contains(value); + } + + /// + /// 向指定键的列表中添加一个值。 + /// + /// 要添加值的键。 + /// 要添加的值。 + public void Add(TKey key, TValue value) + { + if (!TryGetValue(key, out var list)) + { + list = Fetch(); + list.Add(value); + base[key] = list; + return; + } + + list.Add(value); + } + + /// + /// 获取指定键的列表中的第一个值。 + /// + /// 要获取第一个值的键。 + /// 指定键的列表中的第一个值,如果不存在则为默认值。 + public TValue First(TKey key) + { + return !TryGetValue(key, out var list) ? default : list.FirstOrDefault(); + } + + /// + /// 从指定键的列表中移除一个值。 + /// + /// 要移除值的键。 + /// 要移除的值。 + public void RemoveValue(TKey key, TValue value) + { + if (!TryGetValue(key, out var list)) return; + + list.Remove(value); + + if (list.Count == 0) RemoveKey(key); + } + + /// + /// 从字典中移除指定键以及其关联的列表。 + /// + /// 要移除的键。 + public void RemoveKey(TKey key) + { + if (!TryRemove(key, out var list)) return; + + Recycle(list); + } + + /// + /// 从队列中获取一个列表,如果队列为空则创建一个新的列表。 + /// + /// 获取的列表。 + private List Fetch() + { + return _queue.Count <= 0 ? new List() : _queue.Dequeue(); + } + + /// + /// 将一个列表回收到队列中。 + /// + /// 要回收的列表。 + private void Recycle(List list) + { + list.Clear(); + + if (_recyclingLimit != 0 && _queue.Count > _recyclingLimit) return; + + _queue.Enqueue(list); + } + + /// + /// 清空当前类的数据,包括从基类继承的数据以及自定义的数据队列。 + /// + protected new void Clear() + { + base.Clear(); + _queue.Clear(); + } + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/Collection/ConcurrentOneToManyQueuePool.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/Collection/ConcurrentOneToManyQueuePool.cs new file mode 100644 index 0000000..59c4367 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/Collection/ConcurrentOneToManyQueuePool.cs @@ -0,0 +1,194 @@ +#if !FANTASY_WEBGL +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using Fantasy.Pool; + +#pragma warning disable CS8603 + +namespace Fantasy.DataStructure.Collection +{ + /// + /// 表示一个并发的一对多队列池,用于维护具有相同键的多个值的关联关系,实现了 接口。 + /// + /// 关键字的类型,不能为空。 + /// 值的类型。 + public class ConcurrentOneToManyQueuePool : ConcurrentOneToManyQueue, IDisposable, IPool where TKey : notnull + { + private bool _isPool; + private bool _isDispose; + + /// + /// 创建并返回一个 的实例。 + /// + /// 创建的实例。 + public static ConcurrentOneToManyQueuePool Create() + { + var a = MultiThreadPool.Rent>(); + a._isDispose = false; + a._isPool = true; + return a; + } + + /// + /// 释放当前实例所占用的资源,并将实例返回到对象池中,以便重用。 + /// + public void Dispose() + { + if (_isDispose) + { + return; + } + + _isDispose = true; + Clear(); + // 将实例返回到对象池中,以便重用 + MultiThreadPool.Return(this); + } + + /// + /// 获取一个值,该值指示当前实例是否为对象池中的实例。 + /// + /// + public bool IsPool() + { + return _isPool; + } + + /// + /// 设置一个值,该值指示当前实例是否为对象池中的实例。 + /// + /// + public void SetIsPool(bool isPool) + { + _isPool = isPool; + } + } + + /// + /// 表示一个并发的一对多队列,用于维护具有相同键的多个值的关联关系。 + /// + /// 关键字的类型,不能为空。 + /// 值的类型。 + public class ConcurrentOneToManyQueue : ConcurrentDictionary> where TKey : notnull + { + private readonly Queue> _queue = new Queue>(); + private readonly int _recyclingLimit; + + /// + /// 设置最大缓存数量 + /// + /// + /// 1:防止数据量过大、所以超过recyclingLimit的数据还是走GC. + /// 2:设置成0不控制数量,全部缓存 + /// + public ConcurrentOneToManyQueue(int recyclingLimit = 0) + { + _recyclingLimit = recyclingLimit; + } + + /// + /// 判断指定键的队列是否包含指定值。 + /// + /// 要搜索的键。 + /// 要搜索的值。 + /// 如果队列包含值,则为 true;否则为 false。 + public bool Contains(TKey key, TValue value) + { + TryGetValue(key, out var list); + + return list != null && list.Contains(value); + } + + /// + /// 向指定键的队列中添加一个值。 + /// + /// 要添加值的键。 + /// 要添加的值。 + public void Enqueue(TKey key, TValue value) + { + if (!TryGetValue(key, out var list)) + { + list = Fetch(); + list.Enqueue(value); + TryAdd(key, list); + return; + } + + list.Enqueue(value); + } + + /// + /// 从指定键的队列中出队并返回一个值。 + /// + /// 要出队的键。 + /// 出队的值,如果队列为空则为默认值。 + public TValue Dequeue(TKey key) + { + if (!TryGetValue(key, out var list) || list.Count == 0) return default; + + var value = list.Dequeue(); + + if (list.Count == 0) RemoveKey(key); + + return value; + } + + /// + /// 尝试从指定键的队列中出队一个值。 + /// + /// 要出队的键。 + /// 出队的值,如果队列为空则为默认值。 + /// 如果成功出队,则为 true;否则为 false。 + public bool TryDequeue(TKey key, out TValue value) + { + value = Dequeue(key); + + return value != null; + } + + /// + /// 从字典中移除指定键以及其关联的队列。 + /// + /// 要移除的键。 + public void RemoveKey(TKey key) + { + if (!TryGetValue(key, out var list)) return; + + TryRemove(key, out _); + Recycle(list); + } + + /// + /// 从队列中获取一个新的队列,如果队列为空则创建一个新的队列。 + /// + /// 获取的队列。 + private Queue Fetch() + { + return _queue.Count <= 0 ? new Queue() : _queue.Dequeue(); + } + + /// + /// 将一个队列回收到队列池中。 + /// + /// 要回收的队列。 + private void Recycle(Queue list) + { + list.Clear(); + + if (_recyclingLimit != 0 && _queue.Count > _recyclingLimit) return; + + _queue.Enqueue(list); + } + + /// + /// 清空当前类的数据,包括从基类继承的键值对字典中的数据以及自定义的队列池。 + /// + protected new void Clear() + { + base.Clear(); + _queue.Clear(); + } + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/Collection/HashSetPool.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/Collection/HashSetPool.cs new file mode 100644 index 0000000..bb64ae8 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/Collection/HashSetPool.cs @@ -0,0 +1,134 @@ +using System; +using System.Collections.Generic; +using Fantasy.Pool; + +namespace Fantasy.DataStructure.Collection +{ + /// + /// 可释放的哈希集合对象池。 + /// + /// 哈希集合中元素的类型。 + public sealed class HashSetPool : HashSet, IDisposable, IPool + { + private bool _isPool; + private bool _isDispose; + + /// + /// 释放实例所占用的资源,并将实例返回到对象池中,以便重用。 + /// + public void Dispose() + { + if (_isDispose) + { + return; + } + + _isDispose = true; + Clear(); +#if FANTASY_WEBGL + Pool>.Return(this); +#else + MultiThreadPool.Return(this); +#endif + } + + /// + /// 创建一个 哈希集合池的实例。 + /// + /// 创建的实例。 + public static HashSetPool Create() + { +#if FANTASY_WEBGL + var list = Pool>.Rent(); + list._isDispose = false; + list._isPool = true; + return list; +#else + var list = MultiThreadPool.Rent>(); + list._isDispose = false; + list._isPool = true; + return list; +#endif + } + + /// + /// 获取一个值,该值指示当前实例是否为对象池中的实例。 + /// + /// + public bool IsPool() + { + return _isPool; + } + + /// + /// 设置一个值,该值指示当前实例是否为对象池中的实例。 + /// + /// + public void SetIsPool(bool isPool) + { + _isPool = isPool; + } + } + + /// + /// 基本哈希集合对象池,他自持有实际的哈希集合。 + /// + /// 哈希集合中元素的类型。 + public sealed class HashSetBasePool : IDisposable, IPool + { + private bool _isPool; + + /// + /// 存储实际的哈希集合 + /// + public HashSet Set = new HashSet(); + + /// + /// 创建一个 基本哈希集合对象池的实例。 + /// + /// 创建的实例。 + public static HashSetBasePool Create() + { +#if FANTASY_WEBGL + var hashSetBasePool = Pool>.Rent(); + hashSetBasePool._isPool = true; + return hashSetBasePool; +#else + var hashSetBasePool = MultiThreadPool.Rent>(); + hashSetBasePool._isPool = true; + return hashSetBasePool; +#endif + } + + /// + /// 释放实例所占用的资源,并将实例返回到对象池中,以便重用。 + /// + public void Dispose() + { + Set.Clear(); +#if FANTASY_WEBGL + Pool>.Return(this); +#else + MultiThreadPool.Return(this); +#endif + } + + /// + /// 获取一个值,该值指示当前实例是否为对象池中的实例。 + /// + /// + public bool IsPool() + { + return _isPool; + } + + /// + /// 设置一个值,该值指示当前实例是否为对象池中的实例。 + /// + /// + public void SetIsPool(bool isPool) + { + throw new NotImplementedException(); + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/Collection/ListPool.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/Collection/ListPool.cs new file mode 100644 index 0000000..de70fe2 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/Collection/ListPool.cs @@ -0,0 +1,101 @@ +using System; +using System.Collections.Generic; +using Fantasy.Pool; + +// ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract + +namespace Fantasy.DataStructure.Collection +{ + /// + /// 可释放的列表(List)对象池。 + /// + /// 列表中元素的类型。 + public sealed class ListPool : List, IDisposable, IPool + { + private bool _isPool; + private bool _isDispose; + + /// + /// 释放实例所占用的资源,并将实例返回到对象池中,以便重用。 + /// + public void Dispose() + { + if (_isDispose) + { + return; + } + + _isDispose = true; + Clear(); +#if FANTASY_WEBGL + Pool>.Return(this); +#else + MultiThreadPool.Return(this); +#endif + } + + /// + /// 使用指定的元素创建一个 列表(List)对象池的实例。 + /// + /// 要添加到列表的元素。 + /// 创建的实例。 + public static ListPool Create(params T[] args) + { +#if FANTASY_WEBGL + var list = Pool>.Rent(); +#else + var list = MultiThreadPool.Rent>(); +#endif + list._isDispose = false; + list._isPool = true; + + if (args != null) + { + list.AddRange(args); + } + + return list; + } + + /// + /// 使用指定的列表创建一个 列表(List)对象池的实例。 + /// + /// 要添加到列表的元素列表。 + /// 创建的实例。 + public static ListPool Create(List args) + { +#if FANTASY_WEBGL + var list = Pool>.Rent(); +#else + var list = MultiThreadPool.Rent>(); +#endif + list._isDispose = false; + list._isPool = true; + + if (args != null) + { + list.AddRange(args); + } + + return list; + } + + /// + /// 获取一个值,该值指示当前实例是否为对象池中的实例。 + /// + /// + public bool IsPool() + { + return _isPool; + } + + /// + /// 设置一个值,该值指示当前实例是否为对象池中的实例。 + /// + /// + public void SetIsPool(bool isPool) + { + _isPool = isPool; + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/Collection/OneToManyHashSetPool.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/Collection/OneToManyHashSetPool.cs new file mode 100644 index 0000000..8a5766c --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/Collection/OneToManyHashSetPool.cs @@ -0,0 +1,208 @@ +using System; +using System.Collections.Generic; +using Fantasy.Pool; + +#pragma warning disable CS8600 // Converting null literal or possible null value to non-nullable type. + +namespace Fantasy.DataStructure.Collection +{ + /// + /// 一对多哈希集合(OneToManyHashSet)对象池。 + /// + /// 键的类型。 + /// 值的类型。 + public class OneToManyHashSetPool : OneToManyHashSet, IDisposable, IPool where TKey : notnull + { + private bool _isPool; + private bool _isDispose; + + /// + /// 创建一个 一对多哈希集合(OneToManyHashSet)对象池的实例。 + /// + /// 创建的实例。 + public static OneToManyHashSetPool Create() + { +#if FANTASY_WEBGL + var a = Pool>.Rent(); +#else + var a = MultiThreadPool.Rent>(); +#endif + a._isDispose = false; + a._isPool = true; + return a; + } + + /// + /// 释放实例所占用的资源,并将实例返回到对象池中,以便重用。 + /// + public void Dispose() + { + if (_isDispose) + { + return; + } + + _isDispose = true; + Clear(); +#if FANTASY_WEBGL + Pool>.Return(this); +#else + MultiThreadPool.Return(this); +#endif + } + + /// + /// 获取一个值,该值指示当前实例是否为对象池中的实例。 + /// + /// + public bool IsPool() + { + return _isPool; + } + + /// + /// 设置一个值,该值指示当前实例是否为对象池中的实例。 + /// + /// + public void SetIsPool(bool isPool) + { + _isPool = isPool; + } + } + + /// + /// 一对多哈希集合(OneToManyHashSet),用于创建和管理键对应多个值的集合。 + /// + /// 键的类型。 + /// 值的类型。 + public class OneToManyHashSet : Dictionary> where TKey : notnull + { + /// 用于回收和重用的空闲值集合队列。 + private readonly Queue> _queue = new Queue>(); + /// 设置最大回收限制,用于控制值集合的最大数量。 + private readonly int _recyclingLimit = 120; + /// 一个空的、不包含任何元素的哈希集合,用于在查找失败时返回。 + private static HashSet _empty = new HashSet(); + + /// + /// 初始化 类的新实例。 + /// + public OneToManyHashSet() { } + + /// + /// 设置最大缓存数量 + /// + /// + /// 1:防止数据量过大、所以超过recyclingLimit的数据还是走GC. + /// 2:设置成0不控制数量,全部缓存 + /// + public OneToManyHashSet(int recyclingLimit) + { + _recyclingLimit = recyclingLimit; + } + + /// + /// 判断指定的键值对是否存在于集合中。 + /// + /// 键。 + /// 值。 + /// 如果存在则为 true,否则为 false。 + public bool Contains(TKey key, TValue value) + { + TryGetValue(key, out var list); + + return list != null && list.Contains(value); + } + + /// + /// 添加指定的键值对到集合中。 + /// + /// 键。 + /// 值。 + public void Add(TKey key, TValue value) + { + if (!TryGetValue(key, out var list)) + { + list = Fetch(); + list.Add(value); + Add(key, list); + + return; + } + + list.Add(value); + } + + /// + /// 从集合中移除指定键对应的值。 + /// + /// 键。 + /// 要移除的值。 + public void RemoveValue(TKey key, TValue value) + { + if (!TryGetValue(key, out var list)) return; + + list.Remove(value); + + if (list.Count == 0) RemoveKey(key); + } + + /// + /// 从集合中移除指定键及其对应的值集合。 + /// + /// 键。 + public void RemoveKey(TKey key) + { + if (!TryGetValue(key, out var list)) return; + + Remove(key); + Recycle(list); + } + + /// + /// 获取指定键对应的值集合,如果不存在则返回一个空的哈希集合。 + /// + /// 键。 + /// 对应的值集合或空的哈希集合。 + public HashSet GetValue(TKey key) + { + if (TryGetValue(key, out HashSet value)) + { + return value; + } + + return _empty; + } + + /// + /// 从队列中获取一个空闲的值集合,或者创建一个新的。 + /// + /// 值集合。 + private HashSet Fetch() + { + return _queue.Count <= 0 ? new HashSet() : _queue.Dequeue(); + } + + /// + /// 回收值集合到队列中,以便重复利用。 + /// + /// 要回收的值集合。 + private void Recycle(HashSet list) + { + list.Clear(); + + if (_recyclingLimit != 0 && _queue.Count > _recyclingLimit) return; + + _queue.Enqueue(list); + } + + /// + /// 清空集合中的数据并和队列。 + /// + protected new void Clear() + { + base.Clear(); + _queue.Clear(); + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/Collection/OneToManyListPool.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/Collection/OneToManyListPool.cs new file mode 100644 index 0000000..80568ef --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/Collection/OneToManyListPool.cs @@ -0,0 +1,232 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Fantasy.Pool; + +#pragma warning disable CS8600 // Converting null literal or possible null value to non-nullable type. +#pragma warning disable CS8603 // Possible null reference return. + +namespace Fantasy.DataStructure.Collection +{ + /// + /// 可回收的、一对多关系的列表池。 + /// + /// 键的类型。 + /// 值的类型。 + public class OneToManyListPool : OneToManyList, IDisposable, IPool where TKey : notnull + { + private bool _isPool; + private bool _isDispose; + + /// + /// 创建一个 一对多关系的列表池的实例。 + /// + /// 创建的实例。 + public static OneToManyListPool Create() + { +#if FANTASY_WEBGL || FANTASY_EXPORTER + var list = Pool>.Rent(); +#else + var list = MultiThreadPool.Rent>(); +#endif + list._isDispose = false; + list._isPool = true; + return list; + } + + /// + /// 释放当前对象所占用的资源,并将对象回收到对象池中。 + /// + public void Dispose() + { + if (_isDispose) + { + return; + } + + _isDispose = true; + Clear(); +#if FANTASY_WEBGL || FANTASY_EXPORTER + Pool>.Return(this); +#else + MultiThreadPool.Return(this); +#endif + } + + /// + /// 获取一个值,该值指示当前实例是否为对象池中的实例。 + /// + /// + public bool IsPool() + { + return _isPool; + } + + /// + /// 设置一个值,该值指示当前实例是否为对象池中的实例。 + /// + /// + public void SetIsPool(bool isPool) + { + _isPool = isPool; + } + } + + /// + /// 一对多关系的列表字典。 + /// + /// 键的类型。 + /// 值的类型。 + public class OneToManyList : Dictionary> where TKey : notnull + { + private readonly int _recyclingLimit = 120; + private static readonly List Empty = new List(); + private readonly Queue> _queue = new Queue>(); + + /// + /// 初始化一个新的 实例。 + /// + public OneToManyList() { } + + /// + /// 设置最大缓存数量 + /// + /// + /// 1:防止数据量过大、所以超过recyclingLimit的数据还是走GC. + /// 2:设置成0不控制数量,全部缓存 + /// + public OneToManyList(int recyclingLimit) + { + _recyclingLimit = recyclingLimit; + } + + /// + /// 判断给定的键和值是否存在于列表中。 + /// + /// 要搜索的键。 + /// 要搜索的值。 + /// 如果存在则为 ,否则为 + public bool Contains(TKey key, TValue value) + { + TryGetValue(key, out var list); + + return list != null && list.Contains(value); + } + + /// + /// 向列表中添加指定键和值。 + /// + /// 要添加值的键。 + /// 要添加的值。 + public void Add(TKey key, TValue value) + { + if (!TryGetValue(key, out var list)) + { + list = Fetch(); + list.Add(value); + Add(key, list); + + return; + } + + list.Add(value); + } + + /// + /// 获取指定键对应的列表中的第一个值。 + /// + /// 要获取值的键。 + /// 键对应的列表中的第一个值。 + public TValue First(TKey key) + { + return !TryGetValue(key, out var list) ? default : list.FirstOrDefault(); + } + + /// + /// 从列表中移除指定键和值。 + /// + /// 要移除值的键。 + /// 要移除的值。 + /// 如果成功移除则为 ,否则为 + public bool RemoveValue(TKey key, TValue value) + { + if (!TryGetValue(key, out var list)) + { + return true; + } + + var isRemove = list.Remove(value); + + if (list.Count == 0) + { + isRemove = RemoveByKey(key); + } + + return isRemove; + } + + /// + /// 从列表中移除指定键及其关联的所有值。 + /// + /// 要移除的键。 + /// 如果成功移除则为 ,否则为 + public bool RemoveByKey(TKey key) + { + if (!TryGetValue(key, out var list)) + { + return false; + } + + Remove(key); + Recycle(list); + return true; + } + + /// + /// 获取指定键关联的所有值的列表。 + /// + /// 要获取值的键。 + /// 键关联的所有值的列表。 + public List GetValues(TKey key) + { + if (TryGetValue(key, out List list)) + { + return list; + } + + return Empty; + } + + /// + /// 清除字典中的所有键值对,并回收相关的值集合。 + /// + public new void Clear() + { + foreach (var keyValuePair in this) Recycle(keyValuePair.Value); + + base.Clear(); + } + + /// + /// 从空闲值集合队列中获取一个值集合,如果队列为空则创建一个新的值集合。 + /// + /// 从队列中获取的值集合。 + private List Fetch() + { + return _queue.Count <= 0 ? new List() : _queue.Dequeue(); + } + + /// + /// 回收一个不再使用的值集合到空闲值集合队列中。 + /// + /// 要回收的值集合。 + private void Recycle(List list) + { + list.Clear(); + + if (_recyclingLimit != 0 && _queue.Count > _recyclingLimit) return; + + _queue.Enqueue(list); + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/Collection/OneToManyQueuePool.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/Collection/OneToManyQueuePool.cs new file mode 100644 index 0000000..222576e --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/Collection/OneToManyQueuePool.cs @@ -0,0 +1,204 @@ +using System; +using System.Collections.Generic; +using Fantasy.Pool; + +#pragma warning disable CS8603 + +namespace Fantasy.DataStructure.Collection +{ + /// + /// 支持一对多关系的队列池,用于存储具有相同键的值的队列集合。 + /// + /// 键的类型。 + /// 值的类型。 + public class OneToManyQueuePool : OneToManyQueue, IDisposable, IPool where TKey : notnull + { + private bool _isPool; + private bool _isDispose; + + /// + /// 创建一个 一对多关系的队列池的实例。 + /// + /// 创建的实例。 + public static OneToManyQueuePool Create() + { +#if FANTASY_WEBGL + var a = Pool>.Rent(); +#else + var a = MultiThreadPool.Rent>(); +#endif + a._isDispose = false; + a._isPool = true; + return a; + } + + /// + /// 释放当前实例所占用的资源,并将实例回收到对象池中。 + /// + public void Dispose() + { + if (_isDispose) + { + return; + } + + _isDispose = true; + Clear(); +#if FANTASY_WEBGL + Pool>.Return(this); +#else + MultiThreadPool.Return(this); +#endif + } + + /// + /// 获取一个值,该值指示当前实例是否为对象池中的实例。 + /// + /// + public bool IsPool() + { + return _isPool; + } + + /// + /// 设置一个值,该值指示当前实例是否为对象池中的实例。 + /// + /// + public void SetIsPool(bool isPool) + { + _isPool = isPool; + } + } + + /// + /// 支持一对多关系的队列,用于存储具有相同键的值的队列集合。 + /// + /// 键的类型。 + /// 值的类型。 + public class OneToManyQueue : Dictionary> where TKey : notnull + { + private readonly Queue> _queue = new Queue>(); + private readonly int _recyclingLimit; + + /// + /// 创建一个 一对多关系的队列的实例。设置最大缓存数量 + /// + /// + /// 1:防止数据量过大、所以超过recyclingLimit的数据还是走GC. + /// 2:设置成0不控制数量,全部缓存 + /// + public OneToManyQueue(int recyclingLimit = 0) + { + _recyclingLimit = recyclingLimit; + } + + /// + /// 判断指定键的值队列是否包含指定的值。 + /// + /// 要查找的键。 + /// 要查找的值。 + /// 如果存在,则为 true;否则为 false + public bool Contains(TKey key, TValue value) + { + TryGetValue(key, out var list); + + return list != null && list.Contains(value); + } + + /// + /// 将指定的值添加到指定键的值队列中。 + /// + /// 要添加值的键。 + /// 要添加的值。 + public void Enqueue(TKey key, TValue value) + { + if (!TryGetValue(key, out var list)) + { + list = Fetch(); + list.Enqueue(value); + Add(key, list); + return; + } + + list.Enqueue(value); + } + + /// + /// 从指定键的值队列中出队一个值。 + /// + /// 要出队的键。 + /// 出队的值。 + public TValue Dequeue(TKey key) + { + if (!TryGetValue(key, out var list) || list.Count == 0) + { + return default; + } + + var value = list.Dequeue(); + + if (list.Count == 0) + { + RemoveKey(key); + } + + return value; + } + + /// + /// 尝试从指定键的值队列中出队一个值。 + /// + /// 要出队的键。 + /// 出队的值。 + /// 如果成功出队,则为 true;否则为 false + public bool TryDequeue(TKey key, out TValue value) + { + value = Dequeue(key); + + return value != null; + } + + /// + /// 从字典中移除指定键及其对应的值队列。 + /// + /// 要移除的键。 + public void RemoveKey(TKey key) + { + if (!TryGetValue(key, out var list)) return; + + Remove(key); + Recycle(list); + } + + /// + /// 从队列池中获取一个值队列。如果队列池为空,则创建一个新的值队列。 + /// + /// 获取的值队列。 + private Queue Fetch() + { + return _queue.Count <= 0 ? new Queue() : _queue.Dequeue(); + } + + /// + /// 回收一个不再使用的值队列到队列池中,以便重用。 + /// + /// 要回收的值队列。 + private void Recycle(Queue list) + { + list.Clear(); + + if (_recyclingLimit != 0 && _queue.Count > _recyclingLimit) return; + + _queue.Enqueue(list); + } + + /// + /// 清空当前实例的数据,同时回收所有值队列。 + /// + protected new void Clear() + { + base.Clear(); + _queue.Clear(); + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/Collection/ReuseList.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/Collection/ReuseList.cs new file mode 100644 index 0000000..b4395e8 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/Collection/ReuseList.cs @@ -0,0 +1,69 @@ +using System; +using System.Collections.Generic; +using Fantasy.Pool; + +namespace Fantasy.DataStructure.Collection +{ + /// + /// 可重用的列表,继承自 类。该类支持通过对象池重用列表实例,以减少对象分配和释放的开销。 + /// + /// 列表中元素的类型。 + public sealed class ReuseList : List, IDisposable, IPool + { + private bool _isPool; + private bool _isDispose; + + /// + /// 创建一个 可重用的列表的实例。 + /// + /// 创建的实例。 + public static ReuseList Create() + { +#if FANTASY_WEBGL + var list = Pool>.Rent(); +#else + var list = MultiThreadPool.Rent>(); +#endif + list._isDispose = false; + list._isPool = true; + return list; + } + + /// + /// 释放该实例所占用的资源,并将实例返回到对象池中,以便重用。 + /// + public void Dispose() + { + if (_isDispose) + { + return; + } + + _isDispose = true; + Clear(); +#if FANTASY_WEBGL + Pool>.Return(this); +#else + MultiThreadPool.Return(this); +#endif + } + + /// + /// 获取一个值,该值指示当前实例是否为对象池中的实例。 + /// + /// + public bool IsPool() + { + return _isPool; + } + + /// + /// 设置一个值,该值指示当前实例是否为对象池中的实例。 + /// + /// + public void SetIsPool(bool isPool) + { + _isPool = isPool; + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/Collection/SortedConcurrentOneToManyListPool.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/Collection/SortedConcurrentOneToManyListPool.cs new file mode 100644 index 0000000..464ab58 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/Collection/SortedConcurrentOneToManyListPool.cs @@ -0,0 +1,226 @@ +#if !FANTASY_WEBGL +using System; +using System.Collections.Generic; +using System.Linq; +using Fantasy.Pool; + +#pragma warning disable CS8603 + +namespace Fantasy.DataStructure.Collection +{ + /// + /// 基于排序字典和并发集合实现的一对多映射列表的对象池包装类,继承自 类, + /// 同时实现了 接口,以支持对象的重用和释放。 + /// + /// 键的类型。 + /// 值的类型。 + public class SortedConcurrentOneToManyListPool : SortedConcurrentOneToManyList, IDisposable, IPool where TKey : notnull + { + private bool _isPool; + private bool _isDispose; + + /// + /// 创建一个新的 实例,使用默认的参数设置。 + /// + /// 新创建的 实例。 + public static SortedConcurrentOneToManyListPool Create() + { + var a = MultiThreadPool.Rent>(); + a._isDispose = false; + a._isPool = true; + return a; + } + + /// + /// 释放当前对象池实例,将其返回到对象池以供重用。 + /// + public void Dispose() + { + if (_isDispose) + { + return; + } + + _isDispose = true; + Clear(); + MultiThreadPool.Return(this); + } + + /// + /// 获取一个值,该值指示当前实例是否为对象池中的实例。 + /// + /// + public bool IsPool() + { + return _isPool; + } + + /// + /// 设置一个值,该值指示当前实例是否为对象池中的实例。 + /// + /// + public void SetIsPool(bool isPool) + { + _isPool = isPool; + } + } + + /// + /// 基于排序字典和并发集合实现的一多对映射列表类,继承自 类, + /// 用于在多个值与一个键关联的情况下进行管理和存储。该类支持并发操作,适用于多线程环境。 + /// + /// 键的类型。 + /// 值的类型。 + public class SortedConcurrentOneToManyList : SortedDictionary> where TKey : notnull + { + /// 用于同步操作的锁对象,它确保在多线程环境下对数据的安全访问。 + private readonly object _lockObject = new object(); + /// 用于存储缓存的队列。 + private readonly Queue> _queue = new Queue>(); + /// 控制缓存回收的限制。当缓存的数量超过此限制时,旧的缓存将会被回收。 + private readonly int _recyclingLimit; + + /// + /// 初始化一个新的 类的实例,使用默认的参数设置。 + /// + public SortedConcurrentOneToManyList() + { + } + + /// + /// 初始化一个新的 类的实例,指定最大缓存数量。 + /// + /// + /// 1:防止数据量过大、所以超过recyclingLimit的数据还是走GC. + /// 2:设置成0不控制数量,全部缓存 + /// + public SortedConcurrentOneToManyList(int recyclingLimit = 0) + { + _recyclingLimit = recyclingLimit; + } + + /// + /// 检查指定的键和值是否存在于映射列表中。 + /// + /// 要检查的键。 + /// 要检查的值。 + /// 如果存在,则为 true;否则为 false。 + public bool Contains(TKey key, TValue value) + { + lock (_lockObject) + { + TryGetValue(key, out var list); + + return list != null && list.Contains(value); + } + } + + /// + /// 将指定的值添加到与指定键关联的列表中。 + /// + /// 要关联值的键。 + /// 要添加到列表的值。 + public void Add(TKey key, TValue value) + { + lock (_lockObject) + { + if (!TryGetValue(key, out var list)) + { + list = Fetch(); + list.Add(value); + base[key] = list; + return; + } + + list.Add(value); + } + } + + /// + /// 获取与指定键关联的列表中的第一个值。 + /// 如果列表不存在或为空,则返回默认值。 + /// + /// 要获取第一个值的键。 + /// 第一个值,或默认值。 + public TValue First(TKey key) + { + lock (_lockObject) + { + return !TryGetValue(key, out var list) ? default : list.FirstOrDefault(); + } + } + + /// + /// 从与指定键关联的列表中移除指定的值。 + /// 如果列表不存在或值不存在于列表中,则不执行任何操作。 + /// + /// 要移除值的键。 + /// 要移除的值。 + public void RemoveValue(TKey key, TValue value) + { + lock (_lockObject) + { + if (!TryGetValue(key, out var list)) return; + + list.Remove(value); + + if (list.Count == 0) RemoveKey(key); + } + } + + /// + /// 从映射列表中移除指定的键及其关联的列表。 + /// 如果键不存在于映射列表中,则不执行任何操作。 + /// + /// 要移除的键。 + public void RemoveKey(TKey key) + { + lock (_lockObject) + { + if (!TryGetValue(key, out var list)) return; + + Remove(key); + + Recycle(list); + } + } + + /// + /// 从缓存中获取一个可重用的列表。如果缓存中不存在列表,则创建一个新的列表并返回。 + /// + /// 可重用的列表。 + private List Fetch() + { + lock (_lockObject) + { + return _queue.Count <= 0 ? new List() : _queue.Dequeue(); + } + } + + /// + /// 将不再使用的列表回收到缓存中,以便重复利用。如果缓存数量超过限制,则丢弃列表而不进行回收。 + /// + /// 要回收的列表。 + private void Recycle(List list) + { + lock (_lockObject) + { + list.Clear(); + + if (_recyclingLimit != 0 && _queue.Count > _recyclingLimit) return; + + _queue.Enqueue(list); + } + } + + /// + /// 清空映射列表以及队列。 + /// + protected new void Clear() + { + base.Clear(); + _queue.Clear(); + } + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/Collection/SortedOneToManyHashSetPool.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/Collection/SortedOneToManyHashSetPool.cs new file mode 100644 index 0000000..8158db5 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/Collection/SortedOneToManyHashSetPool.cs @@ -0,0 +1,192 @@ +using System; +using System.Collections.Generic; +using Fantasy.Pool; + +namespace Fantasy.DataStructure.Collection +{ + /// + /// 基于排序字典实现的一对多关系的映射哈希集合的对象池包装类,将唯一键映射到多个值的哈希集合。 + /// 同时实现了 接口,以支持对象的重用和释放。 + /// + /// 字典中键的类型。 + /// 哈希集合中值的类型。 + public class SortedOneToManyHashSetPool : SortedOneToManyHashSet, IDisposable, IPool where TKey : notnull + { + private bool _isPool; + private bool _isDispose; + + /// + /// 创建一个 实例。 + /// + /// 新创建的实例。 + public static SortedOneToManyHashSetPool Create() + { +#if FANTASY_WEBGL + var a = Pool>.Rent(); +#else + var a = MultiThreadPool.Rent>(); +#endif + a._isDispose = false; + a._isPool = true; + return a; + } + + /// + /// 释放当前对象池实例,将其返回到对象池以供重用。 + /// + public void Dispose() + { + if (_isDispose) + { + return; + } + + _isDispose = true; + Clear(); +#if FANTASY_WEBGL + Pool>.Return(this); +#else + MultiThreadPool.Return(this); +#endif + } + + /// + /// 获取一个值,该值指示当前实例是否为对象池中的实例。 + /// + /// + public bool IsPool() + { + return _isPool; + } + + /// + /// 设置一个值,该值指示当前实例是否为对象池中的实例。 + /// + /// + public void SetIsPool(bool isPool) + { + _isPool = isPool; + } + } + + /// + /// 基于排序字典实现的一对多关系的映射哈希集合类,将唯一键映射到多个值的哈希集合。 + /// 用于在多个值与一个键关联的情况下进行管理和存储。 + /// + /// 字典中键的类型。 + /// 集合中值的类型。 + public class SortedOneToManyHashSet : SortedDictionary> where TKey : notnull + { + private readonly Queue> _queue = new Queue>(); + private readonly int _recyclingLimit = 120; + + /// + /// 创建一个新的 实例。 + /// + public SortedOneToManyHashSet() { } + + /// + /// 创建一个新的 实例,设置最大缓存数量 + /// + /// + /// 1:防止数据量过大、所以超过recyclingLimit的数据还是走GC. + /// 2:设置成0不控制数量,全部缓存 + /// + public SortedOneToManyHashSet(int recyclingLimit) + { + _recyclingLimit = recyclingLimit; + } + + /// + /// 判断哈希集合中是否包含指定的键值对。 + /// + /// 要查找的键。 + /// 要查找的值。 + /// 如果键值对存在,则为 true;否则为 false。 + public bool Contains(TKey key, TValue value) + { + TryGetValue(key, out var list); + + return list != null && list.Contains(value); + } + + /// + /// 将指定值添加到给定键关联的哈希集合中。 + /// + /// 要添加值的键。 + /// 要添加的值。 + public void Add(TKey key, TValue value) + { + if (!TryGetValue(key, out var list)) + { + list = Fetch(); + list.Add(value); + Add(key, list); + + return; + } + + list.Add(value); + } + + /// + /// 从指定键关联的哈希集合中移除特定值。 + /// 如果哈希集合不存在或值不存在于集合中,则不执行任何操作。 + /// + /// 要移除值的键。 + /// 要移除的值。 + public void RemoveValue(TKey key, TValue value) + { + if (!TryGetValue(key, out var list)) return; + + list.Remove(value); + + if (list.Count == 0) RemoveKey(key); + } + + /// + /// 从字典中移除指定键以及关联的哈希集合,并将集合进行回收。 + /// 如果键不存在于映射列表中,则不执行任何操作。 + /// + /// 要移除的键。 + public void RemoveKey(TKey key) + { + if (!TryGetValue(key, out var list)) return; + + Remove(key); + + Recycle(list); + } + + /// + /// 获取一个空的或回收的哈希集合。 + /// + /// 获取的哈希集合实例。 + private HashSet Fetch() + { + return _queue.Count <= 0 ? new HashSet() : _queue.Dequeue(); + } + + /// + /// 回收一个哈希集合,将其清空并放入回收队列中。 + /// + /// 要回收的哈希集合。 + private void Recycle(HashSet list) + { + list.Clear(); + + if (_recyclingLimit != 0 && _queue.Count > _recyclingLimit) return; + + _queue.Enqueue(list); + } + + /// + /// 重写 Clear 方法,清空字典并清空回收队列。 + /// + protected new void Clear() + { + base.Clear(); + _queue.Clear(); + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/Collection/SortedOneToManyListPool.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/Collection/SortedOneToManyListPool.cs new file mode 100644 index 0000000..f0bae12 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/Collection/SortedOneToManyListPool.cs @@ -0,0 +1,217 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Fantasy.Pool; + +#pragma warning disable CS8603 + +namespace Fantasy.DataStructure.Collection +{ + /// + /// 基于排序字典实现的一对多映射列表的对象池包装类,继承自 类, + /// 同时实现了 接口,以支持对象的重用和释放。 + /// + /// 字典中键的类型。 + /// 列表中值的类型。 + public class SortedOneToManyListPool : SortedOneToManyList, IDisposable, IPool where TKey : notnull + { + private bool _isPool; + private bool _isDispose; + + /// + /// 创建一个 实例。 + /// + /// 新创建的实例。 + public static SortedOneToManyListPool Create() + { +#if FANTASY_WEBGL + var a = Pool>.Rent(); +#else + var a = MultiThreadPool.Rent>(); +#endif + a._isDispose = false; + a._isPool = true; + return a; + } + + /// + /// 释放当前对象池实例,将其返回到对象池以供重用。 + /// + public void Dispose() + { + if (_isDispose) + { + return; + } + + _isDispose = true; + Clear(); +#if FANTASY_WEBGL + Pool>.Return(this); +#else + MultiThreadPool.Return(this); +#endif + } + + /// + /// 获取一个值,该值指示当前实例是否为对象池中的实例。 + /// + /// + public bool IsPool() + { + return _isPool; + } + + /// + /// 设置一个值,该值指示当前实例是否为对象池中的实例。 + /// + /// + public void SetIsPool(bool isPool) + { + _isPool = isPool; + } + } + + /// + /// 基于排序字典实现的一对多关系的映射列表类,将唯一键映射到包含多个值的列表。 + /// 用于在多个值与一个键关联的情况下进行管理和存储。 + /// + /// 字典中键的类型。 + /// 列表中值的类型。 + public class SortedOneToManyList : SortedDictionary> where TKey : notnull + { + private readonly Queue> _queue = new Queue>(); + private readonly int _recyclingLimit; + + /// + /// 创建一个新的 实例。 + /// + public SortedOneToManyList() + { + } + + /// + /// 创建一个新的 实例,设置最大缓存数量 + /// + /// + /// 1:防止数据量过大、所以超过recyclingLimit的数据还是走GC. + /// 2:设置成0不控制数量,全部缓存 + /// + public SortedOneToManyList(int recyclingLimit = 0) + { + _recyclingLimit = recyclingLimit; + } + + /// + /// 判断列表中是否包含指定的键值对。 + /// + /// 要查找的键。 + /// 要查找的值。 + /// 如果键值对存在,则为 true;否则为 false。 + public bool Contains(TKey key, TValue value) + { + TryGetValue(key, out var list); + + return list != null && list.Contains(value); + } + + /// + /// 将指定值添加到给定键关联的列表中。 + /// + /// 要添加值的键。 + /// 要添加的值。 + public void Add(TKey key, TValue value) + { + if (!TryGetValue(key, out var list)) + { + list = Fetch(); + list.Add(value); + base[key] = list; + return; + } + + list.Add(value); + } + + /// + /// 获取指定键关联的列表中的第一个值。 + /// + /// 要查找值的键。 + /// 指定键关联的列表中的第一个值,如果列表为空则返回默认值。 + public TValue First(TKey key) + { + return !TryGetValue(key, out var list) ? default : list.FirstOrDefault(); + } + + /// + /// 从指定键关联的列表中移除特定值。 + /// + /// 要移除值的键。 + /// 要移除的值。 + + public void RemoveValue(TKey key, TValue value) + { + if (!TryGetValue(key, out var list)) + { + return; + } + + list.Remove(value); + + if (list.Count == 0) + { + RemoveKey(key); + } + } + + /// + /// 从字典中移除指定键以及关联的列表,并将列表进行回收。 + /// + /// 要移除的键。 + + public void RemoveKey(TKey key) + { + if (!TryGetValue(key, out var list)) + { + return; + } + + Remove(key); + Recycle(list); + } + + /// + /// 获取一个空的或回收的列表。 + /// + /// 获取的列表实例。 + private List Fetch() + { + return _queue.Count <= 0 ? new List() : _queue.Dequeue(); + } + + /// + /// 回收一个列表,将其清空并放入回收队列中。如果缓存数量超过限制,则丢弃列表而不进行回收 + /// + /// 要回收的列表。 + private void Recycle(List list) + { + list.Clear(); + + if (_recyclingLimit != 0 && _queue.Count > _recyclingLimit) + { + return; + } + + _queue.Enqueue(list); + } + + /// + /// 重写 Clear 方法,清空字典并清空回收队列。 + /// + protected new void Clear() + { + base.Clear(); + _queue.Clear(); + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/Dictionary/DictionaryExtensions.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/Dictionary/DictionaryExtensions.cs new file mode 100644 index 0000000..ed0aa57 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/Dictionary/DictionaryExtensions.cs @@ -0,0 +1,31 @@ +using System.Collections.Generic; +#pragma warning disable CS8601 // Possible null reference assignment. + +namespace Fantasy.DataStructure.Dictionary +{ + /// + /// 提供对字典的扩展方法。 + /// + public static class DictionaryExtensions + { + /// + /// 尝试从字典中移除指定键,并返回相应的值。 + /// + /// 字典中键的类型。 + /// 字典中值的类型。 + /// 要操作的字典实例。 + /// 要移除的键。 + /// 从字典中移除的值(如果成功移除)。 + /// 如果成功移除键值对,则为 true;否则为 false。 + public static bool TryRemove(this IDictionary self, T key, out TV value) + { + if (!self.TryGetValue(key, out value)) + { + return false; + } + + self.Remove(key); + return true; + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/Dictionary/DictionaryPool.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/Dictionary/DictionaryPool.cs new file mode 100644 index 0000000..567901c --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/Dictionary/DictionaryPool.cs @@ -0,0 +1,70 @@ +using System; +using System.Collections.Generic; +using Fantasy.Pool; + +namespace Fantasy.DataStructure.Dictionary +{ + /// + /// 提供一个可以使用对象池管理的字典类。 + /// + /// 字典中键的类型。 + /// 字典中值的类型。 + public sealed class DictionaryPool : Dictionary, IDisposable, IPool where TM : notnull + { + private bool _isPool; + private bool _isDispose; + + /// + /// 释放实例占用的资源。 + /// + public void Dispose() + { + if (_isDispose) + { + return; + } + + _isDispose = true; + Clear(); +#if FANTASY_WEBGL + Pool>.Return(this); +#else + MultiThreadPool.Return(this); +#endif + } + + /// + /// 创建一个新的 实例。 + /// + /// 新创建的实例。 + public static DictionaryPool Create() + { +#if FANTASY_WEBGL + var dictionary = Pool>.Rent(); +#else + var dictionary = MultiThreadPool.Rent>(); +#endif + dictionary._isDispose = false; + dictionary._isPool = true; + return dictionary; + } + + /// + /// 获取一个值,该值指示当前实例是否为对象池中的实例。 + /// + /// + public bool IsPool() + { + return _isPool; + } + + /// + /// 设置一个值,该值指示当前实例是否为对象池中的实例。 + /// + /// + public void SetIsPool(bool isPool) + { + _isPool = isPool; + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/Dictionary/DoubleMapDictionaryPool.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/Dictionary/DoubleMapDictionaryPool.cs new file mode 100644 index 0000000..e868710 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/Dictionary/DoubleMapDictionaryPool.cs @@ -0,0 +1,289 @@ +using System; +using System.Collections.Generic; +using Fantasy.Pool; + +#pragma warning disable CS8601 // Possible null reference assignment. +#pragma warning disable CS8604 // Possible null reference argument. +#pragma warning disable CS8603 // Possible null reference return. + +namespace Fantasy.DataStructure.Dictionary +{ + /// + /// 提供一个双向映射字典对象池类,用于双向键值对映射。 + /// + /// 字典中键的类型。 + /// 字典中值的类型。 + public class DoubleMapDictionaryPool : DoubleMapDictionary, IDisposable, IPool where TKey : notnull where TValue : notnull + { + private bool _isPool; + private bool _isDispose; + + /// + /// 创建一个新的 实例。 + /// + /// 新创建的实例。 + public static DoubleMapDictionaryPool Create() + { +#if FANTASY_WEBGL + var a = Pool>.Rent(); +#else + var a = MultiThreadPool.Rent>(); +#endif + a._isDispose = false; + a._isPool = true; + return a; + } + + /// + /// 释放实例占用的资源。 + /// + public void Dispose() + { + if (_isDispose) + { + return; + } + + _isDispose = true; + Clear(); +#if FANTASY_WEBGL + Pool>.Return(this); +#else + MultiThreadPool.Return(this); +#endif + } + + /// + /// 获取一个值,该值指示当前实例是否为对象池中的实例。 + /// + /// + public bool IsPool() + { + return _isPool; + } + + /// + /// 设置一个值,该值指示当前实例是否为对象池中的实例。 + /// + /// + public void SetIsPool(bool isPool) + { + _isPool = isPool; + } + } + + /// + /// 可以实现双向映射的字典类,用于将键和值进行双向映射。 + /// + /// 键的类型,不能为 null。 + /// 值的类型,不能为 null。 + public class DoubleMapDictionary where TK : notnull where TV : notnull + { + private readonly Dictionary _kv = new Dictionary(); + private readonly Dictionary _vk = new Dictionary(); + + /// + /// 创建一个新的空的 实例。 + /// + public DoubleMapDictionary() { } + + /// + /// 创建一个新的具有指定初始容量的 实例。 + /// + /// 初始容量。 + public DoubleMapDictionary(int capacity) + { + _kv = new Dictionary(capacity); + _vk = new Dictionary(capacity); + } + + /// + /// 获取包含字典中所有键的列表。 + /// + public List Keys => new List(_kv.Keys); + + /// + /// 获取包含字典中所有值的列表。 + /// + public List Values => new List(_vk.Keys); + + /// + /// 对字典中的每个键值对执行指定的操作。 + /// + /// 要执行的操作。 + public void ForEach(Action action) + { + if (action == null) + { + return; + } + + var keys = _kv.Keys; + foreach (var key in keys) + { + action(key, _kv[key]); + } + } + + /// + /// 将指定的键值对添加到字典中。 + /// + /// 要添加的键。 + /// 要添加的值。 + public void Add(TK key, TV value) + { + if (key == null || value == null || _kv.ContainsKey(key) || _vk.ContainsKey(value)) + { + return; + } + + _kv.Add(key, value); + _vk.Add(value, key); + } + + /// + /// 根据指定的键获取相应的值。 + /// + /// 要查找值的键。 + /// 与指定键关联的值,如果找不到键,则返回默认值。 + public TV GetValueByKey(TK key) + { + if (key != null && _kv.ContainsKey(key)) + { + return _kv[key]; + } + + return default; + } + + /// + /// 尝试根据指定的键获取相应的值。 + /// + /// 要查找值的键。 + /// 如果找到,则为与指定键关联的值;否则为值的默认值。 + /// 如果找到键,则为 true;否则为 false。 + public bool TryGetValueByKey(TK key, out TV value) + { + var result = key != null && _kv.ContainsKey(key); + + value = result ? _kv[key] : default; + + return result; + } + + /// + /// 根据指定的值获取相应的键。 + /// + /// 要查找键的值。 + /// 与指定值关联的键,如果找不到值,则返回默认键。 + public TK GetKeyByValue(TV value) + { + if (value != null && _vk.ContainsKey(value)) + { + return _vk[value]; + } + + return default; + } + + /// + /// 尝试根据指定的值获取相应的键。 + /// + /// 要查找键的值。 + /// 如果找到,则为与指定值关联的键;否则为键的默认值。 + /// 如果找到值,则为 true;否则为 false。 + public bool TryGetKeyByValue(TV value, out TK key) + { + var result = value != null && _vk.ContainsKey(value); + + key = result ? _vk[value] : default; + + return result; + } + + /// + /// 根据指定的键移除键值对。 + /// + /// 要移除的键。 + public void RemoveByKey(TK key) + { + if (key == null) + { + return; + } + + if (!_kv.TryGetValue(key, out var value)) + { + return; + } + + _kv.Remove(key); + _vk.Remove(value); + } + + /// + /// 根据指定的值移除键值对。 + /// + /// 要移除的值。 + public void RemoveByValue(TV value) + { + if (value == null) + { + return; + } + + if (!_vk.TryGetValue(value, out var key)) + { + return; + } + + _kv.Remove(key); + _vk.Remove(value); + } + + /// + /// 清空字典中的所有键值对。 + /// + public void Clear() + { + _kv.Clear(); + _vk.Clear(); + } + + /// + /// 判断字典是否包含指定的键。 + /// + /// 要检查的键。 + /// 如果字典包含指定的键,则为 true;否则为 false。 + public bool ContainsKey(TK key) + { + return key != null && _kv.ContainsKey(key); + } + + /// + /// 判断字典是否包含指定的值。 + /// + /// 要检查的值。 + /// 如果字典包含指定的值,则为 true;否则为 false。 + public bool ContainsValue(TV value) + { + return value != null && _vk.ContainsKey(value); + } + + /// + /// 判断字典是否包含指定的键值对。 + /// + /// 要检查的键。 + /// 要检查的值。 + /// 如果字典包含指定的键值对,则为 true;否则为 false。 + public bool Contains(TK key, TV value) + { + if (key == null || value == null) + { + return false; + } + + return _kv.ContainsKey(key) && _vk.ContainsKey(value); + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/Dictionary/EntityDictionary.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/Dictionary/EntityDictionary.cs new file mode 100644 index 0000000..fc4d44f --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/Dictionary/EntityDictionary.cs @@ -0,0 +1,91 @@ +using System; +using System.Collections.Generic; +using Fantasy.Pool; + +namespace Fantasy.DataStructure.Dictionary +{ + /// + /// 提供一个带资源释放功能的实体字典类,支持使用对象池管理。 + /// + /// 字典中键的类型。 + /// 字典中值的类型,必须实现 IDisposable 接口。 + public sealed class EntityDictionary : Dictionary, IDisposable, IPool where TN : IDisposable where TM : notnull + { + private bool _isPool; + private bool _isDispose; + + /// + /// 创建一个新的 实例。 + /// + /// 新创建的实例。 + public static EntityDictionary Create() + { +#if FANTASY_WEBGL + var entityDictionary = Pool>.Rent(); +#else + var entityDictionary = MultiThreadPool.Rent>(); +#endif + entityDictionary._isDispose = false; + entityDictionary._isPool = true; + return entityDictionary; + } + + /// + /// 清空字典中的所有键值对,并释放值的资源。 + /// + public new void Clear() + { + foreach (var keyValuePair in this) + { + keyValuePair.Value.Dispose(); + } + + base.Clear(); + } + + /// + /// 清空字典中的所有键值对,但不释放值的资源。 + /// + public void ClearNotDispose() + { + base.Clear(); + } + + /// + /// 释放实例占用的资源。 + /// + public void Dispose() + { + if (_isDispose) + { + return; + } + + _isDispose = true; + Clear(); +#if FANTASY_WEBGL + Pool>.Return(this); +#else + MultiThreadPool.Return(this); +#endif + } + + /// + /// 获取一个值,该值指示当前实例是否为对象池中的实例。 + /// + /// + public bool IsPool() + { + return _isPool; + } + + /// + /// 设置一个值,该值指示当前实例是否为对象池中的实例。 + /// + /// + public void SetIsPool(bool isPool) + { + _isPool = isPool; + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/Dictionary/OneToManyDictionaryPool.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/Dictionary/OneToManyDictionaryPool.cs new file mode 100644 index 0000000..0515423 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/Dictionary/OneToManyDictionaryPool.cs @@ -0,0 +1,247 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Fantasy.Pool; + +#pragma warning disable CS8603 +#pragma warning disable CS8601 + +namespace Fantasy.DataStructure.Dictionary +{ + /// + /// 一对多映射关系的字典对象池。 + /// + /// 外部字典中的键类型。 + /// 内部字典中的键类型。 + /// 内部字典中的值类型。 + public class OneToManyDictionaryPool : OneToManyDictionary, IDisposable, IPool where TKey : notnull where TValueKey : notnull + { + private bool _isPool; + private bool _isDispose; + + /// + /// 创建一个 的实例。 + /// + /// 新创建的 OneToManyDictionaryPool 实例。 + public static OneToManyDictionaryPool Create() + { +#if FANTASY_WEBGL + var a = Pool>.Rent(); +#else + var a = MultiThreadPool.Rent>(); +#endif + a._isDispose = false; + a._isPool = true; + return a; + } + + /// + /// 释放当前实例及其资源。 + /// + public void Dispose() + { + if (_isDispose) + { + return; + } + + _isDispose = true; + Clear(); +#if FANTASY_WEBGL + Pool>.Return(this); +#else + MultiThreadPool.Return(this); +#endif + } + + /// + /// 获取一个值,该值指示当前实例是否为对象池中的实例。 + /// + /// + public bool IsPool() + { + return _isPool; + } + + /// + /// 设置一个值,该值指示当前实例是否为对象池中的实例。 + /// + /// + public void SetIsPool(bool isPool) + { + _isPool = isPool; + } + } + + /// + /// 一对多映射关系的字典。每个键都对应一个内部字典,该内部字典将键值映射到相应的值。 + /// + /// 外部字典中的键类型。 + /// 内部字典中的键类型。 + /// 内部字典中的值类型。 + public class OneToManyDictionary : Dictionary> + where TKey : notnull where TValueKey : notnull + { + private readonly Queue> _queue = new Queue>(); + private readonly int _recyclingLimit = 120; + + /// + /// 创建一个新的 实例。 + /// + public OneToManyDictionary() { } + + /// + /// 创建一个新的 实例,并指定最大缓存数量。 + /// + /// + /// 1:防止数据量过大、所以超过recyclingLimit的数据还是走GC. + /// 2:设置成0不控制数量,全部缓存 + /// + public OneToManyDictionary(int recyclingLimit = 0) + { + _recyclingLimit = recyclingLimit; + } + + /// + /// 检查是否包含指定的键值对。 + /// + /// 外部字典中的键。 + /// 内部字典中的键。 + /// 如果包含指定的键值对,则为 true;否则为 false。 + public bool Contains(TKey key, TValueKey valueKey) + { + TryGetValue(key, out var dic); + + return dic != null && dic.ContainsKey(valueKey); + } + + /// + /// 尝试获取指定键值对的值。 + /// + /// 外部字典中的键。 + /// 内部字典中的键。 + /// 获取的值,如果操作成功,则为值;否则为默认值。 + /// 如果操作成功,则为 true;否则为 false。 + public bool TryGetValue(TKey key, TValueKey valueKey, out TValue value) + { + value = default; + return TryGetValue(key, out var dic) && dic.TryGetValue(valueKey, out value); + } + + /// + /// 获取指定键的第一个值。 + /// + /// 要获取第一个值的键。 + public TValue First(TKey key) + { + return !TryGetValue(key, out var dic) ? default : dic.First().Value; + } + + /// + /// 向字典中添加指定的键值对。 + /// + /// 要添加键值对的键。 + /// 要添加键值对的内部字典键。 + /// 要添加的值。 + public void Add(TKey key, TValueKey valueKey, TValue value) + { + if (!TryGetValue(key, out var dic)) + { + dic = Fetch(); + dic[valueKey] = value; + // dic.Add(valueKey, value); + Add(key, dic); + + return; + } + + dic[valueKey] = value; + // dic.Add(valueKey, value); + } + + /// + /// 从字典中移除指定的键值对。 + /// + /// 要移除键值对的键。 + /// 要移除键值对的内部字典键。 + /// 如果成功移除键值对,则为 true;否则为 false。 + public bool Remove(TKey key, TValueKey valueKey) + { + if (!TryGetValue(key, out var dic)) return false; + + var result = dic.Remove(valueKey); + + if (dic.Count == 0) RemoveKey(key); + + return result; + } + + /// + /// 从字典中移除指定的键值对。 + /// + /// 要移除键值对的键。 + /// 要移除键值对的内部字典键。 + /// 如果成功移除键值对,则为移除的值;否则为默认值。 + /// 如果成功移除键值对,则为 true;否则为 false。 + public bool Remove(TKey key, TValueKey valueKey, out TValue value) + { + if (!TryGetValue(key, out var dic)) + { + value = default; + return false; + } + + var result = dic.TryGetValue(valueKey, out value); + + if (result) dic.Remove(valueKey); + + if (dic.Count == 0) RemoveKey(key); + + return result; + } + + /// + /// 移除字典中的指定键及其相关的所有键值对。 + /// + /// 要移除的键。 + public void RemoveKey(TKey key) + { + if (!TryGetValue(key, out var dic)) return; + + Remove(key); + Recycle(dic); + } + + /// + /// 从对象池中获取一个内部字典实例,如果池中没有,则创建一个新实例。 + /// + /// 获取的内部字典实例。 + private Dictionary Fetch() + { + return _queue.Count <= 0 ? new Dictionary() : _queue.Dequeue(); + } + + /// + /// 将不再使用的内部字典实例放回对象池中,以便后续重用。 + /// + /// 要放回对象池的内部字典实例。 + private void Recycle(Dictionary dic) + { + dic.Clear(); + + if (_recyclingLimit != 0 && _queue.Count > _recyclingLimit) return; + + _queue.Enqueue(dic); + } + + /// + /// 清空字典中的所有键值对,并将不再使用的内部字典实例放回对象池中。 + /// + public new void Clear() + { + foreach (var keyValuePair in this) Recycle(keyValuePair.Value); + + base.Clear(); + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/Dictionary/OneToManySortedDictionaryPool.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/Dictionary/OneToManySortedDictionaryPool.cs new file mode 100644 index 0000000..127a8ac --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/Dictionary/OneToManySortedDictionaryPool.cs @@ -0,0 +1,250 @@ +using System; +using System.Collections.Generic; +using Fantasy.Pool; + +#pragma warning disable CS8601 + +namespace Fantasy.DataStructure.Dictionary +{ + /// + /// 一对多映射关系的排序字典对象池。 + /// + /// 外部字典中的键类型。 + /// 内部字典中的排序键类型。 + /// 内部字典中的值类型。 + public class OneToManySortedDictionaryPool : OneToManySortedDictionary, IDisposable, IPool where TKey : notnull where TSortedKey : notnull + { + private bool _isPool; + private bool _isDispose; + + /// + /// 创建一个 的实例。 + /// + /// 新创建的 OneToManySortedDictionaryPool 实例。 + public static OneToManySortedDictionaryPool Create() + { +#if FANTASY_WEBGL + var a = Pool>.Rent(); +#else + var a = MultiThreadPool.Rent>(); +#endif + a._isDispose = false; + a._isPool = true; + return a; + } + + /// + /// 释放当前实例及其资源。 + /// + public void Dispose() + { + if (_isDispose) + { + return; + } + + _isDispose = true; + Clear(); +#if FANTASY_WEBGL + Pool>.Return(this); +#else + MultiThreadPool.Return(this); +#endif + } + + /// + /// 获取一个值,该值指示当前实例是否为对象池中的实例。 + /// + /// + public bool IsPool() + { + return _isPool; + } + + /// + /// 设置一个值,该值指示当前实例是否为对象池中的实例。 + /// + /// + public void SetIsPool(bool isPool) + { + _isPool = isPool; + } + } + + /// + /// 一对多映射关系的排序字典。每个外部键映射到一个内部排序字典,该内部排序字典将排序键映射到相应的值。 + /// + /// 外部字典中的键类型。 + /// 内部字典中的排序键类型。 + /// 内部字典中的值类型。 + public class + OneToManySortedDictionary : Dictionary> + where TSortedKey : notnull where TKey : notnull + { + /// 缓存队列的回收限制 + private readonly int _recyclingLimit = 120; + /// 缓存队列,用于存储已回收的内部排序字典 + private readonly Queue> _queue = new Queue>(); + + /// + /// 创建一个新的 实例。 + /// + protected OneToManySortedDictionary() { } + + /// + /// 创建一个新的 实例。设置最大缓存数量 + /// + /// + /// 1:防止数据量过大、所以超过recyclingLimit的数据还是走GC. + /// 2:设置成0不控制数量,全部缓存 + /// + public OneToManySortedDictionary(int recyclingLimit) + { + _recyclingLimit = recyclingLimit; + } + + /// + /// 检查字典是否包含指定的外部键。 + /// + /// 要检查的外部键。 + /// 如果字典包含指定的外部键,则为 true;否则为 false。 + public bool Contains(TKey key) + { + return this.ContainsKey(key); + } + + /// + /// 检查字典是否包含指定的外部键和排序键。 + /// + /// 要检查的外部键。 + /// 要检查的排序键。 + /// 如果字典包含指定的外部键和排序键,则为 true;否则为 false。 + public bool Contains(TKey key, TSortedKey sortedKey) + { + return TryGetValue(key, out var dic) && dic.ContainsKey(sortedKey); + } + + /// + /// 尝试从字典中获取指定外部键对应的内部排序字典。 + /// + /// 要获取内部排序字典的外部键。 + /// 获取到的内部排序字典,如果找不到则为 null。 + /// 如果找到内部排序字典,则为 true;否则为 false。 + public new bool TryGetValue(TKey key, out SortedDictionary dic) + { + return base.TryGetValue(key, out dic); + } + + /// + /// 尝试从字典中获取指定外部键和排序键对应的值。 + /// + /// 要获取值的外部键。 + /// 要获取值的排序键。 + /// 获取到的值,如果找不到则为 default。 + /// 如果找到值,则为 true;否则为 false。 + public bool TryGetValueBySortedKey(TKey key, TSortedKey sortedKey, out TValue value) + { + if (base.TryGetValue(key, out var dic)) + { + return dic.TryGetValue(sortedKey, out value); + } + + value = default; + return false; + } + + /// + /// 向字典中添加一个值,关联到指定的外部键和排序键。 + /// + /// 要关联值的外部键。 + /// 要关联值的排序键。 + /// 要添加的值。 + public void Add(TKey key, TSortedKey sortedKey, TValue value) + { + if (!TryGetValue(key, out var dic)) + { + dic = Fetch(); + dic.Add(sortedKey, value); + Add(key, dic); + + return; + } + + dic.Add(sortedKey, value); + } + + /// + /// 从字典中移除指定外部键和排序键关联的值。 + /// + /// 要移除值的外部键。 + /// 要移除值的排序键。 + /// 如果成功移除值,则为 true;否则为 false。 + public bool RemoveSortedKey(TKey key, TSortedKey sortedKey) + { + if (!TryGetValue(key, out var dic)) + { + return false; + } + + var isRemove = dic.Remove(sortedKey); + + if (dic.Count == 0) + { + isRemove = RemoveKey(key); + } + + return isRemove; + } + + /// + /// 从字典中移除指定外部键及其关联的所有值。 + /// + /// 要移除的外部键。 + /// 如果成功移除外部键及其关联的所有值,则为 true;否则为 false。 + public bool RemoveKey(TKey key) + { + if (!TryGetValue(key, out var list)) + { + return false; + } + + Remove(key); + Recycle(list); + return true; + } + + /// + /// 从缓存队列中获取一个内部排序字典。 + /// + /// 一个内部排序字典。 + private SortedDictionary Fetch() + { + return _queue.Count <= 0 ? new SortedDictionary() : _queue.Dequeue(); + } + + /// + /// 回收一个内部排序字典到缓存队列。 + /// + /// 要回收的内部排序字典。 + private void Recycle(SortedDictionary dic) + { + dic.Clear(); + + if (_recyclingLimit != 0 && _queue.Count > _recyclingLimit) + { + return; + } + + _queue.Enqueue(dic); + } + + /// + /// 清空字典以及内部排序字典缓存队列,释放所有资源。 + /// + protected new void Clear() + { + base.Clear(); + _queue.Clear(); + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/Dictionary/ReuseDictionary.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/Dictionary/ReuseDictionary.cs new file mode 100644 index 0000000..ebe12e9 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/Dictionary/ReuseDictionary.cs @@ -0,0 +1,70 @@ +using System; +using System.Collections.Generic; +using Fantasy.Pool; + +namespace Fantasy.DataStructure.Dictionary +{ + /// + /// 提供一个可以重用的字典类,支持使用对象池管理。 + /// + /// 字典中键的类型。 + /// 字典中值的类型。 + public sealed class ReuseDictionary : Dictionary, IDisposable, IPool where TM : notnull + { + private bool _isPool; + private bool _isDispose; + + /// + /// 创建一个新的 实例。 + /// + /// 新创建的实例。 + public static ReuseDictionary Create() + { +#if FANTASY_WEBGL + var entityDictionary = Pool>.Rent(); +#else + var entityDictionary = MultiThreadPool.Rent>(); +#endif + entityDictionary._isDispose = false; + entityDictionary._isPool = true; + return entityDictionary; + } + + /// + /// 释放实例占用的资源。 + /// + public void Dispose() + { + if (_isDispose) + { + return; + } + + _isDispose = true; + Clear(); +#if FANTASY_WEBGL + Pool>.Return(this); +#else + MultiThreadPool.Return(this); +#endif + } + + /// + /// 获取一个值,该值指示当前实例是否为对象池中的实例。 + /// + /// + public bool IsPool() + { + return _isPool; + } + + /// + /// 设置一个值,该值指示当前实例是否为对象池中的实例。 + /// + /// + public void SetIsPool(bool isPool) + { + _isPool = isPool; + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/Dictionary/SortedDictionaryPool.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/Dictionary/SortedDictionaryPool.cs new file mode 100644 index 0000000..8db66a8 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/Dictionary/SortedDictionaryPool.cs @@ -0,0 +1,70 @@ +using System; +using System.Collections.Generic; +using Fantasy.Pool; + +namespace Fantasy.DataStructure.Dictionary +{ + /// + /// 提供一个可以使用对象池管理的排序字典类。 + /// + /// + /// + public sealed class SortedDictionaryPool : SortedDictionary, IDisposable, IPool where TM : notnull + { + private bool _isPool; + private bool _isDispose; + + /// + /// 释放实例占用的资源。 + /// + public void Dispose() + { + if (_isDispose) + { + return; + } + + _isDispose = true; + Clear(); +#if FANTASY_WEBGL + Pool>.Return(this); +#else + MultiThreadPool.Return(this); +#endif + } + + /// + /// 创建一个新的 实例。 + /// + /// 新创建的实例。 + public static SortedDictionaryPool Create() + { +#if FANTASY_WEBGL + var dictionary = Pool>.Rent(); +#else + var dictionary = MultiThreadPool.Rent>(); +#endif + dictionary._isDispose = false; + dictionary._isPool = true; + return dictionary; + } + + /// + /// 获取一个值,该值指示当前实例是否为对象池中的实例。 + /// + /// + public bool IsPool() + { + return _isPool; + } + + /// + /// 设置一个值,该值指示当前实例是否为对象池中的实例。 + /// + /// + public void SetIsPool(bool isPool) + { + _isPool = isPool; + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/NativeCollections/LICENSE b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/NativeCollections/LICENSE new file mode 100644 index 0000000..2ca2248 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/NativeCollections/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 Nevin + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/NativeCollections/NativeCollections/BitOperationsHelpers.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/NativeCollections/NativeCollections/BitOperationsHelpers.cs new file mode 100644 index 0000000..3b88929 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/NativeCollections/NativeCollections/BitOperationsHelpers.cs @@ -0,0 +1,325 @@ +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +#if NET7_0_OR_GREATER +using System.Numerics; +using System.Runtime.Intrinsics; +#else +using System; +#endif + +// ReSharper disable ALL + +namespace NativeCollections +{ + /// + /// BitOperations helpers + /// + internal static class BitOperationsHelpers + { +#if !NET7_0_OR_GREATER + /// + /// DeBruijn sequence + /// + private static ReadOnlySpan Log2DeBruijn => new byte[32] + { + 0, 9, 1, 10, 13, 21, 2, 29, + 11, 14, 16, 18, 22, 25, 3, 30, + 8, 12, 20, 28, 15, 17, 24, 7, + 19, 27, 23, 6, 26, 5, 4, 31 + }; +#endif + + /// + /// Log2 + /// + /// Value + /// Log2 + public static int Log2(int value) => Log2((uint)value); + + /// + /// Log2 + /// + /// Value + /// Log2 + public static int Log2(uint value) + { +#if NET7_0_OR_GREATER + return BitOperations.Log2(value); +#else + value |= 1; + value |= value >> 1; + value |= value >> 2; + value |= value >> 4; + value |= value >> 8; + value |= value >> 16; + return Unsafe.AddByteOffset(ref MemoryMarshal.GetReference(Log2DeBruijn), (nint)(int)((value * 130329821U) >> 27)); +#endif + } + + /// + /// And + /// + /// Destination + /// Source + /// Count + public static void And(Span destination, Span source, uint count) + { + switch (count) + { + case 7: + destination[6] &= source[6]; + goto case 6; + case 6: + destination[5] &= source[5]; + goto case 5; + case 5: + destination[4] &= source[4]; + goto case 4; + case 4: + destination[3] &= source[3]; + goto case 3; + case 3: + destination[2] &= source[2]; + goto case 2; + case 2: + destination[1] &= source[1]; + goto case 1; + case 1: + destination[0] &= source[0]; + return; + case 0: + return; + } + + ref var left = ref MemoryMarshal.GetReference(destination); + ref var right = ref MemoryMarshal.GetReference(source); +#if NET7_0_OR_GREATER + uint i = 0; + if (Vector256.IsHardwareAccelerated) + { + var n = count - 7; + for (; i < n; i += 8) + { + var result = Vector256.LoadUnsafe(ref left, i) & Vector256.LoadUnsafe(ref right, i); + result.StoreUnsafe(ref left, i); + } + } + else if (Vector128.IsHardwareAccelerated) + { + var n = count - 3; + for (; i < n; i += 4) + { + var result = Vector128.LoadUnsafe(ref left, i) & Vector128.LoadUnsafe(ref right, i); + result.StoreUnsafe(ref left, i); + } + } + + for (; i < count; ++i) + Unsafe.Add(ref left, i) &= Unsafe.Add(ref right, i); +#else + var i = 0; + for (; i < count; ++i) + Unsafe.Add(ref left, i) &= Unsafe.Add(ref right, i); +#endif + } + + /// + /// Or + /// + /// Destination + /// Source + /// Count + public static void Or(Span destination, Span source, uint count) + { + switch (count) + { + case 7: + destination[6] |= source[6]; + goto case 6; + case 6: + destination[5] |= source[5]; + goto case 5; + case 5: + destination[4] |= source[4]; + goto case 4; + case 4: + destination[3] |= source[3]; + goto case 3; + case 3: + destination[2] |= source[2]; + goto case 2; + case 2: + destination[1] |= source[1]; + goto case 1; + case 1: + destination[0] |= source[0]; + return; + case 0: + return; + } + + ref var left = ref MemoryMarshal.GetReference(destination); + ref var right = ref MemoryMarshal.GetReference(source); +#if NET7_0_OR_GREATER + uint i = 0; + if (Vector256.IsHardwareAccelerated) + { + var n = count - 7; + for (; i < n; i += 8) + { + var result = Vector256.LoadUnsafe(ref left, i) | Vector256.LoadUnsafe(ref right, i); + result.StoreUnsafe(ref left, i); + } + } + else if (Vector128.IsHardwareAccelerated) + { + var n = count - 3; + for (; i < n; i += 4) + { + var result = Vector128.LoadUnsafe(ref left, i) | Vector128.LoadUnsafe(ref right, i); + result.StoreUnsafe(ref left, i); + } + } + + for (; i < count; ++i) + Unsafe.Add(ref left, i) |= Unsafe.Add(ref right, i); +#else + var i = 0; + for (; i < count; ++i) + Unsafe.Add(ref left, i) |= Unsafe.Add(ref right, i); +#endif + } + + /// + /// Xor + /// + /// Destination + /// Source + /// Count + public static void Xor(Span destination, Span source, uint count) + { + switch (count) + { + case 7: + destination[6] ^= source[6]; + goto case 6; + case 6: + destination[5] ^= source[5]; + goto case 5; + case 5: + destination[4] ^= source[4]; + goto case 4; + case 4: + destination[3] ^= source[3]; + goto case 3; + case 3: + destination[2] ^= source[2]; + goto case 2; + case 2: + destination[1] ^= source[1]; + goto case 1; + case 1: + destination[0] ^= source[0]; + return; + case 0: + return; + } + + ref var left = ref MemoryMarshal.GetReference(destination); + ref var right = ref MemoryMarshal.GetReference(source); +#if NET7_0_OR_GREATER + uint i = 0; + if (Vector256.IsHardwareAccelerated) + { + var n = count - 7; + for (; i < n; i += 8) + { + var result = Vector256.LoadUnsafe(ref left, i) ^ Vector256.LoadUnsafe(ref right, i); + result.StoreUnsafe(ref left, i); + } + } + else if (Vector128.IsHardwareAccelerated) + { + var n = count - 3; + for (; i < n; i += 4) + { + var result = Vector128.LoadUnsafe(ref left, i) ^ Vector128.LoadUnsafe(ref right, i); + result.StoreUnsafe(ref left, i); + } + } + + for (; i < count; ++i) + Unsafe.Add(ref left, i) ^= Unsafe.Add(ref right, i); +#else + var i = 0; + for (; i < count; ++i) + Unsafe.Add(ref left, i) ^= Unsafe.Add(ref right, i); +#endif + } + + /// + /// Not + /// + /// Destination + /// Count + public static void Not(Span destination, uint count) + { + switch (count) + { + case 7: + destination[6] = ~destination[6]; + goto case 6; + case 6: + destination[5] = ~destination[5]; + goto case 5; + case 5: + destination[4] = ~destination[4]; + goto case 4; + case 4: + destination[3] = ~destination[3]; + goto case 3; + case 3: + destination[2] = ~destination[2]; + goto case 2; + case 2: + destination[1] = ~destination[1]; + goto case 1; + case 1: + destination[0] = ~destination[0]; + return; + case 0: + return; + } + + ref var value = ref MemoryMarshal.GetReference(destination); +#if NET7_0_OR_GREATER + uint i = 0; + if (Vector256.IsHardwareAccelerated) + { + var n = count - 7; + for (; i < n; i += 8) + { + var result = ~Vector256.LoadUnsafe(ref value, i); + result.StoreUnsafe(ref value, i); + } + } + else if (Vector128.IsHardwareAccelerated) + { + var n = count - 3; + for (; i < n; i += 4) + { + var result = ~Vector128.LoadUnsafe(ref value, i); + result.StoreUnsafe(ref value, i); + } + } + + for (; i < count; ++i) + Unsafe.Add(ref value, i) = ~ Unsafe.Add(ref value, i); +#else + var i = 0; + for (; i < count; ++i) + Unsafe.Add(ref value, i) = ~ Unsafe.Add(ref value, i); +#endif + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/NativeCollections/NativeCollections/HashHelpers.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/NativeCollections/NativeCollections/HashHelpers.cs new file mode 100644 index 0000000..fedc510 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/NativeCollections/NativeCollections/HashHelpers.cs @@ -0,0 +1,125 @@ +#if UNITY_2021_3_OR_NEWER || GODOT +using System; +#endif +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// ReSharper disable ALL + +namespace NativeCollections +{ + /// + /// Hash helpers + /// + internal static class HashHelpers + { + /// + /// Primes + /// + private static ReadOnlySpan Primes => new int[72] + { + 3, 7, 11, 17, 23, 29, 37, 47, 59, 71, 89, 107, 131, 163, 197, 239, 293, 353, 431, 521, 631, 761, 919, + 1103, 1327, 1597, 1931, 2333, 2801, 3371, 4049, 4861, 5839, 7013, 8419, 10103, 12143, 14591, + 17519, 21023, 25229, 30293, 36353, 43627, 52361, 62851, 75431, 90523, 108631, 130363, 156437, + 187751, 225307, 270371, 324449, 389357, 467237, 560689, 672827, 807403, 968897, 1162687, 1395263, + 1674319, 2009191, 2411033, 2893249, 3471899, 4166287, 4999559, 5999471, 7199369 + }; + + /// + /// Binary search + /// + /// Min + /// Prime + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static int BinarySearch(int min) + { + var left = 0; + var right = 71; + ref var value = ref MemoryMarshal.GetReference(Primes); + while (left <= right) + { + var mid = left + (right - left) / 2; + if (Unsafe.Add(ref value, mid) >= min) + right = mid - 1; + else + left = mid + 1; + } + + return Unsafe.Add(ref value, left); + } + + /// + /// Is prime + /// + /// Candidate + /// Is prime + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool IsPrime(int candidate) + { + if ((candidate & 1) != 0) + { + var limit = (int)Math.Sqrt(candidate); + for (var divisor = 3; divisor <= limit; divisor += 2) + { + if (candidate % divisor == 0) + return false; + } + + return true; + } + + return candidate == 2; + } + + /// + /// Get prime + /// + /// Min + /// Prime + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int GetPrime(int min) + { + if (min < 0) + throw new ArgumentException("HTCapacityOverflow"); + if (min <= 7199369) + return BinarySearch(min); + for (var i = min | 1; i < int.MaxValue; i += 2) + { + if (IsPrime(i) && (i - 1) % 101 != 0) + return i; + } + + return min; + } + + /// + /// Expand prime + /// + /// Old size + /// Prime + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int ExpandPrime(int oldSize) + { + var newSize = 2 * oldSize; + return (uint)newSize > 2147483587 && 2147483587 > oldSize ? 2147483587 : GetPrime(newSize); + } + + /// + /// Get fast mod multiplier + /// + /// Divisor + /// Fast mod multiplier + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ulong GetFastModMultiplier(uint divisor) => ulong.MaxValue / divisor + 1; + + /// + /// Fast mod + /// + /// Value + /// Divisor + /// Multiplier + /// Mod + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static uint FastMod(uint value, uint divisor, ulong multiplier) => (uint)(((((multiplier * value) >> 32) + 1) * divisor) >> 32); + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeArray.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeArray.cs new file mode 100644 index 0000000..e8c372e --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeArray.cs @@ -0,0 +1,297 @@ +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +#if UNITY_2021_3_OR_NEWER || GODOT +using System; +#endif + +#pragma warning disable CA2208 +#pragma warning disable CS8632 + +// ReSharper disable ALL + +namespace NativeCollections +{ + /// + /// Native array + /// + /// Type + [StructLayout(LayoutKind.Sequential)] + public readonly unsafe struct NativeArray : IDisposable, IEquatable> where T : unmanaged + { + /// + /// Array + /// + private readonly T* _array; + + /// + /// Length + /// + private readonly int _length; + + /// + /// Structure + /// + /// Length + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public NativeArray(int length) + { + if (length < 0) + throw new ArgumentOutOfRangeException(nameof(length), length, "MustBeNonNegative"); + _array = (T*)NativeMemoryAllocator.Alloc((uint)(length * sizeof(T))); + _length = length; + } + + /// + /// Structure + /// + /// Length + /// Zeroed + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public NativeArray(int length, bool zeroed) + { + if (length < 0) + throw new ArgumentOutOfRangeException(nameof(length), length, "MustBeNonNegative"); + _array = zeroed ? (T*)NativeMemoryAllocator.AllocZeroed((uint)(length * sizeof(T))) : (T*)NativeMemoryAllocator.Alloc((uint)(length * sizeof(T))); + _length = length; + } + + /// + /// Structure + /// + /// Array + /// Length + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public NativeArray(T* array, int length) + { + if (length < 0) + throw new ArgumentOutOfRangeException(nameof(length), length, "MustBeNonNegative"); + _array = array; + _length = length; + } + + /// + /// Is created + /// + public bool IsCreated => _array != null; + + /// + /// Is empty + /// + public bool IsEmpty => _length == 0; + + /// + /// Get reference + /// + /// Index + public ref T this[int index] + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => ref _array[index]; + } + + /// + /// Get reference + /// + /// Index + public ref T this[uint index] + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => ref _array[index]; + } + + /// + /// Array + /// + public T* Array => _array; + + /// + /// Length + /// + public int Length => _length; + + /// + /// Equals + /// + /// Other + /// Equals + public bool Equals(NativeArray other) => other == this; + + /// + /// Equals + /// + /// object + /// Equals + public override bool Equals(object? obj) => obj is NativeArray nativeArray && nativeArray == this; + + /// + /// Get hashCode + /// + /// HashCode + public override int GetHashCode() => (int)(nint)_array; + + /// + /// To string + /// + /// String + public override string ToString() => $"NativeArray<{typeof(T).Name}>[{_length}]"; + + /// + /// As span + /// + /// Span + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator Span(NativeArray nativeArray) => nativeArray.AsSpan(); + + /// + /// As readOnly span + /// + /// ReadOnlySpan + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator ReadOnlySpan(NativeArray nativeArray) => nativeArray.AsReadOnlySpan(); + + /// + /// Equals + /// + /// Left + /// Right + /// Equals + public static bool operator ==(NativeArray left, NativeArray right) => left._length == right._length && left._array == right._array; + + /// + /// Not equals + /// + /// Left + /// Right + /// Not equals + public static bool operator !=(NativeArray left, NativeArray right) => left._length != right._length || left._array != right._array; + + /// + /// Dispose + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Dispose() + { + if (_array == null) + return; + NativeMemoryAllocator.Free(_array); + } + + /// + /// Clear + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Clear() => Unsafe.InitBlockUnaligned(_array, 0, (uint)(_length * sizeof(T))); + + /// + /// As span + /// + /// Span + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Span AsSpan() => MemoryMarshal.CreateSpan(ref *_array, _length); + + /// + /// As span + /// + /// Length + /// Span + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Span AsSpan(int length) => MemoryMarshal.CreateSpan(ref *_array, length); + + /// + /// As span + /// + /// Start + /// Length + /// Span + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Span AsSpan(int start, int length) => MemoryMarshal.CreateSpan(ref *(_array + start), length); + + /// + /// As readOnly span + /// + /// ReadOnlySpan + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public ReadOnlySpan AsReadOnlySpan() => MemoryMarshal.CreateReadOnlySpan(ref *_array, _length); + + /// + /// As readOnly span + /// + /// Length + /// ReadOnlySpan + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public ReadOnlySpan AsReadOnlySpan(int length) => MemoryMarshal.CreateReadOnlySpan(ref *_array, length); + + /// + /// As readOnly span + /// + /// Start + /// Length + /// ReadOnlySpan + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public ReadOnlySpan AsReadOnlySpan(int start, int length) => MemoryMarshal.CreateReadOnlySpan(ref *(_array + start), length); + + /// + /// Empty + /// + public static NativeArray Empty => new(); + + /// + /// Get enumerator + /// + /// Enumerator + public Enumerator GetEnumerator() => new(this); + + /// + /// Enumerator + /// + public ref struct Enumerator + { + /// + /// NativeArray + /// + private readonly NativeArray _nativeArray; + + /// + /// Index + /// + private int _index; + + /// + /// Structure + /// + /// NativeArray + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal Enumerator(NativeArray nativeArray) + { + _nativeArray = nativeArray; + _index = -1; + } + + /// + /// Move next + /// + /// Moved + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool MoveNext() + { + var index = _index + 1; + if (index < _nativeArray._length) + { + _index = index; + return true; + } + + return false; + } + + /// + /// Current + /// + public ref T Current + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => ref _nativeArray[_index]; + } + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeArrayPool.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeArrayPool.cs new file mode 100644 index 0000000..b31e428 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeArrayPool.cs @@ -0,0 +1,372 @@ +#if UNITY_2021_3_OR_NEWER || GODOT +using System; +using System.Threading; +#endif +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +#if NET5_0_OR_GREATER +#endif + +#pragma warning disable CA2208 +#pragma warning disable CS8632 + +// ReSharper disable ALL + +namespace NativeCollections +{ + /// + /// NativeMemoryPool + /// + [StructLayout(LayoutKind.Sequential)] + public readonly unsafe struct NativeArrayPool : IDisposable, IEquatable> where T : unmanaged + { + /// + /// Buckets + /// + private readonly NativeArrayPoolBucket* _buckets; + + /// + /// Length + /// + private readonly int _length; + + /// + /// Size + /// + private readonly int _size; + + /// + /// Structure + /// + /// Size + /// Max length + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public NativeArrayPool(int size, int maxLength) + { + if (size <= 0) + throw new ArgumentOutOfRangeException(nameof(size), size, "MustBePositive"); + if (maxLength < 0) + throw new ArgumentOutOfRangeException(nameof(maxLength), maxLength, "MustBeNonNegative"); + if (maxLength > 1073741824) + maxLength = 1073741824; + else if (maxLength < 16) + maxLength = 16; + var length = SelectBucketIndex(maxLength) + 1; + var buckets = (NativeArrayPoolBucket*)NativeMemoryAllocator.Alloc((uint)(length * sizeof(NativeArrayPoolBucket))); + for (var i = 0; i < length; ++i) + buckets[i].Initialize(size, 16 << i); + _buckets = buckets; + _length = length; + _size = size; + } + + /// + /// Is created + /// + public bool IsCreated => _buckets != null; + + /// + /// Size + /// + public int Size => _size; + + /// + /// Max length + /// + public int MaxLength => 16 << (_length - 1); + + /// + /// Equals + /// + /// Other + /// Equals + public bool Equals(NativeArrayPool other) => other == this; + + /// + /// Equals + /// + /// object + /// Equals + public override bool Equals(object? obj) => obj is NativeArrayPool nativeArrayPool && nativeArrayPool == this; + + /// + /// Get hashCode + /// + /// HashCode + public override int GetHashCode() => (int)(nint)_buckets; + + /// + /// To string + /// + /// String + public override string ToString() => $"NativeArrayPool<{typeof(T).Name}>"; + + /// + /// Equals + /// + /// Left + /// Right + /// Equals + public static bool operator ==(NativeArrayPool left, NativeArrayPool right) => left._buckets == right._buckets; + + /// + /// Not equals + /// + /// Left + /// Right + /// Not equals + public static bool operator !=(NativeArrayPool left, NativeArrayPool right) => left._buckets != right._buckets; + + /// + /// Dispose + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Dispose() + { + if (_buckets == null) + return; + for (var i = 0; i < _length; ++i) + _buckets[i].Dispose(); + NativeMemoryAllocator.Free(_buckets); + } + + /// + /// Rent buffer + /// + /// Minimum buffer length + /// Buffer + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public NativeArray Rent(int minimumLength) + { + if (minimumLength < 0) + throw new ArgumentOutOfRangeException(nameof(minimumLength), minimumLength, "MustBeNonNegative"); + var index = SelectBucketIndex(minimumLength); + if (index < _length) + return _buckets[index].Rent(); + throw new ArgumentOutOfRangeException(nameof(minimumLength), minimumLength, "BiggerThanCollection"); + } + + /// + /// Rent buffer + /// + /// Minimum buffer length + /// Buffer + /// Rented + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool TryRent(int minimumLength, out NativeArray array) + { + if (minimumLength < 0) + { + array = default; + return false; + } + + var index = SelectBucketIndex(minimumLength); + if (index < _length) + { + array = _buckets[index].Rent(); + return true; + } + + array = default; + return false; + } + + /// + /// Return buffer + /// + /// Buffer + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Return(in NativeArray array) + { + var length = array.Length; + if (length < 16 || (length & (length - 1)) != 0) + throw new ArgumentException("BufferNotFromPool", nameof(array)); + var bucket = SelectBucketIndex(length); + if (bucket >= _length) + throw new ArgumentException("BufferNotFromPool", nameof(array)); + _buckets[bucket].Return(array.Array); + } + + /// + /// Try return buffer + /// + /// Buffer + /// Returned + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool TryReturn(in NativeArray array) + { + var length = array.Length; + if (length < 16 || (length & (length - 1)) != 0) + return false; + var bucket = SelectBucketIndex(length); + if (bucket >= _length) + return false; + _buckets[bucket].Return(array.Array); + return true; + } + + /// + /// Return buffer + /// + /// Length + /// Buffer + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Return(int length, T* array) + { + if (length < 16 || (length & (length - 1)) != 0) + throw new ArgumentException("BufferNotFromPool", nameof(array)); + var bucket = SelectBucketIndex(length); + if (bucket >= _length) + throw new ArgumentException("BufferNotFromPool", nameof(array)); + _buckets[bucket].Return(array); + } + + /// + /// Try return buffer + /// + /// Length + /// Buffer + /// Returned + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool TryReturn(int length, T* array) + { + if (length < 16 || (length & (length - 1)) != 0) + return false; + var bucket = SelectBucketIndex(length); + if (bucket >= _length) + return false; + _buckets[bucket].Return(array); + return true; + } + + /// + /// Select bucket index + /// + /// Buffer size + /// Bucket index + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static int SelectBucketIndex(int bufferSize) => BitOperationsHelpers.Log2(((uint)bufferSize - 1) | 15) - 3; + + /// + /// Empty + /// + public static NativeArrayPool Empty => new(); + + /// + /// NativeArrayPool bucket + /// + [StructLayout(LayoutKind.Sequential)] + private struct NativeArrayPoolBucket : IDisposable + { + /// + /// Size + /// + private int _size; + + /// + /// Length + /// + private int _length; + + /// + /// Buffers + /// + private T** _array; + + /// + /// Index + /// + private int _index; + + /// + /// Memory pool + /// + private NativeMemoryPool _memoryPool; + + /// + /// State lock + /// + private SpinLock _lock; + + /// + /// Structure + /// + /// Size + /// Length + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Initialize(int size, int length) + { + _size = size; + _length = length; + _array = (T**)NativeMemoryAllocator.AllocZeroed((uint)(size * sizeof(T*))); + _index = 0; + _memoryPool = new NativeMemoryPool(size, length * sizeof(T), 0); + _lock = new SpinLock(); + } + + /// + /// Dispose + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Dispose() + { + NativeMemoryAllocator.Free(_array); + _memoryPool.Dispose(); + } + + /// + /// Rent buffer + /// + /// Buffer + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public NativeArray Rent() + { + T* ptr = null; + var lockTaken = false; + try + { + _lock.Enter(ref lockTaken); + if (_index < _size) + { + ptr = _array[_index]; + _array[_index++] = null; + } + + if (ptr == null) + ptr = (T*)_memoryPool.Rent(); + } + finally + { + if (lockTaken) + _lock.Exit(false); + } + + return new NativeArray(ptr, _length); + } + + /// + /// Return buffer + /// + /// Pointer + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Return(T* ptr) + { + var lockTaken = false; + try + { + _lock.Enter(ref lockTaken); + if (_index != 0) + _array[--_index] = ptr; + else + _memoryPool.Return(ptr); + } + finally + { + if (lockTaken) + _lock.Exit(false); + } + } + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeArrayReference.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeArrayReference.cs new file mode 100644 index 0000000..62a62da --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeArrayReference.cs @@ -0,0 +1,248 @@ +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +#if UNITY_2021_3_OR_NEWER || GODOT +using System; +#endif + +#pragma warning disable CA2208 +#pragma warning disable CS8600 +#pragma warning disable CS8603 +#pragma warning disable CS8632 + +// ReSharper disable ALL + +namespace NativeCollections +{ + /// + /// Native array reference + /// + /// Type + [StructLayout(LayoutKind.Sequential)] + public struct NativeArrayReference : IDisposable, IEquatable> + { + /// + /// Handle + /// + private GCHandle _handle; + + /// + /// Length + /// + private readonly int _length; + + /// + /// Structure + /// + /// Length + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public NativeArrayReference(int length) + { + if (length < 0) + throw new ArgumentOutOfRangeException(nameof(length), length, "MustBeNonNegative"); + _handle = GCHandle.Alloc(new T[length], GCHandleType.Normal); + _length = length; + } + + /// + /// Structure + /// + /// Length + /// GCHandle type + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public NativeArrayReference(int length, GCHandleType type) + { + if (length < 0) + throw new ArgumentOutOfRangeException(nameof(length), length, "MustBeNonNegative"); + _handle = GCHandle.Alloc(new T[length], type); + _length = length; + } + + /// + /// Structure + /// + /// Array + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public NativeArrayReference(T[] array) + { + if (array == null) + throw new ArgumentNullException(nameof(array), "MustBeNotNull"); + _handle = GCHandle.Alloc(array, GCHandleType.Normal); + _length = array.Length; + } + + /// + /// Structure + /// + /// Array + /// GCHandle type + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public NativeArrayReference(T[] array, GCHandleType type) + { + if (array == null) + throw new ArgumentNullException(nameof(array), "MustBeNotNull"); + _handle = GCHandle.Alloc(array, type); + _length = array.Length; + } + + /// + /// Is created + /// + public bool IsCreated => _handle.IsAllocated; + + /// + /// Is empty + /// + public bool IsEmpty => _length == 0; + + /// + /// Get reference + /// + /// Index + public ref T this[int index] + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => ref Array[index]; + } + + /// + /// Get reference + /// + /// Index + public ref T this[uint index] + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => ref Array[index]; + } + + /// + /// Array + /// + public T[] Array + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => (T[])_handle.Target; + } + + /// + /// Length + /// + public int Length => _length; + + /// + /// Equals + /// + /// Other + /// Equals + public bool Equals(NativeArrayReference other) => other == this; + + /// + /// Equals + /// + /// object + /// Equals + public override bool Equals(object? obj) => obj is NativeArrayReference nativeArrayReference && nativeArrayReference == this; + + /// + /// Get hashCode + /// + /// HashCode + public override int GetHashCode() => (int)(nint)_handle; + + /// + /// To string + /// + /// String + public override string ToString() => $"NativeArrayReference<{typeof(T).Name}>"; + + /// + /// Equals + /// + /// Left + /// Right + /// Equals + public static bool operator ==(NativeArrayReference left, NativeArrayReference right) => left._handle == right._handle; + + /// + /// Not equals + /// + /// Left + /// Right + /// Not equals + public static bool operator !=(NativeArrayReference left, NativeArrayReference right) => left._handle != right._handle; + + /// + /// Dispose + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Dispose() + { + if (!_handle.IsAllocated) + return; + _handle.Free(); + } + + /// + /// Empty + /// + public static NativeArrayReference Empty => new(); + + /// + /// Get enumerator + /// + /// Enumerator + public Enumerator GetEnumerator() => new(Array); + + /// + /// Enumerator + /// + public ref struct Enumerator + { + /// + /// Array + /// + private readonly T[] _array; + + /// + /// Index + /// + private int _index; + + /// + /// Structure + /// + /// Array + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal Enumerator(T[] array) + { + _array = array; + _index = -1; + } + + /// + /// Move next + /// + /// Moved + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool MoveNext() + { + var index = _index + 1; + if (index < _array.Length) + { + _index = index; + return true; + } + + return false; + } + + /// + /// Current + /// + public ref T Current + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => ref _array[_index]; + } + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeArraySegment.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeArraySegment.cs new file mode 100644 index 0000000..aeac3df --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeArraySegment.cs @@ -0,0 +1,386 @@ +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +#if UNITY_2021_3_OR_NEWER || GODOT +using System; +#endif + +#pragma warning disable CA2208 +#pragma warning disable CS8632 + +// ReSharper disable ALL + +namespace NativeCollections +{ + /// + /// Native array segment + /// + /// Type + [StructLayout(LayoutKind.Sequential)] + public readonly unsafe struct NativeArraySegment : IDisposable, IEquatable> where T : unmanaged + { + /// + /// Array + /// + private readonly T* _array; + + /// + /// Offset + /// + private readonly int _offset; + + /// + /// Count + /// + private readonly int _count; + + /// + /// Structure + /// + /// Array + /// Count + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public NativeArraySegment(T* array, int count) + { + if (count < 0) + throw new ArgumentOutOfRangeException(nameof(count), count, "MustBeNonNegative"); + _array = array; + _offset = 0; + _count = count; + } + + /// + /// Structure + /// + /// Array + /// Offset + /// Count + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public NativeArraySegment(T* array, int offset, int count) + { + if (offset < 0) + throw new ArgumentOutOfRangeException(nameof(offset), offset, "MustBeNonNegative"); + if (count < 0) + throw new ArgumentOutOfRangeException(nameof(count), count, "MustBeNonNegative"); + _array = array; + _offset = offset; + _count = count; + } + + /// + /// Structure + /// + /// Array + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public NativeArraySegment(NativeArray array) + { + _array = array.Array; + _offset = 0; + _count = array.Length; + } + + /// + /// Structure + /// + /// Array + /// Offset + /// Count + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public NativeArraySegment(NativeArray array, int offset, int count) + { + _array = array.Array; + _offset = offset; + _count = count; + } + + /// + /// Structure + /// + /// Array + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public NativeArraySegment(NativeMemoryArray array) + { + _array = array.Array; + _offset = 0; + _count = array.Length; + } + + /// + /// Structure + /// + /// Array + /// Offset + /// Count + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public NativeArraySegment(NativeMemoryArray array, int offset, int count) + { + _array = array.Array; + _offset = offset; + _count = count; + } + + /// + /// Is created + /// + public bool IsCreated => _array != null; + + /// + /// Is empty + /// + public bool IsEmpty => _count == 0; + + /// + /// Get reference + /// + /// Index + public ref T this[int index] + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => ref _array[_offset + index]; + } + + /// + /// Get reference + /// + /// Index + public ref T this[uint index] + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => ref _array[_offset + index]; + } + + /// + /// Array + /// + public T* Array => _array; + + /// + /// Offset + /// + public int Offset => _offset; + + /// + /// Count + /// + public int Count => _count; + + /// + /// Equals + /// + /// Other + /// Equals + public bool Equals(NativeArraySegment other) => other == this; + + /// + /// Equals + /// + /// object + /// Equals + public override bool Equals(object? obj) => obj is NativeArraySegment nativeArraySegment && nativeArraySegment == this; + + /// + /// Get hashCode + /// + /// HashCode + public override int GetHashCode() => (int)(nint)_array; + + /// + /// To string + /// + /// String + public override string ToString() => $"NativeArraySegment<{typeof(T).Name}>[{_offset}, {_count}]"; + + /// + /// As span + /// + /// Span + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator Span(NativeArraySegment nativeArraySegment) => nativeArraySegment.AsSpan(); + + /// + /// As readOnly span + /// + /// ReadOnlySpan + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator ReadOnlySpan(NativeArraySegment nativeArraySegment) => nativeArraySegment.AsReadOnlySpan(); + + /// + /// As native array + /// + /// Native array segment + /// NativeArray + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator NativeArray(NativeArraySegment nativeArraySegment) => new(nativeArraySegment._array, nativeArraySegment._offset + nativeArraySegment._count); + + /// + /// As native array segment + /// + /// Native array + /// NativeArraySegment + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator NativeArraySegment(NativeArray nativeArray) => new(nativeArray); + + /// + /// As native array segment + /// + /// Native array + /// NativeArraySegment + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator NativeArraySegment(NativeMemoryArray nativeArray) => new(nativeArray); + + /// + /// Equals + /// + /// Left + /// Right + /// Equals + public static bool operator ==(NativeArraySegment left, NativeArraySegment right) => left._offset == right._offset && left._count == right._count && left._array == right._array; + + /// + /// Not equals + /// + /// Left + /// Right + /// Not equals + public static bool operator !=(NativeArraySegment left, NativeArraySegment right) => left._offset != right._offset || left._count != right._count || left._array != right._array; + + /// + /// Dispose + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Dispose() + { + if (_array == null) + return; + NativeMemoryAllocator.Free(_array); + } + + /// + /// As span + /// + /// Span + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Span AsSpan() => MemoryMarshal.CreateSpan(ref *(_array + _offset), _count); + + /// + /// As span + /// + /// Count + /// Span + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Span AsSpan(int count) => MemoryMarshal.CreateSpan(ref *(_array + _offset), count); + + /// + /// As span + /// + /// Start + /// Count + /// Span + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Span AsSpan(int start, int count) => MemoryMarshal.CreateSpan(ref *(_array + _offset + start), count); + + /// + /// As readOnly span + /// + /// ReadOnlySpan + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public ReadOnlySpan AsReadOnlySpan() => MemoryMarshal.CreateReadOnlySpan(ref *(_array + _offset), _count); + + /// + /// As readOnly span + /// + /// Count + /// ReadOnlySpan + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public ReadOnlySpan AsReadOnlySpan(int count) => MemoryMarshal.CreateReadOnlySpan(ref *(_array + _offset), count); + + /// + /// As readOnly span + /// + /// Start + /// Count + /// ReadOnlySpan + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public ReadOnlySpan AsReadOnlySpan(int start, int count) => MemoryMarshal.CreateReadOnlySpan(ref *(_array + _offset + start), count); + + /// + /// Slice + /// + /// Start + /// NativeArraySegment + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public NativeArraySegment Slice(int start) => new(_array, _offset + start, _count - start); + + /// + /// Slice + /// + /// Start + /// Count + /// NativeArraySegment + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public NativeArraySegment Slice(int start, int count) => new(_array, _offset + start, count); + + /// + /// Empty + /// + public static NativeArraySegment Empty => new(); + + /// + /// Get enumerator + /// + /// Enumerator + public Enumerator GetEnumerator() => new(this); + + /// + /// Enumerator + /// + public ref struct Enumerator + { + /// + /// NativeArraySegment + /// + private readonly NativeArraySegment _nativeArraySegment; + + /// + /// Index + /// + private int _index; + + /// + /// Structure + /// + /// NativeArraySegment + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal Enumerator(NativeArraySegment nativeArraySegment) + { + _nativeArraySegment = nativeArraySegment; + _index = -1; + } + + /// + /// Move next + /// + /// Moved + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool MoveNext() + { + var index = _index + 1; + if (index < _nativeArraySegment._count) + { + _index = index; + return true; + } + + return false; + } + + /// + /// Current + /// + public ref T Current + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => ref _nativeArraySegment[_index]; + } + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeBitArray.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeBitArray.cs new file mode 100644 index 0000000..aa192e7 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeBitArray.cs @@ -0,0 +1,590 @@ +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +#if UNITY_2021_3_OR_NEWER || GODOT +using System; +#endif + +#pragma warning disable CA2208 +#pragma warning disable CS8632 + +// ReSharper disable ALL + +namespace NativeCollections +{ + /// + /// Native bit array + /// + [StructLayout(LayoutKind.Sequential)] + public readonly unsafe struct NativeBitArray : IDisposable, IEquatable + { + /// + /// Handle + /// + [StructLayout(LayoutKind.Sequential)] + private struct NativeBitArrayHandle + { + /// + /// Array + /// + public NativeArray Array; + + /// + /// Length + /// + public int Length; + } + + /// + /// Handle + /// + private readonly NativeBitArrayHandle* _handle; + + /// + /// Structure + /// + /// Length + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public NativeBitArray(int length) + { + if (length < 0) + throw new ArgumentOutOfRangeException(nameof(length), length, "MustBeNonNegative"); + _handle = (NativeBitArrayHandle*)NativeMemoryAllocator.Alloc((uint)sizeof(NativeBitArrayHandle)); + _handle->Array = new NativeArray(GetInt32ArrayLengthFromBitLength(length)); + _handle->Length = length; + } + + /// + /// Structure + /// + /// Length + /// Default value + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public NativeBitArray(int length, bool defaultValue) + { + if (length < 0) + throw new ArgumentOutOfRangeException(nameof(length), length, "MustBeNonNegative"); + _handle = (NativeBitArrayHandle*)NativeMemoryAllocator.Alloc((uint)sizeof(NativeBitArrayHandle)); + _handle->Array = new NativeArray(GetInt32ArrayLengthFromBitLength(length)); + _handle->Length = length; + if (defaultValue) + { + _handle->Array.AsSpan().Fill(-1); + Div32Rem(length, out var extraBits); + if (extraBits > 0) + _handle->Array[^1] = (1 << extraBits) - 1; + } + else + { + _handle->Array.Clear(); + } + } + + /// + /// Structure + /// + /// Array + /// Length + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public NativeBitArray(int* array, int length) + { + if (length < 0) + throw new ArgumentOutOfRangeException(nameof(length), length, "MustBeNonNegative"); + _handle = (NativeBitArrayHandle*)NativeMemoryAllocator.Alloc((uint)sizeof(NativeBitArrayHandle)); + _handle->Array = new NativeArray(array, GetInt32ArrayLengthFromBitLength(length)); + _handle->Length = length; + } + + /// + /// Structure + /// + /// Array + /// Length + /// Default value + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public NativeBitArray(int* array, int length, bool defaultValue) + { + if (length < 0) + throw new ArgumentOutOfRangeException(nameof(length), length, "MustBeNonNegative"); + _handle = (NativeBitArrayHandle*)NativeMemoryAllocator.Alloc((uint)sizeof(NativeBitArrayHandle)); + _handle->Array = new NativeArray(array, GetInt32ArrayLengthFromBitLength(length)); + _handle->Length = length; + if (defaultValue) + { + _handle->Array.AsSpan().Fill(-1); + Div32Rem(length, out var extraBits); + if (extraBits > 0) + _handle->Array[^1] = (1 << extraBits) - 1; + } + else + { + _handle->Array.Clear(); + } + } + + /// + /// Structure + /// + /// Array + /// Length + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public NativeBitArray(NativeArray array, int length) + { + if (length < 0) + throw new ArgumentOutOfRangeException(nameof(length), length, "MustBeNonNegative"); + var intCount = GetInt32ArrayLengthFromBitLength(length); + if (array.Length < intCount) + throw new ArgumentOutOfRangeException(nameof(array), array.Length, $"Requires size is {intCount}, but buffer length is {array.Length}."); + _handle = (NativeBitArrayHandle*)NativeMemoryAllocator.Alloc((uint)sizeof(NativeBitArrayHandle)); + _handle->Array = array; + _handle->Length = length; + } + + /// + /// Structure + /// + /// Array + /// Length + /// Default value + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public NativeBitArray(NativeArray array, int length, bool defaultValue) + { + if (length < 0) + throw new ArgumentOutOfRangeException(nameof(length), length, "MustBeNonNegative"); + var intCount = GetInt32ArrayLengthFromBitLength(length); + if (array.Length < intCount) + throw new ArgumentOutOfRangeException(nameof(array), array.Length, $"Requires size is {intCount}, but buffer length is {array.Length}."); + _handle = (NativeBitArrayHandle*)NativeMemoryAllocator.Alloc((uint)sizeof(NativeBitArrayHandle)); + _handle->Array = array; + _handle->Length = length; + if (defaultValue) + { + _handle->Array.AsSpan().Fill(-1); + Div32Rem(length, out var extraBits); + if (extraBits > 0) + _handle->Array[^1] = (1 << extraBits) - 1; + } + else + { + _handle->Array.Clear(); + } + } + + /// + /// Is created + /// + public bool IsCreated => _handle != null; + + /// + /// Array + /// + public NativeArray Array => _handle->Array; + + /// + /// Length + /// + public int Length + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _handle->Length; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + set + { + if (value < 0) + throw new ArgumentOutOfRangeException(nameof(value), value, "MustBeNonNegative"); + var newLength = GetInt32ArrayLengthFromBitLength(value); + if (newLength > _handle->Array.Length || newLength + 256 < _handle->Array.Length) + { + var array = new NativeArray(newLength); + Unsafe.CopyBlockUnaligned(array.Array, _handle->Array.Array, (uint)(_handle->Array.Length * sizeof(int))); + Unsafe.InitBlockUnaligned(array.Array + _handle->Array.Length, 0, (uint)(newLength - _handle->Array.Length)); + _handle->Array.Dispose(); + _handle->Array = array; + } + + if (value > _handle->Length) + { + var last = (_handle->Length - 1) >> 5; + Div32Rem(_handle->Length, out var bits); + if (bits > 0) + _handle->Array[last] &= (1 << bits) - 1; + _handle->Array.AsSpan(last + 1, newLength - last - 1).Clear(); + } + + _handle->Length = value; + } + } + + /// + /// Get or set value + /// + /// Index + public bool this[int index] + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => Get(index); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + set => Set(index, value); + } + + /// + /// Equals + /// + /// Other + /// Equals + public bool Equals(NativeBitArray other) => other == this; + + /// + /// Equals + /// + /// object + /// Equals + public override bool Equals(object? obj) => obj is NativeBitArray nativeBitArray && nativeBitArray == this; + + /// + /// Get hashCode + /// + /// HashCode + public override int GetHashCode() => (int)(nint)_handle; + + /// + /// To string + /// + /// String + public override string ToString() => "NativeBitArray"; + + /// + /// Equals + /// + /// Left + /// Right + /// Equals + public static bool operator ==(NativeBitArray left, NativeBitArray right) => left._handle == right._handle; + + /// + /// Not equals + /// + /// Left + /// Right + /// Not equals + public static bool operator !=(NativeBitArray left, NativeBitArray right) => left._handle != right._handle; + + /// + /// Dispose + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Dispose() + { + if (_handle == null) + return; + _handle->Array.Dispose(); + NativeMemoryAllocator.Free(_handle); + } + + /// + /// Get + /// + /// Index + /// Value + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool Get(int index) + { + if ((uint)index >= (uint)_handle->Length) + throw new ArgumentOutOfRangeException(nameof(index), index, "IndexMustBeLess"); + return (_handle->Array[index >> 5] & (1 << index)) != 0; + } + + /// + /// + /// Index + /// Value + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Set(int index, bool value) + { + if ((uint)index >= (uint)_handle->Length) + throw new ArgumentOutOfRangeException(nameof(index), index, "IndexMustBeLess"); + var bitMask = 1 << index; + ref var segment = ref _handle->Array[index >> 5]; + if (value) + segment |= bitMask; + else + segment &= ~bitMask; + } + + /// + /// Set all + /// + /// Value + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void SetAll(bool value) + { + var arrayLength = GetInt32ArrayLengthFromBitLength(Length); + var span = _handle->Array.AsSpan(0, arrayLength); + if (value) + { + span.Fill(-1); + Div32Rem(_handle->Length, out var extraBits); + if (extraBits > 0) + span[^1] &= (1 << extraBits) - 1; + } + else + { + span.Clear(); + } + } + + /// + /// And + /// + /// Value + /// NativeBitArray + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public NativeBitArray And(NativeBitArray value) + { + if (!value.IsCreated) + throw new ArgumentNullException(nameof(value)); + var count = GetInt32ArrayLengthFromBitLength(Length); + if (Length != value.Length || (uint)count > (uint)_handle->Array.Length || (uint)count > (uint)value._handle->Array.Length) + throw new ArgumentException("ArrayLengthsDiffer"); + BitOperationsHelpers.And(_handle->Array, value._handle->Array, (uint)count); + return this; + } + + /// + /// Or + /// + /// Value + /// NativeBitArray + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public NativeBitArray Or(NativeBitArray value) + { + if (!value.IsCreated) + throw new ArgumentNullException(nameof(value)); + var count = GetInt32ArrayLengthFromBitLength(Length); + if (Length != value.Length || (uint)count > (uint)_handle->Array.Length || (uint)count > (uint)value._handle->Array.Length) + throw new ArgumentException("ArrayLengthsDiffer"); + BitOperationsHelpers.Or(_handle->Array, value._handle->Array, (uint)count); + return this; + } + + /// + /// Xor + /// + /// Value + /// NativeBitArray + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public NativeBitArray Xor(NativeBitArray value) + { + if (!value.IsCreated) + throw new ArgumentNullException(nameof(value)); + var count = GetInt32ArrayLengthFromBitLength(Length); + if (Length != value.Length || (uint)count > (uint)_handle->Array.Length || (uint)count > (uint)value._handle->Array.Length) + throw new ArgumentException("ArrayLengthsDiffer"); + BitOperationsHelpers.Xor(_handle->Array, value._handle->Array, (uint)count); + return this; + } + + /// + /// Not + /// + /// NativeBitArray + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public NativeBitArray Not() + { + var count = GetInt32ArrayLengthFromBitLength(Length); + BitOperationsHelpers.Not(_handle->Array, (uint)count); + return this; + } + + /// + /// Right shift + /// + /// Count + /// NativeBitArray + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public NativeBitArray RightShift(int count) + { + if (count < 0) + throw new ArgumentOutOfRangeException(nameof(count), count, "MustBeNonNegative"); + if (count == 0) + return this; + var toIndex = 0; + var length = GetInt32ArrayLengthFromBitLength(_handle->Length); + if (count < _handle->Length) + { + var fromIndex = Div32Rem(count, out var shiftCount); + Div32Rem(_handle->Length, out var extraBits); + if (shiftCount == 0) + { + unchecked + { + var mask = uint.MaxValue >> (32 - extraBits); + _handle->Array[length - 1] &= (int)mask; + } + + Unsafe.CopyBlockUnaligned(_handle->Array.Array, _handle->Array.Array + fromIndex, (uint)((length - fromIndex) * sizeof(int))); + toIndex = length - fromIndex; + } + else + { + var lastIndex = length - 1; + unchecked + { + while (fromIndex < lastIndex) + { + var right = (uint)_handle->Array[fromIndex] >> shiftCount; + var left = _handle->Array[++fromIndex] << (32 - shiftCount); + _handle->Array[toIndex++] = left | (int)right; + } + + var mask = uint.MaxValue >> (32 - extraBits); + mask &= (uint)_handle->Array[fromIndex]; + _handle->Array[toIndex++] = (int)(mask >> shiftCount); + } + } + } + + _handle->Array.AsSpan(toIndex, length - toIndex).Clear(); + return this; + } + + /// + /// Left shift + /// + /// Count + /// NativeBitArray + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public NativeBitArray LeftShift(int count) + { + if (count < 0) + throw new ArgumentOutOfRangeException(nameof(count), count, "MustBeNonNegative"); + if (count == 0) + return this; + int lengthToClear; + if (count < _handle->Length) + { + var lastIndex = (_handle->Length - 1) >> 5; + lengthToClear = Div32Rem(count, out var shiftCount); + if (shiftCount == 0) + { + Unsafe.CopyBlockUnaligned(_handle->Array.Array + lengthToClear, _handle->Array.Array, (uint)((lastIndex + 1 - lengthToClear) * sizeof(int))); + } + else + { + var fromIndex = lastIndex - lengthToClear; + unchecked + { + while (fromIndex > 0) + { + var left = _handle->Array[fromIndex] << shiftCount; + var right = (uint)_handle->Array[--fromIndex] >> (32 - shiftCount); + _handle->Array[lastIndex] = left | (int)right; + lastIndex--; + } + + _handle->Array[lastIndex] = _handle->Array[fromIndex] << shiftCount; + } + } + } + else + { + lengthToClear = GetInt32ArrayLengthFromBitLength(_handle->Length); + } + + _handle->Array.AsSpan(0, lengthToClear).Clear(); + return this; + } + + /// + /// Has all set + /// + /// All set + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool HasAllSet() + { + Div32Rem(_handle->Length, out var extraBits); + var intCount = GetInt32ArrayLengthFromBitLength(_handle->Length); + if (extraBits != 0) + intCount--; +#if NET8_0_OR_GREATER + if (_handle->Array.AsSpan(0, intCount).ContainsAnyExcept(-1)) + return false; +#elif NET7_0_OR_GREATER + if (_handle->Array.AsSpan(0, intCount).IndexOfAnyExcept(-1) >= 0) + return false; +#else + for (var i = 0; i < intCount; ++i) + { + if (_handle->Array[i] != -1) + return false; + } +#endif + if (extraBits == 0) + return true; + var mask = (1 << extraBits) - 1; + return (_handle->Array[intCount] & mask) == mask; + } + + /// + /// Has any set + /// + /// Any set + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool HasAnySet() + { + Div32Rem(_handle->Length, out var extraBits); + var intCount = GetInt32ArrayLengthFromBitLength(_handle->Length); + if (extraBits != 0) + intCount--; +#if NET8_0_OR_GREATER + if (_handle->Array.AsSpan(0, intCount).ContainsAnyExcept(0)) + return true; +#elif NET7_0_OR_GREATER + if (_handle->Array.AsSpan(0, intCount).IndexOfAnyExcept(0) >= 0) + return true; +#else + for (var i = 0; i < intCount; ++i) + { + if (_handle->Array[i] != 0) + return true; + } +#endif + if (extraBits == 0) + return false; + return (_handle->Array[intCount] & ((1 << extraBits) - 1)) != 0; + } + + /// + /// Get int32 array length from bit length + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static int GetInt32ArrayLengthFromBitLength(int n) + { +#if NET7_0_OR_GREATER + return (n - 1 + (1 << 5)) >>> 5; +#else + return (int)((uint)(n - 1 + (1 << 5)) >> 5); +#endif + } + + /// + /// Divide by 32 and get remainder + /// + /// Number + /// Remainder + /// Quotient + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static int Div32Rem(int number, out int remainder) + { + var quotient = (uint)number / 32; + remainder = number & (32 - 1); + return (int)quotient; + } + + /// + /// Empty + /// + public static NativeBitArray Empty => new(); + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeBuddyMemoryPool.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeBuddyMemoryPool.cs new file mode 100644 index 0000000..b0c1631 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeBuddyMemoryPool.cs @@ -0,0 +1,227 @@ +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +#if UNITY_2021_3_OR_NEWER || GODOT +using System; +#endif + +#pragma warning disable CA2208 +#pragma warning disable CS8632 + +// ReSharper disable ALL + +namespace NativeCollections +{ + /// + /// Native buddy memory pool + /// + [StructLayout(LayoutKind.Sequential)] + public readonly unsafe struct NativeBuddyMemoryPool : IDisposable, IEquatable + { + /// + /// Min block size + /// + private readonly int _minBlockSize; + + /// + /// Max block size + /// + private readonly int _maxBlockSize; + + /// + /// Bit map + /// + private readonly int* _bitmap; + + /// + /// Memory + /// + private readonly byte* _memory; + + /// + /// Structure + /// + /// Min block size + /// Max block size + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public NativeBuddyMemoryPool(int minBlockSize, int maxBlockSize) + { + if (minBlockSize > maxBlockSize) + throw new ArgumentException($"{minBlockSize} cannot be greater than {maxBlockSize}."); + if (minBlockSize <= 0) + throw new ArgumentOutOfRangeException(nameof(minBlockSize), minBlockSize, "MustBePositive"); + if ((minBlockSize & (minBlockSize - 1)) != 0) + throw new ArgumentOutOfRangeException(nameof(minBlockSize), minBlockSize, "MustBePowOf2"); + if ((maxBlockSize & (maxBlockSize - 1)) != 0) + throw new ArgumentOutOfRangeException(nameof(maxBlockSize), maxBlockSize, "MustBePowOf2"); + _minBlockSize = minBlockSize; + _maxBlockSize = maxBlockSize; + var bitmapSize = ((1 << (BitOperationsHelpers.Log2(maxBlockSize / minBlockSize) + 1)) + 31) / 32 * sizeof(int); + var array = (byte*)NativeMemoryAllocator.Alloc((uint)(bitmapSize + maxBlockSize)); + _bitmap = (int*)array; + _memory = array + bitmapSize; + Unsafe.InitBlockUnaligned(array, 0, (uint)bitmapSize); + } + + /// + /// Is created + /// + public bool IsCreated => _bitmap != null; + + /// + /// Min block size + /// + public int MinBlockSize => _minBlockSize; + + /// + /// Max block size + /// + public int MaxBlockSize => _maxBlockSize; + + /// + /// Equals + /// + /// Other + /// Equals + public bool Equals(NativeBuddyMemoryPool other) => other == this; + + /// + /// Equals + /// + /// object + /// Equals + public override bool Equals(object? obj) => obj is NativeBuddyMemoryPool nativeBuddyMemoryPool && nativeBuddyMemoryPool == this; + + /// + /// Get hashCode + /// + /// HashCode + public override int GetHashCode() => (int)(nint)_bitmap; + + /// + /// To string + /// + /// String + public override string ToString() => "NativeBuddyMemoryPool"; + + /// + /// Equals + /// + /// Left + /// Right + /// Equals + public static bool operator ==(NativeBuddyMemoryPool left, NativeBuddyMemoryPool right) => left._bitmap == right._bitmap; + + /// + /// Not equals + /// + /// Left + /// Right + /// Not equals + public static bool operator !=(NativeBuddyMemoryPool left, NativeBuddyMemoryPool right) => left._bitmap != right._bitmap; + + /// + /// Dispose + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Dispose() + { + if (_bitmap == null) + return; + NativeMemoryAllocator.Free(_bitmap); + } + + /// + /// Get layer + /// + /// Size + /// Layer + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private int GetLayer(int size) => size <= _minBlockSize ? 0 : BitOperationsHelpers.Log2((uint)((size - 1) / _minBlockSize)) + 1; + + /// + /// Find free block + /// + /// Layer + /// Free block + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private int FindFreeBlock(int layer) + { + var blocksInLayer = 1 << layer; + var offset = blocksInLayer - 1; + for (var i = 0; i < blocksInLayer; ++i) + { + var index = offset + i; + if ((_bitmap[index / 32] & (1 << (index % 32))) == 0) + return index; + } + + return -1; + } + + /// + /// Merge blocks + /// + /// Layer + /// Index + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void MergeBlocks(int layer, int index) + { + while (layer != 0) + { + var buddyIndex = index % 2 == 0 ? index + 1 : index - 1; + var bitMask = buddyIndex % 32; + ref var segment = ref _bitmap[buddyIndex / 32]; + if ((segment & (1 << bitMask)) != 0) + break; + var parentIndex = index / 2 + ((1 << (layer - 1)) - 1); + (*(_bitmap + index / 32)) &= ~(1 << (index % 32)); + segment &= ~(1 << bitMask); + (*(_bitmap + parentIndex / 32)) |= 1 << (parentIndex % 32); + --layer; + index = parentIndex; + } + } + + /// + /// Rent buffer + /// + /// Buffer + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void* Rent(int size) + { + if (size > _maxBlockSize) + throw new ArgumentOutOfRangeException(nameof(size), $"{size} cannot be greater than {_maxBlockSize}."); + if (size <= 0) + throw new ArgumentOutOfRangeException(nameof(size), size, "MustBePositive"); + var layer = GetLayer(size); + var blockIndex = FindFreeBlock(layer); + if (blockIndex == -1) + return null; + _bitmap[blockIndex / 32] |= 1 << (blockIndex % 32); + return _memory + (_minBlockSize << layer) * (blockIndex - ((1 << layer) - 1)); + } + + /// + /// Return buffer + /// + /// Pointer + /// Size + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Return(void* ptr, int size) + { + if (size > _maxBlockSize) + throw new ArgumentOutOfRangeException(nameof(size), $"{size} cannot be greater than {_maxBlockSize}."); + if (size <= 0) + throw new ArgumentOutOfRangeException(nameof(size), size, "MustBePositive"); + var layer = GetLayer(size); + var blockIndex = (int)((byte*)ptr - _memory) / (_minBlockSize << layer) + ((1 << layer) - 1); + _bitmap[blockIndex / 32] &= ~(1 << (blockIndex % 32)); + MergeBlocks(layer, blockIndex); + } + + /// + /// Empty + /// + public static NativeBuddyMemoryPool Empty => new(); + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeConcurrentDictionary.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeConcurrentDictionary.cs new file mode 100644 index 0000000..ae09294 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeConcurrentDictionary.cs @@ -0,0 +1,1458 @@ +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +#if UNITY_2021_3_OR_NEWER || GODOT +using System; +using System.Threading; +using System.Collections.Generic; +#endif + +#pragma warning disable CA2208 +#pragma warning disable CS8632 + +// ReSharper disable ALL + +namespace NativeCollections +{ + /// + /// Native concurrentDictionary + /// (Slower than ConcurrentDictionary) + /// + /// Type + /// Type + [StructLayout(LayoutKind.Sequential)] + public readonly unsafe struct NativeConcurrentDictionary : IDisposable, IEquatable> where TKey : unmanaged, IEquatable where TValue : unmanaged, IEquatable + { + /// + /// Handle + /// + [StructLayout(LayoutKind.Sequential)] + private struct NativeConcurrentDictionaryHandle + { + /// + /// Tables + /// + public volatile Tables* Tables; + + /// + /// Budget + /// + public int Budget; + + /// + /// Grow lock array + /// + public bool GrowLockArray; + + /// + /// Node pool + /// + public NativeMemoryPool NodePool; + + /// + /// Node lock + /// + public NativeConcurrentSpinLock NodeLock; + + /// + /// Keys + /// + public KeyCollection Keys; + + /// + /// Values + /// + public ValueCollection Values; + } + + /// + /// Handle + /// + private readonly NativeConcurrentDictionaryHandle* _handle; + + /// + /// Keys + /// + public KeyCollection Keys => _handle->Keys; + + /// + /// Values + /// + public ValueCollection Values => _handle->Values; + + /// + /// Structure + /// + /// Size + /// Max free slabs + /// Concurrency level + /// Capacity + /// Grow lock array + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public NativeConcurrentDictionary(int size, int maxFreeSlabs, int concurrencyLevel, int capacity, bool growLockArray) + { + var nodePool = new NativeMemoryPool(size, sizeof(Node), maxFreeSlabs); + if (concurrencyLevel <= 0) + concurrencyLevel = Environment.ProcessorCount; + if (capacity < concurrencyLevel) + capacity = concurrencyLevel; + capacity = HashHelpers.GetPrime(capacity); + var locks = new NativeArrayReference(concurrencyLevel); + for (var i = 0; i < locks.Length; ++i) + locks[i] = new object(); + var countPerLock = new NativeArray(locks.Length, true); + var buckets = new NativeArray(capacity, true); + _handle = (NativeConcurrentDictionaryHandle*)NativeMemoryAllocator.Alloc((uint)sizeof(NativeConcurrentDictionaryHandle)); + _handle->Tables = (Tables*)NativeMemoryAllocator.Alloc((uint)sizeof(Tables)); + _handle->Tables->Initialize(buckets, locks, countPerLock); + _handle->GrowLockArray = growLockArray; + _handle->Budget = buckets.Length / locks.Length; + _handle->NodePool = nodePool; + _handle->NodeLock = new NativeConcurrentSpinLock(-1); + _handle->Keys = new KeyCollection(this); + _handle->Values = new ValueCollection(this); + } + + /// + /// Is created + /// + public bool IsCreated => _handle != null; + + /// + /// Is created + /// + public bool IsEmpty + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get + { + if (!AreAllBucketsEmpty()) + return false; + var locksAcquired = 0; + try + { + AcquireAllLocks(ref locksAcquired); + return AreAllBucketsEmpty(); + } + finally + { + ReleaseLocks(locksAcquired); + } + } + } + + /// + /// Get or set value + /// + /// Key + public TValue this[in TKey key] + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get + { + if (!TryGetValue(key, out var value)) + throw new KeyNotFoundException(key.ToString()); + return value; + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + set => TryAddInternal(_handle->Tables, key, value, true, true, out _); + } + + /// + /// Count + /// + public int Count + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get + { + var locksAcquired = 0; + try + { + AcquireAllLocks(ref locksAcquired); + return GetCountNoLocks(); + } + finally + { + ReleaseLocks(locksAcquired); + } + } + } + + /// + /// Equals + /// + /// Other + /// Equals + public bool Equals(NativeConcurrentDictionary other) => other == this; + + /// + /// Equals + /// + /// object + /// Equals + public override bool Equals(object? obj) => obj is NativeConcurrentDictionary nativeConcurrentDictionary && nativeConcurrentDictionary == this; + + /// + /// Get hashCode + /// + /// HashCode + public override int GetHashCode() => (int)(nint)_handle; + + /// + /// To string + /// + /// String + public override string ToString() => $"NativeConcurrentDictionary<{typeof(TKey).Name}, {typeof(TValue).Name}>"; + + /// + /// Equals + /// + /// Left + /// Right + /// Equals + public static bool operator ==(NativeConcurrentDictionary left, NativeConcurrentDictionary right) => left._handle == right._handle; + + /// + /// Not equals + /// + /// Left + /// Right + /// Not equals + public static bool operator !=(NativeConcurrentDictionary left, NativeConcurrentDictionary right) => left._handle != right._handle; + + /// + /// Dispose + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Dispose() + { + if (_handle == null) + return; + _handle->Tables->Dispose(); + _handle->NodePool.Dispose(); + _handle->NodeLock.Dispose(); + NativeMemoryAllocator.Free(_handle); + } + + /// + /// Clear + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Clear() + { + var locksAcquired = 0; + try + { + AcquireAllLocks(ref locksAcquired); + if (AreAllBucketsEmpty()) + return; + foreach (var bucket in _handle->Tables->Buckets) + { + var node = (Node*)bucket.Node; + while (node != null) + { + var temp = node; + node = node->Next; + _handle->NodePool.Return(temp); + } + } + + var length = HashHelpers.GetPrime(31); + if (_handle->Tables->Buckets.Length != length) + { + _handle->Tables->Buckets.Dispose(); + _handle->Tables->Buckets = new NativeArray(length, true); + } + else + { + _handle->Tables->Buckets.Clear(); + } + + _handle->Tables->CountPerLock.Clear(); + var budget = _handle->Tables->Buckets.Length / _handle->Tables->Locks.Length; + _handle->Budget = budget >= 1 ? budget : 1; + } + finally + { + ReleaseLocks(locksAcquired); + } + } + + /// + /// Try add + /// + /// Key + /// Value + /// Added + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool TryAdd(in TKey key, in TValue value) => TryAddInternal(_handle->Tables, key, value, false, true, out _); + + /// + /// Try remove + /// + /// Key + /// Value + /// Removed + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool TryRemove(in TKey key, out TValue value) + { + var tables = _handle->Tables; + var hashCode = key.GetHashCode(); + while (true) + { + var locks = tables->Locks; + ref var bucket = ref GetBucketAndLock(tables, hashCode, out var lockNo); + if (tables->CountPerLock[lockNo] != 0) + { + Monitor.Enter(locks[lockNo]); + try + { + if (tables != _handle->Tables) + { + tables = _handle->Tables; + continue; + } + + Node* prev = null; + for (var curr = (Node*)bucket; curr != null; curr = curr->Next) + { + if (hashCode == curr->HashCode && curr->Key.Equals(key)) + { + if (prev == null) + Volatile.Write(ref bucket, (nint)curr->Next); + else + prev->Next = curr->Next; + value = curr->Value; + _handle->NodeLock.Enter(); + try + { + _handle->NodePool.Return(curr); + } + finally + { + _handle->NodeLock.Exit(); + } + + tables->CountPerLock[lockNo]--; + return true; + } + + prev = curr; + } + } + finally + { + Monitor.Exit(locks[lockNo]); + } + } + + value = default; + return false; + } + } + + /// + /// Try remove + /// + /// Key value pair + /// Removed + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool TryRemove(in KeyValuePair keyValuePair) + { + var key = keyValuePair.Key; + var oldValue = keyValuePair.Value; + var tables = _handle->Tables; + var hashCode = key.GetHashCode(); + while (true) + { + var locks = tables->Locks; + ref var bucket = ref GetBucketAndLock(tables, hashCode, out var lockNo); + if (tables->CountPerLock[lockNo] != 0) + { + Monitor.Enter(locks[lockNo]); + try + { + if (tables != _handle->Tables) + { + tables = _handle->Tables; + continue; + } + + Node* prev = null; + for (var curr = (Node*)bucket; curr != null; curr = curr->Next) + { + if (hashCode == curr->HashCode && curr->Key.Equals(key)) + { + if (!oldValue.Equals(curr->Value)) + return false; + if (prev == null) + Volatile.Write(ref bucket, (nint)curr->Next); + else + prev->Next = curr->Next; + _handle->NodeLock.Enter(); + try + { + _handle->NodePool.Return(curr); + } + finally + { + _handle->NodeLock.Exit(); + } + + tables->CountPerLock[lockNo]--; + return true; + } + + prev = curr; + } + } + finally + { + Monitor.Exit(locks[lockNo]); + } + } + + return false; + } + } + + /// + /// Contains key + /// + /// Key + /// Contains key + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool ContainsKey(in TKey key) + { + var tables = _handle->Tables; + var hashCode = key.GetHashCode(); + for (var node = (Node*)GetBucket(tables, hashCode); node != null; node = node->Next) + { + if (hashCode == node->HashCode && node->Key.Equals(key)) + return true; + } + + return false; + } + + /// + /// Try to get the value + /// + /// Key + /// Value + /// Got + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool TryGetValue(in TKey key, out TValue value) + { + var tables = _handle->Tables; + var hashCode = key.GetHashCode(); + for (var node = (Node*)GetBucket(tables, hashCode); node != null; node = node->Next) + { + if (hashCode == node->HashCode && node->Key.Equals(key)) + { + value = node->Value; + return true; + } + } + + value = default; + return false; + } + + /// + /// Try update + /// + /// Key + /// New value + /// Comparison value + /// Updated + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool TryUpdate(in TKey key, in TValue newValue, in TValue comparisonValue) => TryUpdateInternal(_handle->Tables, key, newValue, comparisonValue); + + /// + /// Get or add value + /// + /// Key + /// Value + /// Value + public TValue GetOrAdd(in TKey key, in TValue value) + { + var tables = _handle->Tables; + var hashCode = key.GetHashCode(); + if (!TryGetValueInternal(tables, key, hashCode, out var resultingValue)) + TryAddInternal(tables, key, value, false, true, out resultingValue); + return resultingValue; + } + + /// + /// Check all buckets are empty + /// + /// All buckets are empty + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private bool AreAllBucketsEmpty() + { +#if NET8_0_OR_GREATER + return !_handle->Tables->CountPerLock.AsSpan().ContainsAnyExcept(0); +#elif NET7_0_OR_GREATER + return !(_handle->Tables->CountPerLock.AsSpan().IndexOfAnyExcept(0) >= 0); +#else + for (var i = 0; i < _handle->Tables->CountPerLock.Length; ++i) + { + if (_handle->Tables->CountPerLock[i] != 0) + return false; + } + + return true; +#endif + } + + /// + /// Grow table + /// + /// Tables + /// Resize desired + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void GrowTable(Tables* tables, bool resizeDesired) + { + var locksAcquired = 0; + try + { + AcquireFirstLock(ref locksAcquired); + if (tables != _handle->Tables) + return; + var newLength = tables->Buckets.Length; + if (resizeDesired) + { + if (GetCountNoLocks() < tables->Buckets.Length / 4) + { + _handle->Budget = 2 * _handle->Budget; + if (_handle->Budget < 0) + _handle->Budget = int.MaxValue; + return; + } + + if ((newLength = tables->Buckets.Length * 2) < 0 || (newLength = HashHelpers.GetPrime(newLength)) > 2147483591) + { + newLength = 2147483591; + _handle->Budget = int.MaxValue; + } + } + + var newLocks = tables->Locks; + if (_handle->GrowLockArray && tables->Locks.Length < 1024) + { + newLocks = new NativeArrayReference(tables->Locks.Length * 2); + Array.Copy(tables->Locks.Array, newLocks.Array, tables->Locks.Length); + for (var i = tables->Locks.Length; i < newLocks.Length; ++i) + newLocks[i] = new NativeMonitorLock(new object()); + } + + var newBuckets = new NativeArray(newLength, true); + var newCountPerLock = new NativeArray(newLocks.Length, true); + var newTables = (Tables*)NativeMemoryAllocator.Alloc((uint)sizeof(Tables)); + newTables->Initialize(newBuckets, newLocks, newCountPerLock); + AcquirePostFirstLock(tables, ref locksAcquired); + foreach (var bucket in tables->Buckets) + { + var current = (Node*)bucket.Node; + while (current != null) + { + var hashCode = current->HashCode; + var next = current->Next; + ref var newBucket = ref GetBucketAndLock(newTables, hashCode, out var newLockNo); + var newNode = current; + newNode->Initialize(current->Key, current->Value, hashCode, (Node*)newBucket); + newBucket = (nint)newNode; + checked + { + newCountPerLock[newLockNo]++; + } + + current = next; + } + } + + var budget = newBuckets.Length / newLocks.Length; + _handle->Budget = budget >= 1 ? budget : 1; + _handle->Tables->Buckets.Dispose(); + if (_handle->Tables->Locks != newLocks) + _handle->Tables->Locks.Dispose(); + _handle->Tables->CountPerLock.Dispose(); + NativeMemoryAllocator.Free(_handle->Tables); + _handle->Tables = newTables; + } + finally + { + ReleaseLocks(locksAcquired); + } + } + + /// + /// Acquire all locks + /// + /// Locks acquired + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void AcquireAllLocks(ref int locksAcquired) + { + AcquireFirstLock(ref locksAcquired); + AcquirePostFirstLock(_handle->Tables, ref locksAcquired); + } + + /// + /// Acquire first lock + /// + /// Locks acquired + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void AcquireFirstLock(ref int locksAcquired) + { + var locks = _handle->Tables->Locks; + Monitor.Enter(locks[0]); + locksAcquired = 1; + } + + /// + /// Acquire post first locks + /// + /// Tables + /// Locks acquired + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static void AcquirePostFirstLock(Tables* tables, ref int locksAcquired) + { + var locks = tables->Locks; + for (var i = 1; i < locks.Length; ++i) + { + Monitor.Enter(locks[i]); + locksAcquired++; + } + } + + /// + /// Release locks + /// + /// Locks acquired + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void ReleaseLocks(int locksAcquired) + { + var locks = _handle->Tables->Locks; + for (var i = 0; i < locksAcquired; ++i) + Monitor.Exit(locks[i]); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private bool TryAddInternal(Tables* tables, in TKey key, in TValue value, bool updateIfExists, bool acquireLock, out TValue resultingValue) + { + var hashCode = key.GetHashCode(); + while (true) + { + var locks = tables->Locks; + ref var bucket = ref GetBucketAndLock(tables, hashCode, out var lockNo); + var resizeDesired = false; + var lockTaken = false; + try + { + if (acquireLock) + Monitor.Enter(locks[lockNo], ref lockTaken); + if (tables != _handle->Tables) + { + tables = _handle->Tables; + continue; + } + + Node* prev = null; + for (var node = (Node*)bucket; node != null; node = node->Next) + { + if (hashCode == node->HashCode && node->Key.Equals(key)) + { + if (updateIfExists) + { + if (NativeConcurrentDictionaryTypeProps.IsWriteAtomic) + { + node->Value = value; + } + else + { + Node* newNode; + _handle->NodeLock.Enter(); + try + { + newNode = (Node*)_handle->NodePool.Rent(); + } + finally + { + _handle->NodeLock.Exit(); + } + + newNode->Initialize(node->Key, value, hashCode, node->Next); + if (prev == null) + Volatile.Write(ref bucket, (nint)newNode); + else + prev->Next = newNode; + _handle->NodeLock.Enter(); + try + { + _handle->NodePool.Return(node); + } + finally + { + _handle->NodeLock.Exit(); + } + } + + resultingValue = value; + } + else + { + resultingValue = node->Value; + } + + return false; + } + + prev = node; + } + + Node* resultNode; + _handle->NodeLock.Enter(); + try + { + resultNode = (Node*)_handle->NodePool.Rent(); + } + finally + { + _handle->NodeLock.Exit(); + } + + resultNode->Initialize(key, value, hashCode, (Node*)bucket); + Volatile.Write(ref bucket, (nint)resultNode); + checked + { + tables->CountPerLock[lockNo]++; + } + + if (tables->CountPerLock[lockNo] > _handle->Budget) + resizeDesired = true; + } + finally + { + if (lockTaken) + Monitor.Exit(locks[lockNo]); + } + + if (resizeDesired) + GrowTable(tables, resizeDesired); + resultingValue = value; + return true; + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private bool TryUpdateInternal(Tables* tables, in TKey key, in TValue newValue, in TValue comparisonValue) + { + var hashCode = key.GetHashCode(); + while (true) + { + var locks = tables->Locks; + ref var bucket = ref GetBucketAndLock(tables, hashCode, out var lockNo); + Monitor.Enter(locks[lockNo]); + try + { + if (tables != _handle->Tables) + { + tables = _handle->Tables; + continue; + } + + Node* prev = null; + for (var node = (Node*)bucket; node != null; node = node->Next) + { + if (hashCode == node->HashCode && node->Key.Equals(key)) + { + if (node->Value.Equals(comparisonValue)) + { + if (NativeConcurrentDictionaryTypeProps.IsWriteAtomic) + { + node->Value = newValue; + } + else + { + Node* newNode; + _handle->NodeLock.Enter(); + try + { + newNode = (Node*)_handle->NodePool.Rent(); + } + finally + { + _handle->NodeLock.Exit(); + } + + newNode->Initialize(node->Key, newValue, hashCode, node->Next); + if (prev == null) + Volatile.Write(ref bucket, (nint)newNode); + else + prev->Next = newNode; + _handle->NodeLock.Enter(); + try + { + _handle->NodePool.Return(node); + } + finally + { + _handle->NodeLock.Exit(); + } + } + + return true; + } + + return false; + } + + prev = node; + } + + return false; + } + finally + { + Monitor.Exit(locks[lockNo]); + } + } + } + + /// + /// Try to get the value + /// + /// Tables + /// Key + /// HashCode + /// Value + /// Got + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static bool TryGetValueInternal(Tables* tables, in TKey key, int hashCode, out TValue value) + { + for (var node = (Node*)GetBucket(tables, hashCode); node != null; node = node->Next) + { + if (hashCode == node->HashCode && node->Key.Equals(key)) + { + value = node->Value; + return true; + } + } + + value = default; + return false; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private int GetCountNoLocks() + { + var count = 0; + foreach (var value in _handle->Tables->CountPerLock) + { + checked + { + count += value; + } + } + + return count; + } + + /// + /// Get bucket + /// + /// Tables + /// HashCode + /// Bucket + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static nint GetBucket(Tables* tables, int hashCode) + { + var buckets = tables->Buckets; + return IntPtr.Size == 8 ? buckets[HashHelpers.FastMod((uint)hashCode, (uint)buckets.Length, tables->FastModBucketsMultiplier)].Node : buckets[(uint)hashCode % (uint)buckets.Length].Node; + } + + /// + /// Get bucket and lock + /// + /// Tables + /// HashCode + /// Lock no + /// Bucket + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static ref nint GetBucketAndLock(Tables* tables, int hashCode, out uint lockNo) + { + var buckets = tables->Buckets; + var bucketNo = IntPtr.Size == 8 ? HashHelpers.FastMod((uint)hashCode, (uint)buckets.Length, tables->FastModBucketsMultiplier) : (uint)hashCode % (uint)buckets.Length; + lockNo = bucketNo % (uint)tables->Locks.Length; + return ref buckets[bucketNo].Node; + } + + /// + /// Volatile node + /// + private struct VolatileNode + { + /// + /// Node + /// + public volatile nint Node; + } + + /// + /// Node + /// + private struct Node + { + /// + /// Key + /// + public TKey Key; + + /// + /// Value + /// + public TValue Value; + + /// + /// Next + /// + public volatile Node* Next; + + /// + /// HashCode + /// + public int HashCode; + + /// + /// Initialize + /// + /// Key + /// Value + /// HashCode + /// Next + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Initialize(in TKey key, in TValue value, int hashCode, Node* next) + { + Key = key; + Value = value; + Next = next; + HashCode = hashCode; + } + } + + /// + /// Tables + /// + private struct Tables + { + /// + /// Buckets + /// + public NativeArray Buckets; + + /// + /// Fast mod buckets multiplier + /// + public ulong FastModBucketsMultiplier; + + /// + /// Locks + /// + public NativeArrayReference Locks; + + /// + /// Count per lock + /// + public NativeArray CountPerLock; + + /// + /// Initialize + /// + /// Buckets + /// Locks + /// Count per lock + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Initialize(in NativeArray buckets, in NativeArrayReference locks, in NativeArray countPerLock) + { + Buckets = buckets; + Locks = locks; + CountPerLock = countPerLock; + FastModBucketsMultiplier = IntPtr.Size == 8 ? HashHelpers.GetFastModMultiplier((uint)buckets.Length) : 0; + } + + /// + /// Dispose + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Dispose() + { + Buckets.Dispose(); + Locks.Dispose(); + CountPerLock.Dispose(); + } + } + + /// + /// Empty + /// + public static NativeConcurrentDictionary Empty => new(); + + /// + /// Get enumerator + /// + /// Enumerator + public Enumerator GetEnumerator() => new(this); + + /// + /// Enumerator + /// + public struct Enumerator + { + /// + /// NativeConcurrentDictionary + /// + private readonly NativeConcurrentDictionary _nativeConcurrentDictionary; + + /// + /// Buckets + /// + private NativeArray _buckets; + + /// + /// Node + /// + private Node* _node; + + /// + /// Index + /// + private int _index; + + /// + /// State + /// + private int _state; + + /// + /// State uninitialized + /// + private const int STATE_UNINITIALIZED = 0; + + /// + /// State outer loop + /// + private const int STATE_OUTER_LOOP = 1; + + /// + /// State inner loop + /// + private const int STATE_INNER_LOOP = 2; + + /// + /// State done + /// + private const int STATE_DONE = 3; + + /// + /// Current + /// + private KeyValuePair _current; + + /// + /// Structure + /// + /// NativeConcurrentDictionary + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal Enumerator(NativeConcurrentDictionary nativeConcurrentDictionary) + { + _nativeConcurrentDictionary = nativeConcurrentDictionary; + _index = -1; + _buckets = default; + _node = null; + _state = 0; + _current = default; + } + + /// + /// Move next + /// + /// Moved + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool MoveNext() + { + switch (_state) + { + case STATE_UNINITIALIZED: + _buckets = _nativeConcurrentDictionary._handle->Tables->Buckets; + _index = -1; + goto case STATE_OUTER_LOOP; + case STATE_OUTER_LOOP: + var buckets = _buckets; + var i = ++_index; + if ((uint)i < (uint)buckets.Length) + { + _node = (Node*)buckets[i].Node; + _state = STATE_INNER_LOOP; + goto case STATE_INNER_LOOP; + } + + goto default; + case STATE_INNER_LOOP: + if (_node != null) + { + var node = _node; + _current = new KeyValuePair(node->Key, node->Value); + _node = node->Next; + return true; + } + + goto case STATE_OUTER_LOOP; + default: + _state = STATE_DONE; + return false; + } + } + + /// + /// Current + /// + public KeyValuePair Current + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _current; + } + } + + /// + /// Key collection + /// + [StructLayout(LayoutKind.Sequential)] + public readonly struct KeyCollection + { + /// + /// NativeConcurrentDictionary + /// + private readonly NativeConcurrentDictionary _nativeConcurrentDictionary; + + /// + /// Structure + /// + /// NativeConcurrentDictionary + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal KeyCollection(in NativeConcurrentDictionary nativeConcurrentDictionary) => _nativeConcurrentDictionary = nativeConcurrentDictionary; + + /// + /// Get enumerator + /// + /// Enumerator + public Enumerator GetEnumerator() => new(_nativeConcurrentDictionary); + + /// + /// Enumerator + /// + public struct Enumerator + { + /// + /// NativeConcurrentDictionary + /// + private readonly NativeConcurrentDictionary _nativeConcurrentDictionary; + + /// + /// Buckets + /// + private NativeArray _buckets; + + /// + /// Node + /// + private Node* _node; + + /// + /// Index + /// + private int _index; + + /// + /// State + /// + private int _state; + + /// + /// State uninitialized + /// + private const int STATE_UNINITIALIZED = 0; + + /// + /// State outer loop + /// + private const int STATE_OUTER_LOOP = 1; + + /// + /// State inner loop + /// + private const int STATE_INNER_LOOP = 2; + + /// + /// State done + /// + private const int STATE_DONE = 3; + + /// + /// Current + /// + private TKey _current; + + /// + /// Structure + /// + /// NativeConcurrentDictionary + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal Enumerator(NativeConcurrentDictionary nativeConcurrentDictionary) + { + _nativeConcurrentDictionary = nativeConcurrentDictionary; + _index = -1; + _buckets = default; + _node = null; + _state = 0; + _current = default; + } + + /// + /// Move next + /// + /// Moved + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool MoveNext() + { + switch (_state) + { + case STATE_UNINITIALIZED: + _buckets = _nativeConcurrentDictionary._handle->Tables->Buckets; + _index = -1; + goto case STATE_OUTER_LOOP; + case STATE_OUTER_LOOP: + var buckets = _buckets; + var i = ++_index; + if ((uint)i < (uint)buckets.Length) + { + _node = (Node*)buckets[i].Node; + _state = STATE_INNER_LOOP; + goto case STATE_INNER_LOOP; + } + + goto default; + case STATE_INNER_LOOP: + if (_node != null) + { + var node = _node; + _current = node->Key; + _node = node->Next; + return true; + } + + goto case STATE_OUTER_LOOP; + default: + _state = STATE_DONE; + return false; + } + } + + /// + /// Current + /// + public TKey Current + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _current; + } + } + } + + /// + /// Value collection + /// + [StructLayout(LayoutKind.Sequential)] + public readonly struct ValueCollection + { + /// + /// NativeConcurrentDictionary + /// + private readonly NativeConcurrentDictionary _nativeConcurrentDictionary; + + /// + /// Structure + /// + /// NativeConcurrentDictionary + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal ValueCollection(in NativeConcurrentDictionary nativeConcurrentDictionary) => _nativeConcurrentDictionary = nativeConcurrentDictionary; + + /// + /// Get enumerator + /// + /// Enumerator + public Enumerator GetEnumerator() => new(_nativeConcurrentDictionary); + + /// + /// Enumerator + /// + public struct Enumerator + { + /// + /// NativeConcurrentDictionary + /// + private readonly NativeConcurrentDictionary _nativeConcurrentDictionary; + + /// + /// Buckets + /// + private NativeArray _buckets; + + /// + /// Node + /// + private Node* _node; + + /// + /// Index + /// + private int _index; + + /// + /// State + /// + private int _state; + + /// + /// State uninitialized + /// + private const int STATE_UNINITIALIZED = 0; + + /// + /// State outer loop + /// + private const int STATE_OUTER_LOOP = 1; + + /// + /// State inner loop + /// + private const int STATE_INNER_LOOP = 2; + + /// + /// State done + /// + private const int STATE_DONE = 3; + + /// + /// Current + /// + private TValue _current; + + /// + /// Structure + /// + /// NativeConcurrentDictionary + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal Enumerator(NativeConcurrentDictionary nativeConcurrentDictionary) + { + _nativeConcurrentDictionary = nativeConcurrentDictionary; + _index = -1; + _buckets = default; + _node = null; + _state = 0; + _current = default; + } + + /// + /// Move next + /// + /// Moved + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool MoveNext() + { + switch (_state) + { + case STATE_UNINITIALIZED: + _buckets = _nativeConcurrentDictionary._handle->Tables->Buckets; + _index = -1; + goto case STATE_OUTER_LOOP; + case STATE_OUTER_LOOP: + var buckets = _buckets; + var i = ++_index; + if ((uint)i < (uint)buckets.Length) + { + _node = (Node*)buckets[i].Node; + _state = STATE_INNER_LOOP; + goto case STATE_INNER_LOOP; + } + + goto default; + case STATE_INNER_LOOP: + if (_node != null) + { + var node = _node; + _current = node->Value; + _node = node->Next; + return true; + } + + goto case STATE_OUTER_LOOP; + default: + _state = STATE_DONE; + return false; + } + } + + /// + /// Current + /// + public TValue Current + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _current; + } + } + } + } + + /// + /// Native concurrentDictionary type props + /// + /// Type + internal static class NativeConcurrentDictionaryTypeProps where T : unmanaged, IEquatable + { + /// + /// Is write atomic + /// + public static readonly bool IsWriteAtomic = IsWriteAtomicPrivate(); + + /// + /// Is write atomic + /// + /// Is write atomic + private static bool IsWriteAtomicPrivate() + { + if (typeof(T) == typeof(IntPtr) || typeof(T) == typeof(UIntPtr)) + return true; + switch (Type.GetTypeCode(typeof(T))) + { + case TypeCode.Boolean: + case TypeCode.Byte: + case TypeCode.Char: + case TypeCode.Int16: + case TypeCode.Int32: + case TypeCode.SByte: + case TypeCode.Single: + case TypeCode.UInt16: + case TypeCode.UInt32: + return true; + case TypeCode.Double: + case TypeCode.Int64: + case TypeCode.UInt64: + return IntPtr.Size == 8; + default: + return false; + } + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeConcurrentHashSet.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeConcurrentHashSet.cs new file mode 100644 index 0000000..1bfb7b3 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeConcurrentHashSet.cs @@ -0,0 +1,878 @@ +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +#if UNITY_2021_3_OR_NEWER || GODOT +using System; +using System.Threading; +#endif + +#pragma warning disable CA2208 +#pragma warning disable CS8632 + +// ReSharper disable ALL + +namespace NativeCollections +{ + /// + /// Native concurrentHashSet + /// (Slower than ConcurrentHashSet) + /// + /// Type + [StructLayout(LayoutKind.Sequential)] + public readonly unsafe struct NativeConcurrentHashSet : IDisposable, IEquatable> where T : unmanaged, IEquatable + { + /// + /// Handle + /// + [StructLayout(LayoutKind.Sequential)] + private struct NativeConcurrentHashSetHandle + { + /// + /// Tables + /// + public volatile Tables* Tables; + + /// + /// Budget + /// + public int Budget; + + /// + /// Grow lock array + /// + public bool GrowLockArray; + + /// + /// Node pool + /// + public NativeMemoryPool NodePool; + + /// + /// Node lock + /// + public NativeConcurrentSpinLock NodeLock; + } + + /// + /// Handle + /// + private readonly NativeConcurrentHashSetHandle* _handle; + + /// + /// Structure + /// + /// Size + /// Max free slabs + /// Concurrency level + /// Capacity + /// Grow lock array + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public NativeConcurrentHashSet(int size, int maxFreeSlabs, int concurrencyLevel, int capacity, bool growLockArray) + { + var nodePool = new NativeMemoryPool(size, sizeof(Node), maxFreeSlabs); + if (concurrencyLevel <= 0) + concurrencyLevel = Environment.ProcessorCount; + if (capacity < concurrencyLevel) + capacity = concurrencyLevel; + capacity = HashHelpers.GetPrime(capacity); + var locks = new NativeArrayReference(concurrencyLevel); + for (var i = 0; i < locks.Length; ++i) + locks[i] = new object(); + var countPerLock = new NativeArray(locks.Length, true); + var buckets = new NativeArray(capacity, true); + _handle = (NativeConcurrentHashSetHandle*)NativeMemoryAllocator.Alloc((uint)sizeof(NativeConcurrentHashSetHandle)); + _handle->Tables = (Tables*)NativeMemoryAllocator.Alloc((uint)sizeof(Tables)); + _handle->Tables->Initialize(buckets, locks, countPerLock); + _handle->GrowLockArray = growLockArray; + _handle->Budget = buckets.Length / locks.Length; + _handle->NodePool = nodePool; + _handle->NodeLock = new NativeConcurrentSpinLock(-1); + } + + /// + /// Is created + /// + public bool IsCreated => _handle != null; + + /// + /// Is created + /// + public bool IsEmpty + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get + { + if (!AreAllBucketsEmpty()) + return false; + var locksAcquired = 0; + try + { + AcquireAllLocks(ref locksAcquired); + return AreAllBucketsEmpty(); + } + finally + { + ReleaseLocks(locksAcquired); + } + } + } + + /// + /// Count + /// + public int Count + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get + { + var locksAcquired = 0; + try + { + AcquireAllLocks(ref locksAcquired); + return GetCountNoLocks(); + } + finally + { + ReleaseLocks(locksAcquired); + } + } + } + + /// + /// Equals + /// + /// Other + /// Equals + public bool Equals(NativeConcurrentHashSet other) => other == this; + + /// + /// Equals + /// + /// object + /// Equals + public override bool Equals(object? obj) => obj is NativeConcurrentHashSet nativeConcurrentHashSet && nativeConcurrentHashSet == this; + + /// + /// Get hashCode + /// + /// HashCode + public override int GetHashCode() => (int)(nint)_handle; + + /// + /// To string + /// + /// String + public override string ToString() => $"NativeConcurrentHashSet<{typeof(T).Name}>"; + + /// + /// Equals + /// + /// Left + /// Right + /// Equals + public static bool operator ==(NativeConcurrentHashSet left, NativeConcurrentHashSet right) => left._handle == right._handle; + + /// + /// Not equals + /// + /// Left + /// Right + /// Not equals + public static bool operator !=(NativeConcurrentHashSet left, NativeConcurrentHashSet right) => left._handle != right._handle; + + /// + /// Dispose + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Dispose() + { + if (_handle == null) + return; + _handle->Tables->Dispose(); + _handle->NodePool.Dispose(); + _handle->NodeLock.Dispose(); + NativeMemoryAllocator.Free(_handle); + } + + /// + /// Clear + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Clear() + { + var locksAcquired = 0; + try + { + AcquireAllLocks(ref locksAcquired); + if (AreAllBucketsEmpty()) + return; + foreach (var bucket in _handle->Tables->Buckets) + { + var node = (Node*)bucket.Node; + while (node != null) + { + var temp = node; + node = node->Next; + _handle->NodePool.Return(temp); + } + } + + var length = HashHelpers.GetPrime(31); + if (_handle->Tables->Buckets.Length != length) + { + _handle->Tables->Buckets.Dispose(); + _handle->Tables->Buckets = new NativeArray(length, true); + } + else + { + _handle->Tables->Buckets.Clear(); + } + + _handle->Tables->CountPerLock.Clear(); + var budget = _handle->Tables->Buckets.Length / _handle->Tables->Locks.Length; + _handle->Budget = budget >= 1 ? budget : 1; + } + finally + { + ReleaseLocks(locksAcquired); + } + } + + /// + /// Add + /// + /// Key + /// Added + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool Add(in T key) => TryAddInternal(_handle->Tables, key); + + /// + /// Remove + /// + /// Key + /// Removed + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool Remove(in T key) + { + var tables = _handle->Tables; + var hashCode = key.GetHashCode(); + while (true) + { + var locks = tables->Locks; + ref var bucket = ref GetBucketAndLock(tables, hashCode, out var lockNo); + if (tables->CountPerLock[lockNo] != 0) + { + Monitor.Enter(locks[lockNo]); + try + { + if (tables != _handle->Tables) + { + tables = _handle->Tables; + continue; + } + + Node* prev = null; + for (var curr = (Node*)bucket; curr != null; curr = curr->Next) + { + if (hashCode == curr->HashCode && curr->Key.Equals(key)) + { + if (prev == null) + Volatile.Write(ref bucket, (nint)curr->Next); + else + prev->Next = curr->Next; + _handle->NodeLock.Enter(); + try + { + _handle->NodePool.Return(curr); + } + finally + { + _handle->NodeLock.Exit(); + } + + tables->CountPerLock[lockNo]--; + return true; + } + + prev = curr; + } + } + finally + { + Monitor.Exit(locks[lockNo]); + } + } + + return false; + } + } + + /// + /// Contains key + /// + /// Key + /// Contains key + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool Contains(in T key) + { + var tables = _handle->Tables; + var hashCode = key.GetHashCode(); + for (var node = (Node*)GetBucket(tables, hashCode); node != null; node = node->Next) + { + if (hashCode == node->HashCode && node->Key.Equals(key)) + return true; + } + + return false; + } + + /// + /// Try to get the actual value + /// + /// Equal value + /// Actual value + /// Got + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool TryGetValue(in T equalValue, out T actualValue) + { + var tables = _handle->Tables; + var hashCode = equalValue.GetHashCode(); + for (var node = (Node*)GetBucket(tables, hashCode); node != null; node = node->Next) + { + if (hashCode == node->HashCode && node->Key.Equals(equalValue)) + { + actualValue = node->Key; + return true; + } + } + + actualValue = default; + return false; + } + + /// + /// Check all buckets are empty + /// + /// All buckets are empty + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private bool AreAllBucketsEmpty() + { +#if NET8_0_OR_GREATER + return !_handle->Tables->CountPerLock.AsSpan().ContainsAnyExcept(0); +#elif NET7_0_OR_GREATER + return !(_handle->Tables->CountPerLock.AsSpan().IndexOfAnyExcept(0) >= 0); +#else + for (var i = 0; i < _handle->Tables->CountPerLock.Length; ++i) + { + if (_handle->Tables->CountPerLock[i] != 0) + return false; + } + + return true; +#endif + } + + /// + /// Grow table + /// + /// Tables + /// Resize desired + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void GrowTable(Tables* tables, bool resizeDesired) + { + var locksAcquired = 0; + try + { + AcquireFirstLock(ref locksAcquired); + if (tables != _handle->Tables) + return; + var newLength = tables->Buckets.Length; + if (resizeDesired) + { + if (GetCountNoLocks() < tables->Buckets.Length / 4) + { + _handle->Budget = 2 * _handle->Budget; + if (_handle->Budget < 0) + _handle->Budget = int.MaxValue; + return; + } + + if ((newLength = tables->Buckets.Length * 2) < 0 || (newLength = HashHelpers.GetPrime(newLength)) > 2147483591) + { + newLength = 2147483591; + _handle->Budget = int.MaxValue; + } + } + + var newLocks = tables->Locks; + if (_handle->GrowLockArray && tables->Locks.Length < 1024) + { + newLocks = new NativeArrayReference(tables->Locks.Length * 2); + Array.Copy(tables->Locks.Array, newLocks.Array, tables->Locks.Length); + for (var i = tables->Locks.Length; i < newLocks.Length; ++i) + newLocks[i] = new NativeMonitorLock(new object()); + } + + var newBuckets = new NativeArray(newLength, true); + var newCountPerLock = new NativeArray(newLocks.Length, true); + var newTables = (Tables*)NativeMemoryAllocator.Alloc((uint)sizeof(Tables)); + newTables->Initialize(newBuckets, newLocks, newCountPerLock); + AcquirePostFirstLock(tables, ref locksAcquired); + foreach (var bucket in tables->Buckets) + { + var current = (Node*)bucket.Node; + while (current != null) + { + var hashCode = current->HashCode; + var next = current->Next; + ref var newBucket = ref GetBucketAndLock(newTables, hashCode, out var newLockNo); + var newNode = current; + newNode->Initialize(current->Key, hashCode, (Node*)newBucket); + newBucket = (nint)newNode; + checked + { + newCountPerLock[newLockNo]++; + } + + current = next; + } + } + + var budget = newBuckets.Length / newLocks.Length; + _handle->Budget = budget >= 1 ? budget : 1; + _handle->Tables->Buckets.Dispose(); + if (_handle->Tables->Locks != newLocks) + _handle->Tables->Locks.Dispose(); + _handle->Tables->CountPerLock.Dispose(); + NativeMemoryAllocator.Free(_handle->Tables); + _handle->Tables = newTables; + } + finally + { + ReleaseLocks(locksAcquired); + } + } + + /// + /// Acquire all locks + /// + /// Locks acquired + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void AcquireAllLocks(ref int locksAcquired) + { + AcquireFirstLock(ref locksAcquired); + AcquirePostFirstLock(_handle->Tables, ref locksAcquired); + } + + /// + /// Acquire first lock + /// + /// Locks acquired + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void AcquireFirstLock(ref int locksAcquired) + { + var locks = _handle->Tables->Locks; + Monitor.Enter(locks[0]); + locksAcquired = 1; + } + + /// + /// Acquire post first locks + /// + /// Tables + /// Locks acquired + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static void AcquirePostFirstLock(Tables* tables, ref int locksAcquired) + { + var locks = tables->Locks; + for (var i = 1; i < locks.Length; ++i) + { + Monitor.Enter(locks[i]); + locksAcquired++; + } + } + + /// + /// Release locks + /// + /// Locks acquired + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void ReleaseLocks(int locksAcquired) + { + var locks = _handle->Tables->Locks; + for (var i = 0; i < locksAcquired; ++i) + Monitor.Exit(locks[i]); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private bool TryAddInternal(Tables* tables, in T key) + { + var hashCode = key.GetHashCode(); + while (true) + { + var locks = tables->Locks; + ref var bucket = ref GetBucketAndLock(tables, hashCode, out var lockNo); + var resizeDesired = false; + var lockTaken = false; + try + { + Monitor.Enter(locks[lockNo], ref lockTaken); + if (tables != _handle->Tables) + { + tables = _handle->Tables; + continue; + } + + for (var node = (Node*)bucket; node != null; node = node->Next) + { + if (hashCode == node->HashCode && node->Key.Equals(key)) + return false; + } + + Node* resultNode; + _handle->NodeLock.Enter(); + try + { + resultNode = (Node*)_handle->NodePool.Rent(); + } + finally + { + _handle->NodeLock.Exit(); + } + + resultNode->Initialize(key, hashCode, (Node*)bucket); + Volatile.Write(ref bucket, (nint)resultNode); + checked + { + tables->CountPerLock[lockNo]++; + } + + if (tables->CountPerLock[lockNo] > _handle->Budget) + resizeDesired = true; + } + finally + { + if (lockTaken) + Monitor.Exit(locks[lockNo]); + } + + if (resizeDesired) + GrowTable(tables, resizeDesired); + return true; + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private int GetCountNoLocks() + { + var count = 0; + foreach (var value in _handle->Tables->CountPerLock) + { + checked + { + count += value; + } + } + + return count; + } + + /// + /// Get bucket + /// + /// Tables + /// HashCode + /// Bucket + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static nint GetBucket(Tables* tables, int hashCode) + { + var buckets = tables->Buckets; + return IntPtr.Size == 8 ? buckets[HashHelpers.FastMod((uint)hashCode, (uint)buckets.Length, tables->FastModBucketsMultiplier)].Node : buckets[(uint)hashCode % (uint)buckets.Length].Node; + } + + /// + /// Get bucket and lock + /// + /// Tables + /// HashCode + /// Lock no + /// Bucket + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static ref nint GetBucketAndLock(Tables* tables, int hashCode, out uint lockNo) + { + var buckets = tables->Buckets; + var bucketNo = IntPtr.Size == 8 ? HashHelpers.FastMod((uint)hashCode, (uint)buckets.Length, tables->FastModBucketsMultiplier) : (uint)hashCode % (uint)buckets.Length; + lockNo = bucketNo % (uint)tables->Locks.Length; + return ref buckets[bucketNo].Node; + } + + /// + /// Volatile node + /// + private struct VolatileNode + { + /// + /// Node + /// + public volatile nint Node; + } + + /// + /// Node + /// + private struct Node + { + /// + /// Key + /// + public T Key; + + /// + /// Next + /// + public volatile Node* Next; + + /// + /// HashCode + /// + public int HashCode; + + /// + /// Initialize + /// + /// Key + /// HashCode + /// Next + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Initialize(in T key, int hashCode, Node* next) + { + Key = key; + Next = next; + HashCode = hashCode; + } + } + + /// + /// Tables + /// + private struct Tables + { + /// + /// Buckets + /// + public NativeArray Buckets; + + /// + /// Fast mod buckets multiplier + /// + public ulong FastModBucketsMultiplier; + + /// + /// Locks + /// + public NativeArrayReference Locks; + + /// + /// Count per lock + /// + public NativeArray CountPerLock; + + /// + /// Initialize + /// + /// Buckets + /// Locks + /// Count per lock + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Initialize(in NativeArray buckets, in NativeArrayReference locks, in NativeArray countPerLock) + { + Buckets = buckets; + Locks = locks; + CountPerLock = countPerLock; + FastModBucketsMultiplier = IntPtr.Size == 8 ? HashHelpers.GetFastModMultiplier((uint)buckets.Length) : 0; + } + + /// + /// Dispose + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Dispose() + { + Buckets.Dispose(); + Locks.Dispose(); + CountPerLock.Dispose(); + } + } + + /// + /// Empty + /// + public static NativeConcurrentHashSet Empty => new(); + + /// + /// Get enumerator + /// + /// Enumerator + public Enumerator GetEnumerator() => new(this); + + /// + /// Enumerator + /// + public struct Enumerator + { + /// + /// NativeConcurrentHashSet + /// + private readonly NativeConcurrentHashSet _nativeConcurrentHashSet; + + /// + /// Buckets + /// + private NativeArray _buckets; + + /// + /// Node + /// + private Node* _node; + + /// + /// Index + /// + private int _index; + + /// + /// State + /// + private int _state; + + /// + /// State uninitialized + /// + private const int STATE_UNINITIALIZED = 0; + + /// + /// State outer loop + /// + private const int STATE_OUTER_LOOP = 1; + + /// + /// State inner loop + /// + private const int STATE_INNER_LOOP = 2; + + /// + /// State done + /// + private const int STATE_DONE = 3; + + /// + /// Current + /// + private T _current; + + /// + /// Structure + /// + /// NativeConcurrentHashSet + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal Enumerator(NativeConcurrentHashSet nativeConcurrentHashSet) + { + _nativeConcurrentHashSet = nativeConcurrentHashSet; + _index = -1; + _buckets = default; + _node = null; + _state = 0; + _current = default; + } + + /// + /// Move next + /// + /// Moved + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool MoveNext() + { + switch (_state) + { + case STATE_UNINITIALIZED: + _buckets = _nativeConcurrentHashSet._handle->Tables->Buckets; + _index = -1; + goto case STATE_OUTER_LOOP; + case STATE_OUTER_LOOP: + var buckets = _buckets; + var i = ++_index; + if ((uint)i < (uint)buckets.Length) + { + _node = (Node*)buckets[i].Node; + _state = STATE_INNER_LOOP; + goto case STATE_INNER_LOOP; + } + + goto default; + case STATE_INNER_LOOP: + if (_node != null) + { + var node = _node; + _current = node->Key; + _node = node->Next; + return true; + } + + goto case STATE_OUTER_LOOP; + default: + _state = STATE_DONE; + return false; + } + } + + /// + /// Current + /// + public T Current + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _current; + } + } + } + + /// + /// Native concurrentHashSet type props + /// + /// Type + internal static class NativeConcurrentHashSetTypeProps where T : unmanaged, IEquatable + { + /// + /// Is write atomic + /// + public static readonly bool IsWriteAtomic = IsWriteAtomicPrivate(); + + /// + /// Is write atomic + /// + /// Is write atomic + private static bool IsWriteAtomicPrivate() + { + if (typeof(T) == typeof(IntPtr) || typeof(T) == typeof(UIntPtr)) + return true; + switch (Type.GetTypeCode(typeof(T))) + { + case TypeCode.Boolean: + case TypeCode.Byte: + case TypeCode.Char: + case TypeCode.Int16: + case TypeCode.Int32: + case TypeCode.SByte: + case TypeCode.Single: + case TypeCode.UInt16: + case TypeCode.UInt32: + return true; + case TypeCode.Double: + case TypeCode.Int64: + case TypeCode.UInt64: + return IntPtr.Size == 8; + default: + return false; + } + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeConcurrentQueue.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeConcurrentQueue.cs new file mode 100644 index 0000000..9ecc2b9 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeConcurrentQueue.cs @@ -0,0 +1,1288 @@ +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +#if UNITY_2021_3_OR_NEWER || GODOT +using System; +using System.Threading; +#endif + +#pragma warning disable CA2208 +#pragma warning disable CS8632 + +// ReSharper disable ALL + +namespace NativeCollections +{ + /// + /// Native concurrentQueue + /// (Slower than ConcurrentQueue, disable Enumerator, try peek either) + /// + /// Type + [StructLayout(LayoutKind.Sequential)] + public unsafe struct NativeConcurrentQueue : IDisposable, IEquatable> where T : unmanaged + { + /// + /// Handle + /// + private void* _handle; + + /// + /// Not arm64 + /// + private NativeConcurrentQueueNotArm64* NotArm64Handle + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => (NativeConcurrentQueueNotArm64*)_handle; + } + + /// + /// Arm64 + /// + private NativeConcurrentQueueArm64* Arm64Handle + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => (NativeConcurrentQueueArm64*)_handle; + } + + /// + /// Structure + /// + /// Size + /// Max free slabs + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public NativeConcurrentQueue(int size, int maxFreeSlabs) + { + if (RuntimeInformation.ProcessArchitecture != Architecture.Arm64) + { + var segmentPool = new NativeMemoryPool(size, sizeof(NativeConcurrentQueueSegmentNotArm64) + NativeConcurrentQueueSegmentNotArm64.LENGTH * sizeof(NativeConcurrentQueueSegmentNotArm64.Slot), maxFreeSlabs); + _handle = NativeMemoryAllocator.Alloc((uint)sizeof(NativeConcurrentQueueNotArm64)); + NotArm64Handle->Initialize(segmentPool); + } + else + { + var segmentPool = new NativeMemoryPool(size, sizeof(NativeConcurrentQueueSegmentArm64) + NativeConcurrentQueueSegmentArm64.LENGTH * sizeof(NativeConcurrentQueueSegmentArm64.Slot), maxFreeSlabs); + _handle = NativeMemoryAllocator.Alloc((uint)sizeof(NativeConcurrentQueueArm64)); + Arm64Handle->Initialize(segmentPool); + } + } + + /// + /// Is created + /// + public bool IsCreated => _handle != null; + + /// + /// IsEmpty + /// + public bool IsEmpty + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => RuntimeInformation.ProcessArchitecture != Architecture.Arm64 ? NotArm64Handle->IsEmpty : Arm64Handle->IsEmpty; + } + + /// + /// Count + /// + public int Count + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => RuntimeInformation.ProcessArchitecture != Architecture.Arm64 ? NotArm64Handle->Count : Arm64Handle->Count; + } + + /// + /// Equals + /// + /// Other + /// Equals + public bool Equals(NativeConcurrentQueue other) => other == this; + + /// + /// Equals + /// + /// object + /// Equals + public override bool Equals(object? obj) => obj is NativeConcurrentQueue nativeConcurrentQueue && nativeConcurrentQueue == this; + + /// + /// Get hashCode + /// + /// HashCode + public override int GetHashCode() => (int)(nint)_handle; + + /// + /// To string + /// + /// String + public override string ToString() => $"NativeConcurrentQueue<{typeof(T).Name}>"; + + /// + /// Equals + /// + /// Left + /// Right + /// Equals + public static bool operator ==(NativeConcurrentQueue left, NativeConcurrentQueue right) => left._handle == right._handle; + + /// + /// Not equals + /// + /// Left + /// Right + /// Not equals + public static bool operator !=(NativeConcurrentQueue left, NativeConcurrentQueue right) => left._handle != right._handle; + + /// + /// Dispose + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Dispose() + { + if (_handle == null) + return; + if (RuntimeInformation.ProcessArchitecture != Architecture.Arm64) + NotArm64Handle->Dispose(); + else + Arm64Handle->Dispose(); + NativeMemoryAllocator.Free(_handle); + } + + /// + /// Clear + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Clear() + { + if (RuntimeInformation.ProcessArchitecture != Architecture.Arm64) + NotArm64Handle->Clear(); + else + Arm64Handle->Clear(); + } + + /// + /// Enqueue + /// + /// Item + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Enqueue(in T item) + { + if (RuntimeInformation.ProcessArchitecture != Architecture.Arm64) + NotArm64Handle->Enqueue(item); + else + Arm64Handle->Enqueue(item); + } + + /// + /// Try dequeue + /// + /// Item + /// Dequeued + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool TryDequeue(out T result) => RuntimeInformation.ProcessArchitecture != Architecture.Arm64 ? NotArm64Handle->TryDequeue(out result) : Arm64Handle->TryDequeue(out result); + + /// + /// Empty + /// + public static NativeConcurrentQueue Empty => new(); + } + + /// + /// Native concurrentQueue + /// (Slower than ConcurrentQueue, disable Enumerator, try peek either) + /// + /// Type + [StructLayout(LayoutKind.Sequential)] + internal unsafe struct NativeConcurrentQueueNotArm64 : IDisposable where T : unmanaged + { + /// + /// Cross segment lock + /// + private NativeMonitorLock _crossSegmentLock; + + /// + /// Segment pool + /// + private NativeMemoryPool _segmentPool; + + /// + /// Tail + /// + private volatile NativeConcurrentQueueSegmentNotArm64* _tail; + + /// + /// Head + /// + private volatile NativeConcurrentQueueSegmentNotArm64* _head; + + /// + /// IsEmpty + /// + public bool IsEmpty + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get + { + var segment = _head; + while (true) + { + var next = Volatile.Read(ref segment->NextSegment); + if (segment->TryPeek()) + return false; + if (next != IntPtr.Zero) + segment = (NativeConcurrentQueueSegmentNotArm64*)next; + else if (Volatile.Read(ref segment->NextSegment) == IntPtr.Zero) + break; + } + + return true; + } + } + + /// + /// Count + /// + public int Count + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get + { + var spinCount = 0; + while (true) + { + var head = _head; + var tail = _tail; + var headHead = Volatile.Read(ref head->HeadAndTail.Head); + var headTail = Volatile.Read(ref head->HeadAndTail.Tail); + if (head == tail) + { + if (head == _head && tail == _tail && headHead == Volatile.Read(ref head->HeadAndTail.Head) && headTail == Volatile.Read(ref head->HeadAndTail.Tail)) + return GetCount(head, headHead, headTail); + } + else if ((NativeConcurrentQueueSegmentNotArm64*)head->NextSegment == tail) + { + var tailHead = Volatile.Read(ref tail->HeadAndTail.Head); + var tailTail = Volatile.Read(ref tail->HeadAndTail.Tail); + if (head == _head && tail == _tail && headHead == Volatile.Read(ref head->HeadAndTail.Head) && headTail == Volatile.Read(ref head->HeadAndTail.Tail) && tailHead == Volatile.Read(ref tail->HeadAndTail.Head) && tailTail == Volatile.Read(ref tail->HeadAndTail.Tail)) + return GetCount(head, headHead, headTail) + GetCount(tail, tailHead, tailTail); + } + else + { + _crossSegmentLock.Enter(); + try + { + if (head == _head && tail == _tail) + { + var tailHead = Volatile.Read(ref tail->HeadAndTail.Head); + var tailTail = Volatile.Read(ref tail->HeadAndTail.Tail); + if (headHead == Volatile.Read(ref head->HeadAndTail.Head) && headTail == Volatile.Read(ref head->HeadAndTail.Tail) && tailHead == Volatile.Read(ref tail->HeadAndTail.Head) && tailTail == Volatile.Read(ref tail->HeadAndTail.Tail)) + { + var count = GetCount(head, headHead, headTail) + GetCount(tail, tailHead, tailTail); + for (var s = (NativeConcurrentQueueSegmentNotArm64*)head->NextSegment; s != tail; s = (NativeConcurrentQueueSegmentNotArm64*)s->NextSegment) + count += s->HeadAndTail.Tail - NativeConcurrentQueueSegmentNotArm64.FREEZE_OFFSET; + return count; + } + } + } + finally + { + _crossSegmentLock.Exit(); + } + } + + if ((spinCount >= 10 && (spinCount - 10) % 2 == 0) || Environment.ProcessorCount == 1) + { + var yieldsSoFar = spinCount >= 10 ? (spinCount - 10) / 2 : spinCount; + if (yieldsSoFar % 5 == 4) + Thread.Sleep(0); + else + Thread.Yield(); + } + else + { + var iterations = Environment.ProcessorCount / 2; + if (spinCount <= 30 && 1 << spinCount < iterations) + iterations = 1 << spinCount; + Thread.SpinWait(iterations); + } + + spinCount = spinCount == int.MaxValue ? 10 : spinCount + 1; + } + } + } + + /// + /// Structure + /// + /// Segment pool + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Initialize(NativeMemoryPool segmentPool) + { + _crossSegmentLock = new NativeMonitorLock(new object()); + _segmentPool = segmentPool; + var segment = (NativeConcurrentQueueSegmentNotArm64*)_segmentPool.Rent(); + var array = (byte*)segment + sizeof(NativeConcurrentQueueSegmentNotArm64); + segment->Initialize((NativeConcurrentQueueSegmentNotArm64.Slot*)array); + _tail = _head = segment; + } + + /// + /// Dispose + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Dispose() + { + _crossSegmentLock.Dispose(); + _segmentPool.Dispose(); + } + + /// + /// Clear + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Clear() + { + _crossSegmentLock.Enter(); + try + { + _tail->EnsureFrozenForEnqueues(); + var node = _head; + while (node != null) + { + var temp = node; + node = (NativeConcurrentQueueSegmentNotArm64*)node->NextSegment; + _segmentPool.Return(temp); + } + + var segment = (NativeConcurrentQueueSegmentNotArm64*)_segmentPool.Rent(); + var array = (byte*)segment + sizeof(NativeConcurrentQueueSegmentNotArm64); + segment->Initialize((NativeConcurrentQueueSegmentNotArm64.Slot*)array); + _tail = _head = segment; + } + finally + { + _crossSegmentLock.Exit(); + } + } + + /// + /// Enqueue + /// + /// Item + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Enqueue(in T item) + { + if (!_tail->TryEnqueue(item)) + { + while (true) + { + var tail = _tail; + if (tail->TryEnqueue(item)) + return; + _crossSegmentLock.Enter(); + try + { + if (tail == _tail) + { + tail->EnsureFrozenForEnqueues(); + var newTail = (NativeConcurrentQueueSegmentNotArm64*)_segmentPool.Rent(); + var array = (byte*)newTail + sizeof(NativeConcurrentQueueSegmentNotArm64); + newTail->Initialize((NativeConcurrentQueueSegmentNotArm64.Slot*)array); + tail->NextSegment = (nint)newTail; + _tail = newTail; + } + } + finally + { + _crossSegmentLock.Exit(); + } + } + } + } + + /// + /// Try dequeue + /// + /// Item + /// Dequeued + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool TryDequeue(out T result) + { + var head = _head; + if (head->TryDequeue(out result)) + return true; + if (head->NextSegment == IntPtr.Zero) + { + result = default; + return false; + } + + while (true) + { + head = _head; + if (head->TryDequeue(out result)) + return true; + if (head->NextSegment == IntPtr.Zero) + { + result = default; + return false; + } + + if (head->TryDequeue(out result)) + return true; + _crossSegmentLock.Enter(); + try + { + if (head == _head) + { + _head = (NativeConcurrentQueueSegmentNotArm64*)head->NextSegment; + _segmentPool.Return(head); + } + } + finally + { + _crossSegmentLock.Exit(); + } + } + } + + /// + /// Get count + /// + /// Segment + /// Head + /// Tail + /// Count + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static int GetCount(NativeConcurrentQueueSegmentNotArm64* segment, int head, int tail) + { + if (head != tail && head != tail - NativeConcurrentQueueSegmentNotArm64.FREEZE_OFFSET) + { + head &= NativeConcurrentQueueSegmentNotArm64.SLOTS_MASK; + tail &= NativeConcurrentQueueSegmentNotArm64.SLOTS_MASK; + return head < tail ? tail - head : NativeConcurrentQueueSegmentNotArm64.LENGTH - head + tail; + } + + return 0; + } + + /// + /// Get count + /// + /// Head + /// Head head + /// Tail + /// Tail tail + /// Count + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static long GetCount(NativeConcurrentQueueSegmentNotArm64* head, int headHead, NativeConcurrentQueueSegmentNotArm64* tail, int tailTail) + { + long count = 0; + var headTail = (head == tail ? tailTail : Volatile.Read(ref head->HeadAndTail.Tail)) - NativeConcurrentQueueSegmentNotArm64.FREEZE_OFFSET; + if (headHead < headTail) + { + headHead &= NativeConcurrentQueueSegmentNotArm64.SLOTS_MASK; + headTail &= NativeConcurrentQueueSegmentNotArm64.SLOTS_MASK; + count += headHead < headTail ? headTail - headHead : NativeConcurrentQueueSegmentNotArm64.LENGTH - headHead + headTail; + } + + if (head != tail) + { + for (var s = (NativeConcurrentQueueSegmentNotArm64*)head->NextSegment; s != tail; s = (NativeConcurrentQueueSegmentNotArm64*)s->NextSegment) + count += s->HeadAndTail.Tail - NativeConcurrentQueueSegmentNotArm64.FREEZE_OFFSET; + count += tailTail - NativeConcurrentQueueSegmentNotArm64.FREEZE_OFFSET; + } + + return count; + } + } + + /// + /// Native concurrentQueue segment + /// + /// Type + [StructLayout(LayoutKind.Sequential)] + internal unsafe struct NativeConcurrentQueueSegmentNotArm64 where T : unmanaged + { + /// + /// Slots + /// + public Slot* Slots; + + /// + /// Length + /// + public const int LENGTH = 1024; + + /// + /// Slots mask + /// + public const int SLOTS_MASK = LENGTH - 1; + + /// + /// Head and tail + /// + public NativeConcurrentQueuePaddedHeadAndTailNotArm64 HeadAndTail; + + /// + /// Frozen for enqueues + /// + public bool FrozenForEnqueues; + + /// + /// Next segment + /// + public nint NextSegment; + + /// + /// Initialize + /// + /// Slots + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Initialize(Slot* slots) + { + Slots = slots; + for (var i = 0; i < LENGTH; ++i) + Slots[i].SequenceNumber = i; + HeadAndTail = new NativeConcurrentQueuePaddedHeadAndTailNotArm64(); + FrozenForEnqueues = false; + NextSegment = IntPtr.Zero; + } + + /// + /// Freeze offset + /// + public const int FREEZE_OFFSET = LENGTH * 2; + + /// + /// Ensure frozen for enqueues + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void EnsureFrozenForEnqueues() + { + if (!FrozenForEnqueues) + { + FrozenForEnqueues = true; + Interlocked.Add(ref HeadAndTail.Tail, FREEZE_OFFSET); + } + } + + /// + /// Try dequeue + /// + /// Item + /// Dequeued + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool TryDequeue(out T result) + { + var slots = Slots; + var count = 0; + while (true) + { + var currentHead = Volatile.Read(ref HeadAndTail.Head); + var slotsIndex = currentHead & SLOTS_MASK; + var sequenceNumber = Volatile.Read(ref slots[slotsIndex].SequenceNumber); + var diff = sequenceNumber - (currentHead + 1); + if (diff == 0) + { + if (Interlocked.CompareExchange(ref HeadAndTail.Head, currentHead + 1, currentHead) == currentHead) + { + result = slots[slotsIndex].Item; + Volatile.Write(ref slots[slotsIndex].SequenceNumber, currentHead + LENGTH); + return true; + } + } + else if (diff < 0) + { + var frozen = FrozenForEnqueues; + var currentTail = Volatile.Read(ref HeadAndTail.Tail); + if (currentTail - currentHead <= 0 || (frozen && currentTail - FREEZE_OFFSET - currentHead <= 0)) + { + result = default; + return false; + } + + if ((count >= 10 && (count - 10) % 2 == 0) || Environment.ProcessorCount == 1) + { + var yieldsSoFar = count >= 10 ? (count - 10) / 2 : count; + if (yieldsSoFar % 5 == 4) + Thread.Sleep(0); + else + Thread.Yield(); + } + else + { + var iterations = Environment.ProcessorCount / 2; + if (count <= 30 && 1 << count < iterations) + iterations = 1 << count; + Thread.SpinWait(iterations); + } + + count = count == int.MaxValue ? 10 : count + 1; + } + } + } + + /// + /// Try peek + /// + /// Peeked + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool TryPeek() + { + var slots = Slots; + var count = 0; + while (true) + { + var currentHead = Volatile.Read(ref HeadAndTail.Head); + var slotsIndex = currentHead & SLOTS_MASK; + var sequenceNumber = Volatile.Read(ref slots[slotsIndex].SequenceNumber); + var diff = sequenceNumber - (currentHead + 1); + if (diff == 0) + return true; + if (diff < 0) + { + var frozen = FrozenForEnqueues; + var currentTail = Volatile.Read(ref HeadAndTail.Tail); + if (currentTail - currentHead <= 0 || (frozen && currentTail - FREEZE_OFFSET - currentHead <= 0)) + return false; + if ((count >= 10 && (count - 10) % 2 == 0) || Environment.ProcessorCount == 1) + { + var yieldsSoFar = count >= 10 ? (count - 10) / 2 : count; + if (yieldsSoFar % 5 == 4) + Thread.Sleep(0); + else + Thread.Yield(); + } + else + { + var iterations = Environment.ProcessorCount / 2; + if (count <= 30 && 1 << count < iterations) + iterations = 1 << count; + Thread.SpinWait(iterations); + } + + count = count == int.MaxValue ? 10 : count + 1; + } + } + } + + /// + /// Try enqueue + /// + /// Item + /// Enqueued + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool TryEnqueue(in T item) + { + var slots = Slots; + while (true) + { + var currentTail = Volatile.Read(ref HeadAndTail.Tail); + var slotsIndex = currentTail & SLOTS_MASK; + var sequenceNumber = Volatile.Read(ref slots[slotsIndex].SequenceNumber); + var diff = sequenceNumber - currentTail; + if (diff == 0) + { + if (Interlocked.CompareExchange(ref HeadAndTail.Tail, currentTail + 1, currentTail) == currentTail) + { + slots[slotsIndex].Item = item; + Volatile.Write(ref slots[slotsIndex].SequenceNumber, currentTail + 1); + return true; + } + } + else if (diff < 0) + { + return false; + } + } + } + + /// + /// Slot + /// + [StructLayout(LayoutKind.Sequential)] + public struct Slot + { + /// + /// Item + /// + public T Item; + + /// + /// Sequence number + /// + public int SequenceNumber; + } + } + + /// + /// NativeConcurrentQueue padded head and tail + /// + [StructLayout(LayoutKind.Explicit, Size = 3 * CACHE_LINE_SIZE)] + internal struct NativeConcurrentQueuePaddedHeadAndTailNotArm64 + { + /// + /// Head + /// + [FieldOffset(1 * CACHE_LINE_SIZE)] public int Head; + + /// + /// Tail + /// + [FieldOffset(2 * CACHE_LINE_SIZE)] public int Tail; + + /// + /// Catch line size + /// + public const int CACHE_LINE_SIZE = 64; + } + + /// + /// Native concurrentQueue + /// (Slower than ConcurrentQueue, disable Enumerator, try peek either) + /// + /// Type + [StructLayout(LayoutKind.Sequential)] + internal unsafe struct NativeConcurrentQueueArm64 : IDisposable where T : unmanaged + { + /// + /// Cross segment lock + /// + private NativeMonitorLock _crossSegmentLock; + + /// + /// Segment pool + /// + private NativeMemoryPool _segmentPool; + + /// + /// Tail + /// + private volatile NativeConcurrentQueueSegmentArm64* _tail; + + /// + /// Head + /// + private volatile NativeConcurrentQueueSegmentArm64* _head; + + /// + /// IsEmpty + /// + public bool IsEmpty + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get + { + var segment = _head; + while (true) + { + var next = Volatile.Read(ref segment->NextSegment); + if (segment->TryPeek()) + return false; + if (next != IntPtr.Zero) + segment = (NativeConcurrentQueueSegmentArm64*)next; + else if (Volatile.Read(ref segment->NextSegment) == IntPtr.Zero) + break; + } + + return true; + } + } + + /// + /// Count + /// + public int Count + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get + { + var spinCount = 0; + while (true) + { + var head = _head; + var tail = _tail; + var headHead = Volatile.Read(ref head->HeadAndTail.Head); + var headTail = Volatile.Read(ref head->HeadAndTail.Tail); + if (head == tail) + { + if (head == _head && tail == _tail && headHead == Volatile.Read(ref head->HeadAndTail.Head) && headTail == Volatile.Read(ref head->HeadAndTail.Tail)) + return GetCount(head, headHead, headTail); + } + else if ((NativeConcurrentQueueSegmentArm64*)head->NextSegment == tail) + { + var tailHead = Volatile.Read(ref tail->HeadAndTail.Head); + var tailTail = Volatile.Read(ref tail->HeadAndTail.Tail); + if (head == _head && tail == _tail && headHead == Volatile.Read(ref head->HeadAndTail.Head) && headTail == Volatile.Read(ref head->HeadAndTail.Tail) && tailHead == Volatile.Read(ref tail->HeadAndTail.Head) && tailTail == Volatile.Read(ref tail->HeadAndTail.Tail)) + return GetCount(head, headHead, headTail) + GetCount(tail, tailHead, tailTail); + } + else + { + _crossSegmentLock.Enter(); + try + { + if (head == _head && tail == _tail) + { + var tailHead = Volatile.Read(ref tail->HeadAndTail.Head); + var tailTail = Volatile.Read(ref tail->HeadAndTail.Tail); + if (headHead == Volatile.Read(ref head->HeadAndTail.Head) && headTail == Volatile.Read(ref head->HeadAndTail.Tail) && tailHead == Volatile.Read(ref tail->HeadAndTail.Head) && tailTail == Volatile.Read(ref tail->HeadAndTail.Tail)) + { + var count = GetCount(head, headHead, headTail) + GetCount(tail, tailHead, tailTail); + for (var s = (NativeConcurrentQueueSegmentArm64*)head->NextSegment; s != tail; s = (NativeConcurrentQueueSegmentArm64*)s->NextSegment) + count += s->HeadAndTail.Tail - NativeConcurrentQueueSegmentArm64.FREEZE_OFFSET; + return count; + } + } + } + finally + { + _crossSegmentLock.Exit(); + } + } + + if ((spinCount >= 10 && (spinCount - 10) % 2 == 0) || Environment.ProcessorCount == 1) + { + var yieldsSoFar = spinCount >= 10 ? (spinCount - 10) / 2 : spinCount; + if (yieldsSoFar % 5 == 4) + Thread.Sleep(0); + else + Thread.Yield(); + } + else + { + var iterations = Environment.ProcessorCount / 2; + if (spinCount <= 30 && 1 << spinCount < iterations) + iterations = 1 << spinCount; + Thread.SpinWait(iterations); + } + + spinCount = spinCount == int.MaxValue ? 10 : spinCount + 1; + } + } + } + + /// + /// Structure + /// + /// Segment pool + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Initialize(NativeMemoryPool segmentPool) + { + _crossSegmentLock = new NativeMonitorLock(new object()); + _segmentPool = segmentPool; + var segment = (NativeConcurrentQueueSegmentArm64*)_segmentPool.Rent(); + var array = (byte*)segment + sizeof(NativeConcurrentQueueSegmentArm64); + segment->Initialize((NativeConcurrentQueueSegmentArm64.Slot*)array); + _tail = _head = segment; + } + + /// + /// Dispose + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Dispose() + { + _crossSegmentLock.Dispose(); + _segmentPool.Dispose(); + } + + /// + /// Clear + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Clear() + { + _crossSegmentLock.Enter(); + try + { + _tail->EnsureFrozenForEnqueues(); + var node = _head; + while (node != null) + { + var temp = node; + node = (NativeConcurrentQueueSegmentArm64*)node->NextSegment; + _segmentPool.Return(temp); + } + + var segment = (NativeConcurrentQueueSegmentArm64*)_segmentPool.Rent(); + var array = (byte*)segment + sizeof(NativeConcurrentQueueSegmentArm64); + segment->Initialize((NativeConcurrentQueueSegmentArm64.Slot*)array); + _tail = _head = segment; + } + finally + { + _crossSegmentLock.Exit(); + } + } + + /// + /// Enqueue + /// + /// Item + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Enqueue(in T item) + { + if (!_tail->TryEnqueue(item)) + { + while (true) + { + var tail = _tail; + if (tail->TryEnqueue(item)) + return; + _crossSegmentLock.Enter(); + try + { + if (tail == _tail) + { + tail->EnsureFrozenForEnqueues(); + var newTail = (NativeConcurrentQueueSegmentArm64*)_segmentPool.Rent(); + var array = (byte*)newTail + sizeof(NativeConcurrentQueueSegmentArm64); + newTail->Initialize((NativeConcurrentQueueSegmentArm64.Slot*)array); + tail->NextSegment = (nint)newTail; + _tail = newTail; + } + } + finally + { + _crossSegmentLock.Exit(); + } + } + } + } + + /// + /// Try dequeue + /// + /// Item + /// Dequeued + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool TryDequeue(out T result) + { + var head = _head; + if (head->TryDequeue(out result)) + return true; + if (head->NextSegment == IntPtr.Zero) + { + result = default; + return false; + } + + while (true) + { + head = _head; + if (head->TryDequeue(out result)) + return true; + if (head->NextSegment == IntPtr.Zero) + { + result = default; + return false; + } + + if (head->TryDequeue(out result)) + return true; + _crossSegmentLock.Enter(); + try + { + if (head == _head) + { + _head = (NativeConcurrentQueueSegmentArm64*)head->NextSegment; + _segmentPool.Return(head); + } + } + finally + { + _crossSegmentLock.Exit(); + } + } + } + + /// + /// Get count + /// + /// Segment + /// Head + /// Tail + /// Count + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static int GetCount(NativeConcurrentQueueSegmentArm64* segment, int head, int tail) + { + if (head != tail && head != tail - NativeConcurrentQueueSegmentArm64.FREEZE_OFFSET) + { + head &= NativeConcurrentQueueSegmentArm64.SLOTS_MASK; + tail &= NativeConcurrentQueueSegmentArm64.SLOTS_MASK; + return head < tail ? tail - head : NativeConcurrentQueueSegmentArm64.LENGTH - head + tail; + } + + return 0; + } + + /// + /// Get count + /// + /// Head + /// Head head + /// Tail + /// Tail tail + /// Count + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static long GetCount(NativeConcurrentQueueSegmentArm64* head, int headHead, NativeConcurrentQueueSegmentArm64* tail, int tailTail) + { + long count = 0; + var headTail = (head == tail ? tailTail : Volatile.Read(ref head->HeadAndTail.Tail)) - NativeConcurrentQueueSegmentArm64.FREEZE_OFFSET; + if (headHead < headTail) + { + headHead &= NativeConcurrentQueueSegmentArm64.SLOTS_MASK; + headTail &= NativeConcurrentQueueSegmentArm64.SLOTS_MASK; + count += headHead < headTail ? headTail - headHead : NativeConcurrentQueueSegmentArm64.LENGTH - headHead + headTail; + } + + if (head != tail) + { + for (var s = (NativeConcurrentQueueSegmentArm64*)head->NextSegment; s != tail; s = (NativeConcurrentQueueSegmentArm64*)s->NextSegment) + count += s->HeadAndTail.Tail - NativeConcurrentQueueSegmentArm64.FREEZE_OFFSET; + count += tailTail - NativeConcurrentQueueSegmentArm64.FREEZE_OFFSET; + } + + return count; + } + } + + /// + /// Native concurrentQueue segment + /// + /// Type + [StructLayout(LayoutKind.Sequential)] + internal unsafe struct NativeConcurrentQueueSegmentArm64 where T : unmanaged + { + /// + /// Slots + /// + public Slot* Slots; + + /// + /// Length + /// + public const int LENGTH = 1024; + + /// + /// Slots mask + /// + public const int SLOTS_MASK = LENGTH - 1; + + /// + /// Head and tail + /// + public NativeConcurrentQueuePaddedHeadAndTailArm64 HeadAndTail; + + /// + /// Frozen for enqueues + /// + public bool FrozenForEnqueues; + + /// + /// Next segment + /// + public nint NextSegment; + + /// + /// Initialize + /// + /// Slots + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Initialize(Slot* slots) + { + Slots = slots; + for (var i = 0; i < LENGTH; ++i) + Slots[i].SequenceNumber = i; + HeadAndTail = new NativeConcurrentQueuePaddedHeadAndTailArm64(); + FrozenForEnqueues = false; + NextSegment = IntPtr.Zero; + } + + /// + /// Freeze offset + /// + public const int FREEZE_OFFSET = LENGTH * 2; + + /// + /// Ensure frozen for enqueues + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void EnsureFrozenForEnqueues() + { + if (!FrozenForEnqueues) + { + FrozenForEnqueues = true; + Interlocked.Add(ref HeadAndTail.Tail, FREEZE_OFFSET); + } + } + + /// + /// Try dequeue + /// + /// Item + /// Dequeued + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool TryDequeue(out T result) + { + var slots = Slots; + var count = 0; + while (true) + { + var currentHead = Volatile.Read(ref HeadAndTail.Head); + var slotsIndex = currentHead & SLOTS_MASK; + var sequenceNumber = Volatile.Read(ref slots[slotsIndex].SequenceNumber); + var diff = sequenceNumber - (currentHead + 1); + if (diff == 0) + { + if (Interlocked.CompareExchange(ref HeadAndTail.Head, currentHead + 1, currentHead) == currentHead) + { + result = slots[slotsIndex].Item; + Volatile.Write(ref slots[slotsIndex].SequenceNumber, currentHead + LENGTH); + return true; + } + } + else if (diff < 0) + { + var frozen = FrozenForEnqueues; + var currentTail = Volatile.Read(ref HeadAndTail.Tail); + if (currentTail - currentHead <= 0 || (frozen && currentTail - FREEZE_OFFSET - currentHead <= 0)) + { + result = default; + return false; + } + + if ((count >= 10 && (count - 10) % 2 == 0) || Environment.ProcessorCount == 1) + { + var yieldsSoFar = count >= 10 ? (count - 10) / 2 : count; + if (yieldsSoFar % 5 == 4) + Thread.Sleep(0); + else + Thread.Yield(); + } + else + { + var iterations = Environment.ProcessorCount / 2; + if (count <= 30 && 1 << count < iterations) + iterations = 1 << count; + Thread.SpinWait(iterations); + } + + count = count == int.MaxValue ? 10 : count + 1; + } + } + } + + /// + /// Try peek + /// + /// Peeked + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool TryPeek() + { + var slots = Slots; + var count = 0; + while (true) + { + var currentHead = Volatile.Read(ref HeadAndTail.Head); + var slotsIndex = currentHead & SLOTS_MASK; + var sequenceNumber = Volatile.Read(ref slots[slotsIndex].SequenceNumber); + var diff = sequenceNumber - (currentHead + 1); + if (diff == 0) + return true; + if (diff < 0) + { + var frozen = FrozenForEnqueues; + var currentTail = Volatile.Read(ref HeadAndTail.Tail); + if (currentTail - currentHead <= 0 || (frozen && currentTail - FREEZE_OFFSET - currentHead <= 0)) + return false; + if ((count >= 10 && (count - 10) % 2 == 0) || Environment.ProcessorCount == 1) + { + var yieldsSoFar = count >= 10 ? (count - 10) / 2 : count; + if (yieldsSoFar % 5 == 4) + Thread.Sleep(0); + else + Thread.Yield(); + } + else + { + var iterations = Environment.ProcessorCount / 2; + if (count <= 30 && 1 << count < iterations) + iterations = 1 << count; + Thread.SpinWait(iterations); + } + + count = count == int.MaxValue ? 10 : count + 1; + } + } + } + + /// + /// Try enqueue + /// + /// Item + /// Enqueued + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool TryEnqueue(in T item) + { + var slots = Slots; + while (true) + { + var currentTail = Volatile.Read(ref HeadAndTail.Tail); + var slotsIndex = currentTail & SLOTS_MASK; + var sequenceNumber = Volatile.Read(ref slots[slotsIndex].SequenceNumber); + var diff = sequenceNumber - currentTail; + if (diff == 0) + { + if (Interlocked.CompareExchange(ref HeadAndTail.Tail, currentTail + 1, currentTail) == currentTail) + { + slots[slotsIndex].Item = item; + Volatile.Write(ref slots[slotsIndex].SequenceNumber, currentTail + 1); + return true; + } + } + else if (diff < 0) + { + return false; + } + } + } + + /// + /// Slot + /// + [StructLayout(LayoutKind.Sequential)] + public struct Slot + { + /// + /// Item + /// + public T Item; + + /// + /// Sequence number + /// + public int SequenceNumber; + } + } + + /// + /// NativeConcurrentQueue padded head and tail + /// + [StructLayout(LayoutKind.Explicit, Size = 3 * CACHE_LINE_SIZE)] + internal struct NativeConcurrentQueuePaddedHeadAndTailArm64 + { + /// + /// Head + /// + [FieldOffset(1 * CACHE_LINE_SIZE)] public int Head; + + /// + /// Tail + /// + [FieldOffset(2 * CACHE_LINE_SIZE)] public int Tail; + + /// + /// Catch line size + /// + public const int CACHE_LINE_SIZE = 128; + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeConcurrentSpinLock.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeConcurrentSpinLock.cs new file mode 100644 index 0000000..a42b93d --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeConcurrentSpinLock.cs @@ -0,0 +1,180 @@ +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +#if UNITY_2021_3_OR_NEWER || GODOT +using System; +using System.Threading; +#endif + +#pragma warning disable CA2208 +#pragma warning disable CS8632 + +// ReSharper disable ALL + +namespace NativeCollections +{ + /// + /// Native concurrent spinLock + /// + [StructLayout(LayoutKind.Sequential)] + public readonly unsafe struct NativeConcurrentSpinLock : IDisposable, IEquatable + { + /// + /// Handle + /// + [StructLayout(LayoutKind.Sequential)] + private struct NativeConcurrentSpinLockHandle + { + /// + /// Sequence number + /// + public int SequenceNumber; + + /// + /// Next sequence number + /// + public int NextSequenceNumber; + + /// + /// Sleep threshold + /// + public int SleepThreshold; + } + + /// + /// Handle + /// + private readonly NativeConcurrentSpinLockHandle* _handle; + + /// + /// Structure + /// + /// Sleep threshold + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public NativeConcurrentSpinLock(int sleepThreshold) + { + if (sleepThreshold < -1) + sleepThreshold = -1; + else if (sleepThreshold >= 0 && sleepThreshold < 10) + sleepThreshold = 10; + _handle = (NativeConcurrentSpinLockHandle*)NativeMemoryAllocator.Alloc((uint)sizeof(NativeConcurrentSpinLockHandle)); + _handle->SequenceNumber = 0; + _handle->NextSequenceNumber = 1; + _handle->SleepThreshold = sleepThreshold; + } + + /// + /// Is created + /// + public bool IsCreated => _handle != null; + + /// + /// Sleep threshold + /// + public int SleepThreshold => _handle->SleepThreshold; + + /// + /// Equals + /// + /// Other + /// Equals + public bool Equals(NativeConcurrentSpinLock other) => other == this; + + /// + /// Equals + /// + /// object + /// Equals + public override bool Equals(object? obj) => obj is NativeConcurrentSpinLock nativeConcurrentSpinLock && nativeConcurrentSpinLock == this; + + /// + /// Get hashCode + /// + /// HashCode + public override int GetHashCode() => (int)(nint)_handle; + + /// + /// To string + /// + /// String + public override string ToString() => "NativeConcurrentSpinLock"; + + /// + /// Equals + /// + /// Left + /// Right + /// Equals + public static bool operator ==(NativeConcurrentSpinLock left, NativeConcurrentSpinLock right) => left._handle == right._handle; + + /// + /// Not equals + /// + /// Left + /// Right + /// Not equals + public static bool operator !=(NativeConcurrentSpinLock left, NativeConcurrentSpinLock right) => left._handle != right._handle; + + /// + /// Dispose + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Dispose() + { + if (_handle == null) + return; + NativeMemoryAllocator.Free(_handle); + } + + /// + /// Enter + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Enter() + { + var sequenceNumber = Interlocked.Add(ref _handle->SequenceNumber, 1); + if (sequenceNumber != _handle->NextSequenceNumber) + { + var count = 0; + var sleepThreshold = _handle->SleepThreshold; + do + { + if ((count >= 10 && ((count >= sleepThreshold && sleepThreshold >= 0) || (count - 10) % 2 == 0)) || Environment.ProcessorCount == 1) + { + if (count >= sleepThreshold && sleepThreshold >= 0) + { + Thread.Sleep(1); + } + else + { + var yieldsSoFar = count >= 10 ? (count - 10) / 2 : count; + if (yieldsSoFar % 5 == 4) + Thread.Sleep(0); + else + Thread.Yield(); + } + } + else + { + var iterations = Environment.ProcessorCount / 2; + if (count <= 30 && 1 << count < iterations) + iterations = 1 << count; + Thread.SpinWait(iterations); + } + + count = count == int.MaxValue ? 10 : count + 1; + } while (sequenceNumber != _handle->NextSequenceNumber); + } + } + + /// + /// Exit + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Exit() => Interlocked.Add(ref _handle->NextSequenceNumber, 1); + + /// + /// Empty + /// + public static NativeConcurrentSpinLock Empty => new(); + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeConcurrentStack.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeConcurrentStack.cs new file mode 100644 index 0000000..8f98177 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeConcurrentStack.cs @@ -0,0 +1,338 @@ +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +#if !NET6_0_OR_GREATER +using System.Security.Cryptography; +#endif + +#if UNITY_2021_3_OR_NEWER || GODOT +using System; +using System.Threading; +#endif + +#pragma warning disable CA2208 +#pragma warning disable CS8632 + +// ReSharper disable ALL + +namespace NativeCollections +{ + /// + /// Native concurrentStack + /// (Slower than ConcurrentStack, disable Enumerator, try peek, push/pop range either) + /// + /// Type + [StructLayout(LayoutKind.Sequential)] + public readonly unsafe struct NativeConcurrentStack : IDisposable, IEquatable> where T : unmanaged + { + /// + /// Handle + /// + [StructLayout(LayoutKind.Sequential)] + private struct NativeConcurrentStackHandle + { + /// + /// Head + /// + public volatile nint Head; + + /// + /// Node pool + /// + public NativeMemoryPool NodePool; + + /// + /// Node pool lock + /// + public NativeConcurrentSpinLock NodePoolLock; + } + + /// + /// Handle + /// + private readonly NativeConcurrentStackHandle* _handle; + + /// + /// Structure + /// + /// Size + /// Max free slabs + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public NativeConcurrentStack(int size, int maxFreeSlabs) + { + var nodePool = new NativeMemoryPool(size, sizeof(Node), maxFreeSlabs); + _handle = (NativeConcurrentStackHandle*)NativeMemoryAllocator.Alloc((uint)sizeof(NativeConcurrentStackHandle)); + _handle->Head = IntPtr.Zero; + _handle->NodePool = nodePool; + _handle->NodePoolLock = new NativeConcurrentSpinLock(-1); + } + + /// + /// Is created + /// + public bool IsCreated => _handle != null; + + /// + /// IsEmpty + /// + public bool IsEmpty => _handle->Head == IntPtr.Zero; + + /// + /// Count + /// + public int Count + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get + { + var count = 0; + for (var node = (Node*)_handle->Head; node != null; node = node->Next) + count++; + return count; + } + } + + /// + /// Equals + /// + /// Other + /// Equals + public bool Equals(NativeConcurrentStack other) => other == this; + + /// + /// Equals + /// + /// object + /// Equals + public override bool Equals(object? obj) => obj is NativeConcurrentStack nativeConcurrentStack && nativeConcurrentStack == this; + + /// + /// Get hashCode + /// + /// HashCode + public override int GetHashCode() => (int)(nint)_handle; + + /// + /// To string + /// + /// String + public override string ToString() => $"NativeConcurrentStack<{typeof(T).Name}>"; + + /// + /// Equals + /// + /// Left + /// Right + /// Equals + public static bool operator ==(NativeConcurrentStack left, NativeConcurrentStack right) => left._handle == right._handle; + + /// + /// Not equals + /// + /// Left + /// Right + /// Not equals + public static bool operator !=(NativeConcurrentStack left, NativeConcurrentStack right) => left._handle != right._handle; + + /// + /// Dispose + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Dispose() + { + if (_handle == null) + return; + _handle->NodePool.Dispose(); + _handle->NodePoolLock.Dispose(); + NativeMemoryAllocator.Free(_handle); + } + + /// + /// Clear + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Clear() + { + _handle->NodePoolLock.Enter(); + try + { + var node = (Node*)_handle->Head; + while (node != null) + { + var temp = node; + node = node->Next; + _handle->NodePool.Return(temp); + } + } + finally + { + _handle->NodePoolLock.Exit(); + } + } + + /// + /// Push + /// + /// Item + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Push(in T item) + { + Node* newNode; + _handle->NodePoolLock.Enter(); + try + { + newNode = (Node*)_handle->NodePool.Rent(); + } + finally + { + _handle->NodePoolLock.Exit(); + } + + newNode->Value = item; + newNode->Next = (Node*)_handle->Head; + if (Interlocked.CompareExchange(ref _handle->Head, (nint)newNode, (nint)newNode->Next) == (nint)newNode->Next) + return; + var count = 0; + do + { + if ((count >= 10 && (count - 10) % 2 == 0) || Environment.ProcessorCount == 1) + { + var yieldsSoFar = count >= 10 ? (count - 10) / 2 : count; + if (yieldsSoFar % 5 == 4) + Thread.Sleep(0); + else + Thread.Yield(); + } + else + { + var iterations = Environment.ProcessorCount / 2; + if (count <= 30 && 1 << count < iterations) + iterations = 1 << count; + Thread.SpinWait(iterations); + } + + count = count == int.MaxValue ? 10 : count + 1; + newNode->Next = (Node*)_handle->Head; + } while (Interlocked.CompareExchange(ref _handle->Head, (nint)newNode, (nint)newNode->Next) != (nint)newNode->Next); + } + + /// + /// Try pop + /// + /// Item + /// Popped + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool TryPop(out T result) + { + var head = (Node*)_handle->Head; + if (head == null) + { + result = default; + return false; + } + + if (Interlocked.CompareExchange(ref _handle->Head, (nint)head->Next, (nint)head) == (nint)head) + { + result = head->Value; + _handle->NodePoolLock.Enter(); + try + { + _handle->NodePool.Return(head); + } + finally + { + _handle->NodePoolLock.Exit(); + } + + return true; + } + + var count = 0; + var backoff = 1; +#if !NET6_0_OR_GREATER + Span random = stackalloc byte[1]; +#endif + while (true) + { + head = (Node*)_handle->Head; + if (head == null) + { + result = default; + return false; + } + + if (Interlocked.CompareExchange(ref _handle->Head, (nint)head->Next, (nint)head) == (nint)head) + { + result = head->Value; + _handle->NodePoolLock.Enter(); + try + { + _handle->NodePool.Return(head); + } + finally + { + _handle->NodePoolLock.Exit(); + } + + return true; + } + + for (var i = 0; i < backoff; ++i) + { + if ((count >= 10 && (count - 10) % 2 == 0) || Environment.ProcessorCount == 1) + { + var yieldsSoFar = count >= 10 ? (count - 10) / 2 : count; + if (yieldsSoFar % 5 == 4) + Thread.Sleep(0); + else + Thread.Yield(); + } + else + { + var iterations = Environment.ProcessorCount / 2; + if (count <= 30 && 1 << count < iterations) + iterations = 1 << count; + Thread.SpinWait(iterations); + } + + count = count == int.MaxValue ? 10 : count + 1; + } + + if (count >= 10 || Environment.ProcessorCount == 1) + { +#if NET6_0_OR_GREATER + backoff = Random.Shared.Next(1, 8); +#else + RandomNumberGenerator.Fill(random); + backoff = random[0] % 7 + 1; +#endif + } + else + { + backoff *= 2; + } + } + } + + /// + /// Empty + /// + public static NativeConcurrentStack Empty => new(); + + /// + /// Node + /// + [StructLayout(LayoutKind.Sequential)] + private struct Node + { + /// + /// Value + /// + public T Value; + + /// + /// Next + /// + public Node* Next; + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeDictionary.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeDictionary.cs new file mode 100644 index 0000000..173a9fb --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeDictionary.cs @@ -0,0 +1,971 @@ +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +#if UNITY_2021_3_OR_NEWER || GODOT +using System; +using System.Collections.Generic; +#endif + +#pragma warning disable CA2208 +#pragma warning disable CS8632 + +// ReSharper disable ALL + +namespace NativeCollections +{ + /// + /// Native dictionary + /// + /// Type + /// Type + [StructLayout(LayoutKind.Sequential)] + public readonly unsafe struct NativeDictionary : IDisposable, IEquatable> where TKey : unmanaged, IEquatable where TValue : unmanaged + { + /// + /// Handle + /// + [StructLayout(LayoutKind.Sequential)] + private struct NativeDictionaryHandle + { + /// + /// Buckets + /// + public int* Buckets; + + /// + /// Entries + /// + public Entry* Entries; + + /// + /// BucketsLength + /// + public int BucketsLength; + + /// + /// EntriesLength + /// + public int EntriesLength; + + /// + /// FastModMultiplier + /// + public ulong FastModMultiplier; + + /// + /// Count + /// + public int Count; + + /// + /// FreeList + /// + public int FreeList; + + /// + /// FreeCount + /// + public int FreeCount; + + /// + /// Version + /// + public int Version; + + /// + /// Keys + /// + public KeyCollection Keys; + + /// + /// Values + /// + public ValueCollection Values; + } + + /// + /// Handle + /// + private readonly NativeDictionaryHandle* _handle; + + /// + /// Keys + /// + public KeyCollection Keys => _handle->Keys; + + /// + /// Values + /// + public ValueCollection Values => _handle->Values; + + /// + /// Structure + /// + /// Capacity + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public NativeDictionary(int capacity) + { + if (capacity < 0) + throw new ArgumentOutOfRangeException(nameof(capacity), capacity, "MustBeNonNegative"); + if (capacity < 4) + capacity = 4; + _handle = (NativeDictionaryHandle*)NativeMemoryAllocator.Alloc((uint)sizeof(NativeDictionaryHandle)); + _handle->Count = 0; + _handle->FreeCount = 0; + _handle->Version = 0; + Initialize(capacity); + _handle->Keys = new KeyCollection(this); + _handle->Values = new ValueCollection(this); + } + + /// + /// Is created + /// + public bool IsCreated => _handle != null; + + /// + /// Is empty + /// + public bool IsEmpty => _handle->Count - _handle->FreeCount == 0; + + /// + /// Get or set value + /// + /// Key + public TValue this[in TKey key] + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get + { + ref var value = ref FindValue(key); + if (Unsafe.AsPointer(ref Unsafe.AsRef(in value)) != null) + return value; + throw new KeyNotFoundException(key.ToString()); + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + set => TryInsertOverwriteExisting(key, value); + } + + /// + /// Count + /// + public int Count => _handle->Count - _handle->FreeCount; + + /// + /// Equals + /// + /// Other + /// Equals + public bool Equals(NativeDictionary other) => other == this; + + /// + /// Equals + /// + /// object + /// Equals + public override bool Equals(object? obj) => obj is NativeDictionary nativeDictionary && nativeDictionary == this; + + /// + /// Get hashCode + /// + /// HashCode + public override int GetHashCode() => (int)(nint)_handle; + + /// + /// To string + /// + /// String + public override string ToString() => $"NativeDictionary<{typeof(TKey).Name}, {typeof(TValue).Name}>"; + + /// + /// Equals + /// + /// Left + /// Right + /// Equals + public static bool operator ==(NativeDictionary left, NativeDictionary right) => left._handle == right._handle; + + /// + /// Not equals + /// + /// Left + /// Right + /// Not equals + public static bool operator !=(NativeDictionary left, NativeDictionary right) => left._handle != right._handle; + + /// + /// Dispose + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Dispose() + { + if (_handle == null) + return; + NativeMemoryAllocator.Free(_handle->Buckets); + NativeMemoryAllocator.Free(_handle->Entries); + NativeMemoryAllocator.Free(_handle); + } + + /// + /// Clear + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Clear() + { + var count = _handle->Count; + if (count > 0) + { + Unsafe.InitBlockUnaligned(_handle->Buckets, 0, (uint)(count * sizeof(int))); + _handle->Count = 0; + _handle->FreeList = -1; + _handle->FreeCount = 0; + Unsafe.InitBlockUnaligned(_handle->Entries, 0, (uint)(count * sizeof(Entry))); + } + } + + /// + /// Add + /// + /// Key + /// Value + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Add(in TKey key, in TValue value) => TryInsertThrowOnExisting(key, value); + + /// + /// Try add + /// + /// Key + /// Value + /// Added + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool TryAdd(in TKey key, in TValue value) => TryInsertNone(key, value); + + /// + /// Remove + /// + /// Key + /// Removed + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool Remove(in TKey key) + { + uint collisionCount = 0; + var hashCode = (uint)key.GetHashCode(); + ref var bucket = ref GetBucket(hashCode); + var last = -1; + var i = bucket - 1; + while (i >= 0) + { + ref var entry = ref _handle->Entries[i]; + if (entry.HashCode == hashCode && entry.Key.Equals(key)) + { + if (last < 0) + bucket = entry.Next + 1; + else + _handle->Entries[last].Next = entry.Next; + entry.Next = -3 - _handle->FreeList; + _handle->FreeList = i; + _handle->FreeCount++; + return true; + } + + last = i; + i = entry.Next; + collisionCount++; + if (collisionCount > (uint)_handle->EntriesLength) + throw new InvalidOperationException("ConcurrentOperationsNotSupported"); + } + + return false; + } + + /// + /// Remove + /// + /// Key + /// Value + /// Removed + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool Remove(in TKey key, out TValue value) + { + uint collisionCount = 0; + var hashCode = (uint)key.GetHashCode(); + ref var bucket = ref GetBucket(hashCode); + var last = -1; + var i = bucket - 1; + while (i >= 0) + { + ref var entry = ref _handle->Entries[i]; + if (entry.HashCode == hashCode && entry.Key.Equals(key)) + { + if (last < 0) + bucket = entry.Next + 1; + else + _handle->Entries[last].Next = entry.Next; + value = entry.Value; + entry.Next = -3 - _handle->FreeList; + _handle->FreeList = i; + _handle->FreeCount++; + return true; + } + + last = i; + i = entry.Next; + collisionCount++; + if (collisionCount > (uint)_handle->EntriesLength) + throw new InvalidOperationException("ConcurrentOperationsNotSupported"); + } + + value = default; + return false; + } + + /// + /// Contains key + /// + /// Key + /// Contains key + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool ContainsKey(in TKey key) => Unsafe.AsPointer(ref Unsafe.AsRef(in FindValue(key))) != null; + + /// + /// Try to get the value + /// + /// Key + /// Value + /// Got + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool TryGetValue(in TKey key, out TValue value) + { + ref var valRef = ref FindValue(key); + if (Unsafe.AsPointer(ref Unsafe.AsRef(in valRef)) != null) + { + value = valRef; + return true; + } + + value = default; + return false; + } + + /// + /// Ensure capacity + /// + /// Capacity + /// New capacity + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public int EnsureCapacity(int capacity) + { + if (capacity < 0) + throw new ArgumentOutOfRangeException(nameof(capacity), capacity, "MustBeNonNegative"); + var currentCapacity = _handle->EntriesLength; + if (currentCapacity >= capacity) + return currentCapacity; + _handle->Version++; + var newSize = HashHelpers.GetPrime(capacity); + Resize(newSize); + return newSize; + } + + /// + /// Trim excess + /// + /// New capacity + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public int TrimExcess() => TrimExcess(Count); + + /// + /// Trim excess + /// + /// Capacity + /// New capacity + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public int TrimExcess(int capacity) + { + if (capacity < 0) + throw new ArgumentOutOfRangeException(nameof(capacity), capacity, "MustBeNonNegative"); + var newSize = HashHelpers.GetPrime(capacity); + var oldEntries = _handle->Entries; + var currentCapacity = _handle->EntriesLength; + if (newSize >= currentCapacity) + return currentCapacity; + var oldCount = _handle->Count; + _handle->Version++; + NativeMemoryAllocator.Free(_handle->Buckets); + Initialize(newSize); + var newEntries = _handle->Entries; + var newCount = 0; + for (var i = 0; i < oldCount; ++i) + { + var hashCode = oldEntries[i].HashCode; + if (oldEntries[i].Next >= -1) + { + ref var entry = ref newEntries[newCount]; + entry = oldEntries[i]; + ref var bucket = ref GetBucket(hashCode); + entry.Next = bucket - 1; + bucket = newCount + 1; + newCount++; + } + } + + NativeMemoryAllocator.Free(oldEntries); + _handle->Count = newCount; + _handle->FreeCount = 0; + return newSize; + } + + /// + /// Find value + /// + /// Key + /// Value + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private ref TValue FindValue(in TKey key) + { + var hashCode = (uint)key.GetHashCode(); + var i = GetBucket(hashCode); + uint collisionCount = 0; + i--; + do + { + if ((uint)i >= (uint)_handle->EntriesLength) + return ref Unsafe.AsRef(null); + ref var entry = ref _handle->Entries[i]; + if (entry.HashCode == hashCode && entry.Key.Equals(key)) + return ref entry.Value; + i = entry.Next; + collisionCount++; + } while (collisionCount <= (uint)_handle->EntriesLength); + + throw new InvalidOperationException("ConcurrentOperationsNotSupported"); + } + + /// + /// Initialize + /// + /// Capacity + /// New capacity + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void Initialize(int capacity) + { + var size = HashHelpers.GetPrime(capacity); + _handle->FreeList = -1; + _handle->Buckets = (int*)NativeMemoryAllocator.AllocZeroed((uint)(size * sizeof(int))); + _handle->Entries = (Entry*)NativeMemoryAllocator.AllocZeroed((uint)(size * sizeof(Entry))); + _handle->BucketsLength = size; + _handle->EntriesLength = size; + _handle->FastModMultiplier = IntPtr.Size == 8 ? HashHelpers.GetFastModMultiplier((uint)size) : 0; + } + + /// + /// Resize + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void Resize() => Resize(HashHelpers.ExpandPrime(_handle->Count)); + + /// + /// Resize + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void Resize(int newSize) + { + var entries = (Entry*)NativeMemoryAllocator.AllocZeroed((uint)(newSize * sizeof(Entry))); + var count = _handle->Count; + Unsafe.CopyBlockUnaligned(entries, _handle->Entries, (uint)(count * sizeof(Entry))); + var buckets = (int*)NativeMemoryAllocator.AllocZeroed((uint)(newSize * sizeof(int))); + NativeMemoryAllocator.Free(_handle->Buckets); + _handle->Buckets = buckets; + _handle->BucketsLength = newSize; + _handle->FastModMultiplier = IntPtr.Size == 8 ? HashHelpers.GetFastModMultiplier((uint)newSize) : 0; + for (var i = 0; i < count; ++i) + { + if (entries[i].Next >= -1) + { + ref var bucket = ref GetBucket(entries[i].HashCode); + entries[i].Next = bucket - 1; + bucket = i + 1; + } + } + + NativeMemoryAllocator.Free(_handle->Entries); + _handle->Entries = entries; + _handle->EntriesLength = newSize; + } + + /// + /// Insert + /// + /// Key + /// Value + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void TryInsertOverwriteExisting(in TKey key, in TValue value) + { + var hashCode = (uint)key.GetHashCode(); + uint collisionCount = 0; + ref var bucket = ref GetBucket(hashCode); + var i = bucket - 1; + while (true) + { + if ((uint)i >= (uint)_handle->EntriesLength) + break; + if (_handle->Entries[i].HashCode == hashCode && _handle->Entries[i].Key.Equals(key)) + { + _handle->Entries[i].Value = value; + return; + } + + i = _handle->Entries[i].Next; + collisionCount++; + if (collisionCount > (uint)_handle->EntriesLength) + throw new InvalidOperationException("ConcurrentOperationsNotSupported"); + } + + int index; + if (_handle->FreeCount > 0) + { + index = _handle->FreeList; + _handle->FreeList = -3 - _handle->Entries[_handle->FreeList].Next; + _handle->FreeCount--; + } + else + { + var count = _handle->Count; + if (count == _handle->EntriesLength) + { + Resize(); + bucket = ref GetBucket(hashCode); + } + + index = count; + _handle->Count = count + 1; + } + + ref var entry = ref _handle->Entries[index]; + entry.HashCode = hashCode; + entry.Next = bucket - 1; + entry.Key = key; + entry.Value = value; + bucket = index + 1; + _handle->Version++; + } + + /// + /// Insert + /// + /// Key + /// Value + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private bool TryInsertThrowOnExisting(in TKey key, in TValue value) + { + var hashCode = (uint)key.GetHashCode(); + uint collisionCount = 0; + ref var bucket = ref GetBucket(hashCode); + var i = bucket - 1; + while (true) + { + if ((uint)i >= (uint)_handle->EntriesLength) + break; + if (_handle->Entries[i].HashCode == hashCode && _handle->Entries[i].Key.Equals(key)) + throw new ArgumentException($"Argument_AddingDuplicateWithKey, {key}"); + i = _handle->Entries[i].Next; + collisionCount++; + if (collisionCount > (uint)_handle->EntriesLength) + throw new InvalidOperationException("ConcurrentOperationsNotSupported"); + } + + int index; + if (_handle->FreeCount > 0) + { + index = _handle->FreeList; + _handle->FreeList = -3 - _handle->Entries[_handle->FreeList].Next; + _handle->FreeCount--; + } + else + { + var count = _handle->Count; + if (count == _handle->EntriesLength) + { + Resize(); + bucket = ref GetBucket(hashCode); + } + + index = count; + _handle->Count = count + 1; + } + + ref var entry = ref _handle->Entries[index]; + entry.HashCode = hashCode; + entry.Next = bucket - 1; + entry.Key = key; + entry.Value = value; + bucket = index + 1; + _handle->Version++; + return true; + } + + /// + /// Insert + /// + /// Key + /// Value + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private bool TryInsertNone(in TKey key, in TValue value) + { + var hashCode = (uint)key.GetHashCode(); + uint collisionCount = 0; + ref var bucket = ref GetBucket(hashCode); + var i = bucket - 1; + while (true) + { + if ((uint)i >= (uint)_handle->EntriesLength) + break; + if (_handle->Entries[i].HashCode == hashCode && _handle->Entries[i].Key.Equals(key)) + return false; + i = _handle->Entries[i].Next; + collisionCount++; + if (collisionCount > (uint)_handle->EntriesLength) + throw new InvalidOperationException("ConcurrentOperationsNotSupported"); + } + + int index; + if (_handle->FreeCount > 0) + { + index = _handle->FreeList; + _handle->FreeList = -3 - _handle->Entries[_handle->FreeList].Next; + _handle->FreeCount--; + } + else + { + var count = _handle->Count; + if (count == _handle->EntriesLength) + { + Resize(); + bucket = ref GetBucket(hashCode); + } + + index = count; + _handle->Count = count + 1; + } + + ref var entry = ref _handle->Entries[index]; + entry.HashCode = hashCode; + entry.Next = bucket - 1; + entry.Key = key; + entry.Value = value; + bucket = index + 1; + _handle->Version++; + return true; + } + + /// + /// Get bucket ref + /// + /// HashCode + /// Bucket ref + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private ref int GetBucket(uint hashCode) => ref IntPtr.Size == 8 ? ref _handle->Buckets[HashHelpers.FastMod(hashCode, (uint)_handle->BucketsLength, _handle->FastModMultiplier)] : ref _handle->Buckets[hashCode % _handle->BucketsLength]; + + /// + /// Entry + /// + private struct Entry + { + /// + /// HashCode + /// + public uint HashCode; + + /// + /// Next + /// + public int Next; + + /// + /// Key + /// + public TKey Key; + + /// + /// Value + /// + public TValue Value; + } + + /// + /// Empty + /// + public static NativeDictionary Empty => new(); + + /// + /// Get enumerator + /// + /// Enumerator + public Enumerator GetEnumerator() => new(this); + + /// + /// Enumerator + /// + public struct Enumerator + { + /// + /// NativeDictionary + /// + private readonly NativeDictionary _nativeDictionary; + + /// + /// Version + /// + private readonly int _version; + + /// + /// Index + /// + private int _index; + + /// + /// Current + /// + private KeyValuePair _current; + + /// + /// Structure + /// + /// NativeDictionary + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal Enumerator(in NativeDictionary nativeDictionary) + { + _nativeDictionary = nativeDictionary; + _version = nativeDictionary._handle->Version; + _index = 0; + _current = default; + } + + /// + /// Move next + /// + /// Moved + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool MoveNext() + { + if (_version != _nativeDictionary._handle->Version) + throw new InvalidOperationException("EnumFailedVersion"); + while ((uint)_index < (uint)_nativeDictionary._handle->Count) + { + ref var entry = ref _nativeDictionary._handle->Entries[_index++]; + if (entry.Next >= -1) + { + _current = new KeyValuePair(entry.Key, entry.Value); + return true; + } + } + + _index = _nativeDictionary._handle->Count + 1; + _current = default; + return false; + } + + /// + /// Current + /// + public KeyValuePair Current + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _current; + } + } + + /// + /// Key collection + /// + [StructLayout(LayoutKind.Sequential)] + public readonly struct KeyCollection + { + /// + /// NativeDictionary + /// + private readonly NativeDictionary _nativeDictionary; + + /// + /// Structure + /// + /// NativeDictionary + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal KeyCollection(in NativeDictionary nativeDictionary) => _nativeDictionary = nativeDictionary; + + /// + /// Get enumerator + /// + /// Enumerator + public Enumerator GetEnumerator() => new(_nativeDictionary); + + /// + /// Enumerator + /// + public struct Enumerator + { + /// + /// NativeDictionary + /// + private readonly NativeDictionary _nativeDictionary; + + /// + /// Index + /// + private int _index; + + /// + /// Version + /// + private readonly int _version; + + /// + /// Current + /// + private TKey _currentKey; + + /// + /// Structure + /// + /// NativeDictionary + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal Enumerator(in NativeDictionary nativeDictionary) + { + _nativeDictionary = nativeDictionary; + _version = nativeDictionary._handle->Version; + _index = 0; + _currentKey = default; + } + + /// + /// Move next + /// + /// Moved + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool MoveNext() + { + if (_version != _nativeDictionary._handle->Version) + throw new InvalidOperationException("EnumFailedVersion"); + while ((uint)_index < (uint)_nativeDictionary._handle->Count) + { + ref var entry = ref _nativeDictionary._handle->Entries[_index++]; + if (entry.Next >= -1) + { + _currentKey = entry.Key; + return true; + } + } + + _index = _nativeDictionary._handle->Count + 1; + _currentKey = default; + return false; + } + + /// + /// Current + /// + public TKey Current + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _currentKey; + } + } + } + + /// + /// Value collection + /// + [StructLayout(LayoutKind.Sequential)] + public readonly struct ValueCollection + { + /// + /// NativeDictionary + /// + private readonly NativeDictionary _nativeDictionary; + + /// + /// Structure + /// + /// NativeDictionary + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal ValueCollection(in NativeDictionary nativeDictionary) => _nativeDictionary = nativeDictionary; + + /// + /// Get enumerator + /// + /// Enumerator + public Enumerator GetEnumerator() => new(_nativeDictionary); + + /// + /// Enumerator + /// + public struct Enumerator + { + /// + /// NativeDictionary + /// + private readonly NativeDictionary _nativeDictionary; + + /// + /// Index + /// + private int _index; + + /// + /// Version + /// + private readonly int _version; + + /// + /// Current + /// + private TValue _currentValue; + + /// + /// Structure + /// + /// NativeDictionary + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal Enumerator(in NativeDictionary nativeDictionary) + { + _nativeDictionary = nativeDictionary; + _version = nativeDictionary._handle->Version; + _index = 0; + _currentValue = default; + } + + /// + /// Move next + /// + /// Moved + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool MoveNext() + { + if (_version != _nativeDictionary._handle->Version) + throw new InvalidOperationException("EnumFailedVersion"); + while ((uint)_index < (uint)_nativeDictionary._handle->Count) + { + ref var entry = ref _nativeDictionary._handle->Entries[_index++]; + if (entry.Next >= -1) + { + _currentValue = entry.Value; + return true; + } + } + + _index = _nativeDictionary._handle->Count + 1; + _currentValue = default; + return false; + } + + /// + /// Current + /// + public TValue Current + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _currentValue; + } + } + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeHashSet.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeHashSet.cs new file mode 100644 index 0000000..c886df6 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeHashSet.cs @@ -0,0 +1,550 @@ +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +#if UNITY_2021_3_OR_NEWER || GODOT +using System; +#endif + +#pragma warning disable CA2208 +#pragma warning disable CS8632 + +// ReSharper disable ALL + +namespace NativeCollections +{ + /// + /// Native hashSet + /// + /// Type + [StructLayout(LayoutKind.Sequential)] + public readonly unsafe struct NativeHashSet : IDisposable, IEquatable> where T : unmanaged, IEquatable + { + /// + /// Handle + /// + [StructLayout(LayoutKind.Sequential)] + private struct NativeHashSetHandle + { + /// + /// Buckets + /// + public int* Buckets; + + /// + /// Entries + /// + public Entry* Entries; + + /// + /// BucketsLength + /// + public int BucketsLength; + + /// + /// EntriesLength + /// + public int EntriesLength; + + /// + /// FastModMultiplier + /// + public ulong FastModMultiplier; + + /// + /// Count + /// + public int Count; + + /// + /// FreeList + /// + public int FreeList; + + /// + /// FreeCount + /// + public int FreeCount; + + /// + /// Version + /// + public int Version; + } + + /// + /// Handle + /// + private readonly NativeHashSetHandle* _handle; + + /// + /// Structure + /// + /// Capacity + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public NativeHashSet(int capacity) + { + if (capacity < 0) + throw new ArgumentOutOfRangeException(nameof(capacity), capacity, "MustBeNonNegative"); + if (capacity < 4) + capacity = 4; + _handle = (NativeHashSetHandle*)NativeMemoryAllocator.Alloc((uint)sizeof(NativeHashSetHandle)); + _handle->Count = 0; + _handle->FreeCount = 0; + _handle->Version = 0; + Initialize(capacity); + } + + /// + /// Is created + /// + public bool IsCreated => _handle != null; + + /// + /// Is empty + /// + public bool IsEmpty => _handle->Count - _handle->FreeCount == 0; + + /// + /// Count + /// + public int Count => _handle->Count - _handle->FreeCount; + + /// + /// Equals + /// + /// Other + /// Equals + public bool Equals(NativeHashSet other) => other == this; + + /// + /// Equals + /// + /// object + /// Equals + public override bool Equals(object? obj) => obj is NativeHashSet nativeHashSet && nativeHashSet == this; + + /// + /// Get hashCode + /// + /// HashCode + public override int GetHashCode() => (int)(nint)_handle; + + /// + /// To string + /// + /// String + public override string ToString() => $"NativeHashSet<{typeof(T).Name}>"; + + /// + /// Equals + /// + /// Left + /// Right + /// Equals + public static bool operator ==(NativeHashSet left, NativeHashSet right) => left._handle == right._handle; + + /// + /// Not equals + /// + /// Left + /// Right + /// Not equals + public static bool operator !=(NativeHashSet left, NativeHashSet right) => left._handle != right._handle; + + /// + /// Dispose + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Dispose() + { + if (_handle == null) + return; + NativeMemoryAllocator.Free(_handle->Buckets); + NativeMemoryAllocator.Free(_handle->Entries); + NativeMemoryAllocator.Free(_handle); + } + + /// + /// Clear + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Clear() + { + var count = _handle->Count; + if (count > 0) + { + Unsafe.InitBlockUnaligned(_handle->Buckets, 0, (uint)(_handle->BucketsLength * sizeof(int))); + _handle->Count = 0; + _handle->FreeList = -1; + _handle->FreeCount = 0; + Unsafe.InitBlockUnaligned(_handle->Entries, 0, (uint)(count * sizeof(Entry))); + } + } + + /// + /// Add + /// + /// Item + /// Added + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool Add(in T item) + { + uint collisionCount = 0; + var hashCode = item.GetHashCode(); + ref var bucket = ref GetBucketRef(hashCode); + var i = bucket - 1; + while (i >= 0) + { + ref var entry = ref _handle->Entries[i]; + if (entry.HashCode == hashCode && entry.Value.Equals(item)) + return false; + i = entry.Next; + collisionCount++; + if (collisionCount > (uint)_handle->EntriesLength) + throw new InvalidOperationException("ConcurrentOperationsNotSupported"); + } + + int index; + if (_handle->FreeCount > 0) + { + index = _handle->FreeList; + _handle->FreeCount--; + _handle->FreeList = -3 - _handle->Entries[_handle->FreeList].Next; + } + else + { + var count = _handle->Count; + if (count == _handle->EntriesLength) + { + Resize(); + bucket = ref GetBucketRef(hashCode); + } + + index = count; + _handle->Count = count + 1; + } + + ref var newEntry = ref _handle->Entries[index]; + newEntry.HashCode = hashCode; + newEntry.Next = bucket - 1; + newEntry.Value = item; + bucket = index + 1; + _handle->Version++; + return true; + } + + /// + /// Remove + /// + /// Item + /// Removed + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool Remove(in T item) + { + uint collisionCount = 0; + var last = -1; + var hashCode = item.GetHashCode(); + ref var bucket = ref GetBucketRef(hashCode); + var i = bucket - 1; + while (i >= 0) + { + ref var entry = ref _handle->Entries[i]; + if (entry.HashCode == hashCode && entry.Value.Equals(item)) + { + if (last < 0) + bucket = entry.Next + 1; + else + _handle->Entries[last].Next = entry.Next; + entry.Next = -3 - _handle->FreeList; + _handle->FreeList = i; + _handle->FreeCount++; + return true; + } + + last = i; + i = entry.Next; + collisionCount++; + if (collisionCount > (uint)_handle->EntriesLength) + throw new InvalidOperationException("ConcurrentOperationsNotSupported"); + } + + return false; + } + + /// + /// Contains + /// + /// Item + /// Contains + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool Contains(in T item) => FindItemIndex(item) >= 0; + + /// + /// Try to get the actual value + /// + /// Equal value + /// Actual value + /// Got + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool TryGetValue(in T equalValue, out T actualValue) + { + var index = FindItemIndex(equalValue); + if (index >= 0) + { + actualValue = _handle->Entries[index].Value; + return true; + } + + actualValue = default; + return false; + } + + /// + /// Ensure capacity + /// + /// Capacity + /// New capacity + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public int EnsureCapacity(int capacity) + { + if (capacity < 0) + throw new ArgumentOutOfRangeException(nameof(capacity), capacity, "MustBeNonNegative"); + var currentCapacity = _handle->EntriesLength; + if (currentCapacity >= capacity) + return currentCapacity; + var newSize = HashHelpers.GetPrime(capacity); + Resize(newSize); + return newSize; + } + + /// + /// Trim excess + /// + /// New capacity + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public int TrimExcess() + { + var capacity = _handle->Count - _handle->FreeCount; + var newSize = HashHelpers.GetPrime(capacity); + var oldEntries = _handle->Entries; + var currentCapacity = _handle->EntriesLength; + if (newSize >= currentCapacity) + return currentCapacity; + var oldCount = _handle->Count; + _handle->Version++; + NativeMemoryAllocator.Free(_handle->Buckets); + Initialize(newSize); + var newEntries = _handle->Entries; + var count = 0; + for (var i = 0; i < oldCount; ++i) + { + var hashCode = oldEntries[i].HashCode; + if (oldEntries[i].Next >= -1) + { + ref var entry = ref newEntries[count]; + entry = oldEntries[i]; + ref var bucket = ref GetBucketRef(hashCode); + entry.Next = bucket - 1; + bucket = count + 1; + count++; + } + } + + NativeMemoryAllocator.Free(oldEntries); + _handle->Count = capacity; + _handle->FreeCount = 0; + return newSize; + } + + /// + /// Initialize + /// + /// Capacity + /// New capacity + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private int Initialize(int capacity) + { + var size = HashHelpers.GetPrime(capacity); + _handle->FreeList = -1; + _handle->Buckets = (int*)NativeMemoryAllocator.AllocZeroed((uint)(size * sizeof(int))); + _handle->Entries = (Entry*)NativeMemoryAllocator.AllocZeroed((uint)(size * sizeof(Entry))); + _handle->BucketsLength = size; + _handle->EntriesLength = size; + _handle->FastModMultiplier = IntPtr.Size == 8 ? HashHelpers.GetFastModMultiplier((uint)size) : 0; + return size; + } + + /// + /// Resize + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void Resize() => Resize(HashHelpers.ExpandPrime(_handle->Count)); + + /// + /// Resize + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void Resize(int newSize) + { + var entries = (Entry*)NativeMemoryAllocator.AllocZeroed((uint)(newSize * sizeof(Entry))); + var count = _handle->Count; + Unsafe.CopyBlockUnaligned(entries, _handle->Entries, (uint)(_handle->EntriesLength * sizeof(Entry))); + var buckets = (int*)NativeMemoryAllocator.AllocZeroed((uint)(newSize * sizeof(int))); + NativeMemoryAllocator.Free(_handle->Buckets); + _handle->Buckets = buckets; + _handle->BucketsLength = newSize; + _handle->FastModMultiplier = IntPtr.Size == 8 ? HashHelpers.GetFastModMultiplier((uint)newSize) : 0; + for (var i = 0; i < count; ++i) + { + ref var entry = ref entries[i]; + if (entry.Next >= -1) + { + ref var bucket = ref GetBucketRef(entry.HashCode); + entry.Next = bucket - 1; + bucket = i + 1; + } + } + + NativeMemoryAllocator.Free(_handle->Entries); + _handle->Entries = entries; + _handle->EntriesLength = newSize; + } + + /// + /// Find item index + /// + /// Item + /// Index + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private int FindItemIndex(in T item) + { + uint collisionCount = 0; + var hashCode = item.GetHashCode(); + var i = GetBucketRef(hashCode) - 1; + while (i >= 0) + { + ref var entry = ref _handle->Entries[i]; + if (entry.HashCode == hashCode && entry.Value.Equals(item)) + return i; + i = entry.Next; + collisionCount++; + if (collisionCount > (uint)_handle->EntriesLength) + throw new InvalidOperationException("ConcurrentOperationsNotSupported"); + } + + return -1; + } + + /// + /// Get bucket ref + /// + /// HashCode + /// Bucket ref + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private ref int GetBucketRef(int hashCode) => ref IntPtr.Size == 8 ? ref _handle->Buckets[HashHelpers.FastMod((uint)hashCode, (uint)_handle->BucketsLength, _handle->FastModMultiplier)] : ref _handle->Buckets[(uint)hashCode % (uint)_handle->BucketsLength]; + + /// + /// Entry + /// + private struct Entry + { + /// + /// HashCode + /// + public int HashCode; + + /// + /// Next + /// + public int Next; + + /// + /// Value + /// + public T Value; + } + + /// + /// Empty + /// + public static NativeHashSet Empty => new(); + + /// + /// Get enumerator + /// + /// Enumerator + public Enumerator GetEnumerator() => new(this); + + /// + /// Enumerator + /// + public struct Enumerator + { + /// + /// NativeHashSet + /// + private readonly NativeHashSet _nativeHashSet; + + /// + /// Version + /// + private readonly int _version; + + /// + /// Index + /// + private int _index; + + /// + /// Current + /// + private T _current; + + /// + /// Structure + /// + /// NativeHashSet + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal Enumerator(in NativeHashSet nativeHashSet) + { + _nativeHashSet = nativeHashSet; + _version = nativeHashSet._handle->Version; + _index = 0; + _current = default; + } + + /// + /// Move next + /// + /// Moved + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool MoveNext() + { + if (_version != _nativeHashSet._handle->Version) + throw new InvalidOperationException("EnumFailedVersion"); + while ((uint)_index < (uint)_nativeHashSet._handle->Count) + { + ref var entry = ref _nativeHashSet._handle->Entries[_index++]; + if (entry.Next >= -1) + { + _current = entry.Value; + return true; + } + } + + _index = _nativeHashSet._handle->Count + 1; + _current = default; + return false; + } + + /// + /// Current + /// + public T Current + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _current; + } + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeList.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeList.cs new file mode 100644 index 0000000..e96dc80 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeList.cs @@ -0,0 +1,676 @@ +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +#if UNITY_2021_3_OR_NEWER || GODOT +using System; +#endif + +#pragma warning disable CA2208 +#pragma warning disable CS8632 + +// ReSharper disable ALL + +namespace NativeCollections +{ + /// + /// Native list + /// + /// Type + [StructLayout(LayoutKind.Sequential)] + public readonly unsafe struct NativeList : IDisposable, IEquatable> where T : unmanaged, IEquatable + { + /// + /// Handle + /// + [StructLayout(LayoutKind.Sequential)] + private struct NativeListHandle + { + /// + /// Array + /// + public T* Array; + + /// + /// Length + /// + public int Length; + + /// + /// Size + /// + public int Size; + + /// + /// Version + /// + public int Version; + } + + /// + /// Handle + /// + private readonly NativeListHandle* _handle; + + /// + /// Structure + /// + /// Capacity + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public NativeList(int capacity) + { + if (capacity < 0) + throw new ArgumentOutOfRangeException(nameof(capacity), capacity, "MustBeNonNegative"); + if (capacity < 4) + capacity = 4; + _handle = (NativeListHandle*)NativeMemoryAllocator.Alloc((uint)sizeof(NativeListHandle)); + _handle->Array = (T*)NativeMemoryAllocator.Alloc((uint)(capacity * sizeof(T))); + _handle->Length = capacity; + _handle->Size = 0; + _handle->Version = 0; + } + + /// + /// Is created + /// + public bool IsCreated => _handle != null; + + /// + /// Is empty + /// + public bool IsEmpty => _handle->Size == 0; + + /// + /// Get or set value + /// + /// Index + public ref T this[int index] + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => ref _handle->Array[index]; + } + + /// + /// Get or set value + /// + /// Index + public ref T this[uint index] + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => ref _handle->Array[index]; + } + + /// + /// Count + /// + public int Count => _handle->Size; + + /// + /// Capacity + /// + public int Capacity + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _handle->Length; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + set + { + if (value < _handle->Size) + throw new ArgumentOutOfRangeException(nameof(Capacity), value, "SmallCapacity"); + if (value != _handle->Length) + { + if (value > 0) + { + var newItems = (T*)NativeMemoryAllocator.Alloc((uint)(value * sizeof(T))); + if (_handle->Size > 0) + Unsafe.CopyBlockUnaligned(newItems, _handle->Array, (uint)(_handle->Size * sizeof(T))); + NativeMemoryAllocator.Free(_handle->Array); + _handle->Array = newItems; + _handle->Length = value; + } + else + { + NativeMemoryAllocator.Free(_handle->Array); + _handle->Array = (T*)NativeMemoryAllocator.Alloc(0); + _handle->Length = 0; + } + } + } + } + + /// + /// Equals + /// + /// Other + /// Equals + public bool Equals(NativeList other) => other == this; + + /// + /// Equals + /// + /// object + /// Equals + public override bool Equals(object? obj) => obj is NativeList nativeList && nativeList == this; + + /// + /// Get hashCode + /// + /// HashCode + public override int GetHashCode() => (int)(nint)_handle; + + /// + /// To string + /// + /// String + public override string ToString() => $"NativeList<{typeof(T).Name}>"; + + /// + /// As span + /// + /// Span + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator Span(NativeList nativeList) => nativeList.AsSpan(); + + /// + /// As readOnly span + /// + /// ReadOnlySpan + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator ReadOnlySpan(NativeList nativeList) => nativeList.AsReadOnlySpan(); + + /// + /// Equals + /// + /// Left + /// Right + /// Equals + public static bool operator ==(NativeList left, NativeList right) => left._handle == right._handle; + + /// + /// Not equals + /// + /// Left + /// Right + /// Not equals + public static bool operator !=(NativeList left, NativeList right) => left._handle != right._handle; + + /// + /// Dispose + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Dispose() + { + if (_handle == null) + return; + NativeMemoryAllocator.Free(_handle->Array); + NativeMemoryAllocator.Free(_handle); + } + + /// + /// As span + /// + /// Span + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Span AsSpan() => MemoryMarshal.CreateSpan(ref *_handle->Array, _handle->Length); + + /// + /// As span + /// + /// Length + /// Span + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Span AsSpan(int length) => MemoryMarshal.CreateSpan(ref *_handle->Array, length); + + /// + /// As span + /// + /// Start + /// Length + /// Span + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Span AsSpan(int start, int length) => MemoryMarshal.CreateSpan(ref *(_handle->Array + start), length); + + /// + /// As readOnly span + /// + /// ReadOnlySpan + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public ReadOnlySpan AsReadOnlySpan() => MemoryMarshal.CreateReadOnlySpan(ref *_handle->Array, _handle->Length); + + /// + /// As readOnly span + /// + /// Length + /// ReadOnlySpan + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public ReadOnlySpan AsReadOnlySpan(int length) => MemoryMarshal.CreateReadOnlySpan(ref *_handle->Array, length); + + /// + /// As readOnly span + /// + /// Start + /// Length + /// ReadOnlySpan + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public ReadOnlySpan AsReadOnlySpan(int start, int length) => MemoryMarshal.CreateReadOnlySpan(ref *(_handle->Array + start), length); + + /// + /// Clear + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Clear() + { + _handle->Version++; + _handle->Size = 0; + } + + /// + /// Add + /// + /// Item + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Add(in T item) + { + _handle->Version++; + var size = _handle->Size; + if ((uint)size < (uint)_handle->Length) + { + _handle->Size = size + 1; + _handle->Array[size] = item; + } + else + { + Grow(size + 1); + _handle->Size = size + 1; + _handle->Array[size] = item; + } + } + + /// + /// Add range + /// + /// Collection + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void AddRange(in NativeList collection) + { + var count = collection._handle->Size; + if (count > 0) + { + if (_handle->Length - _handle->Size < count) + Grow(checked(_handle->Size + count)); + Unsafe.CopyBlockUnaligned(_handle->Array + _handle->Size, collection._handle->Array, (uint)(collection._handle->Size * sizeof(T))); + _handle->Size += count; + _handle->Version++; + } + } + + /// + /// Insert + /// + /// Index + /// Item + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Insert(int index, in T item) + { + if ((uint)index > (uint)_handle->Size) + throw new ArgumentOutOfRangeException(nameof(index), index, "ListInsert"); + if (_handle->Size == _handle->Length) + Grow(_handle->Size + 1); + if (index < _handle->Size) + Unsafe.CopyBlockUnaligned(_handle->Array + (index + 1), _handle->Array + index, (uint)((_handle->Size - index) * sizeof(T))); + _handle->Array[index] = item; + _handle->Size++; + _handle->Version++; + } + + /// + /// Insert + /// + /// Index + /// Collection + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void InsertRange(int index, in NativeList collection) + { + if ((uint)index > (uint)_handle->Size) + throw new ArgumentOutOfRangeException(nameof(index), index, "IndexMustBeLessOrEqual"); + var count = collection._handle->Size; + if (count > 0) + { + if (_handle->Length - _handle->Size < count) + Grow(checked(_handle->Size + count)); + if (index < _handle->Size) + Unsafe.CopyBlockUnaligned(_handle->Array + index + count, _handle->Array + index, (uint)((_handle->Size - index) * sizeof(T))); + if (this == collection) + { + Unsafe.CopyBlockUnaligned(_handle->Array + index, _handle->Array, (uint)(index * sizeof(T))); + Unsafe.CopyBlockUnaligned(_handle->Array + index * 2, _handle->Array + index + count, (uint)((_handle->Size - index) * sizeof(T))); + } + else + { + Unsafe.CopyBlockUnaligned(_handle->Array + index, collection._handle->Array, (uint)(collection._handle->Size * sizeof(T))); + } + + _handle->Size += count; + _handle->Version++; + } + } + + /// + /// Remove + /// + /// Item + /// Removed + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool Remove(in T item) + { + var index = IndexOf(item); + if (index >= 0) + { + RemoveAt(index); + return true; + } + + return false; + } + + /// + /// Remove at + /// + /// Index + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void RemoveAt(int index) + { + if ((uint)index >= (uint)_handle->Size) + throw new ArgumentOutOfRangeException(nameof(index), index, "IndexMustBeLess"); + _handle->Size--; + if (index < _handle->Size) + Unsafe.CopyBlockUnaligned(_handle->Array + index, _handle->Array + (index + 1), (uint)((_handle->Size - index) * sizeof(T))); + _handle->Version++; + } + + /// + /// Remove range + /// + /// Index + /// Count + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void RemoveRange(int index, int count) + { + if (index < 0) + throw new ArgumentOutOfRangeException(nameof(index), index, "NeedNonNegNum"); + if (count < 0) + throw new ArgumentOutOfRangeException(nameof(count), count, "NeedNonNegNum"); + var offset = _handle->Size - index; + if (offset < count) + throw new ArgumentOutOfRangeException(offset.ToString(), "InvalidOffLen"); + if (count > 0) + { + _handle->Size -= count; + if (index < _handle->Size) + Unsafe.CopyBlockUnaligned(_handle->Array + index, _handle->Array + (index + count), (uint)((_handle->Size - index) * sizeof(T))); + _handle->Version++; + } + } + + /// + /// Reverse + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Reverse() + { + if (_handle->Size > 1) + MemoryMarshal.CreateSpan(ref *_handle->Array, _handle->Size).Reverse(); + _handle->Version++; + } + + /// + /// Reverse + /// + /// Index + /// Count + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Reverse(int index, int count) + { + if (index < 0) + throw new ArgumentOutOfRangeException(nameof(index), index, "NeedNonNegNum"); + if (count < 0) + throw new ArgumentOutOfRangeException(nameof(count), count, "NeedNonNegNum"); + var offset = _handle->Size - index; + if (offset < count) + throw new ArgumentOutOfRangeException(offset.ToString(), "InvalidOffLen"); + if (count > 1) + MemoryMarshal.CreateSpan(ref *(_handle->Array + index), count).Reverse(); + _handle->Version++; + } + + /// + /// Contains + /// + /// Item + /// Contains + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool Contains(in T item) => _handle->Size != 0 && IndexOf(item) >= 0; + + /// + /// Ensure capacity + /// + /// Capacity + /// New capacity + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public int EnsureCapacity(int capacity) + { + if (capacity < 0) + throw new ArgumentOutOfRangeException(nameof(capacity), capacity, "MustBeNonNegative"); + if (_handle->Length < capacity) + Grow(capacity); + return _handle->Length; + } + + /// + /// Trim excess + /// + /// New capacity + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public int TrimExcess() + { + var threshold = (int)(_handle->Length * 0.9); + if (_handle->Size < threshold) + Capacity = _handle->Size; + return _handle->Length; + } + + /// + /// Grow + /// + /// Capacity + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void Grow(int capacity) + { + var newCapacity = 2 * _handle->Length; + if ((uint)newCapacity > 2147483591) + newCapacity = 2147483591; + var expected = _handle->Length + 4; + newCapacity = newCapacity > expected ? newCapacity : expected; + if (newCapacity < capacity) + newCapacity = capacity; + Capacity = newCapacity; + } + + /// + /// Index of + /// + /// Item + /// Index + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public int IndexOf(in T item) => _handle->Size == 0 ? -1 : MemoryMarshal.CreateReadOnlySpan(ref *_handle->Array, _handle->Size).IndexOf(item); + + /// + /// Index of + /// + /// Item + /// Index + /// Index + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public int IndexOf(in T item, int index) + { + if (_handle->Size == 0) + return -1; + if (index < 0) + throw new ArgumentOutOfRangeException(nameof(index), index, "NeedNonNegNum"); + if (index > _handle->Size) + throw new ArgumentOutOfRangeException(nameof(index), index, "IndexMustBeLessOrEqual"); + return MemoryMarshal.CreateReadOnlySpan(ref *(_handle->Array + index), _handle->Size - index).IndexOf(item); + } + + /// + /// Index of + /// + /// Item + /// Index + /// Count + /// Index + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public int IndexOf(in T item, int index, int count) + { + if (_handle->Size == 0) + return -1; + if (index < 0) + throw new ArgumentOutOfRangeException(nameof(index), index, "NeedNonNegNum"); + if (count < 0) + throw new ArgumentOutOfRangeException(nameof(count), count, "NeedNonNegNum"); + if (index > _handle->Size) + throw new ArgumentOutOfRangeException(nameof(index), index, "IndexMustBeLessOrEqual"); + if (index > _handle->Size - count) + throw new ArgumentOutOfRangeException(nameof(count), count, "BiggerThanCollection"); + return MemoryMarshal.CreateReadOnlySpan(ref *(_handle->Array + index), count).IndexOf(item); + } + + /// + /// Last index of + /// + /// Item + /// Index + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public int LastIndexOf(in T item) => _handle->Size == 0 ? -1 : MemoryMarshal.CreateReadOnlySpan(ref *(_handle->Array + (_handle->Size - 1)), _handle->Size).LastIndexOf(item); + + /// + /// Last index of + /// + /// Item + /// Index + /// Index + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public int LastIndexOf(in T item, int index) + { + if (_handle->Size == 0) + return -1; + if (index < 0) + throw new ArgumentOutOfRangeException(nameof(index), index, "NeedNonNegNum"); + if (index >= _handle->Size) + throw new ArgumentOutOfRangeException(nameof(index), index, "IndexMustBeLess"); + return MemoryMarshal.CreateReadOnlySpan(ref *(_handle->Array + index), index + 1).LastIndexOf(item); + } + + /// + /// Last index of + /// + /// Item + /// Index + /// Count + /// Index + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public int LastIndexOf(in T item, int index, int count) + { + if (_handle->Size == 0) + return -1; + if (index < 0) + throw new ArgumentOutOfRangeException(nameof(index), index, "NeedNonNegNum"); + if (count < 0) + throw new ArgumentOutOfRangeException(nameof(count), count, "NeedNonNegNum"); + if (index >= _handle->Size) + throw new ArgumentOutOfRangeException(nameof(index), index, "BiggerThanCollection"); + if (count > index + 1) + throw new ArgumentOutOfRangeException(nameof(count), count, "BiggerThanCollection"); + return MemoryMarshal.CreateReadOnlySpan(ref *(_handle->Array + index), count).LastIndexOf(item); + } + + /// + /// Empty + /// + public static NativeList Empty => new(); + + /// + /// Get enumerator + /// + /// Enumerator + public Enumerator GetEnumerator() => new(this); + + /// + /// Enumerator + /// + public struct Enumerator + { + /// + /// NativeList + /// + private readonly NativeList _nativeList; + + /// + /// Version + /// + private readonly int _version; + + /// + /// Index + /// + private int _index; + + /// + /// Current + /// + private T _current; + + /// + /// Structure + /// + /// NativeList + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal Enumerator(in NativeList nativeList) + { + _nativeList = nativeList; + _index = 0; + _version = nativeList._handle->Version; + _current = default; + } + + /// + /// Move next + /// + /// Moved + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool MoveNext() + { + var localList = _nativeList; + if (_version == localList._handle->Version && (uint)_index < (uint)localList._handle->Size) + { + _current = localList._handle->Array[_index]; + _index++; + return true; + } + + if (_version != _nativeList._handle->Version) + throw new InvalidOperationException("EnumFailedVersion"); + _index = _nativeList._handle->Size + 1; + _current = default; + return false; + } + + /// + /// Current + /// + public T Current + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _current; + } + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeMemoryAllocator.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeMemoryAllocator.cs new file mode 100644 index 0000000..10986fb --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeMemoryAllocator.cs @@ -0,0 +1,233 @@ +#if UNITY_2021_3_OR_NEWER || GODOT +using System; +#endif + +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +#if NET7_0_OR_GREATER +using System.Runtime.Intrinsics; +#endif + +// ReSharper disable ALL + +namespace NativeCollections +{ + /// + /// Native memory allocator + /// + public static unsafe class NativeMemoryAllocator + { + /// + /// Alloc + /// + /// Byte count + /// Memory + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void* Alloc(uint byteCount) + { +#if NET6_0_OR_GREATER + return NativeMemory.Alloc(byteCount); +#else + return (void*)Marshal.AllocHGlobal((nint)byteCount); +#endif + } + + /// + /// Alloc zeroed + /// + /// Byte count + /// Memory + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void* AllocZeroed(uint byteCount) + { +#if NET6_0_OR_GREATER + return NativeMemory.AllocZeroed(byteCount, 1); +#else + var ptr = (void*)Marshal.AllocHGlobal((nint)byteCount); + Unsafe.InitBlockUnaligned(ptr, 0, byteCount); + return ptr; +#endif + } + + /// + /// Free + /// + /// Pointer + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void Free(void* ptr) + { +#if NET6_0_OR_GREATER + NativeMemory.Free(ptr); +#else + Marshal.FreeHGlobal((nint)ptr); +#endif + } + + /// + /// Copy + /// + /// Destination + /// Source + /// Byte count + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void Copy(void* destination, void* source, uint byteCount) => Unsafe.CopyBlockUnaligned(destination, source, byteCount); + + /// + /// Move + /// + /// Destination + /// Source + /// Byte count + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void Move(void* destination, void* source, uint byteCount) => Buffer.MemoryCopy(source, destination, byteCount, byteCount); + + /// + /// Set + /// + /// Start address + /// Value + /// Byte count + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void Set(void* startAddress, byte value, uint byteCount) => Unsafe.InitBlockUnaligned(startAddress, value, byteCount); + + /// + /// Compare + /// + /// Left + /// Right + /// Byte count + /// Sequences equal + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool Compare(void* left, void* right, uint byteCount) + { + ref var first = ref *(byte*)left; + ref var second = ref *(byte*)right; + nuint length = byteCount; + if (length >= (nuint)sizeof(nuint)) + { + if (!Unsafe.AreSame(ref first, ref second)) + { +#if NET7_0_OR_GREATER + if (Vector128.IsHardwareAccelerated) + { +#if NET8_0_OR_GREATER + if (Vector512.IsHardwareAccelerated && length >= (nuint)Vector512.Count) + { + nuint offset = 0; + var lengthToExamine = length - (nuint)Vector512.Count; + if (lengthToExamine != 0) + { + do + { + if (Vector512.LoadUnsafe(ref first, offset) != Vector512.LoadUnsafe(ref second, offset)) + return false; + offset += (nuint)Vector512.Count; + } while (lengthToExamine > offset); + } + + return Vector512.LoadUnsafe(ref first, lengthToExamine) == Vector512.LoadUnsafe(ref second, lengthToExamine); + } +#endif + if (Vector256.IsHardwareAccelerated && length >= (nuint)Vector256.Count) + { + nuint offset = 0; + var lengthToExamine = length - (nuint)Vector256.Count; + if (lengthToExamine != 0) + { + do + { + if (Vector256.LoadUnsafe(ref first, offset) != Vector256.LoadUnsafe(ref second, offset)) + return false; + offset += (nuint)Vector256.Count; + } while (lengthToExamine > offset); + } + + return Vector256.LoadUnsafe(ref first, lengthToExamine) == Vector256.LoadUnsafe(ref second, lengthToExamine); + } + + if (length >= (nuint)Vector128.Count) + { + nuint offset = 0; + var lengthToExamine = length - (nuint)Vector128.Count; + if (lengthToExamine != 0) + { + do + { + if (Vector128.LoadUnsafe(ref first, offset) != Vector128.LoadUnsafe(ref second, offset)) + return false; + offset += (nuint)Vector128.Count; + } while (lengthToExamine > offset); + } + + return Vector128.LoadUnsafe(ref first, lengthToExamine) == Vector128.LoadUnsafe(ref second, lengthToExamine); + } + } + + if (IntPtr.Size == 8 && Vector128.IsHardwareAccelerated) + { + var offset = length - (nuint)sizeof(nuint); + var differentBits = Unsafe.ReadUnaligned(ref first) - Unsafe.ReadUnaligned(ref second); + differentBits |= Unsafe.ReadUnaligned(ref Unsafe.AddByteOffset(ref first, offset)) - Unsafe.ReadUnaligned(ref Unsafe.AddByteOffset(ref second, offset)); + return differentBits == 0; + } + else +#endif + { + nuint offset = 0; + var lengthToExamine = length - (nuint)sizeof(nuint); + if (lengthToExamine > 0) + { + do + { +#if NET7_0_OR_GREATER + if (Unsafe.ReadUnaligned(ref Unsafe.AddByteOffset(ref first, offset)) != Unsafe.ReadUnaligned(ref Unsafe.AddByteOffset(ref second, offset))) +#else + if (Unsafe.ReadUnaligned(ref Unsafe.AddByteOffset(ref first, (nint)offset)) != Unsafe.ReadUnaligned(ref Unsafe.AddByteOffset(ref second, (nint)offset))) +#endif + return false; + offset += (nuint)sizeof(nuint); + } while (lengthToExamine > offset); + } +#if NET7_0_OR_GREATER + return Unsafe.ReadUnaligned(ref Unsafe.AddByteOffset(ref first, lengthToExamine)) == Unsafe.ReadUnaligned(ref Unsafe.AddByteOffset(ref second, lengthToExamine)); +#else + return Unsafe.ReadUnaligned(ref Unsafe.AddByteOffset(ref first, (nint)lengthToExamine)) == Unsafe.ReadUnaligned(ref Unsafe.AddByteOffset(ref second, (nint)lengthToExamine)); +#endif + } + } + + return true; + } + + if (length < sizeof(uint) || IntPtr.Size != 8) + { + uint differentBits = 0; + var offset = length & 2; + if (offset != 0) + { + differentBits = Unsafe.ReadUnaligned(ref first); + differentBits -= Unsafe.ReadUnaligned(ref second); + } + + if ((length & 1) != 0) +#if NET7_0_OR_GREATER + differentBits |= Unsafe.AddByteOffset(ref first, offset) - (uint)Unsafe.AddByteOffset(ref second, offset); +#else + differentBits |= Unsafe.AddByteOffset(ref first, (nint)offset) - (uint)Unsafe.AddByteOffset(ref second, (nint)offset); +#endif + return differentBits == 0; + } + else + { + var offset = length - sizeof(uint); + var differentBits = Unsafe.ReadUnaligned(ref first) - Unsafe.ReadUnaligned(ref second); +#if NET7_0_OR_GREATER + differentBits |= Unsafe.ReadUnaligned(ref Unsafe.AddByteOffset(ref first, offset)) - Unsafe.ReadUnaligned(ref Unsafe.AddByteOffset(ref second, offset)); +#else + differentBits |= Unsafe.ReadUnaligned(ref Unsafe.AddByteOffset(ref first, (nint)offset)) - Unsafe.ReadUnaligned(ref Unsafe.AddByteOffset(ref second, (nint)offset)); +#endif + return differentBits == 0; + } + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeMemoryArray.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeMemoryArray.cs new file mode 100644 index 0000000..7b1e4dc --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeMemoryArray.cs @@ -0,0 +1,329 @@ +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +#if UNITY_2021_3_OR_NEWER || GODOT +using System; +#endif + +#pragma warning disable CA2208 +#pragma warning disable CS8632 + +// ReSharper disable ALL + +namespace NativeCollections +{ + /// + /// Native memory array + /// + /// Type + [StructLayout(LayoutKind.Sequential)] + public readonly unsafe struct NativeMemoryArray : IDisposable, IEquatable> where T : unmanaged + { + /// + /// Array + /// + private readonly T* _array; + + /// + /// Length + /// + private readonly int _length; + + /// + /// Structure + /// + /// Length + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public NativeMemoryArray(int length) + { + if (length < 0) + throw new ArgumentOutOfRangeException(nameof(length), length, "MustBeNonNegative"); + _array = (T*)NativeMemoryAllocator.Alloc((uint)(length * sizeof(T))); + _length = length; + } + + /// + /// Structure + /// + /// Length + /// Zeroed + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public NativeMemoryArray(int length, bool zeroed) + { + if (length < 0) + throw new ArgumentOutOfRangeException(nameof(length), length, "MustBeNonNegative"); + _array = zeroed ? (T*)NativeMemoryAllocator.AllocZeroed((uint)(length * sizeof(T))) : (T*)NativeMemoryAllocator.Alloc((uint)(length * sizeof(T))); + _length = length; + } + + /// + /// Structure + /// + /// Array + /// Length + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public NativeMemoryArray(T* array, int length) + { + if (length < 0) + throw new ArgumentOutOfRangeException(nameof(length), length, "MustBeNonNegative"); + _array = array; + _length = length; + } + + /// + /// Is created + /// + public bool IsCreated => _array != null; + + /// + /// Is empty + /// + public bool IsEmpty => _length == 0; + + /// + /// Get reference + /// + /// Index + public T* this[int index] + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _array + index; + } + + /// + /// Get reference + /// + /// Index + public T* this[uint index] + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _array + index; + } + + /// + /// Array + /// + public T* Array => _array; + + /// + /// Length + /// + public int Length => _length; + + /// + /// Equals + /// + /// Other + /// Equals + public bool Equals(NativeMemoryArray other) => other == this; + + /// + /// Equals + /// + /// object + /// Equals + public override bool Equals(object? obj) => obj is NativeMemoryArray nativeMemoryArray && nativeMemoryArray == this; + + /// + /// Get hashCode + /// + /// HashCode + public override int GetHashCode() => (int)(nint)_array; + + /// + /// To string + /// + /// String + public override string ToString() => $"NativeMemoryArray<{typeof(T).Name}>[{_length}]"; + + /// + /// As span + /// + /// Span + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator Span(NativeMemoryArray nativeMemoryArray) => nativeMemoryArray.AsSpan(); + + /// + /// As readOnly span + /// + /// ReadOnlySpan + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator ReadOnlySpan(NativeMemoryArray nativeMemoryArray) => nativeMemoryArray.AsReadOnlySpan(); + + /// + /// As native array + /// + /// Native memory array + /// NativeArray + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator NativeArray(NativeMemoryArray nativeMemoryArray) => new(nativeMemoryArray._array, nativeMemoryArray._length); + + /// + /// As native memory array + /// + /// Native array + /// NativeMemoryArray + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator NativeMemoryArray(NativeArray nativeArray) => new(nativeArray.Array, nativeArray.Length); + + /// + /// As native array segment + /// + /// Native memory array + /// NativeArraySegment + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator NativeArraySegment(NativeMemoryArray nativeMemoryArray) => new(nativeMemoryArray._array, nativeMemoryArray._length); + + /// + /// As native memory array + /// + /// Native array segment + /// NativeMemoryArray + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator NativeMemoryArray(NativeArraySegment nativeArraySegment) => new(nativeArraySegment.Array, nativeArraySegment.Offset + nativeArraySegment.Count); + + /// + /// Equals + /// + /// Left + /// Right + /// Equals + public static bool operator ==(NativeMemoryArray left, NativeMemoryArray right) => left._length == right._length && left._array == right._array; + + /// + /// Not equals + /// + /// Left + /// Right + /// Not equals + public static bool operator !=(NativeMemoryArray left, NativeMemoryArray right) => left._length != right._length || left._array != right._array; + + /// + /// Dispose + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Dispose() + { + if (_array == null) + return; + NativeMemoryAllocator.Free(_array); + } + + /// + /// Clear + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Clear() => Unsafe.InitBlockUnaligned(_array, 0, (uint)(_length * sizeof(T))); + + /// + /// As span + /// + /// Span + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Span AsSpan() => MemoryMarshal.CreateSpan(ref *_array, _length); + + /// + /// As span + /// + /// Length + /// Span + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Span AsSpan(int length) => MemoryMarshal.CreateSpan(ref *_array, length); + + /// + /// As span + /// + /// Start + /// Length + /// Span + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Span AsSpan(int start, int length) => MemoryMarshal.CreateSpan(ref *(_array + start), length); + + /// + /// As readOnly span + /// + /// ReadOnlySpan + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public ReadOnlySpan AsReadOnlySpan() => MemoryMarshal.CreateReadOnlySpan(ref *_array, _length); + + /// + /// As readOnly span + /// + /// Length + /// ReadOnlySpan + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public ReadOnlySpan AsReadOnlySpan(int length) => MemoryMarshal.CreateReadOnlySpan(ref *_array, length); + + /// + /// As readOnly span + /// + /// Start + /// Length + /// ReadOnlySpan + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public ReadOnlySpan AsReadOnlySpan(int start, int length) => MemoryMarshal.CreateReadOnlySpan(ref *(_array + start), length); + + /// + /// Empty + /// + public static NativeMemoryArray Empty => new(); + + /// + /// Get enumerator + /// + /// Enumerator + public Enumerator GetEnumerator() => new(this); + + /// + /// Enumerator + /// + public ref struct Enumerator + { + /// + /// NativeMemoryArray + /// + private readonly NativeMemoryArray _nativeMemoryArray; + + /// + /// Index + /// + private int _index; + + /// + /// Structure + /// + /// NativeMemoryArray + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal Enumerator(NativeMemoryArray nativeMemoryArray) + { + _nativeMemoryArray = nativeMemoryArray; + _index = -1; + } + + /// + /// Move next + /// + /// Moved + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool MoveNext() + { + var index = _index + 1; + if (index < _nativeMemoryArray._length) + { + _index = index; + return true; + } + + return false; + } + + /// + /// Current + /// + public T* Current + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _nativeMemoryArray[_index]; + } + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeMemoryBucket.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeMemoryBucket.cs new file mode 100644 index 0000000..01b8d60 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeMemoryBucket.cs @@ -0,0 +1,199 @@ +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +#if UNITY_2021_3_OR_NEWER || GODOT +using System; +#endif + +#pragma warning disable CA2208 +#pragma warning disable CS8632 + +// ReSharper disable ALL + +namespace NativeCollections +{ + /// + /// Native memory bucket + /// + [StructLayout(LayoutKind.Sequential)] + public readonly unsafe struct NativeMemoryBucket : IDisposable, IEquatable + { + /// + /// Handle + /// + [StructLayout(LayoutKind.Sequential)] + private struct NativeMemoryBucketHandle + { + /// + /// Size + /// + public int Size; + + /// + /// Length + /// + public int Length; + + /// + /// Array + /// + public void** Array; + + /// + /// Index + /// + public int Index; + + /// + /// Memory pool + /// + public NativeMemoryPool MemoryPool; + } + + /// + /// Handle + /// + private readonly NativeMemoryBucketHandle* _handle; + + /// + /// Structure + /// + /// Size + /// Length + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public NativeMemoryBucket(int size, int length) + { + if (size <= 0) + throw new ArgumentOutOfRangeException(nameof(size), size, "MustBePositive"); + if (length < 0) + throw new ArgumentOutOfRangeException(nameof(length), length, "MustBeNonNegative"); + _handle = (NativeMemoryBucketHandle*)NativeMemoryAllocator.Alloc((uint)sizeof(NativeMemoryBucketHandle)); + _handle->Size = size; + _handle->Length = length; + _handle->Array = (void**)NativeMemoryAllocator.AllocZeroed((uint)(size * sizeof(void*))); + _handle->Index = 0; + _handle->MemoryPool = new NativeMemoryPool(size, length, 0); + } + + /// + /// Is created + /// + public bool IsCreated => _handle != null; + + /// + /// Is empty + /// + public bool IsEmpty => _handle->Index == 0; + + /// + /// Is full + /// + public bool IsFull => _handle->Index == _handle->Size; + + /// + /// Size + /// + public int Size => _handle->Size; + + /// + /// Length + /// + public int Length => _handle->Length; + + /// + /// Count + /// + public int Count => _handle->Index; + + /// + /// Equals + /// + /// Other + /// Equals + public bool Equals(NativeMemoryBucket other) => other == this; + + /// + /// Equals + /// + /// object + /// Equals + public override bool Equals(object? obj) => obj is NativeMemoryBucket nativeMemoryBucket && nativeMemoryBucket == this; + + /// + /// Get hashCode + /// + /// HashCode + public override int GetHashCode() => (int)(nint)_handle; + + /// + /// To string + /// + /// String + public override string ToString() => "NativeMemoryBucket"; + + /// + /// Equals + /// + /// Left + /// Right + /// Equals + public static bool operator ==(NativeMemoryBucket left, NativeMemoryBucket right) => left._handle == right._handle; + + /// + /// Not equals + /// + /// Left + /// Right + /// Not equals + public static bool operator !=(NativeMemoryBucket left, NativeMemoryBucket right) => left._handle != right._handle; + + /// + /// Dispose + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Dispose() + { + if (_handle == null) + return; + NativeMemoryAllocator.Free(_handle->Array); + _handle->MemoryPool.Dispose(); + NativeMemoryAllocator.Free(_handle); + } + + /// + /// Rent buffer + /// + /// Buffer + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void* Rent() + { + void* buffer = null; + if (_handle->Index < _handle->Size) + { + buffer = _handle->Array[_handle->Index]; + _handle->Array[_handle->Index++] = null; + } + + if (buffer == null) + buffer = _handle->MemoryPool.Rent(); + return buffer; + } + + /// + /// Return buffer + /// + /// Pointer + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Return(void* ptr) + { + if (_handle->Index != 0) + _handle->Array[--_handle->Index] = ptr; + else + _handle->MemoryPool.Return(ptr); + } + + /// + /// Empty + /// + public static NativeMemoryBucket Empty => new(); + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeMemoryPool.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeMemoryPool.cs new file mode 100644 index 0000000..2c009cf --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeMemoryPool.cs @@ -0,0 +1,388 @@ +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +#if UNITY_2021_3_OR_NEWER || GODOT +using System; +#endif + +#pragma warning disable CA2208 +#pragma warning disable CS8632 + +// ReSharper disable ALL + +namespace NativeCollections +{ + /// + /// Native memory pool + /// + [StructLayout(LayoutKind.Sequential)] + public readonly unsafe struct NativeMemoryPool : IDisposable, IEquatable + { + /// + /// Handle + /// + [StructLayout(LayoutKind.Sequential)] + private struct NativeMemoryPoolHandle + { + /// + /// Slab + /// + public NativeMemorySlab* Slab; + + /// + /// Free slab + /// + public NativeMemorySlab* FreeSlab; + + /// + /// Slabs + /// + public int Slabs; + + /// + /// Free slabs + /// + public int FreeSlabs; + + /// + /// Max free slabs + /// + public int MaxFreeSlabs; + + /// + /// Size + /// + public int Size; + + /// + /// Length + /// + public int Length; + } + + /// + /// Slab + /// + [StructLayout(LayoutKind.Sequential)] + private struct NativeMemorySlab + { + /// + /// Next + /// + public NativeMemorySlab* Next; + + /// + /// Previous + /// + public NativeMemorySlab* Previous; + + /// + /// Node + /// + public NativeMemoryNode* Node; + + /// + /// Count + /// + public int Count; + } + + /// + /// Node + /// + [StructLayout(LayoutKind.Explicit)] + private struct NativeMemoryNode + { + /// + /// Slab + /// + [FieldOffset(0)] public NativeMemorySlab* Slab; + + /// + /// Next + /// + [FieldOffset(0)] public NativeMemoryNode* Next; + } + + /// + /// Handle + /// + private readonly NativeMemoryPoolHandle* _handle; + + /// + /// Structure + /// + /// Size + /// Length + /// Max free slabs + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public NativeMemoryPool(int size, int length, int maxFreeSlabs) + { + if (size <= 0) + throw new ArgumentOutOfRangeException(nameof(size), size, "MustBePositive"); + if (length < 0) + throw new ArgumentOutOfRangeException(nameof(length), length, "MustBeNonNegative"); + if (maxFreeSlabs < 0) + throw new ArgumentOutOfRangeException(nameof(maxFreeSlabs), maxFreeSlabs, "MustBeNonNegative"); + var nodeSize = sizeof(NativeMemoryNode) + length; + var array = (byte*)NativeMemoryAllocator.Alloc((uint)(sizeof(NativeMemorySlab) + size * nodeSize)); + var slab = (NativeMemorySlab*)array; + slab->Next = slab; + slab->Previous = slab; + array += sizeof(NativeMemorySlab); + NativeMemoryNode* next = null; + for (var i = size - 1; i >= 0; --i) + { + var node = (NativeMemoryNode*)(array + i * nodeSize); + node->Next = next; + next = node; + } + + slab->Node = next; + slab->Count = size; + _handle = (NativeMemoryPoolHandle*)NativeMemoryAllocator.Alloc((uint)sizeof(NativeMemoryPoolHandle)); + _handle->Slab = slab; + _handle->FreeSlab = null; + _handle->Slabs = 1; + _handle->FreeSlabs = 0; + _handle->MaxFreeSlabs = maxFreeSlabs; + _handle->Size = size; + _handle->Length = length; + } + + /// + /// Is created + /// + public bool IsCreated => _handle != null; + + /// + /// Slabs + /// + public int Slabs => _handle->Slabs; + + /// + /// Free slabs + /// + public int FreeSlabs => _handle->FreeSlabs; + + /// + /// Max free slabs + /// + public int MaxFreeSlabs => _handle->MaxFreeSlabs; + + /// + /// Size + /// + public int Size => _handle->Size; + + /// + /// Length + /// + public int Length => _handle->Length; + + /// + /// Equals + /// + /// Other + /// Equals + public bool Equals(NativeMemoryPool other) => other == this; + + /// + /// Equals + /// + /// object + /// Equals + public override bool Equals(object? obj) => obj is NativeMemoryPool nativeMemoryPool && nativeMemoryPool == this; + + /// + /// Get hashCode + /// + /// HashCode + public override int GetHashCode() => (int)(nint)_handle; + + /// + /// To string + /// + /// String + public override string ToString() => "NativeMemoryPool"; + + /// + /// Equals + /// + /// Left + /// Right + /// Equals + public static bool operator ==(NativeMemoryPool left, NativeMemoryPool right) => left._handle == right._handle; + + /// + /// Not equals + /// + /// Left + /// Right + /// Not equals + public static bool operator !=(NativeMemoryPool left, NativeMemoryPool right) => left._handle != right._handle; + + /// + /// Dispose + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Dispose() + { + if (_handle == null) + return; + var node = _handle->Slab; + while (_handle->Slabs > 0) + { + _handle->Slabs--; + var temp = node; + node = node->Next; + NativeMemoryAllocator.Free(temp); + } + + node = _handle->FreeSlab; + while (_handle->FreeSlabs > 0) + { + _handle->FreeSlabs--; + var temp = node; + node = node->Next; + NativeMemoryAllocator.Free(temp); + } + + NativeMemoryAllocator.Free(_handle); + } + + /// + /// Rent buffer + /// + /// Buffer + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void* Rent() + { + NativeMemoryNode* node; + var slab = _handle->Slab; + if (slab->Count == 0) + { + _handle->Slab = slab->Next; + slab = _handle->Slab; + if (slab->Count == 0) + { + var size = _handle->Size; + if (_handle->FreeSlabs == 0) + { + var nodeSize = sizeof(NativeMemoryNode) + _handle->Length; + var array = (byte*)NativeMemoryAllocator.Alloc((uint)(sizeof(NativeMemorySlab) + size * nodeSize)); + slab = (NativeMemorySlab*)array; + array += sizeof(NativeMemorySlab); + NativeMemoryNode* next = null; + for (var i = size - 1; i >= 0; --i) + { + node = (NativeMemoryNode*)(array + i * nodeSize); + node->Next = next; + next = node; + } + + slab->Node = next; + } + else + { + slab = _handle->FreeSlab; + _handle->FreeSlab = slab->Next; + _handle->FreeSlabs--; + } + + slab->Next = _handle->Slab; + slab->Previous = _handle->Slab->Previous; + slab->Count = size; + _handle->Slab->Previous->Next = slab; + _handle->Slab->Previous = slab; + _handle->Slab = slab; + _handle->Slabs++; + } + } + + node = slab->Node; + slab->Node = node->Next; + node->Slab = slab; + slab->Count--; + return (byte*)node + sizeof(NativeMemoryNode); + } + + /// + /// Return buffer + /// + /// Pointer + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Return(void* ptr) + { + var node = (NativeMemoryNode*)((byte*)ptr - sizeof(NativeMemoryNode)); + var slab = node->Slab; + slab->Count++; + if (slab->Count == _handle->Size && slab != _handle->Slab) + { + slab->Previous->Next = slab->Next; + slab->Next->Previous = slab->Previous; + if (_handle->FreeSlabs == _handle->MaxFreeSlabs) + { + NativeMemoryAllocator.Free(slab); + } + else + { + node->Next = slab->Node; + slab->Node = node; + slab->Next = _handle->FreeSlab; + _handle->FreeSlab = slab; + _handle->FreeSlabs++; + } + + _handle->Slabs--; + return; + } + + node->Next = slab->Node; + slab->Node = node; + } + + /// + /// Trim excess + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void TrimExcess() + { + var node = _handle->FreeSlab; + while (_handle->FreeSlabs > 0) + { + _handle->FreeSlabs--; + var temp = node; + node = node->Next; + NativeMemoryAllocator.Free(temp); + } + + _handle->FreeSlab = node; + } + + /// + /// Trim excess + /// + /// Remaining free slabs + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void TrimExcess(int capacity) + { + if (capacity < 0) + throw new ArgumentOutOfRangeException(nameof(capacity), capacity, "MustBeNonNegative"); + var node = _handle->FreeSlab; + while (_handle->FreeSlabs > capacity) + { + _handle->FreeSlabs--; + var temp = node; + node = node->Next; + NativeMemoryAllocator.Free(temp); + } + + _handle->FreeSlab = node; + } + + /// + /// Empty + /// + public static NativeMemoryPool Empty => new(); + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeMemoryReader.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeMemoryReader.cs new file mode 100644 index 0000000..3ca294a --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeMemoryReader.cs @@ -0,0 +1,274 @@ +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +#if UNITY_2021_3_OR_NEWER || GODOT +using System; +#endif + +#pragma warning disable CA2208 +#pragma warning disable CS8632 + +// ReSharper disable ALL + +namespace NativeCollections +{ + /// + /// Native memory reader + /// + [StructLayout(LayoutKind.Sequential)] + public unsafe ref struct NativeMemoryReader + { + /// + /// Array + /// + public readonly byte* Array; + + /// + /// Length + /// + public readonly int Length; + + /// + /// Position + /// + public int Position; + + /// + /// Structure + /// + /// Array + /// Length + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public NativeMemoryReader(byte* array, int length) + { + if (length < 0) + throw new ArgumentOutOfRangeException(nameof(length), length, "MustBeNonNegative"); + Array = array; + Length = length; + Position = 0; + } + + /// + /// Remaining + /// + public int Remaining => Length - Position; + + /// + /// Get reference + /// + /// Index + public byte* this[int index] + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => Array + index; + } + + /// + /// Get reference + /// + /// Index + public byte* this[uint index] + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => Array + index; + } + + /// + /// Equals + /// + /// Other + /// Equals + public bool Equals(NativeMemoryReader other) => other == this; + + /// + /// Equals + /// + /// object + /// Equals + public override bool Equals(object? obj) => throw new NotSupportedException("Cannot call Equals on NativeMemoryReader"); + + /// + /// Get hashCode + /// + /// HashCode + public override int GetHashCode() => HashCode.Combine((int)(nint)Array, Length, Position); + + /// + /// To string + /// + /// String + public override string ToString() => "NativeMemoryReader"; + + /// + /// Equals + /// + /// Left + /// Right + /// Equals + public static bool operator ==(NativeMemoryReader left, NativeMemoryReader right) => left.Array == right.Array && left.Length == right.Length && left.Position == right.Position; + + /// + /// Not equals + /// + /// Left + /// Right + /// Not equals + public static bool operator !=(NativeMemoryReader left, NativeMemoryReader right) => left.Array != right.Array || left.Length != right.Length || left.Position != right.Position; + + /// + /// Advance + /// + /// Count + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Advance(int count) + { + var newPosition = Position + count; + if (newPosition < 0 || newPosition > Length) + throw new ArgumentOutOfRangeException(nameof(count), "Cannot advance past the end of the buffer."); + Position = newPosition; + } + + /// + /// Try advance + /// + /// Count + /// Advanced + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool TryAdvance(int count) + { + var newPosition = Position + count; + if (newPosition < 0 || newPosition > Length) + return false; + Position = newPosition; + return true; + } + + /// + /// Read + /// + /// object + /// Type + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Read(T* obj) where T : unmanaged + { + if (Position + sizeof(T) > Length) + throw new ArgumentOutOfRangeException(nameof(T), $"Requires size is {sizeof(T)}, but buffer length is {Remaining}."); + Unsafe.CopyBlockUnaligned(obj, Array + Position, (uint)sizeof(T)); + Position += sizeof(T); + } + + /// + /// Try read + /// + /// object + /// Type + /// Read + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool TryRead(T* obj) where T : unmanaged + { + if (Position + sizeof(T) > Length) + return false; + Unsafe.CopyBlockUnaligned(obj, Array + Position, (uint)sizeof(T)); + Position += sizeof(T); + return true; + } + + /// + /// Read + /// + /// object + /// Count + /// Type + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Read(T* obj, int count) where T : unmanaged + { + count *= sizeof(T); + if (Position + count > Length) + throw new ArgumentOutOfRangeException(nameof(T), $"Requires size is {count}, but buffer length is {Remaining}."); + Unsafe.CopyBlockUnaligned(obj, Array + Position, (uint)count); + Position += count; + } + + /// + /// Try read + /// + /// object + /// Count + /// Type + /// Read + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool TryRead(T* obj, int count) where T : unmanaged + { + count *= sizeof(T); + if (Position + count > Length) + return false; + Unsafe.CopyBlockUnaligned(obj, Array + Position, (uint)count); + Position += count; + return true; + } + + /// + /// Read + /// + /// object + /// Type + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Read(ref T obj) where T : unmanaged + { + if (Position + sizeof(T) > Length) + throw new ArgumentOutOfRangeException(nameof(T), $"Requires size is {sizeof(T)}, but buffer length is {Remaining}."); + obj = Unsafe.ReadUnaligned(Array + Position); + Position += sizeof(T); + } + + /// + /// Try read + /// + /// object + /// Type + /// Read + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool TryRead(ref T obj) where T : unmanaged + { + if (Position + sizeof(T) > Length) + return false; + obj = Unsafe.ReadUnaligned(Array + Position); + Position += sizeof(T); + return true; + } + + /// + /// Read bytes + /// + /// Buffer + /// Length + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ReadBytes(byte* buffer, int length) + { + if (Position + length > Length) + throw new ArgumentOutOfRangeException(nameof(length), $"Requires size is {length}, but buffer length is {Remaining}."); + Unsafe.CopyBlockUnaligned(buffer, Array + Position, (uint)length); + Position += length; + } + + /// + /// Try read bytes + /// + /// Buffer + /// Length + /// Read + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool TryReadBytes(byte* buffer, int length) + { + if (Position + length > Length) + return false; + Unsafe.CopyBlockUnaligned(buffer, Array + Position, (uint)length); + Position += length; + return true; + } + + /// + /// Empty + /// + public static NativeMemoryReader Empty => new(); + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeMemoryReaderExtensions.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeMemoryReaderExtensions.cs new file mode 100644 index 0000000..c38538e --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeMemoryReaderExtensions.cs @@ -0,0 +1,55 @@ +using System.Runtime.CompilerServices; +#if UNITY_2021_3_OR_NEWER || GODOT +using System; +#endif + +#pragma warning disable CA2208 +#pragma warning disable CS8632 + +// ReSharper disable ALL + +namespace NativeCollections +{ + /// + /// Native memory reader extensions + /// + public static unsafe class NativeMemoryReaderExtensions + { + /// + /// Read + /// + /// Reader + /// Type + /// object + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static T Read(this ref NativeMemoryReader reader) where T : unmanaged + { + if (reader.Position + sizeof(T) > reader.Length) + throw new ArgumentOutOfRangeException(nameof(T), $"Requires size is {sizeof(T)}, but buffer length is {reader.Remaining}."); + var obj = Unsafe.ReadUnaligned(reader.Array + reader.Position); + reader.Position += sizeof(T); + return obj; + } + + /// + /// Try read + /// + /// Reader + /// object + /// Type + /// Read + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool TryRead(this ref NativeMemoryReader reader, out T obj) where T : unmanaged + { + if (reader.Position + sizeof(T) > reader.Length) + { + obj = default; + return false; + } + + obj = Unsafe.ReadUnaligned(reader.Array + reader.Position); + reader.Position += sizeof(T); + return true; + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeMemoryStream.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeMemoryStream.cs new file mode 100644 index 0000000..81c3ef1 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeMemoryStream.cs @@ -0,0 +1,571 @@ +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +#if UNITY_2021_3_OR_NEWER || GODOT +using System; +using System.IO; +#endif + +#pragma warning disable CA2208 +#pragma warning disable CS8632 + +// ReSharper disable ALL + +namespace NativeCollections +{ + /// + /// Native memory stream + /// + [StructLayout(LayoutKind.Sequential)] + public unsafe struct NativeMemoryStream : IDisposable, IEquatable + { + /// + /// Handle + /// + [StructLayout(LayoutKind.Sequential)] + private struct NativeMemoryStreamHandle + { + /// + /// Array + /// + public byte* Array; + + /// + /// Position + /// + public int Position; + + /// + /// Length + /// + public int Length; + + /// + /// Capacity + /// + public int Capacity; + } + + /// + /// Handle + /// + private readonly NativeMemoryStreamHandle* _handle; + + /// + /// Structure + /// + /// Capacity + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public NativeMemoryStream(int capacity) + { + if (capacity < 0) + throw new ArgumentOutOfRangeException(nameof(capacity), capacity, "MustBeNonNegative"); + if (capacity < 4) + capacity = 4; + _handle = (NativeMemoryStreamHandle*)NativeMemoryAllocator.Alloc((uint)sizeof(NativeMemoryStreamHandle)); + _handle->Array = (byte*)NativeMemoryAllocator.Alloc((uint)capacity); + _handle->Position = 0; + _handle->Length = 0; + _handle->Capacity = capacity; + } + + /// + /// Is created + /// + public bool IsCreated => _handle != null; + + /// + /// Is empty + /// + public bool IsEmpty => _handle->Length == 0; + + /// + /// Get reference + /// + /// Index + public ref byte this[int index] + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => ref _handle->Array[index]; + } + + /// + /// Get reference + /// + /// Index + public ref byte this[uint index] + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => ref _handle->Array[index]; + } + + /// + /// Can read + /// + public bool CanRead => IsCreated; + + /// + /// Can seek + /// + public bool CanSeek => IsCreated; + + /// + /// Can write + /// + public bool CanWrite => IsCreated; + + /// + /// Length + /// + public int Length + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get + { + EnsureNotClosed(); + return _handle->Length; + } + } + + /// + /// Position + /// + public int Position + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get + { + EnsureNotClosed(); + return _handle->Position; + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + set + { + if (value < 0) + throw new ArgumentOutOfRangeException(nameof(Position), value, "MustBeNonNegative"); + EnsureNotClosed(); + _handle->Position = value; + } + } + + /// + /// Capacity + /// + public int Capacity + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get + { + EnsureNotClosed(); + return _handle->Capacity; + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + set + { + EnsureNotClosed(); + if (value < _handle->Length) + throw new ArgumentOutOfRangeException(nameof(Capacity), value, "SmallCapacity"); + if (value != _handle->Capacity) + { + if (value > 0) + { + var newBuffer = (byte*)NativeMemoryAllocator.Alloc((uint)value); + if (_handle->Length > 0) + Unsafe.CopyBlockUnaligned(newBuffer, _handle->Array, (uint)_handle->Length); + NativeMemoryAllocator.Free(_handle->Array); + _handle->Array = newBuffer; + } + else + { + NativeMemoryAllocator.Free(_handle->Array); + _handle->Array = (byte*)NativeMemoryAllocator.Alloc(0); + } + + _handle->Capacity = value; + } + } + } + + /// + /// Equals + /// + /// Other + /// Equals + public bool Equals(NativeMemoryStream other) => other == this; + + /// + /// Equals + /// + /// object + /// Equals + public override bool Equals(object? obj) => obj is NativeMemoryStream nativeMemoryStream && nativeMemoryStream == this; + + /// + /// Get hashCode + /// + /// HashCode + public override int GetHashCode() => (int)(nint)_handle; + + /// + /// To string + /// + /// String + public override string ToString() => $"NativeMemoryStream<{_handle->Length}>"; + + /// + /// As span + /// + /// Span + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator Span(NativeMemoryStream nativeList) => nativeList.AsSpan(); + + /// + /// As readOnly span + /// + /// ReadOnlySpan + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator ReadOnlySpan(NativeMemoryStream nativeList) => nativeList.AsReadOnlySpan(); + + /// + /// Equals + /// + /// Left + /// Right + /// Equals + public static bool operator ==(NativeMemoryStream left, NativeMemoryStream right) => left._handle == right._handle; + + /// + /// Not equals + /// + /// Left + /// Right + /// Not equals + public static bool operator !=(NativeMemoryStream left, NativeMemoryStream right) => left._handle != right._handle; + + /// + /// Dispose + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Dispose() + { + if (_handle == null) + return; + NativeMemoryAllocator.Free(_handle->Array); + NativeMemoryAllocator.Free(_handle); + } + + /// + /// As span + /// + /// Span + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Span AsSpan() => MemoryMarshal.CreateSpan(ref *_handle->Array, _handle->Length); + + /// + /// As span + /// + /// Length + /// Span + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Span AsSpan(int length) => MemoryMarshal.CreateSpan(ref *_handle->Array, length); + + /// + /// As span + /// + /// Start + /// Length + /// Span + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Span AsSpan(int start, int length) => MemoryMarshal.CreateSpan(ref *(_handle->Array + start), length); + + /// + /// As readOnly span + /// + /// ReadOnlySpan + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public ReadOnlySpan AsReadOnlySpan() => MemoryMarshal.CreateReadOnlySpan(ref *_handle->Array, _handle->Length); + + /// + /// As readOnly span + /// + /// Length + /// ReadOnlySpan + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public ReadOnlySpan AsReadOnlySpan(int length) => MemoryMarshal.CreateReadOnlySpan(ref *_handle->Array, length); + + /// + /// As readOnly span + /// + /// Start + /// Length + /// ReadOnlySpan + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public ReadOnlySpan AsReadOnlySpan(int start, int length) => MemoryMarshal.CreateReadOnlySpan(ref *(_handle->Array + start), length); + + /// + /// Get buffer + /// + /// Buffer + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public byte* GetBuffer() => _handle->Array; + + /// + /// Seek + /// + /// Offset + /// Seek origin + /// Position + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public int Seek(int offset, SeekOrigin loc) + { + if (offset > 2147483647) + throw new ArgumentOutOfRangeException(nameof(offset), offset, "StreamLength"); + EnsureNotClosed(); + switch (loc) + { + case SeekOrigin.Begin: + { + if (offset < 0) + throw new IOException("IO_SeekBeforeBegin"); + _handle->Position = offset; + break; + } + case SeekOrigin.Current: + { + var tempPosition = unchecked(_handle->Position + offset); + if (tempPosition < 0) + throw new IOException("IO_SeekBeforeBegin"); + _handle->Position = tempPosition; + break; + } + case SeekOrigin.End: + { + var tempPosition = unchecked(_handle->Length + offset); + if (tempPosition < 0) + throw new IOException("IO_SeekBeforeBegin"); + _handle->Position = tempPosition; + break; + } + default: + throw new ArgumentException("InvalidSeekOrigin"); + } + + return _handle->Position; + } + + /// + /// Set length + /// + /// Length + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void SetLength(int length) + { + if (length < 0 || length > 2147483647) + throw new ArgumentOutOfRangeException(nameof(length), length, "StreamLength"); + EnsureNotClosed(); + var allocatedNewArray = EnsureCapacity(length); + if (!allocatedNewArray && length > _handle->Length) + Unsafe.InitBlock(_handle->Array + _handle->Length, 0, (uint)(length - _handle->Length)); + _handle->Length = length; + if (_handle->Position > length) + _handle->Position = length; + } + + /// + /// Read + /// + /// Buffer + /// Offset + /// Count + /// Bytes + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public int Read(byte* buffer, int offset, int count) + { + EnsureNotClosed(); + var n = _handle->Length - _handle->Position; + if (n > count) + n = count; + if (n <= 0) + return 0; + if (n <= 8) + { + var byteCount = n; + while (--byteCount >= 0) + buffer[offset + byteCount] = _handle->Array[_handle->Position + byteCount]; + } + else + { + Unsafe.CopyBlockUnaligned(buffer + offset, _handle->Array + _handle->Position, (uint)n); + } + + _handle->Position += n; + return n; + } + + /// + /// Read + /// + /// Buffer + /// Bytes + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public int Read(Span buffer) + { + EnsureNotClosed(); + var size = _handle->Length - _handle->Position; + var n = size < buffer.Length ? size : buffer.Length; + if (n <= 0) + return 0; + Unsafe.CopyBlockUnaligned(ref buffer[0], ref *(_handle->Array + _handle->Position), (uint)n); + _handle->Position += n; + return n; + } + + /// + /// Read + /// + /// Byte + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public int ReadByte() + { + EnsureNotClosed(); + return _handle->Position >= _handle->Length ? -1 : _handle->Array[_handle->Position++]; + } + + /// + /// Write + /// + /// Buffer + /// Offset + /// Count + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Write(byte* buffer, int offset, int count) + { + EnsureNotClosed(); + var i = _handle->Position + count; + if (i < 0) + throw new IOException("IO_StreamTooLong"); + if (i > _handle->Length) + { + var mustZero = _handle->Position > _handle->Length; + if (i > _handle->Capacity) + { + var allocatedNewArray = EnsureCapacity(i); + if (allocatedNewArray) + mustZero = false; + } + + if (mustZero) + Unsafe.InitBlock(_handle->Array + _handle->Length, 0, (uint)(i - _handle->Length)); + _handle->Length = i; + } + + if (count <= 8 && buffer != _handle->Array) + { + var byteCount = count; + while (--byteCount >= 0) + _handle->Array[_handle->Position + byteCount] = buffer[offset + byteCount]; + } + else + { + Unsafe.CopyBlockUnaligned(_handle->Array + _handle->Position, buffer + offset, (uint)count); + } + + _handle->Position = i; + } + + /// + /// Write + /// + /// Buffer + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Write(ReadOnlySpan buffer) + { + EnsureNotClosed(); + var i = _handle->Position + buffer.Length; + if (i < 0) + throw new IOException("IO_StreamTooLong"); + if (i > _handle->Length) + { + var mustZero = _handle->Position > _handle->Length; + if (i > _handle->Capacity) + { + var allocatedNewArray = EnsureCapacity(i); + if (allocatedNewArray) + mustZero = false; + } + + if (mustZero) + Unsafe.InitBlock(_handle->Array + _handle->Length, 0, (uint)(i - _handle->Length)); + _handle->Length = i; + } + + Unsafe.CopyBlockUnaligned(ref *(_handle->Array + _handle->Position), ref MemoryMarshal.GetReference(buffer), (uint)buffer.Length); + _handle->Position = i; + } + + /// + /// Write + /// + /// Byte + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void WriteByte(byte value) + { + EnsureNotClosed(); + if (_handle->Position >= _handle->Length) + { + var newLength = _handle->Position + 1; + var mustZero = _handle->Position > _handle->Length; + if (newLength >= _handle->Capacity) + { + var allocatedNewArray = EnsureCapacity(newLength); + if (allocatedNewArray) + mustZero = false; + } + + if (mustZero) + Unsafe.InitBlock(_handle->Array + _handle->Length, 0, (uint)(_handle->Position - _handle->Length)); + _handle->Length = newLength; + } + + _handle->Array[_handle->Position++] = value; + } + + /// + /// Ensure capacity + /// + /// Capacity + /// Ensured + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private bool EnsureCapacity(int capacity) + { + if (capacity < 0) + throw new IOException("IO_StreamTooLong"); + if (capacity > _handle->Capacity) + { + var newCapacity = capacity > 256 ? capacity : 256; + if (newCapacity < _handle->Capacity * 2) + newCapacity = _handle->Capacity * 2; + if ((uint)(_handle->Capacity * 2) > 2147483591) + newCapacity = capacity > 2147483591 ? capacity : 2147483591; + Capacity = newCapacity; + return true; + } + + return false; + } + + /// + /// Ensure not closed + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void EnsureNotClosed() + { + if (_handle == null) + throw new ObjectDisposedException("StreamClosed"); + } + + /// + /// Empty + /// + public static NativeMemoryStream Empty => new(); + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeMemoryWriter.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeMemoryWriter.cs new file mode 100644 index 0000000..e5b8e20 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeMemoryWriter.cs @@ -0,0 +1,370 @@ +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +#if UNITY_2021_3_OR_NEWER || GODOT +using System; +#endif + +#pragma warning disable CA2208 +#pragma warning disable CS8632 + +// ReSharper disable ALL + +namespace NativeCollections +{ + /// + /// Native memory writer + /// + [StructLayout(LayoutKind.Sequential)] + public unsafe ref struct NativeMemoryWriter + { + /// + /// Array + /// + public readonly byte* Array; + + /// + /// Length + /// + public readonly int Length; + + /// + /// Position + /// + public int Position; + + /// + /// Structure + /// + /// Array + /// Length + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public NativeMemoryWriter(byte* array, int length) + { + if (length < 0) + throw new ArgumentOutOfRangeException(nameof(length), length, "MustBeNonNegative"); + Array = array; + Length = length; + Position = 0; + } + + /// + /// Remaining + /// + public int Remaining => Length - Position; + + /// + /// Get reference + /// + /// Index + public byte* this[int index] + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => Array + index; + } + + /// + /// Get reference + /// + /// Index + public byte* this[uint index] + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => Array + index; + } + + /// + /// Equals + /// + /// Other + /// Equals + public bool Equals(NativeMemoryWriter other) => other == this; + + /// + /// Equals + /// + /// object + /// Equals + public override bool Equals(object? obj) => throw new NotSupportedException("Cannot call Equals on NativeMemoryWriter"); + + /// + /// Get hashCode + /// + /// HashCode + public override int GetHashCode() => HashCode.Combine((int)(nint)Array, Length, Position); + + /// + /// To string + /// + /// String + public override string ToString() => "NativeMemoryWriter"; + + /// + /// Equals + /// + /// Left + /// Right + /// Equals + public static bool operator ==(NativeMemoryWriter left, NativeMemoryWriter right) => left.Array == right.Array && left.Length == right.Length && left.Position == right.Position; + + /// + /// Not equals + /// + /// Left + /// Right + /// Not equals + public static bool operator !=(NativeMemoryWriter left, NativeMemoryWriter right) => left.Array != right.Array || left.Length != right.Length || left.Position != right.Position; + + /// + /// Advance + /// + /// Count + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Advance(int count) + { + var newPosition = Position + count; + if (newPosition < 0 || newPosition > Length) + throw new ArgumentOutOfRangeException(nameof(count), "Cannot advance past the end of the buffer."); + Position = newPosition; + } + + /// + /// Try advance + /// + /// Count + /// Advanced + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool TryAdvance(int count) + { + var newPosition = Position + count; + if (newPosition < 0 || newPosition > Length) + return false; + Position = newPosition; + return true; + } + + /// + /// Write + /// + /// object + /// Type + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Write(T* obj) where T : unmanaged + { + if (Position + sizeof(T) > Length) + throw new ArgumentOutOfRangeException(nameof(T), $"Requires size is {sizeof(T)}, but buffer length is {Remaining}."); + Unsafe.CopyBlockUnaligned(Array + Position, obj, (uint)sizeof(T)); + Position += sizeof(T); + } + + /// + /// Try write + /// + /// object + /// Type + /// Wrote + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool TryWrite(T* obj) where T : unmanaged + { + if (Position + sizeof(T) > Length) + return false; + Unsafe.CopyBlockUnaligned(Array + Position, obj, (uint)sizeof(T)); + Position += sizeof(T); + return true; + } + + /// + /// Write + /// + /// object + /// Count + /// Type + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Write(T* obj, int count) where T : unmanaged + { + count *= sizeof(T); + if (Position + count > Length) + throw new ArgumentOutOfRangeException(nameof(T), $"Requires size is {count}, but buffer length is {Remaining}."); + Unsafe.CopyBlockUnaligned(Array + Position, obj, (uint)count); + Position += count; + } + + /// + /// Try write + /// + /// object + /// Count + /// Type + /// Wrote + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool TryWrite(T* obj, int count) where T : unmanaged + { + count *= sizeof(T); + if (Position + count > Length) + return false; + Unsafe.CopyBlockUnaligned(Array + Position, obj, (uint)count); + Position += count; + return true; + } + + /// + /// Write + /// + /// object + /// Type + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Write(in T obj) where T : unmanaged + { + if (Position + sizeof(T) > Length) + throw new ArgumentOutOfRangeException(nameof(T), $"Requires size is {sizeof(T)}, but buffer length is {Remaining}."); + Unsafe.WriteUnaligned(Array + Position, obj); + Position += sizeof(T); + } + + /// + /// Try write + /// + /// object + /// Type + /// Wrote + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool TryWrite(in T obj) where T : unmanaged + { + if (Position + sizeof(T) > Length) + return false; + Unsafe.WriteUnaligned(Array + Position, obj); + Position += sizeof(T); + return true; + } + + /// + /// Write bytes + /// + /// Buffer + /// Length + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void WriteBytes(byte* buffer, int length) + { + if (Position + length > Length) + throw new ArgumentOutOfRangeException(nameof(length), $"Requires size is {length}, but buffer length is {Remaining}."); + Unsafe.CopyBlockUnaligned(Array + Position, buffer, (uint)length); + Position += length; + } + + /// + /// Try write bytes + /// + /// Buffer + /// Length + /// Wrote + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool TryWriteBytes(byte* buffer, int length) + { + if (Position + length > Length) + return false; + Unsafe.CopyBlockUnaligned(Array + Position, buffer, (uint)length); + Position += length; + return true; + } + + /// + /// Clear + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Clear() => Position = 0; + + /// + /// As span + /// + /// Span + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Span AsSpan() => MemoryMarshal.CreateSpan(ref *Array, Position); + + /// + /// As span + /// + /// Length + /// Span + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Span AsSpan(int length) => MemoryMarshal.CreateSpan(ref *Array, length); + + /// + /// As span + /// + /// Start + /// Length + /// Span + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Span AsSpan(int start, int length) => MemoryMarshal.CreateSpan(ref *(Array + start), length); + + /// + /// As readOnly span + /// + /// ReadOnlySpan + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public ReadOnlySpan AsReadOnlySpan() => MemoryMarshal.CreateReadOnlySpan(ref *Array, Position); + + /// + /// As readOnly span + /// + /// Length + /// ReadOnlySpan + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public ReadOnlySpan AsReadOnlySpan(int length) => MemoryMarshal.CreateReadOnlySpan(ref *Array, length); + + /// + /// As readOnly span + /// + /// Start + /// Length + /// ReadOnlySpan + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public ReadOnlySpan AsReadOnlySpan(int start, int length) => MemoryMarshal.CreateReadOnlySpan(ref *(Array + start), length); + + /// + /// As span + /// + /// Span + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator Span(NativeMemoryWriter writer) => writer.AsSpan(); + + /// + /// As readOnly span + /// + /// ReadOnlySpan + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator ReadOnlySpan(NativeMemoryWriter writer) => writer.AsReadOnlySpan(); + + /// + /// As native memory reader + /// + /// NativeMemoryReader + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator NativeMemoryReader(NativeMemoryWriter writer) => new(writer.Array, writer.Position); + + /// + /// As native memory writer + /// + /// NativeMemoryWriter + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator NativeMemoryWriter(NativeArray writer) => new(writer.Array, writer.Length); + + /// + /// As native memory writer + /// + /// NativeMemoryWriter + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator NativeMemoryWriter(NativeMemoryArray writer) => new(writer.Array, writer.Length); + + /// + /// As native memory writer + /// + /// NativeMemoryWriter + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator NativeMemoryWriter(NativeArraySegment writer) => new(writer.Array + writer.Offset, writer.Count); + + /// + /// Empty + /// + public static NativeMemoryWriter Empty => new(); + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeMonitorLock.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeMonitorLock.cs new file mode 100644 index 0000000..47bf8a5 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeMonitorLock.cs @@ -0,0 +1,210 @@ +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +#if NET7_0_OR_GREATER +#endif + +#if UNITY_2021_3_OR_NEWER || GODOT +using System; +using System.Threading; +#endif + +#pragma warning disable CA2208 +#pragma warning disable CS8604 +#pragma warning disable CS8632 + +// ReSharper disable ALL + +namespace NativeCollections +{ + /// + /// Native monitorLock + /// + [StructLayout(LayoutKind.Sequential)] + public struct NativeMonitorLock : IDisposable, IEquatable + { + /// + /// Handle + /// + private GCHandle _handle; + + /// + /// Structure + /// + /// Value + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public NativeMonitorLock(object value) => _handle = GCHandle.Alloc(value, GCHandleType.Normal); + + /// + /// Structure + /// + /// Value + /// GCHandle type + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public NativeMonitorLock(object value, GCHandleType type) => _handle = GCHandle.Alloc(value, type); + + /// + /// Is created + /// + public bool IsCreated => _handle.IsAllocated; + + /// + /// Equals + /// + /// Other + /// Equals + public bool Equals(NativeMonitorLock other) => other == this; + + /// + /// Equals + /// + /// object + /// Equals + public override bool Equals(object? obj) => obj is NativeMonitorLock nativeMonitorLock && nativeMonitorLock == this; + + /// + /// Get hashCode + /// + /// HashCode + public override int GetHashCode() => (int)(nint)_handle; + + /// + /// To string + /// + /// String + public override string ToString() => "NativeMonitorLock"; + + /// + /// Equals + /// + /// Left + /// Right + /// Equals + public static bool operator ==(NativeMonitorLock left, NativeMonitorLock right) => left._handle == right._handle; + + /// + /// Not equals + /// + /// Left + /// Right + /// Not equals + public static bool operator !=(NativeMonitorLock left, NativeMonitorLock right) => left._handle != right._handle; + + /// + /// Dispose + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Dispose() + { + if (!_handle.IsAllocated) + return; + _handle.Free(); + } + + /// + /// Enter + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Enter() => Monitor.Enter(_handle.Target); + + /// + /// Enter + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Enter(ref bool lockTaken) => Monitor.Enter(_handle.Target, ref lockTaken); + + /// + /// Enter + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool TryEnter() => Monitor.TryEnter(_handle.Target); + + /// + /// Enter + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void TryEnter(ref bool lockTaken) => Monitor.TryEnter(_handle.Target, ref lockTaken); + + /// + /// Enter + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool TryEnter(int millisecondsTimeout) => Monitor.TryEnter(_handle.Target, millisecondsTimeout); + + /// + /// Enter + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void TryEnter(int millisecondsTimeout, ref bool lockTaken) => Monitor.TryEnter(_handle.Target, millisecondsTimeout, ref lockTaken); + + /// + /// Is entered + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool IsEntered() => Monitor.IsEntered(_handle.Target); + + /// + /// Wait + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool Wait(int millisecondsTimeout) => Monitor.Wait(_handle.Target, millisecondsTimeout); + + /// + /// Pulse + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Pulse() => Monitor.Pulse(_handle.Target); + + /// + /// Pulse all + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PulseAll() => Monitor.PulseAll(_handle.Target); + + /// + /// Try enter + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool TryEnter(TimeSpan timeout) => Monitor.TryEnter(_handle.Target, timeout); + + /// + /// Try enter + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void TryEnter(TimeSpan timeout, ref bool lockTaken) => Monitor.TryEnter(_handle.Target, timeout, ref lockTaken); + + /// + /// Wait + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool Wait(TimeSpan timeout) => Monitor.Wait(_handle.Target, timeout); + + /// + /// Wait + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool Wait() => Monitor.Wait(_handle.Target); + + /// + /// Wait + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool Wait(int millisecondsTimeout, bool exitContext) => Monitor.Wait(_handle.Target, millisecondsTimeout, exitContext); + + /// + /// Wait + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool Wait(TimeSpan timeout, bool exitContext) => Monitor.Wait(_handle.Target, timeout, exitContext); + + /// + /// Exit + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Exit() => Monitor.Exit(_handle.Target); + + /// + /// Empty + /// + public static NativeMonitorLock Empty => new(); + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativePriorityQueue.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativePriorityQueue.cs new file mode 100644 index 0000000..da6e60d --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativePriorityQueue.cs @@ -0,0 +1,618 @@ +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +#if UNITY_2021_3_OR_NEWER || GODOT +using System; +#endif + +#pragma warning disable CA2208 +#pragma warning disable CS8632 + +// ReSharper disable ALL + +namespace NativeCollections +{ + /// + /// Native priorityQueue + /// + /// Type + /// Type + [StructLayout(LayoutKind.Sequential)] + public readonly unsafe struct NativePriorityQueue : IDisposable, IEquatable> where TElement : unmanaged where TPriority : unmanaged, IComparable + { + /// + /// Handle + /// + [StructLayout(LayoutKind.Sequential)] + private struct NativePriorityQueueHandle + { + /// + /// Nodes + /// + public ValueTuple* Nodes; + + /// + /// Length + /// + public int Length; + + /// + /// Unordered items + /// + public UnorderedItemsCollection UnorderedItems; + + /// + /// Size + /// + public int Size; + + /// + /// Version + /// + public int Version; + } + + /// + /// Handle + /// + private readonly NativePriorityQueueHandle* _handle; + + /// + /// Structure + /// + /// Capacity + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public NativePriorityQueue(int capacity) + { + if (capacity < 0) + throw new ArgumentOutOfRangeException(nameof(capacity), capacity, "MustBeNonNegative"); + if (capacity < 4) + capacity = 4; + _handle = (NativePriorityQueueHandle*)NativeMemoryAllocator.Alloc((uint)sizeof(NativePriorityQueueHandle)); + _handle->Nodes = (ValueTuple*)NativeMemoryAllocator.Alloc((uint)(capacity * sizeof(ValueTuple))); + _handle->Length = capacity; + _handle->UnorderedItems = new UnorderedItemsCollection(this); + _handle->Size = 0; + _handle->Version = 0; + } + + /// + /// Is created + /// + public bool IsCreated => _handle != null; + + /// + /// Is empty + /// + public bool IsEmpty => _handle->Size == 0; + + /// + /// Get reference + /// + /// Index + public (TElement Element, TPriority Priority) this[int index] + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _handle->Nodes[index]; + } + + /// + /// Count + /// + public int Count => _handle->Size; + + /// + /// Unordered items + /// + public UnorderedItemsCollection UnorderedItems => _handle->UnorderedItems; + + /// + /// Equals + /// + /// Other + /// Equals + public bool Equals(NativePriorityQueue other) => other == this; + + /// + /// Equals + /// + /// object + /// Equals + public override bool Equals(object? obj) => obj is NativePriorityQueue nativeQueue && nativeQueue == this; + + /// + /// Get hashCode + /// + /// HashCode + public override int GetHashCode() => (int)(nint)_handle; + + /// + /// To string + /// + /// String + public override string ToString() => $"NativePriorityQueue<{typeof(TElement).Name}, {typeof(TPriority).Name}>"; + + /// + /// Equals + /// + /// Left + /// Right + /// Equals + public static bool operator ==(NativePriorityQueue left, NativePriorityQueue right) => left._handle == right._handle; + + /// + /// Not equals + /// + /// Left + /// Right + /// Not equals + public static bool operator !=(NativePriorityQueue left, NativePriorityQueue right) => left._handle != right._handle; + + /// + /// Dispose + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Dispose() + { + if (_handle == null) + return; + NativeMemoryAllocator.Free(_handle->Nodes); + NativeMemoryAllocator.Free(_handle); + } + + /// + /// Clear + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Clear() + { + _handle->Size = 0; + ++_handle->Version; + } + + /// + /// Enqueue + /// + /// Element + /// Priority + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Enqueue(in TElement element, in TPriority priority) + { + var size = _handle->Size; + ++_handle->Version; + if (_handle->Length == size) + Grow(size + 1); + _handle->Size = size + 1; + MoveUp(new ValueTuple(element, priority), size); + } + + /// + /// Try enqueue + /// + /// Element + /// Priority + /// Enqueued + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool TryEnqueue(in TElement element, in TPriority priority) + { + var size = _handle->Size; + ++_handle->Version; + if (_handle->Length != size) + { + _handle->Size = size + 1; + MoveUp(new ValueTuple(element, priority), size); + return true; + } + + return false; + } + + /// + /// Enqueue dequeue + /// + /// Element + /// Priority + /// Element + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public TElement EnqueueDequeue(in TElement element, in TPriority priority) + { + if (_handle->Size != 0) + { + var node = _handle->Nodes[0]; + if (priority.CompareTo(node.Item2) > 0) + { + MoveDown(new ValueTuple(element, priority), 0); + ++_handle->Version; + return node.Item1; + } + } + + return element; + } + + /// + /// Try enqueue dequeue + /// + /// Element + /// Priority + /// Element + /// Enqueued + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool TryEnqueueDequeue(in TElement element, in TPriority priority, out TElement result) + { + if (_handle->Size != 0) + { + var node = _handle->Nodes[0]; + if (priority.CompareTo(node.Item2) > 0) + { + MoveDown(new ValueTuple(element, priority), 0); + ++_handle->Version; + result = node.Item1; + return true; + } + } + + result = element; + return false; + } + + /// + /// Dequeue + /// + /// Item + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public TElement Dequeue() + { + if (_handle->Size == 0) + throw new InvalidOperationException("EmptyQueue"); + var element = _handle->Nodes[0].Item1; + RemoveRootNode(); + return element; + } + + /// + /// Try dequeue + /// + /// Element + /// Dequeued + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool TryDequeue(out TElement element) + { + if (_handle->Size != 0) + { + var tuple = _handle->Nodes[0]; + element = tuple.Item1; + RemoveRootNode(); + return true; + } + + element = default; + return false; + } + + /// + /// Try dequeue + /// + /// Element + /// Priority + /// Dequeued + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool TryDequeue(out TElement element, out TPriority priority) + { + if (_handle->Size != 0) + { + var tuple = _handle->Nodes[0]; + element = tuple.Item1; + priority = tuple.Item2; + RemoveRootNode(); + return true; + } + + element = default; + priority = default; + return false; + } + + /// + /// Dequeue enqueue + /// + /// Element + /// Priority + /// Element + public TElement DequeueEnqueue(in TElement element, in TPriority priority) + { + if (_handle->Size == 0) + throw new InvalidOperationException("EmptyQueue"); + var node = _handle->Nodes[0]; + if (priority.CompareTo(node.Item2) > 0) + MoveDown(new ValueTuple(element, priority), 0); + else + _handle->Nodes[0] = new ValueTuple(element, priority); + ++_handle->Version; + return node.Item1; + } + + /// + /// Try dequeue enqueue + /// + /// Element + /// Priority + /// Element + /// Dequeued + public bool TryDequeueEnqueue(in TElement element, in TPriority priority, out TElement result) + { + if (_handle->Size == 0) + { + result = default; + return false; + } + + var node = _handle->Nodes[0]; + if (priority.CompareTo(node.Item2) > 0) + MoveDown(new ValueTuple(element, priority), 0); + else + _handle->Nodes[0] = new ValueTuple(element, priority); + ++_handle->Version; + result = node.Item1; + return true; + } + + /// + /// Peek + /// + /// Item + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public TElement Peek() => _handle->Size == 0 ? throw new InvalidOperationException("EmptyQueue") : _handle->Nodes[0].Item1; + + /// + /// Try peek + /// + /// Element + /// Priority + /// Peeked + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool TryPeek(out TElement element, out TPriority priority) + { + if (_handle->Size != 0) + { + var tuple = _handle->Nodes[0]; + element = tuple.Item1; + priority = tuple.Item2; + return true; + } + + element = default; + priority = default; + return false; + } + + /// + /// Ensure capacity + /// + /// Capacity + /// New capacity + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public int EnsureCapacity(int capacity) + { + if (capacity < 0) + throw new ArgumentOutOfRangeException(nameof(capacity), capacity, "MustBeNonNegative"); + if (_handle->Length < capacity) + { + Grow(capacity); + ++_handle->Version; + } + + return _handle->Length; + } + + /// + /// Trim excess + /// + /// New capacity + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void TrimExcess() + { + if (_handle->Size >= (int)(_handle->Length * 0.9)) + return; + var nodes = (ValueTuple*)NativeMemoryAllocator.Alloc((uint)(_handle->Size * sizeof(ValueTuple))); + Unsafe.CopyBlockUnaligned(nodes, _handle->Nodes, (uint)_handle->Size); + NativeMemoryAllocator.Free(_handle->Nodes); + _handle->Nodes = nodes; + _handle->Length = _handle->Size; + ++_handle->Version; + } + + /// + /// Grow + /// + /// Capacity + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void Grow(int capacity) + { + var newCapacity = 2 * _handle->Length; + if ((uint)newCapacity > 2147483591) + newCapacity = 2147483591; + var expected = _handle->Length + 4; + newCapacity = newCapacity > expected ? newCapacity : expected; + if (newCapacity < capacity) + newCapacity = capacity; + var nodes = (ValueTuple*)NativeMemoryAllocator.Alloc((uint)(newCapacity * sizeof(ValueTuple))); + Unsafe.CopyBlockUnaligned(nodes, _handle->Nodes, (uint)_handle->Size); + NativeMemoryAllocator.Free(_handle->Nodes); + _handle->Nodes = nodes; + _handle->Length = newCapacity; + } + + /// + /// Remove root node + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void RemoveRootNode() + { + var index = --_handle->Size; + ++_handle->Version; + if (index > 0) + { + var node = _handle->Nodes[index]; + MoveDown(node, 0); + } + } + + /// + /// Move up + /// + /// Node + /// Node index + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void MoveUp(in ValueTuple node, int nodeIndex) + { + var nodes = _handle->Nodes; + int parentIndex; + for (; nodeIndex > 0; nodeIndex = parentIndex) + { + parentIndex = (nodeIndex - 1) >> 2; + var tuple = nodes[parentIndex]; + if (node.Item2.CompareTo(tuple.Item2) < 0) + nodes[nodeIndex] = tuple; + else + break; + } + + nodes[nodeIndex] = node; + } + + /// + /// Move down + /// + /// Node + /// Node index + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void MoveDown(in ValueTuple node, int nodeIndex) + { + var nodes = _handle->Nodes; + int firstChildIndex; + int first; + for (var size = _handle->Size; (firstChildIndex = (nodeIndex << 2) + 1) < size; nodeIndex = first) + { + var valueTuple = nodes[firstChildIndex]; + first = firstChildIndex; + var minSize = firstChildIndex + 4; + var second = minSize <= size ? minSize : size; + while (++firstChildIndex < second) + { + var tuple = nodes[firstChildIndex]; + if (tuple.Item2.CompareTo(valueTuple.Item2) < 0) + { + valueTuple = tuple; + first = firstChildIndex; + } + } + + if (node.Item2.CompareTo(valueTuple.Item2) > 0) + nodes[nodeIndex] = valueTuple; + else + break; + } + + nodes[nodeIndex] = node; + } + + /// + /// Empty + /// + public static NativePriorityQueue Empty => new(); + + /// + /// Unordered items collection + /// + [StructLayout(LayoutKind.Sequential)] + public readonly struct UnorderedItemsCollection + { + /// + /// NativePriorityQueue + /// + private readonly NativePriorityQueue _nativePriorityQueue; + + /// + /// Structure + /// + /// Native priorityQueue + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal UnorderedItemsCollection(NativePriorityQueue nativePriorityQueue) => _nativePriorityQueue = nativePriorityQueue; + + /// + /// Get enumerator + /// + /// Enumerator + public Enumerator GetEnumerator() => new(_nativePriorityQueue); + + /// + /// Enumerator + /// + public struct Enumerator + { + /// + /// NativePriorityQueue + /// + private readonly NativePriorityQueue _nativePriorityQueue; + + /// + /// Version + /// + private readonly int _version; + + /// + /// Index + /// + private int _index; + + /// + /// Current + /// + private ValueTuple _current; + + /// + /// Structure + /// + /// Native priorityQueue + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal Enumerator(NativePriorityQueue nativePriorityQueue) + { + _nativePriorityQueue = nativePriorityQueue; + _index = 0; + _version = nativePriorityQueue._handle->Version; + _current = default; + } + + /// + /// Move next + /// + /// Moved + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool MoveNext() + { + if (_version != _nativePriorityQueue._handle->Version) + throw new InvalidOperationException("EnumFailedVersion"); + if ((uint)_index >= (uint)_nativePriorityQueue._handle->Size) + { + _index = _nativePriorityQueue._handle->Size + 1; + _current = default; + return false; + } + + _current = _nativePriorityQueue._handle->Nodes[_index]; + ++_index; + return true; + } + + /// + /// Current + /// + public (TElement Element, TPriority Priority) Current + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _current; + } + } + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeQueue.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeQueue.cs new file mode 100644 index 0000000..689ff66 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeQueue.cs @@ -0,0 +1,455 @@ +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +#if UNITY_2021_3_OR_NEWER || GODOT +using System; +#endif + +#pragma warning disable CA2208 +#pragma warning disable CS8632 + +// ReSharper disable ALL + +namespace NativeCollections +{ + /// + /// Native queue + /// + /// Type + [StructLayout(LayoutKind.Sequential)] + public readonly unsafe struct NativeQueue : IDisposable, IEquatable> where T : unmanaged + { + /// + /// Handle + /// + [StructLayout(LayoutKind.Sequential)] + private struct NativeQueueHandle + { + /// + /// Array + /// + public T* Array; + + /// + /// Length + /// + public int Length; + + /// + /// Head + /// + public int Head; + + /// + /// Tail + /// + public int Tail; + + /// + /// Size + /// + public int Size; + + /// + /// Version + /// + public int Version; + } + + /// + /// Handle + /// + private readonly NativeQueueHandle* _handle; + + /// + /// Structure + /// + /// Capacity + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public NativeQueue(int capacity) + { + if (capacity < 0) + throw new ArgumentOutOfRangeException(nameof(capacity), capacity, "MustBeNonNegative"); + if (capacity < 4) + capacity = 4; + _handle = (NativeQueueHandle*)NativeMemoryAllocator.Alloc((uint)sizeof(NativeQueueHandle)); + _handle->Array = (T*)NativeMemoryAllocator.Alloc((uint)(capacity * sizeof(T))); + _handle->Length = capacity; + _handle->Head = 0; + _handle->Tail = 0; + _handle->Size = 0; + _handle->Version = 0; + } + + /// + /// Is created + /// + public bool IsCreated => _handle != null; + + /// + /// Is empty + /// + public bool IsEmpty => _handle->Size == 0; + + /// + /// Get reference + /// + /// Index + public ref T this[int index] + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => ref _handle->Array[index]; + } + + /// + /// Get reference + /// + /// Index + public ref T this[uint index] + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => ref _handle->Array[index]; + } + + /// + /// Count + /// + public int Count => _handle->Size; + + /// + /// Equals + /// + /// Other + /// Equals + public bool Equals(NativeQueue other) => other == this; + + /// + /// Equals + /// + /// object + /// Equals + public override bool Equals(object? obj) => obj is NativeQueue nativeQueue && nativeQueue == this; + + /// + /// Get hashCode + /// + /// HashCode + public override int GetHashCode() => (int)(nint)_handle; + + /// + /// To string + /// + /// String + public override string ToString() => $"NativeQueue<{typeof(T).Name}>"; + + /// + /// Equals + /// + /// Left + /// Right + /// Equals + public static bool operator ==(NativeQueue left, NativeQueue right) => left._handle == right._handle; + + /// + /// Not equals + /// + /// Left + /// Right + /// Not equals + public static bool operator !=(NativeQueue left, NativeQueue right) => left._handle != right._handle; + + /// + /// Dispose + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Dispose() + { + if (_handle == null) + return; + NativeMemoryAllocator.Free(_handle->Array); + NativeMemoryAllocator.Free(_handle); + } + + /// + /// Clear + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Clear() + { + _handle->Size = 0; + _handle->Head = 0; + _handle->Tail = 0; + _handle->Version++; + } + + /// + /// Enqueue + /// + /// Item + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Enqueue(in T item) + { + if (_handle->Size == _handle->Length) + Grow(_handle->Size + 1); + _handle->Array[_handle->Tail] = item; + MoveNext(ref _handle->Tail); + _handle->Size++; + _handle->Version++; + } + + /// + /// Try enqueue + /// + /// Item + /// Enqueued + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool TryEnqueue(in T item) + { + if (_handle->Size != _handle->Length) + { + _handle->Array[_handle->Tail] = item; + MoveNext(ref _handle->Tail); + _handle->Size++; + _handle->Version++; + return true; + } + + return false; + } + + /// + /// Dequeue + /// + /// Item + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public T Dequeue() + { + if (_handle->Size == 0) + throw new InvalidOperationException("EmptyQueue"); + var removed = _handle->Array[_handle->Head]; + MoveNext(ref _handle->Head); + _handle->Size--; + _handle->Version++; + return removed; + } + + /// + /// Try dequeue + /// + /// Item + /// Dequeued + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool TryDequeue(out T result) + { + if (_handle->Size == 0) + { + result = default; + return false; + } + + result = _handle->Array[_handle->Head]; + MoveNext(ref _handle->Head); + _handle->Size--; + _handle->Version++; + return true; + } + + /// + /// Peek + /// + /// Item + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public T Peek() => _handle->Size == 0 ? throw new InvalidOperationException("EmptyQueue") : _handle->Array[_handle->Head]; + + /// + /// Try peek + /// + /// Item + /// Peeked + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool TryPeek(out T result) + { + if (_handle->Size == 0) + { + result = default; + return false; + } + + result = _handle->Array[_handle->Head]; + return true; + } + + /// + /// Ensure capacity + /// + /// Capacity + /// New capacity + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public int EnsureCapacity(int capacity) + { + if (capacity < 0) + throw new ArgumentOutOfRangeException(nameof(capacity), capacity, "MustBeNonNegative"); + if (_handle->Length < capacity) + Grow(capacity); + return _handle->Length; + } + + /// + /// Trim excess + /// + /// New capacity + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public int TrimExcess() + { + var threshold = (int)(_handle->Length * 0.9); + if (_handle->Size < threshold) + SetCapacity(_handle->Size); + return _handle->Length; + } + + /// + /// Set capacity + /// + /// Capacity + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void SetCapacity(int capacity) + { + var newArray = (T*)NativeMemoryAllocator.Alloc((uint)(capacity * sizeof(T))); + if (_handle->Size > 0) + { + if (_handle->Head < _handle->Tail) + { + Unsafe.CopyBlockUnaligned(newArray, _handle->Array + _handle->Head, (uint)(_handle->Size * sizeof(T))); + } + else + { + Unsafe.CopyBlockUnaligned(newArray, _handle->Array + _handle->Head, (uint)((_handle->Length - _handle->Head) * sizeof(T))); + Unsafe.CopyBlockUnaligned(newArray + _handle->Length - _handle->Head, _handle->Array, (uint)(_handle->Tail * sizeof(T))); + } + } + + NativeMemoryAllocator.Free(_handle->Array); + _handle->Array = newArray; + _handle->Length = capacity; + _handle->Head = 0; + _handle->Tail = _handle->Size == capacity ? 0 : _handle->Size; + _handle->Version++; + } + + /// + /// Grow + /// + /// Capacity + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void Grow(int capacity) + { + var newCapacity = 2 * _handle->Length; + if ((uint)newCapacity > 2147483591) + newCapacity = 2147483591; + var expected = _handle->Length + 4; + newCapacity = newCapacity > expected ? newCapacity : expected; + if (newCapacity < capacity) + newCapacity = capacity; + SetCapacity(newCapacity); + } + + /// + /// Move next + /// + /// Index + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void MoveNext(ref int index) + { + var tmp = index + 1; + if (tmp == _handle->Length) + tmp = 0; + index = tmp; + } + + /// + /// Empty + /// + public static NativeQueue Empty => new(); + + /// + /// Get enumerator + /// + /// Enumerator + public Enumerator GetEnumerator() => new(this); + + /// + /// Enumerator + /// + public struct Enumerator + { + /// + /// NativeQueue + /// + private readonly NativeQueue _nativeQueue; + + /// + /// Version + /// + private readonly int _version; + + /// + /// Index + /// + private int _index; + + /// + /// Current + /// + private T _currentElement; + + /// + /// Structure + /// + /// NativeQueue + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal Enumerator(in NativeQueue nativeQueue) + { + _nativeQueue = nativeQueue; + _version = nativeQueue._handle->Version; + _index = -1; + _currentElement = default; + } + + /// + /// Move next + /// + /// Moved + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool MoveNext() + { + if (_version != _nativeQueue._handle->Version) + throw new InvalidOperationException("EnumFailedVersion"); + if (_index == -2) + return false; + _index++; + if (_index == _nativeQueue._handle->Size) + { + _index = -2; + _currentElement = default; + return false; + } + + var array = _nativeQueue._handle->Array; + var capacity = (uint)_nativeQueue._handle->Length; + var arrayIndex = (uint)(_nativeQueue._handle->Head + _index); + if (arrayIndex >= capacity) + arrayIndex -= capacity; + _currentElement = array[arrayIndex]; + return true; + } + + /// + /// Current + /// + public T Current + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _index < 0 ? throw new InvalidOperationException(_index == -1 ? "EnumNotStarted" : "EnumEnded") : _currentElement; + } + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeReference.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeReference.cs new file mode 100644 index 0000000..76ffcc9 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeReference.cs @@ -0,0 +1,149 @@ +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +#if UNITY_2021_3_OR_NEWER || GODOT +using System; +#endif + +#pragma warning disable CA2208 +#pragma warning disable CS8632 + +// ReSharper disable ALL + +namespace NativeCollections +{ + /// + /// Native reference + /// + /// Type + [StructLayout(LayoutKind.Sequential)] + public readonly unsafe struct NativeReference : IDisposable, IEquatable> where T : unmanaged + { + /// + /// Handle + /// + private readonly T* _handle; + + /// + /// Structure + /// + /// Handle + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public NativeReference(T* handle) => _handle = handle; + + /// + /// Structure + /// + /// Handle + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public NativeReference(nint handle) => _handle = (T*)handle; + + /// + /// Is created + /// + public bool IsCreated => _handle != null; + + /// + /// Handle + /// + public T* Handle + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _handle; + } + + /// + /// Value + /// + public ref T Value + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => ref *_handle; + } + + /// + /// Equals + /// + /// Other + /// Equals + public bool Equals(NativeReference other) => other == this; + + /// + /// Equals + /// + /// object + /// Equals + public override bool Equals(object? obj) => obj is NativeReference nativeReference && nativeReference == this; + + /// + /// Get hashCode + /// + /// HashCode + public override int GetHashCode() => (int)(nint)_handle; + + /// + /// To string + /// + /// String + public override string ToString() => $"NativeReference<{typeof(T).Name}>"; + + /// + /// As reference + /// + /// NativeReference + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator NativeReference(T* handle) => new(handle); + + /// + /// As handle + /// + /// Handle + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator T*(NativeReference nativeReference) => nativeReference._handle; + + /// + /// As reference + /// + /// NativeReference + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator NativeReference(nint handle) => new((T*)handle); + + /// + /// As handle + /// + /// Handle + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator nint(NativeReference nativeReference) => (nint)nativeReference._handle; + + /// + /// Equals + /// + /// Left + /// Right + /// Equals + public static bool operator ==(NativeReference left, NativeReference right) => left._handle == right._handle; + + /// + /// Not equals + /// + /// Left + /// Right + /// Not equals + public static bool operator !=(NativeReference left, NativeReference right) => left._handle != right._handle; + + /// + /// Dispose + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Dispose() + { + if (_handle == null) + return; + NativeMemoryAllocator.Free(_handle); + } + + /// + /// Empty + /// + public static NativeReference Empty => new(); + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeSortedDictionary.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeSortedDictionary.cs new file mode 100644 index 0000000..42de38c --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeSortedDictionary.cs @@ -0,0 +1,1262 @@ +#if UNITY_2021_3_OR_NEWER || GODOT +using System; +using System.Collections.Generic; +#endif +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +#if NET5_0_OR_GREATER +#endif + +#pragma warning disable CA2208 +#pragma warning disable CS8632 + +// ReSharper disable ALL + +namespace NativeCollections +{ + /// + /// Native dictionary + /// + /// Type + /// Type + [StructLayout(LayoutKind.Sequential)] + public readonly unsafe struct NativeSortedDictionary : IDisposable, IEquatable> where TKey : unmanaged, IComparable where TValue : unmanaged + { + /// + /// Handle + /// + [StructLayout(LayoutKind.Sequential)] + private struct NativeSortedDictionaryHandle + { + /// + /// Root + /// + public Node* Root; + + /// + /// Count + /// + public int Count; + + /// + /// Version + /// + public int Version; + + /// + /// Node pool + /// + public NativeMemoryPool NodePool; + + /// + /// Keys + /// + public KeyCollection Keys; + + /// + /// Values + /// + public ValueCollection Values; + } + + /// + /// Handle + /// + private readonly NativeSortedDictionaryHandle* _handle; + + /// + /// Keys + /// + public KeyCollection Keys => _handle->Keys; + + /// + /// Values + /// + public ValueCollection Values => _handle->Values; + + /// + /// Structure + /// + /// MemoryPool size + /// MemoryPool maxFreeSlabs + public NativeSortedDictionary(int size, int maxFreeSlabs) + { + var nodePool = new NativeMemoryPool(size, sizeof(Node), maxFreeSlabs); + _handle = (NativeSortedDictionaryHandle*)NativeMemoryAllocator.Alloc((uint)sizeof(NativeSortedDictionaryHandle)); + _handle->Root = null; + _handle->Count = 0; + _handle->Version = 0; + _handle->NodePool = nodePool; + _handle->Keys = new KeyCollection(this); + _handle->Values = new ValueCollection(this); + } + + /// + /// Is created + /// + public bool IsCreated => _handle != null; + + /// + /// Is empty + /// + public bool IsEmpty => _handle->Count == 0; + + /// + /// Count + /// + public int Count => _handle->Count; + + /// + /// Min + /// + public KeyValuePair? Min + { + get + { + if (_handle->Root == null) + return default; + var current = _handle->Root; + while (current->Left != null) + current = current->Left; + return new KeyValuePair(current->Key, current->Value); + } + } + + /// + /// Max + /// + public KeyValuePair? Max + { + get + { + if (_handle->Root == null) + return default; + var current = _handle->Root; + while (current->Right != null) + current = current->Right; + return new KeyValuePair(current->Key, current->Value); + } + } + + /// + /// Get or set value + /// + /// Key + public TValue this[in TKey key] + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get + { + if (!TryGetValue(key, out var value)) + throw new KeyNotFoundException(key.ToString()); + return value; + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + set + { + var node = FindNode(key); + if (node == null) + { + Add(key, value); + } + else + { + node->Value = value; + _handle->Version++; + } + } + } + + /// + /// Equals + /// + /// Other + /// Equals + public bool Equals(NativeSortedDictionary other) => other == this; + + /// + /// Equals + /// + /// object + /// Equals + public override bool Equals(object? obj) => obj is NativeSortedDictionary nativeSortedDictionary && nativeSortedDictionary == this; + + /// + /// Get hashCode + /// + /// HashCode + public override int GetHashCode() => (int)(nint)_handle; + + /// + /// To string + /// + /// String + public override string ToString() => $"NativeSortedDictionary<{typeof(TKey).Name}, {typeof(TValue).Name}>"; + + /// + /// Equals + /// + /// Left + /// Right + /// Equals + public static bool operator ==(NativeSortedDictionary left, NativeSortedDictionary right) => left._handle == right._handle; + + /// + /// Not equals + /// + /// Left + /// Right + /// Not equals + public static bool operator !=(NativeSortedDictionary left, NativeSortedDictionary right) => left._handle != right._handle; + + /// + /// Dispose + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Dispose() + { + if (_handle == null) + return; + _handle->NodePool.Dispose(); + NativeMemoryAllocator.Free(_handle); + } + + /// + /// Clear + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Clear() + { + if (_handle->Root != null) + { + var nodeStack = new NativeStack(2 * Log2(_handle->Count + 1)); + nodeStack.Push((nint)_handle->Root); + while (nodeStack.TryPop(out var node)) + { + var currentNode = (Node*)node; + if (currentNode->Left != null) + nodeStack.Push((nint)currentNode->Left); + if (currentNode->Right != null) + nodeStack.Push((nint)currentNode->Right); + _handle->NodePool.Return(currentNode); + } + + nodeStack.Dispose(); + } + + _handle->Root = null; + _handle->Count = 0; + ++_handle->Version; + } + + /// + /// Add + /// + /// Key + /// Value + /// Added + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool Add(in TKey key, in TValue value) + { + if (_handle->Root == null) + { + _handle->Root = (Node*)_handle->NodePool.Rent(); + _handle->Root->Key = key; + _handle->Root->Value = value; + _handle->Root->Left = null; + _handle->Root->Right = null; + _handle->Root->Color = NodeColor.Black; + _handle->Count = 1; + _handle->Version++; + return true; + } + + var current = _handle->Root; + Node* parent = null; + Node* grandParent = null; + Node* greatGrandParent = null; + _handle->Version++; + var order = 0; + while (current != null) + { + order = key.CompareTo(current->Key); + if (order == 0) + { + _handle->Root->ColorBlack(); + return false; + } + + if (current->Is4Node) + { + current->Split4Node(); + if (Node.IsNonNullRed(parent)) + InsertionBalance(current, parent, grandParent, greatGrandParent); + } + + greatGrandParent = grandParent; + grandParent = parent; + parent = current; + current = order < 0 ? current->Left : current->Right; + } + + var node = (Node*)_handle->NodePool.Rent(); + node->Key = key; + node->Value = value; + node->Left = null; + node->Right = null; + node->Color = NodeColor.Red; + if (order > 0) + parent->Right = node; + else + parent->Left = node; + if (parent->IsRed) + InsertionBalance(node, parent, grandParent, greatGrandParent); + _handle->Root->ColorBlack(); + ++_handle->Count; + return true; + } + + /// + /// Remove + /// + /// Key + /// Removed + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool Remove(in TKey key) + { + if (_handle->Root == null) + return false; + _handle->Version++; + var current = _handle->Root; + Node* parent = null; + Node* grandParent = null; + Node* match = null; + Node* parentOfMatch = null; + var foundMatch = false; + while (current != null) + { + if (current->Is2Node) + { + if (parent == null) + { + current->ColorRed(); + } + else + { + var sibling = parent->GetSibling(current); + if (sibling->IsRed) + { + if (parent->Right == sibling) + parent->RotateLeft(); + else + parent->RotateRight(); + parent->ColorRed(); + sibling->ColorBlack(); + ReplaceChildOrRoot(grandParent, parent, sibling); + grandParent = sibling; + if (parent == match) + parentOfMatch = sibling; + sibling = parent->GetSibling(current); + } + + if (sibling->Is2Node) + { + parent->Merge2Nodes(); + } + else + { + var newGrandParent = parent->Rotate(parent->GetRotation(current, sibling)); + newGrandParent->Color = parent->Color; + parent->ColorBlack(); + current->ColorRed(); + ReplaceChildOrRoot(grandParent, parent, newGrandParent); + if (parent == match) + parentOfMatch = newGrandParent; + } + } + } + + var order = foundMatch ? -1 : key.CompareTo(current->Key); + if (order == 0) + { + foundMatch = true; + match = current; + parentOfMatch = parent; + } + + grandParent = parent; + parent = current; + current = order < 0 ? current->Left : current->Right; + } + + if (match != null) + { + ReplaceNode(match, parentOfMatch, parent, grandParent); + --_handle->Count; + _handle->NodePool.Return(match); + } + + if (_handle->Root != null) + _handle->Root->ColorBlack(); + return foundMatch; + } + + /// + /// Remove + /// + /// Key + /// Value + /// Removed + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool Remove(in TKey key, out TValue value) + { + if (_handle->Root == null) + { + value = default; + return false; + } + + _handle->Version++; + var current = _handle->Root; + Node* parent = null; + Node* grandParent = null; + Node* match = null; + Node* parentOfMatch = null; + var foundMatch = false; + while (current != null) + { + if (current->Is2Node) + { + if (parent == null) + { + current->ColorRed(); + } + else + { + var sibling = parent->GetSibling(current); + if (sibling->IsRed) + { + if (parent->Right == sibling) + parent->RotateLeft(); + else + parent->RotateRight(); + parent->ColorRed(); + sibling->ColorBlack(); + ReplaceChildOrRoot(grandParent, parent, sibling); + grandParent = sibling; + if (parent == match) + parentOfMatch = sibling; + sibling = parent->GetSibling(current); + } + + if (sibling->Is2Node) + { + parent->Merge2Nodes(); + } + else + { + var newGrandParent = parent->Rotate(parent->GetRotation(current, sibling)); + newGrandParent->Color = parent->Color; + parent->ColorBlack(); + current->ColorRed(); + ReplaceChildOrRoot(grandParent, parent, newGrandParent); + if (parent == match) + parentOfMatch = newGrandParent; + } + } + } + + var order = foundMatch ? -1 : key.CompareTo(current->Key); + if (order == 0) + { + foundMatch = true; + match = current; + parentOfMatch = parent; + } + + grandParent = parent; + parent = current; + current = order < 0 ? current->Left : current->Right; + } + + if (match != null) + { + value = match->Value; + ReplaceNode(match, parentOfMatch, parent, grandParent); + --_handle->Count; + _handle->NodePool.Return(match); + } + else + { + value = default; + } + + if (_handle->Root != null) + _handle->Root->ColorBlack(); + return foundMatch; + } + + /// + /// Contains key + /// + /// Key + /// Contains key + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool ContainsKey(in TKey key) => FindNode(key) != null; + + /// + /// Try to get the actual value + /// + /// Key + /// Value + /// Got + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool TryGetValue(in TKey key, out TValue value) + { + var node = FindNode(key); + if (node != null) + { + value = node->Value; + return true; + } + + value = default; + return false; + } + + /// + /// Insertion balance + /// + /// Current + /// Parent + /// Grand parent + /// GreatGrand parent + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void InsertionBalance(Node* current, Node* parent, Node* grandParent, Node* greatGrandParent) + { + var parentIsOnRight = grandParent->Right == parent; + var currentIsOnRight = parent->Right == current; + Node* newChildOfGreatGrandParent; + if (parentIsOnRight == currentIsOnRight) + newChildOfGreatGrandParent = currentIsOnRight ? grandParent->RotateLeft() : grandParent->RotateRight(); + else + newChildOfGreatGrandParent = currentIsOnRight ? grandParent->RotateLeftRight() : grandParent->RotateRightLeft(); + grandParent->ColorRed(); + newChildOfGreatGrandParent->ColorBlack(); + ReplaceChildOrRoot(greatGrandParent, grandParent, newChildOfGreatGrandParent); + } + + /// + /// Replace child or root + /// + /// Parent + /// Child + /// New child + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void ReplaceChildOrRoot(Node* parent, Node* child, Node* newChild) + { + if (parent != null) + parent->ReplaceChild(child, newChild); + else + _handle->Root = newChild; + } + + /// + /// Replace node + /// + /// Match + /// Parent of match + /// Successor + /// Parent of successor + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void ReplaceNode(Node* match, Node* parentOfMatch, Node* successor, Node* parentOfSuccessor) + { + if (successor == match) + { + successor = match->Left; + } + else + { + if (successor->Right != null) + successor->Right->ColorBlack(); + if (parentOfSuccessor != match) + { + parentOfSuccessor->Left = successor->Right; + successor->Right = match->Right; + } + + successor->Left = match->Left; + } + + if (successor != null) + successor->Color = match->Color; + ReplaceChildOrRoot(parentOfMatch, match, successor); + } + + /// + /// Find node + /// + /// Key + /// Node + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private Node* FindNode(in TKey key) + { + var current = _handle->Root; + while (current != null) + { + var order = key.CompareTo(current->Key); + if (order == 0) + return current; + current = order < 0 ? current->Left : current->Right; + } + + return null; + } + + /// + /// Log2 + /// + /// Value + /// Log2 + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static int Log2(int value) => BitOperationsHelpers.Log2(value); + + /// + /// Node + /// + [StructLayout(LayoutKind.Sequential)] + private struct Node + { + /// + /// Is non null red + /// + /// Node + /// Is non null red + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool IsNonNullRed(Node* node) => node != null && node->IsRed; + + /// + /// Is null or black + /// + /// Node + /// Is null or black + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static bool IsNullOrBlack(Node* node) => node == null || node->IsBlack; + + /// + /// Key + /// + public TKey Key + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + set; + } + + /// + /// Value + /// + public TValue Value + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + set; + } + + /// + /// Left + /// + public Node* Left + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + set; + } + + /// + /// Right + /// + public Node* Right + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + set; + } + + /// + /// Color + /// + public NodeColor Color + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + set; + } + + /// + /// Is black + /// + private bool IsBlack + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => Color == NodeColor.Black; + } + + /// + /// Is red + /// + public bool IsRed + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => Color == NodeColor.Red; + } + + /// + /// Is 2 node + /// + public bool Is2Node + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => IsBlack && IsNullOrBlack(Left) && IsNullOrBlack(Right); + } + + /// + /// Is 4 node + /// + public bool Is4Node + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => IsNonNullRed(Left) && IsNonNullRed(Right); + } + + /// + /// Set color to black + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ColorBlack() => Color = NodeColor.Black; + + /// + /// Set color to red + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ColorRed() => Color = NodeColor.Red; + + /// + /// Get rotation + /// + /// Current + /// Sibling + /// Rotation + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public TreeRotation GetRotation(Node* current, Node* sibling) + { + var currentIsLeftChild = Left == current; + return IsNonNullRed(sibling->Left) ? currentIsLeftChild ? TreeRotation.RightLeft : TreeRotation.Right : currentIsLeftChild ? TreeRotation.Left : TreeRotation.LeftRight; + } + + /// + /// Get sibling + /// + /// Node + /// Sibling + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Node* GetSibling(Node* node) => node == Left ? Right : Left; + + /// + /// Split 4 node + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Split4Node() + { + ColorRed(); + Left->ColorBlack(); + Right->ColorBlack(); + } + + /// + /// Rotate + /// + /// Rotation + /// Node + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Node* Rotate(TreeRotation rotation) + { + Node* removeRed; + switch (rotation) + { + case TreeRotation.Right: + removeRed = Left->Left; + removeRed->ColorBlack(); + return RotateRight(); + case TreeRotation.Left: + removeRed = Right->Right; + removeRed->ColorBlack(); + return RotateLeft(); + case TreeRotation.RightLeft: + return RotateRightLeft(); + case TreeRotation.LeftRight: + return RotateLeftRight(); + default: + return null; + } + } + + /// + /// Rotate left + /// + /// Node + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Node* RotateLeft() + { + var child = Right; + Right = child->Left; + child->Left = (Node*)Unsafe.AsPointer(ref this); + return child; + } + + /// + /// Rotate left right + /// + /// Node + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Node* RotateLeftRight() + { + var child = Left; + var grandChild = child->Right; + Left = grandChild->Right; + grandChild->Right = (Node*)Unsafe.AsPointer(ref this); + child->Right = grandChild->Left; + grandChild->Left = child; + return grandChild; + } + + /// + /// Rotate right + /// + /// Node + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Node* RotateRight() + { + var child = Left; + Left = child->Right; + child->Right = (Node*)Unsafe.AsPointer(ref this); + return child; + } + + /// + /// Rotate right left + /// + /// Node + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Node* RotateRightLeft() + { + var child = Right; + var grandChild = child->Left; + Right = grandChild->Left; + grandChild->Left = (Node*)Unsafe.AsPointer(ref this); + child->Left = grandChild->Right; + grandChild->Right = child; + return grandChild; + } + + /// + /// Merge 2 nodes + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Merge2Nodes() + { + ColorBlack(); + Left->ColorRed(); + Right->ColorRed(); + } + + /// + /// Replace child + /// + /// Child + /// New child + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ReplaceChild(Node* child, Node* newChild) + { + if (Left == child) + Left = newChild; + else + Right = newChild; + } + } + + /// + /// Empty + /// + public static NativeSortedDictionary Empty => new(); + + /// + /// Get enumerator + /// + /// Enumerator + public Enumerator GetEnumerator() => new(this); + + /// + /// Enumerator + /// + public struct Enumerator : IDisposable + { + /// + /// NativeHashSet + /// + private readonly NativeSortedDictionary _nativeSortedDictionary; + + /// + /// Version + /// + private readonly int _version; + + /// + /// Node stack + /// + private readonly NativeStack _nodeStack; + + /// + /// Current + /// + private Node* _currentNode; + + /// + /// Current + /// + private KeyValuePair _current; + + /// + /// Structure + /// + /// NativeSortedDictionary + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal Enumerator(NativeSortedDictionary nativeSortedDictionary) + { + _nativeSortedDictionary = nativeSortedDictionary; + _version = nativeSortedDictionary._handle->Version; + _nodeStack = new NativeStack(2 * Log2(nativeSortedDictionary.Count + 1)); + _currentNode = null; + _current = default; + var node = _nativeSortedDictionary._handle->Root; + while (node != null) + { + var next = node->Left; + _nodeStack.Push((nint)node); + node = next; + } + } + + /// + /// Move next + /// + /// Moved + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool MoveNext() + { + if (_version != _nativeSortedDictionary._handle->Version) + throw new InvalidOperationException("EnumFailedVersion"); + if (!_nodeStack.TryPop(out var result)) + { + _currentNode = null; + _current = default; + return false; + } + + _currentNode = (Node*)result; + _current = new KeyValuePair(_currentNode->Key, _currentNode->Value); + var node = _currentNode->Right; + while (node != null) + { + var next = node->Left; + _nodeStack.Push((nint)node); + node = next; + } + + return true; + } + + /// + /// Current + /// + public KeyValuePair Current + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _current; + } + + /// + /// Dispose + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Dispose() => _nodeStack.Dispose(); + } + + /// + /// Key collection + /// + [StructLayout(LayoutKind.Sequential)] + public readonly struct KeyCollection + { + /// + /// NativeSortedDictionary + /// + private readonly NativeSortedDictionary _nativeSortedDictionary; + + /// + /// Structure + /// + /// NativeSortedDictionary + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal KeyCollection(NativeSortedDictionary nativeSortedDictionary) => _nativeSortedDictionary = nativeSortedDictionary; + + /// + /// Get enumerator + /// + /// Enumerator + public Enumerator GetEnumerator() => new(_nativeSortedDictionary); + + /// + /// Enumerator + /// + public struct Enumerator : IDisposable + { + /// + /// NativeHashSet + /// + private readonly NativeSortedDictionary _nativeSortedDictionary; + + /// + /// Version + /// + private readonly int _version; + + /// + /// Node stack + /// + private readonly NativeStack _nodeStack; + + /// + /// Current + /// + private Node* _currentNode; + + /// + /// Current + /// + private TKey _current; + + /// + /// Structure + /// + /// NativeSortedDictionary + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal Enumerator(NativeSortedDictionary nativeSortedDictionary) + { + _nativeSortedDictionary = nativeSortedDictionary; + _version = nativeSortedDictionary._handle->Version; + _nodeStack = new NativeStack(2 * Log2(nativeSortedDictionary.Count + 1)); + _currentNode = null; + _current = default; + var node = _nativeSortedDictionary._handle->Root; + while (node != null) + { + var next = node->Left; + _nodeStack.Push((nint)node); + node = next; + } + } + + /// + /// Move next + /// + /// Moved + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool MoveNext() + { + if (_version != _nativeSortedDictionary._handle->Version) + throw new InvalidOperationException("EnumFailedVersion"); + if (!_nodeStack.TryPop(out var result)) + { + _currentNode = null; + _current = default; + return false; + } + + _currentNode = (Node*)result; + _current = _currentNode->Key; + var node = _currentNode->Right; + while (node != null) + { + var next = node->Left; + _nodeStack.Push((nint)node); + node = next; + } + + return true; + } + + /// + /// Current + /// + public TKey Current + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _current; + } + + /// + /// Dispose + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Dispose() => _nodeStack.Dispose(); + } + } + + /// + /// Value collection + /// + [StructLayout(LayoutKind.Sequential)] + public readonly struct ValueCollection + { + /// + /// NativeSortedDictionary + /// + private readonly NativeSortedDictionary _nativeSortedDictionary; + + /// + /// Structure + /// + /// NativeSortedDictionary + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal ValueCollection(NativeSortedDictionary nativeSortedDictionary) => _nativeSortedDictionary = nativeSortedDictionary; + + /// + /// Get enumerator + /// + /// Enumerator + public Enumerator GetEnumerator() => new(_nativeSortedDictionary); + + /// + /// Enumerator + /// + public struct Enumerator : IDisposable + { + /// + /// NativeHashSet + /// + private readonly NativeSortedDictionary _nativeSortedDictionary; + + /// + /// Version + /// + private readonly int _version; + + /// + /// Node stack + /// + private readonly NativeStack _nodeStack; + + /// + /// Current + /// + private Node* _currentNode; + + /// + /// Current + /// + private TValue _current; + + /// + /// Structure + /// + /// NativeSortedDictionary + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal Enumerator(NativeSortedDictionary nativeSortedDictionary) + { + _nativeSortedDictionary = nativeSortedDictionary; + _version = nativeSortedDictionary._handle->Version; + _nodeStack = new NativeStack(2 * Log2(nativeSortedDictionary.Count + 1)); + _currentNode = null; + _current = default; + var node = _nativeSortedDictionary._handle->Root; + while (node != null) + { + var next = node->Left; + _nodeStack.Push((nint)node); + node = next; + } + } + + /// + /// Move next + /// + /// Moved + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool MoveNext() + { + if (_version != _nativeSortedDictionary._handle->Version) + throw new InvalidOperationException("EnumFailedVersion"); + if (!_nodeStack.TryPop(out var result)) + { + _currentNode = null; + _current = default; + return false; + } + + _currentNode = (Node*)result; + _current = _currentNode->Value; + var node = _currentNode->Right; + while (node != null) + { + var next = node->Left; + _nodeStack.Push((nint)node); + node = next; + } + + return true; + } + + /// + /// Current + /// + public TValue Current + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _current; + } + + /// + /// Dispose + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Dispose() => _nodeStack.Dispose(); + } + } + + /// + /// Node color + /// + private enum NodeColor : byte + { + Black, + Red + } + + /// + /// Tree rotation + /// + private enum TreeRotation : byte + { + Left, + LeftRight, + Right, + RightLeft + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeSortedList.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeSortedList.cs new file mode 100644 index 0000000..bb43bbf --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeSortedList.cs @@ -0,0 +1,695 @@ +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +#if UNITY_2021_3_OR_NEWER || GODOT +using System; +using System.Collections.Generic; +#endif + +#pragma warning disable CA2208 +#pragma warning disable CS8632 + +// ReSharper disable ALL + +namespace NativeCollections +{ + /// + /// Native sortedList + /// + /// Type + /// Type + [StructLayout(LayoutKind.Sequential)] + public readonly unsafe struct NativeSortedList where TKey : unmanaged, IComparable where TValue : unmanaged + { + /// + /// Handle + /// + [StructLayout(LayoutKind.Sequential)] + private struct NativeSortedListHandle + { + /// + /// Keys + /// + public TKey* Buckets; + + /// + /// Values + /// + public TValue* Entries; + + /// + /// Size + /// + public int Size; + + /// + /// Version + /// + public int Version; + + /// + /// Capacity + /// + public int Capacity; + + /// + /// Keys + /// + public KeyCollection Keys; + + /// + /// Values + /// + public ValueCollection Values; + } + + /// + /// Handle + /// + private readonly NativeSortedListHandle* _handle; + + /// + /// Keys + /// + public KeyCollection Keys => _handle->Keys; + + /// + /// Values + /// + public ValueCollection Values => _handle->Values; + + /// + /// Structure + /// + /// Capacity + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public NativeSortedList(int capacity) + { + if (capacity < 0) + throw new ArgumentOutOfRangeException(nameof(capacity), capacity, "MustBeNonNegative"); + if (capacity < 4) + capacity = 4; + _handle = (NativeSortedListHandle*)NativeMemoryAllocator.Alloc((uint)sizeof(NativeSortedListHandle)); + _handle->Buckets = (TKey*)NativeMemoryAllocator.Alloc((uint)(capacity * sizeof(TKey))); + _handle->Entries = (TValue*)NativeMemoryAllocator.Alloc((uint)(capacity * sizeof(TValue))); + _handle->Size = 0; + _handle->Version = 0; + _handle->Capacity = capacity; + _handle->Keys = new KeyCollection(this); + _handle->Values = new ValueCollection(this); + } + + /// + /// Is created + /// + public bool IsCreated => _handle != null; + + /// + /// Is empty + /// + public bool IsEmpty => _handle->Size == 0; + + /// + /// Get or set value + /// + /// Key + public TValue this[TKey key] + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get + { + var index = BinarySearch(_handle->Buckets, _handle->Size, key); + return index >= 0 ? _handle->Entries[index] : throw new KeyNotFoundException(key.ToString()); + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + set + { + var index = BinarySearch(_handle->Buckets, _handle->Size, key); + if (index >= 0) + { + _handle->Entries[index] = value; + ++_handle->Version; + } + else + { + Insert(~index, key, value); + } + } + } + + /// + /// Count + /// + public int Count => _handle->Size; + + /// + /// Capacity + /// + public int Capacity + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _handle->Capacity; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + set + { + if (value < _handle->Size) + throw new ArgumentOutOfRangeException(nameof(value), value, "SmallCapacity"); + if (value != _handle->Capacity) + { + if (value > 0) + { + var keys = (TKey*)NativeMemoryAllocator.Alloc((uint)(value * sizeof(TKey))); + var values = (TValue*)NativeMemoryAllocator.Alloc((uint)(value * sizeof(TValue))); + if (_handle->Size > 0) + { + Unsafe.CopyBlockUnaligned(keys, _handle->Buckets, (uint)(_handle->Size * sizeof(TKey))); + Unsafe.CopyBlockUnaligned(values, _handle->Entries, (uint)(_handle->Size * sizeof(TValue))); + } + + NativeMemoryAllocator.Free(_handle->Buckets); + NativeMemoryAllocator.Free(_handle->Entries); + _handle->Buckets = keys; + _handle->Entries = values; + } + else + { + NativeMemoryAllocator.Free(_handle->Buckets); + NativeMemoryAllocator.Free(_handle->Entries); + _handle->Buckets = (TKey*)NativeMemoryAllocator.Alloc(0); + _handle->Entries = (TValue*)NativeMemoryAllocator.Alloc(0); + } + + _handle->Capacity = value; + } + } + } + + /// + /// Equals + /// + /// Other + /// Equals + public bool Equals(NativeSortedList other) => other == this; + + /// + /// Equals + /// + /// object + /// Equals + public override bool Equals(object? obj) => obj is NativeSortedList nativeSortedList && nativeSortedList == this; + + /// + /// Get hashCode + /// + /// HashCode + public override int GetHashCode() => (int)(nint)_handle; + + /// + /// To string + /// + /// String + public override string ToString() => $"NativeSortedList<{typeof(TKey).Name}, {typeof(TValue).Name}>"; + + /// + /// Equals + /// + /// Left + /// Right + /// Equals + public static bool operator ==(NativeSortedList left, NativeSortedList right) => left._handle == right._handle; + + /// + /// Not equals + /// + /// Left + /// Right + /// Not equals + public static bool operator !=(NativeSortedList left, NativeSortedList right) => left._handle != right._handle; + + /// + /// Dispose + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Dispose() + { + if (_handle == null) + return; + NativeMemoryAllocator.Free(_handle->Buckets); + NativeMemoryAllocator.Free(_handle->Entries); + NativeMemoryAllocator.Free(_handle); + } + + /// + /// Clear + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Clear() + { + ++_handle->Version; + _handle->Size = 0; + } + + /// + /// Add + /// + /// Key + /// Value + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Add(in TKey key, in TValue value) + { + var num = BinarySearch(_handle->Buckets, _handle->Size, key); + if (num >= 0) + throw new ArgumentException($"AddingDuplicate, {key}", nameof(key)); + Insert(~num, key, value); + } + + /// + /// Remove + /// + /// Key + /// Removed + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool Remove(in TKey key) + { + var index = BinarySearch(_handle->Buckets, _handle->Size, key); + if (index >= 0) + { + --_handle->Size; + if (index < _handle->Size) + { + Unsafe.CopyBlockUnaligned(_handle->Buckets + index, _handle->Buckets + index + 1, (uint)((_handle->Size - index) * sizeof(TKey))); + Unsafe.CopyBlockUnaligned(_handle->Entries + index, _handle->Entries + index + 1, (uint)((_handle->Size - index) * sizeof(TValue))); + } + + ++_handle->Version; + return true; + } + + return false; + } + + /// + /// Remove + /// + /// Key + /// Value + /// Removed + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool Remove(in TKey key, out TValue value) + { + var index = BinarySearch(_handle->Buckets, _handle->Size, key); + if (index >= 0) + { + value = _handle->Entries[index]; + --_handle->Size; + if (index < _handle->Size) + { + Unsafe.CopyBlockUnaligned(_handle->Buckets + index, _handle->Buckets + index + 1, (uint)((_handle->Size - index) * sizeof(TKey))); + Unsafe.CopyBlockUnaligned(_handle->Entries + index, _handle->Entries + index + 1, (uint)((_handle->Size - index) * sizeof(TValue))); + } + + ++_handle->Version; + return true; + } + + value = default; + return false; + } + + /// + /// Contains key + /// + /// Key + /// Contains key + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool ContainsKey(in TKey key) => BinarySearch(_handle->Buckets, _handle->Size, key) >= 0; + + /// + /// Try to get the value + /// + /// Key + /// Value + /// Got + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool TryGetValue(in TKey key, out TValue value) + { + var index = BinarySearch(_handle->Buckets, _handle->Size, key); + if (index >= 0) + { + value = _handle->Entries[index]; + return true; + } + + value = default; + return false; + } + + /// + /// Ensure capacity + /// + /// Capacity + /// New capacity + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void EnsureCapacity(int capacity) + { + if (_handle->Capacity < capacity) + { + var newCapacity = 2 * _handle->Capacity; + if ((uint)newCapacity > 2147483591) + newCapacity = 2147483591; + var expected = _handle->Capacity + 4; + newCapacity = newCapacity > expected ? newCapacity : expected; + if (newCapacity < capacity) + newCapacity = capacity; + Capacity = newCapacity; + } + } + + /// + /// Trim excess + /// + /// New capacity + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public int TrimExcess() + { + var threshold = (int)(_handle->Capacity * 0.9); + if (_handle->Size < threshold) + Capacity = _handle->Size; + return _handle->Capacity; + } + + /// + /// Insert + /// + /// Index + /// Key + /// Value + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void Insert(int index, in TKey key, in TValue value) + { + if (_handle->Size == _handle->Capacity) + EnsureCapacity(_handle->Size + 1); + if (index < _handle->Size) + { + Unsafe.CopyBlockUnaligned(_handle->Buckets + index + 1, _handle->Buckets + index, (uint)((_handle->Size - index) * sizeof(TKey))); + Unsafe.CopyBlockUnaligned(_handle->Entries + index + 1, _handle->Entries + index, (uint)((_handle->Size - index) * sizeof(TValue))); + } + + _handle->Buckets[index] = key; + _handle->Entries[index] = value; + ++_handle->Size; + ++_handle->Version; + } + + /// + /// Binary search + /// + /// Start + /// Length + /// Comparable + /// Index + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static int BinarySearch(TKey* start, int length, in TKey comparable) + { + var low = 0; + var high = length - 1; + while (low <= high) + { + var i = (int)(((uint)high + (uint)low) >> 1); + var c = comparable.CompareTo(*(start + i)); + if (c == 0) + return i; + if (c > 0) + low = i + 1; + else + high = i - 1; + } + + return ~low; + } + + /// + /// Empty + /// + public static NativeSortedList Empty => new(); + + /// + /// Get enumerator + /// + /// Enumerator + public Enumerator GetEnumerator() => new(this); + + /// + /// Enumerator + /// + public struct Enumerator + { + /// + /// NativeSortedList + /// + private readonly NativeSortedList _nativeSortedList; + + /// + /// Current + /// + private KeyValuePair _current; + + /// + /// Index + /// + private int _index; + + /// + /// Version + /// + private readonly int _version; + + /// + /// Structure + /// + /// NativeSortedList + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal Enumerator(NativeSortedList nativeSortedList) + { + _nativeSortedList = nativeSortedList; + _current = default; + _index = 0; + _version = _nativeSortedList._handle->Version; + } + + /// + /// Move next + /// + /// Moved + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool MoveNext() + { + if (_version != _nativeSortedList._handle->Version) + throw new InvalidOperationException("EnumFailedVersion"); + if ((uint)_index < (uint)_nativeSortedList._handle->Size) + { + _current = new KeyValuePair(_nativeSortedList._handle->Buckets[_index], _nativeSortedList._handle->Entries[_index]); + ++_index; + return true; + } + + _index = _nativeSortedList._handle->Size + 1; + return false; + } + + /// + /// Current + /// + public KeyValuePair Current + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _current; + } + } + + /// + /// Key collection + /// + [StructLayout(LayoutKind.Sequential)] + public readonly struct KeyCollection + { + /// + /// NativeSortedList + /// + private readonly NativeSortedList _nativeSortedList; + + /// + /// Structure + /// + /// NativeSortedList + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal KeyCollection(NativeSortedList nativeSortedList) => _nativeSortedList = nativeSortedList; + + /// + /// Get enumerator + /// + /// Enumerator + public Enumerator GetEnumerator() => new(_nativeSortedList); + + /// + /// Enumerator + /// + public struct Enumerator + { + /// + /// NativeSortedList + /// + private readonly NativeSortedList _nativeSortedList; + + /// + /// Current + /// + private TKey _current; + + /// + /// Index + /// + private int _index; + + /// + /// Version + /// + private readonly int _version; + + /// + /// Structure + /// + /// NativeSortedList + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal Enumerator(NativeSortedList nativeSortedList) + { + _nativeSortedList = nativeSortedList; + _current = default; + _index = 0; + _version = _nativeSortedList._handle->Version; + } + + /// + /// Move next + /// + /// Moved + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool MoveNext() + { + if (_version != _nativeSortedList._handle->Version) + throw new InvalidOperationException("EnumFailedVersion"); + if ((uint)_index < (uint)_nativeSortedList._handle->Size) + { + _current = _nativeSortedList._handle->Buckets[_index]; + ++_index; + return true; + } + + _index = _nativeSortedList._handle->Size + 1; + return false; + } + + /// + /// Current + /// + public TKey Current + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _current; + } + } + } + + /// + /// Value collection + /// + [StructLayout(LayoutKind.Sequential)] + public readonly struct ValueCollection + { + /// + /// NativeSortedList + /// + private readonly NativeSortedList _nativeSortedList; + + /// + /// Structure + /// + /// NativeSortedList + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal ValueCollection(NativeSortedList nativeSortedList) => _nativeSortedList = nativeSortedList; + + /// + /// Get enumerator + /// + /// Enumerator + public Enumerator GetEnumerator() => new(_nativeSortedList); + + /// + /// Enumerator + /// + public struct Enumerator + { + /// + /// NativeSortedList + /// + private readonly NativeSortedList _nativeSortedList; + + /// + /// Current + /// + private TValue _current; + + /// + /// Index + /// + private int _index; + + /// + /// Version + /// + private readonly int _version; + + /// + /// Structure + /// + /// NativeSortedList + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal Enumerator(NativeSortedList nativeSortedList) + { + _nativeSortedList = nativeSortedList; + _current = default; + _index = 0; + _version = _nativeSortedList._handle->Version; + } + + /// + /// Move next + /// + /// Moved + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool MoveNext() + { + if (_version != _nativeSortedList._handle->Version) + throw new InvalidOperationException("EnumFailedVersion"); + if ((uint)_index < (uint)_nativeSortedList._handle->Size) + { + _current = _nativeSortedList._handle->Entries[_index]; + ++_index; + return true; + } + + _index = _nativeSortedList._handle->Size + 1; + return false; + } + + /// + /// Current + /// + public TValue Current + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _current; + } + } + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeSortedSet.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeSortedSet.cs new file mode 100644 index 0000000..f339276 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeSortedSet.cs @@ -0,0 +1,973 @@ +#if UNITY_2021_3_OR_NEWER || GODOT +using System; +#endif +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +#if NET5_0_OR_GREATER +#endif + +#pragma warning disable CA2208 +#pragma warning disable CS8632 + +// ReSharper disable ALL + +namespace NativeCollections +{ + /// + /// Native sortedSet + /// + /// Type + [StructLayout(LayoutKind.Sequential)] + public readonly unsafe struct NativeSortedSet : IDisposable, IEquatable> where T : unmanaged, IComparable + { + /// + /// Handle + /// + [StructLayout(LayoutKind.Sequential)] + private struct NativeSortedSetHandle + { + /// + /// Root + /// + public Node* Root; + + /// + /// Count + /// + public int Count; + + /// + /// Version + /// + public int Version; + + /// + /// Node pool + /// + public NativeMemoryPool NodePool; + } + + /// + /// Handle + /// + private readonly NativeSortedSetHandle* _handle; + + /// + /// Structure + /// + /// MemoryPool size + /// MemoryPool maxFreeSlabs + public NativeSortedSet(int size, int maxFreeSlabs) + { + var nodePool = new NativeMemoryPool(size, sizeof(Node), maxFreeSlabs); + _handle = (NativeSortedSetHandle*)NativeMemoryAllocator.Alloc((uint)sizeof(NativeSortedSetHandle)); + _handle->Root = null; + _handle->Count = 0; + _handle->Version = 0; + _handle->NodePool = nodePool; + } + + /// + /// Is created + /// + public bool IsCreated => _handle != null; + + /// + /// Is empty + /// + public bool IsEmpty => _handle->Count == 0; + + /// + /// Count + /// + public int Count => _handle->Count; + + /// + /// Min + /// + public T? Min + { + get + { + if (_handle->Root == null) + return default; + var current = _handle->Root; + while (current->Left != null) + current = current->Left; + return current->Item; + } + } + + /// + /// Max + /// + public T? Max + { + get + { + if (_handle->Root == null) + return default; + var current = _handle->Root; + while (current->Right != null) + current = current->Right; + return current->Item; + } + } + + /// + /// Equals + /// + /// Other + /// Equals + public bool Equals(NativeSortedSet other) => other == this; + + /// + /// Equals + /// + /// object + /// Equals + public override bool Equals(object? obj) => obj is NativeSortedSet nativeSortedSet && nativeSortedSet == this; + + /// + /// Get hashCode + /// + /// HashCode + public override int GetHashCode() => (int)(nint)_handle; + + /// + /// To string + /// + /// String + public override string ToString() => $"NativeSortedSet<{typeof(T).Name}>"; + + /// + /// Equals + /// + /// Left + /// Right + /// Equals + public static bool operator ==(NativeSortedSet left, NativeSortedSet right) => left._handle == right._handle; + + /// + /// Not equals + /// + /// Left + /// Right + /// Not equals + public static bool operator !=(NativeSortedSet left, NativeSortedSet right) => left._handle != right._handle; + + /// + /// Dispose + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Dispose() + { + if (_handle == null) + return; + _handle->NodePool.Dispose(); + NativeMemoryAllocator.Free(_handle); + } + + /// + /// Clear + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Clear() + { + if (_handle->Root != null) + { + var nodeStack = new NativeStack(2 * Log2(_handle->Count + 1)); + nodeStack.Push((nint)_handle->Root); + while (nodeStack.TryPop(out var node)) + { + var currentNode = (Node*)node; + if (currentNode->Left != null) + nodeStack.Push((nint)currentNode->Left); + if (currentNode->Right != null) + nodeStack.Push((nint)currentNode->Right); + _handle->NodePool.Return(currentNode); + } + + nodeStack.Dispose(); + } + + _handle->Root = null; + _handle->Count = 0; + ++_handle->Version; + } + + /// + /// Add + /// + /// Item + /// Added + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool Add(in T item) + { + if (_handle->Root == null) + { + _handle->Root = (Node*)_handle->NodePool.Rent(); + _handle->Root->Item = item; + _handle->Root->Left = null; + _handle->Root->Right = null; + _handle->Root->Color = NodeColor.Black; + _handle->Count = 1; + _handle->Version++; + return true; + } + + var current = _handle->Root; + Node* parent = null; + Node* grandParent = null; + Node* greatGrandParent = null; + _handle->Version++; + var order = 0; + while (current != null) + { + order = item.CompareTo(current->Item); + if (order == 0) + { + _handle->Root->ColorBlack(); + return false; + } + + if (current->Is4Node) + { + current->Split4Node(); + if (Node.IsNonNullRed(parent)) + InsertionBalance(current, parent, grandParent, greatGrandParent); + } + + greatGrandParent = grandParent; + grandParent = parent; + parent = current; + current = order < 0 ? current->Left : current->Right; + } + + var node = (Node*)_handle->NodePool.Rent(); + node->Item = item; + node->Left = null; + node->Right = null; + node->Color = NodeColor.Red; + if (order > 0) + parent->Right = node; + else + parent->Left = node; + if (parent->IsRed) + InsertionBalance(node, parent, grandParent, greatGrandParent); + _handle->Root->ColorBlack(); + ++_handle->Count; + return true; + } + + /// + /// Add + /// + /// Equal value + /// Actual value + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Add(in T equalValue, in T actualValue) + { + var node = FindNode(equalValue); + if (node == null) + { + Add(actualValue); + } + else + { + node->Item = actualValue; + _handle->Version++; + } + } + + /// + /// Remove + /// + /// Item + /// Removed + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool Remove(in T item) + { + if (_handle->Root == null) + return false; + _handle->Version++; + var current = _handle->Root; + Node* parent = null; + Node* grandParent = null; + Node* match = null; + Node* parentOfMatch = null; + var foundMatch = false; + while (current != null) + { + if (current->Is2Node) + { + if (parent == null) + { + current->ColorRed(); + } + else + { + var sibling = parent->GetSibling(current); + if (sibling->IsRed) + { + if (parent->Right == sibling) + parent->RotateLeft(); + else + parent->RotateRight(); + parent->ColorRed(); + sibling->ColorBlack(); + ReplaceChildOrRoot(grandParent, parent, sibling); + grandParent = sibling; + if (parent == match) + parentOfMatch = sibling; + sibling = parent->GetSibling(current); + } + + if (sibling->Is2Node) + { + parent->Merge2Nodes(); + } + else + { + var newGrandParent = parent->Rotate(parent->GetRotation(current, sibling)); + newGrandParent->Color = parent->Color; + parent->ColorBlack(); + current->ColorRed(); + ReplaceChildOrRoot(grandParent, parent, newGrandParent); + if (parent == match) + parentOfMatch = newGrandParent; + } + } + } + + var order = foundMatch ? -1 : item.CompareTo(current->Item); + if (order == 0) + { + foundMatch = true; + match = current; + parentOfMatch = parent; + } + + grandParent = parent; + parent = current; + current = order < 0 ? current->Left : current->Right; + } + + if (match != null) + { + ReplaceNode(match, parentOfMatch, parent, grandParent); + --_handle->Count; + _handle->NodePool.Return(match); + } + + if (_handle->Root != null) + _handle->Root->ColorBlack(); + return foundMatch; + } + + /// + /// Remove + /// + /// Equal value + /// Actual value + /// Removed + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool Remove(in T equalValue, out T actualValue) + { + if (_handle->Root == null) + { + actualValue = default; + return false; + } + + _handle->Version++; + var current = _handle->Root; + Node* parent = null; + Node* grandParent = null; + Node* match = null; + Node* parentOfMatch = null; + var foundMatch = false; + while (current != null) + { + if (current->Is2Node) + { + if (parent == null) + { + current->ColorRed(); + } + else + { + var sibling = parent->GetSibling(current); + if (sibling->IsRed) + { + if (parent->Right == sibling) + parent->RotateLeft(); + else + parent->RotateRight(); + parent->ColorRed(); + sibling->ColorBlack(); + ReplaceChildOrRoot(grandParent, parent, sibling); + grandParent = sibling; + if (parent == match) + parentOfMatch = sibling; + sibling = parent->GetSibling(current); + } + + if (sibling->Is2Node) + { + parent->Merge2Nodes(); + } + else + { + var newGrandParent = parent->Rotate(parent->GetRotation(current, sibling)); + newGrandParent->Color = parent->Color; + parent->ColorBlack(); + current->ColorRed(); + ReplaceChildOrRoot(grandParent, parent, newGrandParent); + if (parent == match) + parentOfMatch = newGrandParent; + } + } + } + + var order = foundMatch ? -1 : equalValue.CompareTo(current->Item); + if (order == 0) + { + foundMatch = true; + match = current; + parentOfMatch = parent; + } + + grandParent = parent; + parent = current; + current = order < 0 ? current->Left : current->Right; + } + + if (match != null) + { + actualValue = match->Item; + ReplaceNode(match, parentOfMatch, parent, grandParent); + --_handle->Count; + _handle->NodePool.Return(match); + } + else + { + actualValue = default; + } + + if (_handle->Root != null) + _handle->Root->ColorBlack(); + return foundMatch; + } + + /// + /// Contains + /// + /// Item + /// Contains + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool Contains(in T item) => FindNode(item) != null; + + /// + /// Try to get the actual value + /// + /// Equal value + /// Actual value + /// Got + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool TryGetValue(in T equalValue, out T actualValue) + { + var node = FindNode(equalValue); + if (node != null) + { + actualValue = node->Item; + return true; + } + + actualValue = default; + return false; + } + + /// + /// Insertion balance + /// + /// Current + /// Parent + /// Grand parent + /// GreatGrand parent + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void InsertionBalance(Node* current, Node* parent, Node* grandParent, Node* greatGrandParent) + { + var parentIsOnRight = grandParent->Right == parent; + var currentIsOnRight = parent->Right == current; + Node* newChildOfGreatGrandParent; + if (parentIsOnRight == currentIsOnRight) + newChildOfGreatGrandParent = currentIsOnRight ? grandParent->RotateLeft() : grandParent->RotateRight(); + else + newChildOfGreatGrandParent = currentIsOnRight ? grandParent->RotateLeftRight() : grandParent->RotateRightLeft(); + grandParent->ColorRed(); + newChildOfGreatGrandParent->ColorBlack(); + ReplaceChildOrRoot(greatGrandParent, grandParent, newChildOfGreatGrandParent); + } + + /// + /// Replace child or root + /// + /// Parent + /// Child + /// New child + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void ReplaceChildOrRoot(Node* parent, Node* child, Node* newChild) + { + if (parent != null) + parent->ReplaceChild(child, newChild); + else + _handle->Root = newChild; + } + + /// + /// Replace node + /// + /// Match + /// Parent of match + /// Successor + /// Parent of successor + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void ReplaceNode(Node* match, Node* parentOfMatch, Node* successor, Node* parentOfSuccessor) + { + if (successor == match) + { + successor = match->Left; + } + else + { + if (successor->Right != null) + successor->Right->ColorBlack(); + if (parentOfSuccessor != match) + { + parentOfSuccessor->Left = successor->Right; + successor->Right = match->Right; + } + + successor->Left = match->Left; + } + + if (successor != null) + successor->Color = match->Color; + ReplaceChildOrRoot(parentOfMatch, match, successor); + } + + /// + /// Find node + /// + /// Item + /// Node + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private Node* FindNode(in T item) + { + var current = _handle->Root; + while (current != null) + { + var order = item.CompareTo(current->Item); + if (order == 0) + return current; + current = order < 0 ? current->Left : current->Right; + } + + return null; + } + + /// + /// Log2 + /// + /// Value + /// Log2 + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static int Log2(int value) => BitOperationsHelpers.Log2(value); + + /// + /// Node + /// + [StructLayout(LayoutKind.Sequential)] + private struct Node + { + /// + /// Is non null red + /// + /// Node + /// Is non null red + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool IsNonNullRed(Node* node) => node != null && node->IsRed; + + /// + /// Is null or black + /// + /// Node + /// Is null or black + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static bool IsNullOrBlack(Node* node) => node == null || node->IsBlack; + + /// + /// Item + /// + public T Item + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + set; + } + + /// + /// Left + /// + public Node* Left + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + set; + } + + /// + /// Right + /// + public Node* Right + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + set; + } + + /// + /// Color + /// + public NodeColor Color + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + set; + } + + /// + /// Is black + /// + private bool IsBlack + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => Color == NodeColor.Black; + } + + /// + /// Is red + /// + public bool IsRed + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => Color == NodeColor.Red; + } + + /// + /// Is 2 node + /// + public bool Is2Node + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => IsBlack && IsNullOrBlack(Left) && IsNullOrBlack(Right); + } + + /// + /// Is 4 node + /// + public bool Is4Node + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => IsNonNullRed(Left) && IsNonNullRed(Right); + } + + /// + /// Set color to black + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ColorBlack() => Color = NodeColor.Black; + + /// + /// Set color to red + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ColorRed() => Color = NodeColor.Red; + + /// + /// Get rotation + /// + /// Current + /// Sibling + /// Rotation + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public TreeRotation GetRotation(Node* current, Node* sibling) + { + var currentIsLeftChild = Left == current; + return IsNonNullRed(sibling->Left) ? currentIsLeftChild ? TreeRotation.RightLeft : TreeRotation.Right : currentIsLeftChild ? TreeRotation.Left : TreeRotation.LeftRight; + } + + /// + /// Get sibling + /// + /// Node + /// Sibling + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Node* GetSibling(Node* node) => node == Left ? Right : Left; + + /// + /// Split 4 node + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Split4Node() + { + ColorRed(); + Left->ColorBlack(); + Right->ColorBlack(); + } + + /// + /// Rotate + /// + /// Rotation + /// Node + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Node* Rotate(TreeRotation rotation) + { + Node* removeRed; + switch (rotation) + { + case TreeRotation.Right: + removeRed = Left->Left; + removeRed->ColorBlack(); + return RotateRight(); + case TreeRotation.Left: + removeRed = Right->Right; + removeRed->ColorBlack(); + return RotateLeft(); + case TreeRotation.RightLeft: + return RotateRightLeft(); + case TreeRotation.LeftRight: + return RotateLeftRight(); + default: + return null; + } + } + + /// + /// Rotate left + /// + /// Node + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Node* RotateLeft() + { + var child = Right; + Right = child->Left; + child->Left = (Node*)Unsafe.AsPointer(ref this); + return child; + } + + /// + /// Rotate left right + /// + /// Node + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Node* RotateLeftRight() + { + var child = Left; + var grandChild = child->Right; + Left = grandChild->Right; + grandChild->Right = (Node*)Unsafe.AsPointer(ref this); + child->Right = grandChild->Left; + grandChild->Left = child; + return grandChild; + } + + /// + /// Rotate right + /// + /// Node + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Node* RotateRight() + { + var child = Left; + Left = child->Right; + child->Right = (Node*)Unsafe.AsPointer(ref this); + return child; + } + + /// + /// Rotate right left + /// + /// Node + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Node* RotateRightLeft() + { + var child = Right; + var grandChild = child->Left; + Right = grandChild->Left; + grandChild->Left = (Node*)Unsafe.AsPointer(ref this); + child->Left = grandChild->Right; + grandChild->Right = child; + return grandChild; + } + + /// + /// Merge 2 nodes + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Merge2Nodes() + { + ColorBlack(); + Left->ColorRed(); + Right->ColorRed(); + } + + /// + /// Replace child + /// + /// Child + /// New child + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ReplaceChild(Node* child, Node* newChild) + { + if (Left == child) + Left = newChild; + else + Right = newChild; + } + } + + /// + /// Empty + /// + public static NativeSortedSet Empty => new(); + + /// + /// Get enumerator + /// + /// Enumerator + public Enumerator GetEnumerator() => new(this); + + /// + /// Enumerator + /// + public struct Enumerator : IDisposable + { + /// + /// NativeHashSet + /// + private readonly NativeSortedSet _nativeSortedSet; + + /// + /// Version + /// + private readonly int _version; + + /// + /// Node stack + /// + private readonly NativeStack _nodeStack; + + /// + /// Current + /// + private Node* _currentNode; + + /// + /// Current + /// + private T _current; + + /// + /// Structure + /// + /// NativeSortedSet + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal Enumerator(NativeSortedSet nativeSortedSet) + { + _nativeSortedSet = nativeSortedSet; + _version = nativeSortedSet._handle->Version; + _nodeStack = new NativeStack(2 * Log2(nativeSortedSet.Count + 1)); + _currentNode = null; + _current = default; + var node = _nativeSortedSet._handle->Root; + while (node != null) + { + var next = node->Left; + _nodeStack.Push((nint)node); + node = next; + } + } + + /// + /// Move next + /// + /// Moved + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool MoveNext() + { + if (_version != _nativeSortedSet._handle->Version) + throw new InvalidOperationException("EnumFailedVersion"); + if (!_nodeStack.TryPop(out var result)) + { + _currentNode = null; + _current = default; + return false; + } + + _currentNode = (Node*)result; + _current = _currentNode->Item; + var node = _currentNode->Right; + while (node != null) + { + var next = node->Left; + _nodeStack.Push((nint)node); + node = next; + } + + return true; + } + + /// + /// Current + /// + public T Current + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _current; + } + + /// + /// Dispose + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Dispose() => _nodeStack.Dispose(); + } + + /// + /// Node color + /// + private enum NodeColor : byte + { + Black, + Red + } + + /// + /// Tree rotation + /// + private enum TreeRotation : byte + { + Left, + LeftRight, + Right, + RightLeft + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeStack.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeStack.cs new file mode 100644 index 0000000..5a295a2 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeStack.cs @@ -0,0 +1,425 @@ +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +#if UNITY_2021_3_OR_NEWER || GODOT +using System; +#endif + +#pragma warning disable CA2208 +#pragma warning disable CS8632 + +// ReSharper disable ALL + +namespace NativeCollections +{ + /// + /// Native stack + /// + /// Type + [StructLayout(LayoutKind.Sequential)] + public readonly unsafe struct NativeStack : IDisposable, IEquatable> where T : unmanaged + { + /// + /// Handle + /// + [StructLayout(LayoutKind.Sequential)] + private struct NativeStackHandle + { + /// + /// Array + /// + public T* Array; + + /// + /// Length + /// + public int Length; + + /// + /// Size + /// + public int Size; + + /// + /// Version + /// + public int Version; + } + + /// + /// Handle + /// + private readonly NativeStackHandle* _handle; + + /// + /// Structure + /// + /// Capacity + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public NativeStack(int capacity) + { + if (capacity < 0) + throw new ArgumentOutOfRangeException(nameof(capacity), capacity, "MustBeNonNegative"); + if (capacity < 4) + capacity = 4; + _handle = (NativeStackHandle*)NativeMemoryAllocator.Alloc((uint)sizeof(NativeStackHandle)); + _handle->Array = (T*)NativeMemoryAllocator.Alloc((uint)(capacity * sizeof(T))); + _handle->Length = capacity; + _handle->Size = 0; + _handle->Version = 0; + } + + /// + /// Is created + /// + public bool IsCreated => _handle != null; + + /// + /// Is empty + /// + public bool IsEmpty => _handle->Size == 0; + + /// + /// Get reference + /// + /// Index + public ref T this[int index] + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => ref _handle->Array[index]; + } + + /// + /// Get reference + /// + /// Index + public ref T this[uint index] + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => ref _handle->Array[index]; + } + + /// + /// Count + /// + public int Count => _handle->Size; + + /// + /// Equals + /// + /// Other + /// Equals + public bool Equals(NativeStack other) => other == this; + + /// + /// Equals + /// + /// object + /// Equals + public override bool Equals(object? obj) => obj is NativeStack nativeStack && nativeStack == this; + + /// + /// Get hashCode + /// + /// HashCode + public override int GetHashCode() => (int)(nint)_handle; + + /// + /// To string + /// + /// String + public override string ToString() => $"NativeStack<{typeof(T).Name}>"; + + /// + /// Equals + /// + /// Left + /// Right + /// Equals + public static bool operator ==(NativeStack left, NativeStack right) => left._handle == right._handle; + + /// + /// Not equals + /// + /// Left + /// Right + /// Not equals + public static bool operator !=(NativeStack left, NativeStack right) => left._handle != right._handle; + + /// + /// Dispose + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Dispose() + { + if (_handle == null) + return; + NativeMemoryAllocator.Free(_handle->Array); + NativeMemoryAllocator.Free(_handle); + } + + /// + /// Clear + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Clear() + { + _handle->Size = 0; + _handle->Version++; + } + + /// + /// Push + /// + /// Item + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Push(in T item) + { + var size = _handle->Size; + if ((uint)size < (uint)_handle->Length) + { + _handle->Array[size] = item; + _handle->Version++; + _handle->Size = size + 1; + } + else + { + Grow(_handle->Size + 1); + _handle->Array[_handle->Size] = item; + _handle->Version++; + _handle->Size++; + } + } + + /// + /// Try push + /// + /// Item + /// Pushed + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool TryPush(in T item) + { + var size = _handle->Size; + if ((uint)size < (uint)_handle->Length) + { + _handle->Array[size] = item; + _handle->Version++; + _handle->Size = size + 1; + return true; + } + + return false; + } + + /// + /// Pop + /// + /// Item + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public T Pop() + { + var size = _handle->Size - 1; + if ((uint)size >= (uint)_handle->Length) + throw new InvalidOperationException("EmptyStack"); + _handle->Version++; + _handle->Size = size; + var item = _handle->Array[size]; + return item; + } + + /// + /// Try pop + /// + /// Item + /// Popped + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool TryPop(out T result) + { + var size = _handle->Size - 1; + if ((uint)size >= (uint)_handle->Length) + { + result = default; + return false; + } + + _handle->Version++; + _handle->Size = size; + result = _handle->Array[size]; + return true; + } + + /// + /// Peek + /// + /// Item + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public T Peek() + { + var size = _handle->Size - 1; + return (uint)size >= (uint)_handle->Length ? throw new InvalidOperationException("EmptyStack") : _handle->Array[size]; + } + + /// + /// Try peek + /// + /// Item + /// Peeked + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool TryPeek(out T result) + { + var size = _handle->Size - 1; + if ((uint)size >= (uint)_handle->Length) + { + result = default; + return false; + } + + result = _handle->Array[size]; + return true; + } + + /// + /// Ensure capacity + /// + /// Capacity + /// New capacity + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public int EnsureCapacity(int capacity) + { + if (capacity < 0) + throw new ArgumentOutOfRangeException(nameof(capacity), capacity, "MustBeNonNegative"); + if (_handle->Length < capacity) + Grow(capacity); + return _handle->Length; + } + + /// + /// Trim excess + /// + /// New capacity + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public int TrimExcess() + { + var threshold = (int)(_handle->Length * 0.9); + if (_handle->Size < threshold) + SetCapacity(_handle->Size); + return _handle->Length; + } + + /// + /// Set capacity + /// + /// Capacity + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void SetCapacity(int capacity) + { + var newArray = (T*)NativeMemoryAllocator.Alloc((uint)(capacity * sizeof(T))); + if (_handle->Size > 0) + Unsafe.CopyBlockUnaligned(newArray, _handle->Array, (uint)(_handle->Length * sizeof(T))); + NativeMemoryAllocator.Free(_handle->Array); + _handle->Array = newArray; + _handle->Length = capacity; + } + + /// + /// Grow + /// + /// Capacity + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void Grow(int capacity) + { + var newCapacity = 2 * _handle->Length; + if ((uint)newCapacity > 2147483591) + newCapacity = 2147483591; + var expected = _handle->Length + 4; + newCapacity = newCapacity > expected ? newCapacity : expected; + if (newCapacity < capacity) + newCapacity = capacity; + SetCapacity(newCapacity); + } + + /// + /// Empty + /// + public static NativeStack Empty => new(); + + /// + /// Get enumerator + /// + /// Enumerator + public Enumerator GetEnumerator() => new(this); + + /// + /// Enumerator + /// + public struct Enumerator + { + /// + /// NativeStack + /// + private readonly NativeStack _nativeStack; + + /// + /// Version + /// + private readonly int _version; + + /// + /// Index + /// + private int _index; + + /// + /// Current element + /// + private T _currentElement; + + /// + /// Structure + /// + /// NativeStack + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal Enumerator(in NativeStack nativeStack) + { + _nativeStack = nativeStack; + _version = nativeStack._handle->Version; + _index = -2; + _currentElement = default; + } + + /// + /// Move next + /// + /// Moved + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool MoveNext() + { + if (_version != _nativeStack._handle->Version) + throw new InvalidOperationException("EnumFailedVersion"); + bool returned; + if (_index == -2) + { + _index = _nativeStack._handle->Size - 1; + returned = _index >= 0; + if (returned) + _currentElement = _nativeStack._handle->Array[_index]; + return returned; + } + + if (_index == -1) + return false; + returned = --_index >= 0; + _currentElement = returned ? _nativeStack._handle->Array[_index] : default; + return returned; + } + + /// + /// Current + /// + public T Current + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _index < 0 ? throw new InvalidOperationException(_index == -1 ? "EnumNotStarted" : "EnumEnded") : _currentElement; + } + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/NativeCollections/README.md b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/NativeCollections/README.md new file mode 100644 index 0000000..c3b41cf --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/NativeCollections/README.md @@ -0,0 +1,3 @@ +# NativeCollections + +This project is a pure C# native collections for (Unity/Godot/.NET) \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/PriorityQueue/PriorityQueueGenerics.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/PriorityQueue/PriorityQueueGenerics.cs new file mode 100644 index 0000000..2ef6704 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/PriorityQueue/PriorityQueueGenerics.cs @@ -0,0 +1,121 @@ +// ReSharper disable SwapViaDeconstruction +// ReSharper disable UseIndexFromEndExpression +// ReSharper disable ConvertToPrimaryConstructor +using System; +using System.Collections.Generic; +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member + +#pragma warning disable CS8601 // Possible null reference assignment. +namespace Fantasy.DataStructure.PriorityQueue +{ + /// + /// 优先队列 + /// + /// 节点数据 + /// 排序的类型、 + public sealed class PriorityQueue where TPriority : IComparable + { + private readonly List> _heap; + + public PriorityQueue(int initialCapacity = 16) + { + _heap = new List>(initialCapacity); + } + + public int Count => _heap.Count; + + public void Enqueue(TElement element, TPriority priority) + { + _heap.Add(new PriorityQueueItem(element, priority)); + HeapifyUp(_heap.Count - 1); + } + + public TElement Dequeue() + { + if (_heap.Count == 0) + { + throw new InvalidOperationException("The queue is empty."); + } + + var item = _heap[0]; + _heap[0] = _heap[_heap.Count - 1]; + _heap.RemoveAt(_heap.Count - 1); + HeapifyDown(0); + return item.Element; + } + + public bool TryDequeue(out TElement element) + { + if (_heap.Count == 0) + { + element = default(TElement); + return false; + } + + element = Dequeue(); + return true; + } + + public TElement Peek() + { + if (_heap.Count == 0) + { + throw new InvalidOperationException("The queue is empty."); + } + return _heap[0].Element; + } + + // ReSharper disable once IdentifierTypo + private void HeapifyUp(int index) + { + while (index > 0) + { + var parentIndex = (index - 1) / 2; + if (_heap[index].Priority.CompareTo(_heap[parentIndex].Priority) >= 0) + { + break; + } + Swap(index, parentIndex); + index = parentIndex; + } + } + + // ReSharper disable once IdentifierTypo + private void HeapifyDown(int index) + { + var lastIndex = _heap.Count - 1; + while (true) + { + var smallestIndex = index; + var leftChildIndex = 2 * index + 1; + var rightChildIndex = 2 * index + 2; + + if (leftChildIndex <= lastIndex && _heap[leftChildIndex].Priority.CompareTo(_heap[smallestIndex].Priority) < 0) + { + smallestIndex = leftChildIndex; + } + + if (rightChildIndex <= lastIndex && _heap[rightChildIndex].Priority.CompareTo(_heap[smallestIndex].Priority) < 0) + { + smallestIndex = rightChildIndex; + } + + if (smallestIndex == index) + { + break; + } + + Swap(index, smallestIndex); + index = smallestIndex; + } + } + + private void Swap(int index1, int index2) + { + var temp = _heap[index1]; + _heap[index1] = _heap[index2]; + _heap[index2] = temp; + } + } +} + diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/PriorityQueue/PriorityQueueItem.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/PriorityQueue/PriorityQueueItem.cs new file mode 100644 index 0000000..5b020b2 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/PriorityQueue/PriorityQueueItem.cs @@ -0,0 +1,30 @@ +// ReSharper disable ConvertToPrimaryConstructor +// ReSharper disable SwapViaDeconstruction +// ReSharper disable InconsistentNaming +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member +namespace Fantasy.DataStructure.PriorityQueue +{ + public struct PriorityQueueItemUint + { + public T Element { get; set; } + public uint Priority { get; set; } + + public PriorityQueueItemUint(T element, uint priority) + { + Element = element; + Priority = priority; + } + } + + public struct PriorityQueueItem + { + public T Element { get; } + public T1 Priority { get; } + + public PriorityQueueItem(T element, T1 priority) + { + Element = element; + Priority = priority; + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/PriorityQueue/PriorityQueueSimple.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/PriorityQueue/PriorityQueueSimple.cs new file mode 100644 index 0000000..63a4418 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/PriorityQueue/PriorityQueueSimple.cs @@ -0,0 +1,116 @@ +// ReSharper disable SwapViaDeconstruction +// ReSharper disable UseIndexFromEndExpression +// ReSharper disable ConvertToPrimaryConstructor +using System; +using System.Collections.Generic; +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member +#pragma warning disable CS8601 // Possible null reference assignment. +namespace Fantasy.DataStructure.PriorityQueue +{ + public sealed class PriorityQueue where T : IComparable + { + private readonly List _heap; + + public PriorityQueue(int initialCapacity = 16) + { + _heap = new List(initialCapacity); + } + + public int Count => _heap.Count; + + public void Enqueue(T item) + { + _heap.Add(item); + HeapifyUp(_heap.Count - 1); + } + + public T Dequeue() + { + if (_heap.Count == 0) + { + throw new InvalidOperationException("The queue is empty."); + } + + var item = _heap[0]; + var heapCount = _heap.Count - 1; + _heap[0] = _heap[heapCount]; + _heap.RemoveAt(heapCount); + HeapifyDown(0); + return item; + } + + public bool TryDequeue(out T item) + { + if (_heap.Count == 0) + { + item = default(T); + return false; + } + + item = Dequeue(); + return true; + } + + public T Peek() + { + if (_heap.Count == 0) + { + throw new InvalidOperationException("The queue is empty."); + } + return _heap[0]; + } + + // ReSharper disable once IdentifierTypo + private void HeapifyUp(int index) + { + while (index > 0) + { + var parentIndex = (index - 1) / 2; + if (_heap[index].CompareTo(_heap[parentIndex]) >= 0) + { + break; + } + Swap(index, parentIndex); + index = parentIndex; + } + } + + // ReSharper disable once IdentifierTypo + private void HeapifyDown(int index) + { + var lastIndex = _heap.Count - 1; + while (true) + { + var smallestIndex = index; + var leftChildIndex = 2 * index + 1; + var rightChildIndex = 2 * index + 2; + + if (leftChildIndex <= lastIndex && _heap[leftChildIndex].CompareTo(_heap[smallestIndex]) < 0) + { + smallestIndex = leftChildIndex; + } + + if (rightChildIndex <= lastIndex && _heap[rightChildIndex].CompareTo(_heap[smallestIndex]) < 0) + { + smallestIndex = rightChildIndex; + } + + if (smallestIndex == index) + { + break; + } + + Swap(index, smallestIndex); + index = smallestIndex; + } + } + + private void Swap(int index1, int index2) + { + var temp = _heap[index1]; + _heap[index1] = _heap[index2]; + _heap[index2] = temp; + } + } +} + diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/SkipTable/SkipTable.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/SkipTable/SkipTable.cs new file mode 100644 index 0000000..acbc2c1 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/SkipTable/SkipTable.cs @@ -0,0 +1,190 @@ + +#pragma warning disable CS8602 // Dereference of a possibly null reference. +#pragma warning disable CS8601 // Possible null reference assignment. +#pragma warning disable CS8604 // Possible null reference argument. +#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. +#pragma warning disable CS8600 // Converting null literal or possible null value to non-nullable type. +namespace Fantasy.DataStructure.SkipTable +{ + /// + /// 跳表数据结构(升序版) + /// + /// 跳表中存储的值的类型。 + public class SkipTable : SkipTableBase + { + /// + /// 创建一个新的跳表实例。 + /// + /// 跳表的最大层数。 + public SkipTable(int maxLayer = 8) : base(maxLayer) { } + + /// + /// 向跳表中添加一个新节点。 + /// + /// 节点的主排序键。 + /// 节点的副排序键。 + /// 节点的唯一键。 + /// 要添加的值。 + public override void Add(long sortKey, long viceKey, long key, TValue value) + { + var rLevel = 1; + + while (rLevel <= MaxLayer && Random.Next(3) == 0) + { + ++rLevel; + } + + SkipTableNode cur = TopHeader, last = null; + + for (var layer = MaxLayer; layer >= 1; --layer) + { + // 节点有next节点,且 (next主键 < 插入主键) 或 (next主键 == 插入主键 且 next副键 < 插入副键) + while (cur.Right != null && ((cur.Right.SortKey < sortKey) || + (cur.Right.SortKey == sortKey && cur.Right.ViceKey < viceKey))) + { + cur = cur.Right; + } + + if (layer <= rLevel) + { + var currentRight = cur.Right; + + // 在当前层插入新节点 + cur.Right = new SkipTableNode(sortKey, viceKey, key, value, layer == 1 ? cur.Index + 1 : 0, cur, cur.Right, null); + + if (currentRight != null) + { + currentRight.Left = cur.Right; + } + + if (last != null) + { + last.Down = cur.Right; + } + + if (layer == 1) + { + // 更新索引信息 + cur.Right.Index = cur.Index + 1; + Node.Add(key, cur.Right); + + SkipTableNode v = cur.Right.Right; + + while (v != null) + { + v.Index++; + v = v.Right; + } + } + + last = cur.Right; + } + + cur = cur.Down; + } + } + + /// + /// 从跳表中移除一个节点。 + /// + /// 节点的主排序键。 + /// 节点的副排序键。 + /// 节点的唯一键。 + /// 被移除的节点的值。 + /// 如果成功移除节点,则为 true;否则为 false。 + public override bool Remove(long sortKey, long viceKey, long key, out TValue value) + { + value = default; + var seen = false; + var cur = TopHeader; + + for (var layer = MaxLayer; layer >= 1; --layer) + { + // 先按照主键查找 再 按副键查找 + while (cur.Right != null && cur.Right.SortKey < sortKey && cur.Right.Key != key) cur = cur.Right; + while (cur.Right != null && (cur.Right.SortKey == sortKey && cur.Right.ViceKey <= viceKey) && + cur.Right.Key != key) cur = cur.Right; + + var isFind = false; + var currentCur = cur; + SkipTableNode removeCur = null; + // 如果当前不是要删除的节点、但主键和副键都一样、需要特殊处理下。 + if (cur.Right != null && cur.Right.Key == key) + { + isFind = true; + removeCur = cur.Right; + currentCur = cur; + } + else + { + // 先向左查找下 + var currentNode = cur.Left; + while (currentNode != null && currentNode.SortKey == sortKey && currentNode.ViceKey == viceKey) + { + if (currentNode.Key == key) + { + isFind = true; + removeCur = currentNode; + currentCur = currentNode.Left; + break; + } + + currentNode = currentNode.Left; + } + + // 再向右查找下 + if (!isFind) + { + currentNode = cur.Right; + while (currentNode != null && currentNode.SortKey == sortKey && currentNode.ViceKey == viceKey) + { + if (currentNode.Key == key) + { + isFind = true; + removeCur = currentNode; + currentCur = currentNode.Left; + break; + } + + currentNode = currentNode.Right; + } + } + } + + if (isFind && currentCur != null) + { + value = removeCur.Value; + currentCur.Right = removeCur.Right; + + if (removeCur.Right != null) + { + removeCur.Right.Left = currentCur; + removeCur.Right = null; + } + + removeCur.Left = null; + removeCur.Down = null; + removeCur.Value = default; + + if (layer == 1) + { + var tempCur = currentCur.Right; + while (tempCur != null) + { + tempCur.Index--; + tempCur = tempCur.Right; + } + + Node.Remove(removeCur.Key); + } + + seen = true; + } + + cur = cur.Down; + } + + return seen; + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/SkipTable/SkipTableBase.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/SkipTable/SkipTableBase.cs new file mode 100644 index 0000000..82783e8 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/SkipTable/SkipTableBase.cs @@ -0,0 +1,282 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Fantasy.DataStructure.Collection; + +#pragma warning disable CS8601 +#pragma warning disable CS8603 +#pragma warning disable CS8625 +#pragma warning disable CS8604 + +namespace Fantasy.DataStructure.SkipTable +{ + /// + /// 抽象的跳表基类,提供跳表的基本功能和操作。 + /// + /// 跳表中存储的值的类型。 + public abstract class SkipTableBase : IEnumerable> + { + /// + /// 跳表的最大层数 + /// + public readonly int MaxLayer; + /// + /// 跳表的顶部头节点 + /// + public readonly SkipTableNode TopHeader; + /// + /// 跳表的底部头节点 + /// + public SkipTableNode BottomHeader; + /// + /// 跳表中节点的数量,使用了 Node 字典的计数 + /// + public int Count => Node.Count; + /// + /// 用于生成随机数的随机数生成器 + /// + protected readonly Random Random = new Random(); + /// + /// 存储跳表节点的字典 + /// + protected readonly Dictionary> Node = new(); + /// + /// 用于辅助反向查找的栈 + /// + protected readonly Stack> AntiFindStack = new Stack>(); + + /// + /// 初始化一个新的跳表实例。 + /// + /// 跳表的最大层数,默认为 8。 + protected SkipTableBase(int maxLayer = 8) + { + MaxLayer = maxLayer; + var cur = TopHeader = new SkipTableNode(long.MinValue, 0, 0, default, 0, null, null, null); + + for (var layer = MaxLayer - 1; layer >= 1; --layer) + { + cur.Down = new SkipTableNode(long.MinValue, 0, 0, default, 0, null, null, null); + cur = cur.Down; + } + + BottomHeader = cur; + } + + /// + /// 获取指定键的节点的值,若不存在则返回默认值。 + /// + /// 要查找的键。 + public TValue this[long key] => !TryGetValueByKey(key, out TValue value) ? default : value; + + /// + /// 获取指定键的节点在跳表中的排名。 + /// + /// 要查找的键。 + /// 节点的排名。 + public int GetRanking(long key) + { + if (!Node.TryGetValue(key, out var node)) + { + return 0; + } + + return node.Index; + } + + /// + /// 获取指定键的反向排名,即在比该键更大的节点中的排名。 + /// + /// 要查找的键。 + /// 反向排名。 + public int GetAntiRanking(long key) + { + var ranking = GetRanking(key); + + if (ranking == 0) + { + return 0; + } + + return Count + 1 - ranking; + } + + /// + /// 尝试通过键获取节点的值。 + /// + /// 要查找的键。 + /// 获取到的节点的值,如果键不存在则为默认值。 + /// 是否成功获取节点的值。 + public bool TryGetValueByKey(long key, out TValue value) + { + if (!Node.TryGetValue(key, out var node)) + { + value = default; + return false; + } + + value = node.Value; + return true; + } + + /// + /// 尝试通过键获取节点。 + /// + /// 要查找的键。 + /// 获取到的节点,如果键不存在则为 null。 + /// 是否成功获取节点。 + public bool TryGetNodeByKey(long key, out SkipTableNode node) + { + if (Node.TryGetValue(key, out node)) + { + return true; + } + + return false; + } + + /// + /// 在跳表中查找节点,返回从起始位置到结束位置的节点列表。 + /// + /// 起始位置的排名。 + /// 结束位置的排名。 + /// 用于存储节点列表的 实例。 + public void Find(int start, int end, ListPool> list) + { + var cur = BottomHeader; + var count = end - start; + + for (var i = 0; i < start; i++) + { + cur = cur.Right; + } + + for (var i = 0; i <= count; i++) + { + if (cur == null) + { + break; + } + + list.Add(cur); + cur = cur.Right; + } + } + + /// + /// 在跳表中进行反向查找节点,返回从结束位置到起始位置的节点列表。 + /// + /// 结束位置的排名。 + /// 起始位置的排名。 + /// 用于存储节点列表的 实例。 + public void AntiFind(int start, int end, ListPool> list) + { + var cur = BottomHeader; + start = Count + 1 - start; + end = start - end; + + for (var i = 0; i < start; i++) + { + cur = cur.Right; + + if (cur == null) + { + break; + } + + if (i < end) + { + continue; + } + + AntiFindStack.Push(cur); + } + + while (AntiFindStack.TryPop(out var node)) + { + list.Add(node); + } + } + + /// + /// 获取跳表中最后一个节点的值。 + /// + /// 最后一个节点的值。 + public TValue GetLastValue() + { + var cur = TopHeader; + + while (cur.Right != null || cur.Down != null) + { + while (cur.Right != null) + { + cur = cur.Right; + } + + if (cur.Down != null) + { + cur = cur.Down; + } + } + + return cur.Value; + } + + /// + /// 移除跳表中指定键的节点。 + /// + /// 要移除的节点的键。 + /// 移除是否成功。 + public bool Remove(long key) + { + if (!Node.TryGetValue(key, out var node)) + { + return false; + } + + return Remove(node.SortKey, node.ViceKey, key, out _); + } + + /// + /// 向跳表中添加节点。 + /// + /// 节点的排序键。 + /// 节点的副键。 + /// 节点的键。 + /// 节点的值。 + public abstract void Add(long sortKey, long viceKey, long key, TValue value); + + /// + /// 从跳表中移除指定键的节点。 + /// + /// 节点的排序键。 + /// 节点的副键。 + /// 节点的键。 + /// 被移除的节点的值。 + /// 移除是否成功。 + public abstract bool Remove(long sortKey, long viceKey, long key, out TValue value); + + /// + /// 返回一个枚举器,用于遍历跳表中的节点。 + /// + /// 一个可用于遍历跳表节点的枚举器。 + public IEnumerator> GetEnumerator() + { + var cur = BottomHeader.Right; + while (cur != null) + { + yield return cur; + cur = cur.Right; + } + } + + /// + /// 返回一个非泛型枚举器,用于遍历跳表中的节点。 + /// + /// 一个非泛型枚举器,可用于遍历跳表节点。 + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/SkipTable/SkipTableDesc.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/SkipTable/SkipTableDesc.cs new file mode 100644 index 0000000..63daa16 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/SkipTable/SkipTableDesc.cs @@ -0,0 +1,188 @@ + +#pragma warning disable CS8600 // Converting null literal or possible null value to non-nullable type. +#pragma warning disable CS8604 // Possible null reference argument. +#pragma warning disable CS8602 // Dereference of a possibly null reference. +#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. +#pragma warning disable CS8601 // Possible null reference assignment. +namespace Fantasy.DataStructure.SkipTable +{ + /// + /// 跳表降序版,用于存储降序排列的数据。 + /// + /// 存储的值的类型。 + public class SkipTableDesc : SkipTableBase + { + /// + /// 初始化跳表降序版的新实例。 + /// + /// 跳表的最大层数,默认为 8。 + public SkipTableDesc(int maxLayer = 8) : base(maxLayer) { } + + /// + /// 向跳表中添加一个节点,根据降序规则进行插入。 + /// + /// 排序主键。 + /// 副键。 + /// 键。 + /// 值。 + public override void Add(long sortKey, long viceKey, long key, TValue value) + { + var rLevel = 1; + + while (rLevel <= MaxLayer && Random.Next(3) == 0) + { + ++rLevel; + } + + SkipTableNode cur = TopHeader, last = null; + + for (var layer = MaxLayer; layer >= 1; --layer) + { + // 节点有next节点,且 (next主键 > 插入主键) 或 (next主键 == 插入主键 且 next副键 > 插入副键) + while (cur.Right != null && ((cur.Right.SortKey > sortKey) || + (cur.Right.SortKey == sortKey && cur.Right.ViceKey > viceKey))) + { + cur = cur.Right; + } + + if (layer <= rLevel) + { + var currentRight = cur.Right; + cur.Right = new SkipTableNode(sortKey, viceKey, key, value, + layer == 1 ? cur.Index + 1 : 0, cur, cur.Right, null); + + if (currentRight != null) + { + currentRight.Left = cur.Right; + } + + if (last != null) + { + last.Down = cur.Right; + } + + if (layer == 1) + { + cur.Right.Index = cur.Index + 1; + Node.Add(key, cur.Right); + + SkipTableNode v = cur.Right.Right; + + while (v != null) + { + v.Index++; + v = v.Right; + } + } + + last = cur.Right; + } + + cur = cur.Down; + } + } + + /// + /// 从跳表中移除一个节点,根据降序规则进行移除。 + /// + /// 排序主键。 + /// 副键。 + /// 键。 + /// 移除的节点值。 + /// 如果成功移除节点,则返回 true,否则返回 false。 + public override bool Remove(long sortKey, long viceKey, long key, out TValue value) + { + value = default; + var seen = false; + var cur = TopHeader; + + for (var layer = MaxLayer; layer >= 1; --layer) + { + // 先按照主键查找 再 按副键查找 + while (cur.Right != null && cur.Right.SortKey > sortKey && cur.Right.Key != key) cur = cur.Right; + while (cur.Right != null && (cur.Right.SortKey == sortKey && cur.Right.ViceKey >= viceKey) && + cur.Right.Key != key) cur = cur.Right; + + var isFind = false; + var currentCur = cur; + SkipTableNode removeCur = null; + // 如果当前不是要删除的节点、但主键和副键都一样、需要特殊处理下。 + if (cur.Right != null && cur.Right.Key == key) + { + isFind = true; + removeCur = cur.Right; + currentCur = cur; + } + else + { + // 先向左查找下 + var currentNode = cur.Left; + while (currentNode != null && currentNode.SortKey == sortKey && currentNode.ViceKey == viceKey) + { + if (currentNode.Key == key) + { + isFind = true; + removeCur = currentNode; + currentCur = currentNode.Left; + break; + } + + currentNode = currentNode.Left; + } + + // 再向右查找下 + if (!isFind) + { + currentNode = cur.Right; + while (currentNode != null && currentNode.SortKey == sortKey && currentNode.ViceKey == viceKey) + { + if (currentNode.Key == key) + { + isFind = true; + removeCur = currentNode; + currentCur = currentNode.Left; + break; + } + + currentNode = currentNode.Right; + } + } + } + + if (isFind && currentCur != null) + { + value = removeCur.Value; + currentCur.Right = removeCur.Right; + + if (removeCur.Right != null) + { + removeCur.Right.Left = currentCur; + removeCur.Right = null; + } + + removeCur.Left = null; + removeCur.Down = null; + removeCur.Value = default; + + if (layer == 1) + { + var tempCur = currentCur.Right; + while (tempCur != null) + { + tempCur.Index--; + tempCur = tempCur.Right; + } + + Node.Remove(removeCur.Key); + } + + seen = true; + } + + cur = cur.Down; + } + + return seen; + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/SkipTable/SkipTableNode.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/SkipTable/SkipTableNode.cs new file mode 100644 index 0000000..8a1a144 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/DataStructure/SkipTable/SkipTableNode.cs @@ -0,0 +1,68 @@ +namespace Fantasy.DataStructure.SkipTable +{ + /// + /// 跳跃表节点。 + /// + /// 节点的值的类型。 + public class SkipTableNode + { + /// + /// 节点在跳跃表中的索引。 + /// + public int Index; + /// + /// 节点的主键。 + /// + public long Key; + /// + /// 节点的排序键。 + /// + public long SortKey; + /// + /// 节点的副键。 + /// + public long ViceKey; + /// + /// 节点存储的值。 + /// + public TValue Value; + /// + /// 指向左侧节点的引用。 + /// + public SkipTableNode Left; + /// + /// 指向右侧节点的引用。 + /// + public SkipTableNode Right; + /// + /// 指向下一层节点的引用。 + /// + public SkipTableNode Down; + + /// + /// 初始化跳跃表节点的新实例。 + /// + /// 节点的排序键。 + /// 节点的副键。 + /// 节点的主键。 + /// 节点存储的值。 + /// 节点在跳跃表中的索引。 + /// 指向左侧节点的引用。 + /// 指向右侧节点的引用。 + /// 指向下一层节点的引用。 + public SkipTableNode(long sortKey, long viceKey, long key, TValue value, int index, + SkipTableNode l, + SkipTableNode r, + SkipTableNode d) + { + Left = l; + Right = r; + Down = d; + Value = value; + Key = key; + Index = index; + SortKey = sortKey; + ViceKey = viceKey; + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Entitas/Component/CoroutineLock/CoroutineLock.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Entitas/Component/CoroutineLock/CoroutineLock.cs new file mode 100644 index 0000000..a95d8f3 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Entitas/Component/CoroutineLock/CoroutineLock.cs @@ -0,0 +1,140 @@ +using System; +using System.Collections.Generic; +using Fantasy.Pool; + +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. +#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. +namespace Fantasy.Async +{ + /// + /// 协程锁专用的对象池 + /// + public sealed class CoroutineLockPool : PoolCore + { + /// + /// 协程锁专用的对象池的构造函数 + /// + public CoroutineLockPool() : base(2000) { } + } + + /// + /// 协程锁 + /// + public sealed class CoroutineLock : IPool, IDisposable + { + private Scene _scene; + private CoroutineLockComponent _coroutineLockComponent; + private readonly Dictionary _queue = new Dictionary(); + /// + /// 表示是否是对象池中创建的 + /// + private bool _isPool; + /// + /// 协程锁的类型 + /// + public long CoroutineLockType { get; private set; } + + internal void Initialize(CoroutineLockComponent coroutineLockComponent, ref long coroutineLockType) + { + _scene = coroutineLockComponent.Scene; + CoroutineLockType = coroutineLockType; + _coroutineLockComponent = coroutineLockComponent; + } + /// + /// 销毁协程锁,如果调用了该方法,所有使用当前协程锁等待的逻辑会按照顺序释放锁。 + /// + public void Dispose() + { + foreach (var (_, coroutineLockQueue) in _queue) + { + while (TryCoroutineLockQueueDequeue(coroutineLockQueue)) { } + } + + _queue.Clear(); + _scene = null; + CoroutineLockType = 0; + _coroutineLockComponent = null; + } + /// + /// 等待上一个任务完成 + /// + /// 需要等待的Id + /// 用于查询协程锁的标记,可不传入,只有在超时的时候排查是哪个锁超时时使用 + /// 等待多久会超时,当到达设定的时候会把当前锁给按照超时处理 + /// + public async FTask Wait(long coroutineLockQueueKey, string tag = null, int timeOut = 30000) + { + var waitCoroutineLock = _coroutineLockComponent.WaitCoroutineLockPool.Rent(this, ref coroutineLockQueueKey, tag, timeOut); + + if (!_queue.TryGetValue(coroutineLockQueueKey, out var queue)) + { + queue = _coroutineLockComponent.CoroutineLockQueuePool.Rent(); + _queue.Add(coroutineLockQueueKey, queue); + return waitCoroutineLock; + } + + queue.Enqueue(waitCoroutineLock); + return await waitCoroutineLock.Tcs; + } + /// + /// 按照先入先出的顺序,释放最早的一个协程锁 + /// + /// + public void Release(long coroutineLockQueueKey) + { + if (!_queue.TryGetValue(coroutineLockQueueKey, out var coroutineLockQueue)) + { + return; + } + + if (!TryCoroutineLockQueueDequeue(coroutineLockQueue)) + { + _queue.Remove(coroutineLockQueueKey); + } + } + + private bool TryCoroutineLockQueueDequeue(CoroutineLockQueue coroutineLockQueue) + { + if (!coroutineLockQueue.TryDequeue(out var waitCoroutineLock)) + { + _coroutineLockComponent.CoroutineLockQueuePool.Return(coroutineLockQueue); + return false; + } + + if (waitCoroutineLock.TimerId != 0) + { + _scene.TimerComponent.Net.Remove(waitCoroutineLock.TimerId); + } + + try + { + // 放到下一帧执行,如果不这样会导致逻辑的顺序不正常。 + _scene.ThreadSynchronizationContext.Post(waitCoroutineLock.SetResult); + } + catch (Exception e) + { + Log.Error($"Error in disposing CoroutineLock: {e}"); + } + + return true; + } + + /// + /// 获取一个值,该值指示当前实例是否为对象池中的实例。 + /// + /// + public bool IsPool() + { + return _isPool; + } + + /// + /// 设置一个值,该值指示当前实例是否为对象池中的实例。 + /// + /// + public void SetIsPool(bool isPool) + { + _isPool = isPool; + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Entitas/Component/CoroutineLock/CoroutineLockComponent.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Entitas/Component/CoroutineLock/CoroutineLockComponent.cs new file mode 100644 index 0000000..4644274 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Entitas/Component/CoroutineLock/CoroutineLockComponent.cs @@ -0,0 +1,100 @@ +using System.Collections.Generic; +using Fantasy.Entitas; + +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. +#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. + +namespace Fantasy.Async +{ + /// + /// 协程锁组件 + /// + public class CoroutineLockComponent : Entity + { + private long _lockId; + private CoroutineLockPool _coroutineLockPool; + internal WaitCoroutineLockPool WaitCoroutineLockPool { get; private set; } + internal CoroutineLockQueuePool CoroutineLockQueuePool { get; private set; } + private readonly Dictionary _coroutineLocks = new Dictionary(); + internal CoroutineLockComponent Initialize() + { + _coroutineLockPool = new CoroutineLockPool(); + CoroutineLockQueuePool = new CoroutineLockQueuePool(); + WaitCoroutineLockPool = new WaitCoroutineLockPool(this); + return this; + } + + internal long LockId => ++_lockId; + +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member + public override void Dispose() +#pragma warning restore CS1591 // Missing XML comment for publicly visible type or member + { + if (IsDisposed) + { + return; + } + + _lockId = 0; + base.Dispose(); + } + + /// + /// 创建一个新的协程锁 + /// 使用这个方法创建的协程锁,需要手动释放管理CoroutineLock。 + /// 不会再CoroutineLockComponent理进行管理。 + /// + /// + /// + public CoroutineLock Create(long coroutineLockType) + { + var coroutineLock = _coroutineLockPool.Rent(); + coroutineLock.Initialize(this, ref coroutineLockType); + return coroutineLock; + } + + /// + /// 请求一个协程锁。 + /// 使用这个方法创建的协程锁,会自动释放CoroutineLockQueueType。 + /// + /// 锁类型 + /// 锁队列Id + /// 当某些锁超时,需要一个标记来方便排查问题,正常的情况下这个默认为null就可以。 + /// 设置锁的超时时间,让超过设置的时间会触发超时,保证锁不会因为某一个锁一直不解锁导致卡住的问题。 + /// + /// 返回的WaitCoroutineLock通过Dispose来解除这个锁、建议用using来保住这个锁。 + /// 也可以返回的WaitCoroutineLock通过CoroutineLockComponent.UnLock来解除这个锁。 + /// + public FTask Wait(long coroutineLockType, long coroutineLockQueueKey, string tag = null, int time = 30000) + { + if (!_coroutineLocks.TryGetValue(coroutineLockType, out var coroutineLock)) + { + coroutineLock = _coroutineLockPool.Rent(); + coroutineLock.Initialize(this, ref coroutineLockType); + _coroutineLocks.Add(coroutineLockType, coroutineLock); + } + + return coroutineLock.Wait(coroutineLockQueueKey, tag, time); + } + + /// + /// 解除一个协程锁。 + /// + /// + /// + public void Release(int coroutineLockType, long coroutineLockQueueKey) + { + if (IsDisposed) + { + return; + } + + if (!_coroutineLocks.TryGetValue(coroutineLockType, out var coroutineLock)) + { + return; + } + + coroutineLock.Release(coroutineLockQueueKey); + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Entitas/Component/CoroutineLock/CoroutineLockQueue.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Entitas/Component/CoroutineLock/CoroutineLockQueue.cs new file mode 100644 index 0000000..2948aca --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Entitas/Component/CoroutineLock/CoroutineLockQueue.cs @@ -0,0 +1,35 @@ +// ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract +using System.Collections.Generic; +using Fantasy.Pool; + +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. +#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. +namespace Fantasy.Async +{ + internal sealed class CoroutineLockQueuePool : PoolCore + { + public CoroutineLockQueuePool() : base(2000) { } + } + + internal sealed class CoroutineLockQueue : Queue, IPool + { + private bool _isPool; + /// + /// 获取一个值,该值指示当前实例是否为对象池中的实例。 + /// + /// + public bool IsPool() + { + return _isPool; + } + + /// + /// 设置一个值,该值指示当前实例是否为对象池中的实例。 + /// + /// + public void SetIsPool(bool isPool) + { + _isPool = isPool; + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Entitas/Component/CoroutineLock/WaitCoroutineLock.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Entitas/Component/CoroutineLock/WaitCoroutineLock.cs new file mode 100644 index 0000000..28d04d4 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Entitas/Component/CoroutineLock/WaitCoroutineLock.cs @@ -0,0 +1,146 @@ +using System; +using Fantasy.Event; +using Fantasy.Pool; + +#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. +namespace Fantasy.Async +{ + internal sealed class WaitCoroutineLockPool : PoolCore + { + private readonly Scene _scene; + private readonly CoroutineLockComponent _coroutineLockComponent; + + public WaitCoroutineLockPool(CoroutineLockComponent coroutineLockComponent) : base(2000) + { + _scene = coroutineLockComponent.Scene; + _coroutineLockComponent = coroutineLockComponent; + } + + public WaitCoroutineLock Rent(CoroutineLock coroutineLock, ref long coroutineLockQueueKey, string tag = null, int timeOut = 30000) + { + var timerId = 0L; + var lockId = _coroutineLockComponent.LockId; + var waitCoroutineLock = _coroutineLockComponent.WaitCoroutineLockPool.Rent(); + + if (timeOut > 0) + { + timerId = _scene.TimerComponent.Net.OnceTimer(timeOut, new CoroutineLockTimeout(ref lockId, waitCoroutineLock)); + } + + waitCoroutineLock.Initialize(coroutineLock, this, ref coroutineLockQueueKey, ref timerId, ref lockId, tag); + return waitCoroutineLock; + } + } + + internal struct CoroutineLockTimeout + { + public readonly long LockId; + public readonly WaitCoroutineLock WaitCoroutineLock; + + public CoroutineLockTimeout(ref long lockId, WaitCoroutineLock waitCoroutineLock) + { + LockId = lockId; + WaitCoroutineLock = waitCoroutineLock; + } + } + + internal sealed class OnCoroutineLockTimeout : EventSystem + { + protected override void Handler(CoroutineLockTimeout self) + { + var selfWaitCoroutineLock = self.WaitCoroutineLock; + + if (self.LockId != selfWaitCoroutineLock.LockId) + { + return; + } + + Log.Error($"coroutine lock timeout CoroutineLockQueueType:{selfWaitCoroutineLock.CoroutineLock.CoroutineLockType} Key:{selfWaitCoroutineLock.CoroutineLockQueueKey} Tag:{selfWaitCoroutineLock.Tag}"); + } + } + + /// + /// 一个协程锁的实例,用户可以用过这个手动释放锁 + /// + public sealed class WaitCoroutineLock : IPool, IDisposable + { + private bool _isPool; + internal string Tag { get; private set; } + internal long LockId { get; private set; } + internal long TimerId { get; private set; } + internal long CoroutineLockQueueKey { get; private set; } + internal CoroutineLock CoroutineLock { get; private set; } + + private bool _isSetResult; + private FTask _tcs; + private WaitCoroutineLockPool _waitCoroutineLockPool; + internal void Initialize(CoroutineLock coroutineLock, WaitCoroutineLockPool waitCoroutineLockPool, ref long coroutineLockQueueKey, ref long timerId, ref long lockId, string tag) + { + Tag = tag; + LockId = lockId; + TimerId = timerId; + CoroutineLock = coroutineLock; + CoroutineLockQueueKey = coroutineLockQueueKey; + _waitCoroutineLockPool = waitCoroutineLockPool; + } + /// + /// 释放协程锁 + /// + public void Dispose() + { + if (LockId == 0) + { + Log.Error("WaitCoroutineLock is already disposed"); + return; + } + + CoroutineLock.Release(CoroutineLockQueueKey); + + _tcs = null; + Tag = null; + LockId = 0; + TimerId = 0; + _isSetResult = false; + CoroutineLockQueueKey = 0; + _waitCoroutineLockPool.Return(this); + CoroutineLock = null; + _waitCoroutineLockPool = null; + } + + internal FTask Tcs + { + get { return _tcs ??= FTask.Create(); } + } + + internal void SetResult() + { + if (_isSetResult) + { + Log.Error("WaitCoroutineLock is already SetResult"); + return; + } + + _isSetResult = true; + Tcs.SetResult(this); + } + + /// + /// 获取一个值,该值指示当前实例是否为对象池中的实例。 + /// + /// + public bool IsPool() + { + return _isPool; + } + + /// + /// 设置一个值,该值指示当前实例是否为对象池中的实例。 + /// + /// + public void SetIsPool(bool isPool) + { + _isPool = isPool; + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Entitas/Component/EntityComponent.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Entitas/Component/EntityComponent.cs new file mode 100644 index 0000000..aa92314 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Entitas/Component/EntityComponent.cs @@ -0,0 +1,399 @@ +// ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using Fantasy.Assembly; +using Fantasy.Async; +using Fantasy.DataStructure.Collection; +using Fantasy.Entitas; +using Fantasy.Entitas.Interface; +using Fantasy.Helper; + +#pragma warning disable CS8604 // Possible null reference argument. +#pragma warning disable CS8600 // Converting null literal or possible null value to non-nullable type. +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member +namespace Fantasy.Entitas +{ + internal sealed class UpdateQueueInfo + { + public bool IsStop; + public readonly Type Type; + public readonly long RunTimeId; + + public UpdateQueueInfo(Type type, long runTimeId) + { + Type = type; + IsStop = false; + RunTimeId = runTimeId; + } + } + + internal sealed class FrameUpdateQueueInfo + { + public readonly Type Type; + public readonly long RunTimeId; + + public FrameUpdateQueueInfo(Type type, long runTimeId) + { + Type = type; + RunTimeId = runTimeId; + } + } + + /// + /// Entity管理组件 + /// + public sealed class EntityComponent : Entity, ISceneUpdate, IAssembly + { + private readonly OneToManyList _assemblyList = new(); + private readonly OneToManyList _assemblyHashCodes = new(); + + private readonly Dictionary _awakeSystems = new(); + private readonly Dictionary _updateSystems = new(); + private readonly Dictionary _destroySystems = new(); + private readonly Dictionary _deserializeSystems = new(); + private readonly Dictionary _frameUpdateSystem = new(); + + private readonly Dictionary _hashCodes = new Dictionary(); + private readonly Queue _updateQueue = new Queue(); + private readonly Queue _frameUpdateQueue = new Queue(); + private readonly Dictionary _updateQueueDic = new Dictionary(); + + internal async FTask Initialize() + { + await AssemblySystem.Register(this); + return this; + } + + #region Assembly + + public FTask Load(long assemblyIdentity) + { + var task = FTask.Create(false); + Scene.ThreadSynchronizationContext.Post(() => + { + LoadInner(assemblyIdentity); + task.SetResult(); + }); + return task; + } + + public FTask ReLoad(long assemblyIdentity) + { + var task = FTask.Create(false); + Scene.ThreadSynchronizationContext.Post(() => + { + OnUnLoadInner(assemblyIdentity); + LoadInner(assemblyIdentity); + task.SetResult(); + }); + + return task; + } + + public FTask OnUnLoad(long assemblyIdentity) + { + var task = FTask.Create(false); + Scene.ThreadSynchronizationContext.Post(() => + { + OnUnLoadInner(assemblyIdentity); + task.SetResult(); + }); + return task; + } + + private void LoadInner(long assemblyIdentity) + { + foreach (var entityType in AssemblySystem.ForEach(assemblyIdentity, typeof(IEntity))) + { + _hashCodes.Add(entityType, HashCodeHelper.ComputeHash64(entityType.FullName)); + _assemblyHashCodes.Add(assemblyIdentity, entityType); + } + + foreach (var entitiesSystemType in AssemblySystem.ForEach(assemblyIdentity, typeof(IEntitiesSystem))) + { + Type entitiesType = null; + var entity = Activator.CreateInstance(entitiesSystemType); + + switch (entity) + { + case IAwakeSystem iAwakeSystem: + { + entitiesType = iAwakeSystem.EntitiesType(); + _awakeSystems.Add(entitiesType, iAwakeSystem); + break; + } + case IDestroySystem iDestroySystem: + { + entitiesType = iDestroySystem.EntitiesType(); + _destroySystems.Add(entitiesType, iDestroySystem); + break; + } + case IDeserializeSystem iDeserializeSystem: + { + entitiesType = iDeserializeSystem.EntitiesType(); + _deserializeSystems.Add(entitiesType, iDeserializeSystem); + break; + } + case IUpdateSystem iUpdateSystem: + { + entitiesType = iUpdateSystem.EntitiesType(); + _updateSystems.Add(entitiesType, iUpdateSystem); + break; + } + case IFrameUpdateSystem iFrameUpdateSystem: + { + entitiesType = iFrameUpdateSystem.EntitiesType(); + _frameUpdateSystem.Add(entitiesType, iFrameUpdateSystem); + break; + } + default: + { + Log.Error($"IEntitiesSystem not support type {entitiesSystemType}"); + return; + } + } + + _assemblyList.Add(assemblyIdentity, entitiesType); + } + } + + private void OnUnLoadInner(long assemblyIdentity) + { + if (_assemblyHashCodes.TryGetValue(assemblyIdentity, out var entityType)) + { + foreach (var type in entityType) + { + _hashCodes.Remove(type); + } + + _assemblyHashCodes.RemoveByKey(assemblyIdentity); + } + + if (_assemblyList.TryGetValue(assemblyIdentity, out var assembly)) + { + foreach (var type in assembly) + { + _awakeSystems.Remove(type); + _updateSystems.Remove(type); + _destroySystems.Remove(type); + _deserializeSystems.Remove(type); + _frameUpdateSystem.Remove(type); + } + + _assemblyList.RemoveByKey(assemblyIdentity); + } + } + + #endregion + + #region Event + + /// + /// 触发实体的唤醒方法 + /// + /// 实体对象 + public void Awake(Entity entity) + { + if (!_awakeSystems.TryGetValue(entity.Type, out var awakeSystem)) + { + return; + } + + try + { + awakeSystem.Invoke(entity); + } + catch (Exception e) + { + Log.Error($"{entity.Type.FullName} Error {e}"); + } + } + + /// + /// 触发实体的销毁方法 + /// + /// 实体对象 + public void Destroy(Entity entity) + { + if (!_destroySystems.TryGetValue(entity.Type, out var system)) + { + return; + } + + try + { + system.Invoke(entity); + } + catch (Exception e) + { + Log.Error($"{entity.Type.FullName} Destroy Error {e}"); + } + } + + /// + /// 触发实体的反序列化方法 + /// + /// 实体对象 + public void Deserialize(Entity entity) + { + if (!_deserializeSystems.TryGetValue(entity.Type, out var system)) + { + return; + } + + try + { + system.Invoke(entity); + } + catch (Exception e) + { + Log.Error($"{entity.Type.FullName} Deserialize Error {e}"); + } + } + + #endregion + + #region Update + + /// + /// 将实体加入更新队列,准备进行更新 + /// + /// 实体对象 + public void StartUpdate(Entity entity) + { + var type = entity.Type; + var entityRuntimeId = entity.RuntimeId; + + if (_updateSystems.ContainsKey(type)) + { + var updateQueueInfo = new UpdateQueueInfo(type, entityRuntimeId); + _updateQueue.Enqueue(updateQueueInfo); + _updateQueueDic.Add(entityRuntimeId, updateQueueInfo); + } + + if (_frameUpdateSystem.ContainsKey(type)) + { + _frameUpdateQueue.Enqueue(new FrameUpdateQueueInfo(type, entityRuntimeId)); + } + } + + /// + /// 停止实体进行更新 + /// + /// 实体对象 + public void StopUpdate(Entity entity) + { + if (!_updateQueueDic.Remove(entity.RuntimeId, out var updateQueueInfo)) + { + return; + } + + updateQueueInfo.IsStop = true; + } + + /// + /// 执行实体系统的更新逻辑 + /// + public void Update() + { + var updateQueueCount = _updateQueue.Count; + + while (updateQueueCount-- > 0) + { + var updateQueueStruct = _updateQueue.Dequeue(); + + if (updateQueueStruct.IsStop) + { + continue; + } + + if (!_updateSystems.TryGetValue(updateQueueStruct.Type, out var updateSystem)) + { + continue; + } + + var entity = Scene.GetEntity(updateQueueStruct.RunTimeId); + + if (entity == null || entity.IsDisposed) + { + _updateQueueDic.Remove(updateQueueStruct.RunTimeId); + continue; + } + + _updateQueue.Enqueue(updateQueueStruct); + + try + { + updateSystem.Invoke(entity); + } + catch (Exception e) + { + Log.Error($"{updateQueueStruct.Type.FullName} Update Error {e}"); + } + } + } + + /// + /// 执行实体系统的帧更新逻辑 + /// + public void FrameUpdate() + { + var count = _frameUpdateQueue.Count; + + while (count-- > 0) + { + var frameUpdateQueueStruct = _frameUpdateQueue.Dequeue(); + + if (!_frameUpdateSystem.TryGetValue(frameUpdateQueueStruct.Type, out var frameUpdateSystem)) + { + continue; + } + + var entity = Scene.GetEntity(frameUpdateQueueStruct.RunTimeId); + + if (entity == null || entity.IsDisposed) + { + continue; + } + + _frameUpdateQueue.Enqueue(frameUpdateQueueStruct); + + try + { + frameUpdateSystem.Invoke(entity); + } + catch (Exception e) + { + Log.Error($"{frameUpdateQueueStruct.Type.FullName} FrameUpdate Error {e}"); + } + } + } + + #endregion + + public long GetHashCode(Type type) + { + return _hashCodes[type]; + } + + /// + /// 释放实体系统管理器资源 + /// + public override void Dispose() + { + _updateQueue.Clear(); + _frameUpdateQueue.Clear(); + + _assemblyList.Clear(); + _awakeSystems.Clear(); + _updateSystems.Clear(); + _destroySystems.Clear(); + _deserializeSystems.Clear(); + _frameUpdateSystem.Clear(); + + AssemblySystem.UnRegister(this); + base.Dispose(); + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Entitas/Component/EventComponent/EventComponent.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Entitas/Component/EventComponent/EventComponent.cs new file mode 100644 index 0000000..d2213f7 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Entitas/Component/EventComponent/EventComponent.cs @@ -0,0 +1,252 @@ +using System; +using System.Reflection; +using Fantasy.Assembly; +using Fantasy.Async; +using Fantasy.DataStructure.Collection; +using Fantasy.Entitas; + +// ReSharper disable PossibleMultipleEnumeration +#pragma warning disable CS8600 // Converting null literal or possible null value to non-nullable type. +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member +// ReSharper disable MethodOverloadWithOptionalParameter + +namespace Fantasy.Event +{ + internal sealed class EventCache + { + public readonly Type EnventType; + public readonly object Obj; + public EventCache(Type enventType, object obj) + { + EnventType = enventType; + Obj = obj; + } + } + + public sealed class EventComponent : Entity, IAssembly + { + private readonly OneToManyList _events = new(); + private readonly OneToManyList _asyncEvents = new(); + private readonly OneToManyList _assemblyEvents = new(); + private readonly OneToManyList _assemblyAsyncEvents = new(); + + internal async FTask Initialize() + { + await AssemblySystem.Register(this); + return this; + } + + #region Assembly + + public async FTask Load(long assemblyIdentity) + { + var tcs = FTask.Create(false); + Scene.ThreadSynchronizationContext.Post(() => + { + LoadInner(assemblyIdentity); + tcs.SetResult(); + }); + await tcs; + } + + public async FTask ReLoad(long assemblyIdentity) + { + var tcs = FTask.Create(false); + Scene.ThreadSynchronizationContext.Post(() => + { + OnUnLoadInner(assemblyIdentity); + LoadInner(assemblyIdentity); + tcs.SetResult(); + }); + await tcs; + } + + public async FTask OnUnLoad(long assemblyIdentity) + { + var tcs = FTask.Create(false); + Scene.ThreadSynchronizationContext.Post(() => + { + OnUnLoadInner(assemblyIdentity); + tcs.SetResult(); + }); + await tcs; + } + + private void LoadInner(long assemblyIdentity) + { + foreach (var type in AssemblySystem.ForEach(assemblyIdentity, typeof(IEvent))) + { + var @event = (IEvent)Activator.CreateInstance(type); + + if (@event == null) + { + continue; + } + + var eventType = @event.EventType(); + _events.Add(eventType, @event); + _assemblyEvents.Add(assemblyIdentity, new EventCache(eventType, @event)); + } + + foreach (var type in AssemblySystem.ForEach(assemblyIdentity, typeof(IAsyncEvent))) + { + var @event = (IAsyncEvent)Activator.CreateInstance(type); + + if (@event == null) + { + continue; + } + + var eventType = @event.EventType(); + _asyncEvents.Add(eventType, @event); + _assemblyAsyncEvents.Add(assemblyIdentity, new EventCache(eventType, @event)); + } + } + + private void OnUnLoadInner(long assemblyIdentity) + { + if (_assemblyEvents.TryGetValue(assemblyIdentity, out var events)) + { + foreach (var @event in events) + { + _events.RemoveValue(@event.EnventType, (IEvent)@event.Obj); + } + + _assemblyEvents.RemoveByKey(assemblyIdentity); + } + + if (_assemblyAsyncEvents.TryGetValue(assemblyIdentity, out var asyncEvents)) + { + foreach (var @event in asyncEvents) + { + _asyncEvents.RemoveValue(@event.EnventType, (IAsyncEvent)@event.Obj); + } + + _assemblyAsyncEvents.RemoveByKey(assemblyIdentity); + } + } + + #endregion + + #region Publish + + /// + /// 发布一个值类型的事件数据。 + /// + /// 事件数据类型(值类型)。 + /// 事件数据实例。 + public void Publish(TEventData eventData) where TEventData : struct + { + if (!_events.TryGetValue(typeof(TEventData), out var list)) + { + return; + } + + foreach (var @event in list) + { + try + { + @event.Invoke(eventData); + } + catch (Exception e) + { + Log.Error(e); + } + } + } + + /// + /// 发布一个继承自 Entity 的事件数据。 + /// + /// 事件数据类型(继承自 Entity)。 + /// 事件数据实例。 + /// 是否释放事件数据。 + public void Publish(TEventData eventData, bool isDisposed = true) where TEventData : Entity + { + if (!_events.TryGetValue(typeof(TEventData), out var list)) + { + return; + } + + foreach (var @event in list) + { + try + { + @event.Invoke(eventData); + } + catch (Exception e) + { + Log.Error(e); + } + } + + if (isDisposed) + { + eventData.Dispose(); + } + } + + /// + /// 异步发布一个值类型的事件数据。 + /// + /// 事件数据类型(值类型)。 + /// 事件数据实例。 + /// 表示异步操作的任务。 + public async FTask PublishAsync(TEventData eventData) where TEventData : struct + { + if (!_asyncEvents.TryGetValue(typeof(TEventData), out var list)) + { + return; + } + + using var tasks = ListPool.Create(); + + foreach (var @event in list) + { + tasks.Add(@event.InvokeAsync(eventData)); + } + + await FTask.WaitAll(tasks); + } + + /// + /// 异步发布一个继承自 Entity 的事件数据。 + /// + /// 事件数据类型(继承自 Entity)。 + /// 事件数据实例。 + /// 是否释放事件数据。 + /// 表示异步操作的任务。 + public async FTask PublishAsync(TEventData eventData, bool isDisposed = true) where TEventData : Entity + { + if (!_asyncEvents.TryGetValue(eventData.GetType(), out var list)) + { + return; + } + + using var tasks = ListPool.Create(); + + foreach (var @event in list) + { + tasks.Add(@event.InvokeAsync(eventData)); + } + + await FTask.WaitAll(tasks); + + if (isDisposed) + { + eventData.Dispose(); + } + } + + #endregion + + public override void Dispose() + { + _events.Clear(); + _asyncEvents.Clear(); + _assemblyEvents.Clear(); + _assemblyAsyncEvents.Clear(); + base.Dispose(); + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Entitas/Component/EventComponent/Interface/IEvent.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Entitas/Component/EventComponent/Interface/IEvent.cs new file mode 100644 index 0000000..5314995 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Entitas/Component/EventComponent/Interface/IEvent.cs @@ -0,0 +1,112 @@ +using System; +using Fantasy.Async; + +namespace Fantasy.Event +{ + /// + /// 事件的接口 + /// + public interface IEvent + { + /// + /// 用于指定事件的Type + /// + /// + Type EventType(); + /// + /// 时间内部使用的入口 + /// + /// + void Invoke(object self); + } + + /// + /// 异步事件的接口 + /// + public interface IAsyncEvent + { + /// + /// + /// + /// + Type EventType(); + /// + /// + /// + /// + FTask InvokeAsync(object self); + } + + /// + /// 事件的抽象类,要使用事件必须要继承这个抽象接口。 + /// + /// 要监听的事件泛型类型 + public abstract class EventSystem : IEvent + { + private readonly Type _selfType = typeof(T); + /// + /// + /// + /// + public Type EventType() + { + return _selfType; + } + /// + /// 事件调用的方法,要在这个方法里编写事件发生的逻辑 + /// + /// + protected abstract void Handler(T self); + /// + /// + /// + /// + public void Invoke(object self) + { + try + { + Handler((T) self); + } + catch (Exception e) + { + Log.Error($"{_selfType.Name} Error {e}"); + } + } + } + /// + /// 异步事件的抽象类,要使用事件必须要继承这个抽象接口。 + /// + /// 要监听的事件泛型类型 + public abstract class AsyncEventSystem : IAsyncEvent + { + private readonly Type _selfType = typeof(T); + /// + /// + /// + /// + public Type EventType() + { + return _selfType; + } + /// + /// 事件调用的方法,要在这个方法里编写事件发生的逻辑 + /// + /// + protected abstract FTask Handler(T self); + /// + /// + /// + /// + public async FTask InvokeAsync(object self) + { + try + { + await Handler((T) self); + } + catch (Exception e) + { + Log.Error($"{_selfType.Name} Error {e}"); + } + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Entitas/Component/MessagePoolComponent.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Entitas/Component/MessagePoolComponent.cs new file mode 100644 index 0000000..f1ddb23 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Entitas/Component/MessagePoolComponent.cs @@ -0,0 +1,139 @@ +// ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract + +using System; +using System.Collections.Generic; +using System.Runtime.CompilerServices; +using Fantasy.DataStructure.Collection; +using Fantasy.Entitas; +using Fantasy.Pool; +using Fantasy.Serialize; + +namespace Fantasy.Entitas +{ + /// + /// 消息的对象池组件 + /// + public sealed class MessagePoolComponent : Entity + { + private int _poolCount; + private const int MaxCapacity = ushort.MaxValue; + private readonly OneToManyQueue _poolQueue = new OneToManyQueue(); + private readonly Dictionary> _typeCheckCache = new Dictionary>(); + /// + /// 销毁组件 + /// + public override void Dispose() + { + _poolCount = 0; + _poolQueue.Clear(); + _typeCheckCache.Clear(); + base.Dispose(); + } + /// + /// 从对象池里获取一个消息,如果没有就创建一个新的 + /// + /// 消息的泛型类型 + /// + public T Rent() where T : AMessage, new() + { + if (!_poolQueue.TryDequeue(typeof(T), out var queue)) + { + var instance = new T(); + instance.SetScene(Scene); + instance.SetIsPool(true); + return instance; + } + + queue.SetIsPool(true); + _poolCount--; + return (T)queue; + } + + /// + /// + /// + /// 消息的类型 + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public AMessage Rent(Type type) + { + if (!_poolQueue.TryDequeue(type, out var queue)) + { + if (!_typeCheckCache.TryGetValue(type, out var createInstance)) + { + if (!typeof(AMessage).IsAssignableFrom(type)) + { + throw new NotSupportedException($"{this.GetType().FullName} Type:{type.FullName} must inherit from IPool"); + } + else + { + createInstance = CreateInstance.CreateMessage(type); + _typeCheckCache[type] = createInstance; + } + } + + var instance = createInstance(); + instance.SetScene(Scene); + instance.SetIsPool(true); + return instance; + } + + queue.SetIsPool(true); + _poolCount--; + return queue; + } + /// + /// 返还一个消息到对象池中 + /// + /// + public void Return(AMessage obj) + { + if (obj == null) + { + return; + } + + if (!obj.IsPool()) + { + return; + } + + if (_poolCount >= MaxCapacity) + { + return; + } + + _poolCount++; + obj.SetIsPool(false); + _poolQueue.Enqueue(obj.GetType(), obj); + } + + /// + /// + /// + /// 返还的消息 + /// 返还的消息泛型类型 + public void Return(T obj) where T : AMessage + { + if (obj == null) + { + return; + } + + if (!obj.IsPool()) + { + return; + } + + if (_poolCount >= MaxCapacity) + { + return; + } + + _poolCount++; + obj.SetIsPool(false); + _poolQueue.Enqueue(typeof(T), obj); + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Entitas/Component/SingleCollectionComponent/SingleCollectionComponent.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Entitas/Component/SingleCollectionComponent/SingleCollectionComponent.cs new file mode 100644 index 0000000..9ecfdd2 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Entitas/Component/SingleCollectionComponent/SingleCollectionComponent.cs @@ -0,0 +1,167 @@ +// ReSharper disable SuspiciousTypeConversion.Global + +using Fantasy.Assembly; +using Fantasy.Async; +using Fantasy.DataStructure.Collection; +using Fantasy.Entitas; +using Fantasy.Entitas.Interface; +using Fantasy.Helper; + +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member +#pragma warning disable CS8604 // Possible null reference argument. +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. +#if FANTASY_NET +namespace Fantasy.SingleCollection +{ + /// + /// 用于处理Entity下的实体进行数据库分表存储的组件 + /// + public sealed class SingleCollectionComponent : Entity, IAssembly + { + private CoroutineLock _coroutineLock; + private readonly OneToManyHashSet _collection = new OneToManyHashSet(); + + private readonly OneToManyList _assemblyCollections = + new OneToManyList(); + + private sealed class SingleCollectionInfo(Type rootType, string collectionName) + { + public readonly Type RootType = rootType; + public readonly string CollectionName = collectionName; + } + + internal async FTask Initialize() + { + var coroutineLockType = HashCodeHelper.ComputeHash64(GetType().FullName); + _coroutineLock = Scene.CoroutineLockComponent.Create(coroutineLockType); + await AssemblySystem.Register(this); + return this; + } + + #region Assembly + + public async FTask Load(long assemblyIdentity) + { + var tcs = FTask.Create(false); + Scene.ThreadSynchronizationContext.Post(() => + { + LoadInner(assemblyIdentity); + tcs.SetResult(); + }); + await tcs; + } + + public async FTask ReLoad(long assemblyIdentity) + { + var tcs = FTask.Create(false); + Scene.ThreadSynchronizationContext.Post(() => + { + OnUnLoadInner(assemblyIdentity); + LoadInner(assemblyIdentity); + tcs.SetResult(); + }); + await tcs; + } + + public async FTask OnUnLoad(long assemblyIdentity) + { + var tcs = FTask.Create(false); + Scene.ThreadSynchronizationContext.Post(() => + { + OnUnLoadInner(assemblyIdentity); + tcs.SetResult(); + }); + await tcs; + } + + private void LoadInner(long assemblyIdentity) + { + foreach (var type in AssemblySystem.ForEach(assemblyIdentity, typeof(ISupportedSingleCollection))) + { + var customAttributes = type.GetCustomAttributes(typeof(SingleCollectionAttribute), false); + if (customAttributes.Length == 0) + { + Log.Error( + $"type {type.FullName} Implemented the interface of ISingleCollection, requiring the implementation of SingleCollectionAttribute"); + continue; + } + + var singleCollectionAttribute = (SingleCollectionAttribute)customAttributes[0]; + var rootType = singleCollectionAttribute.RootType; + var collectionName = singleCollectionAttribute.CollectionName; + _collection.Add(rootType, collectionName); + _assemblyCollections.Add(assemblyIdentity, new SingleCollectionInfo(rootType, collectionName)); + } + } + + private void OnUnLoadInner(long assemblyIdentity) + { + if (!_assemblyCollections.TryGetValue(assemblyIdentity, out var types)) + { + return; + } + + foreach (var singleCollectionInfo in types) + { + _collection.RemoveValue(singleCollectionInfo.RootType, singleCollectionInfo.CollectionName); + } + + _assemblyCollections.RemoveByKey(assemblyIdentity); + } + + #endregion + + #region Collections + + /// + /// 通过数据库获取某一个实体类型下所有的分表数据到当前实体下,并且会自动建立父子关系。 + /// + /// 实体实例 + /// 实体泛型类型 + public async FTask GetCollections(T entity) where T : Entity, ISingleCollectionRoot + { + if (!_collection.TryGetValue(typeof(T), out var collections)) + { + return; + } + + var worldDateBase = Scene.World.DataBase; + + using (await _coroutineLock.Wait(entity.Id)) + { + foreach (var collectionName in collections) + { + var singleCollection = await worldDateBase.QueryNotLock(entity.Id, true, collectionName); + entity.AddComponent(singleCollection); + } + } + } + + /// + /// 存储当前实体下支持分表的组件到数据中,包括存储实体本身。 + /// + /// 实体实例 + /// 实体泛型类型 + public async FTask SaveCollections(T entity) where T : Entity, ISingleCollectionRoot + { + using var collections = ListPool.Create(); + + foreach (var treeEntity in entity.ForEachSingleCollection) + { + if (treeEntity is not ISupportedSingleCollection) + { + continue; + } + + collections.Add(treeEntity); + } + + collections.Add(entity); + await entity.Scene.World.DataBase.Save(entity.Id, collections); + } + + #endregion + } +} + +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Entitas/Component/TimerComponent/Interface/TimerHandler.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Entitas/Component/TimerComponent/Interface/TimerHandler.cs new file mode 100644 index 0000000..9e1f4c9 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Entitas/Component/TimerComponent/Interface/TimerHandler.cs @@ -0,0 +1,10 @@ +using Fantasy.Event; + +namespace Fantasy.Timer +{ + /// + /// 计时器抽象类,提供了一个基础框架,用于创建处理计时器事件的具体类。 + /// + /// 事件的类型参数 + public abstract class TimerHandler : EventSystem { } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Entitas/Component/TimerComponent/TimeWheel/ScheduledTask.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Entitas/Component/TimerComponent/TimeWheel/ScheduledTask.cs new file mode 100644 index 0000000..d644386 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Entitas/Component/TimerComponent/TimeWheel/ScheduledTask.cs @@ -0,0 +1,49 @@ +// #pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. +// #pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. +// namespace Fantasy +// { +// public sealed class ScheduledTaskPool : PoolCore +// { +// public ScheduledTaskPool() : base(2000) { } +// +// public ScheduledTask Rent(Action action, ref int rounds, ref int finalSlot) +// { +// var scheduledTask = Rent(); +// scheduledTask.Rounds = rounds; +// scheduledTask.Action = action; +// scheduledTask.FinalSlot = finalSlot; +// return scheduledTask; +// } +// +// public override void Return(ScheduledTask item) +// { +// base.Return(item); +// item.Dispose(); +// } +// } +// +// public sealed class ScheduledTask : IPool, IDisposable +// { +// public int Rounds; +// public int FinalSlot; +// public Action Action; +// public LinkedListNode Node; +// +// public bool IsPool { get; set; } +// public ScheduledTask() { } +// public ScheduledTask(Action action, ref int rounds, ref int finalSlot) +// { +// Action = action; +// Rounds = rounds; +// FinalSlot = finalSlot; +// } +// +// public void Dispose() +// { +// Rounds = 0; +// FinalSlot = 0; +// Action = null; +// Node = null; +// } +// } +// } \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Entitas/Component/TimerComponent/TimeWheel/TimeWheel.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Entitas/Component/TimerComponent/TimeWheel/TimeWheel.cs new file mode 100644 index 0000000..58916b1 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Entitas/Component/TimerComponent/TimeWheel/TimeWheel.cs @@ -0,0 +1,134 @@ +// using System.Runtime.CompilerServices; +// // ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract +// #pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. +// +// namespace Fantasy +// { +// public sealed class TimeWheel +// { +// private int _currentIndex; +// private ScheduledTaskPool _scheduledTaskPool; +// +// private readonly Scene _scene; +// private readonly int _wheelSize; +// private readonly int _tickDuration; +// private readonly TimeWheel _upperLevelWheel; +// private readonly LinkedList[] _wheel; +// private readonly Queue _tasksToReschedule = new Queue(); +// private readonly Dictionary _taskDictionary = new Dictionary(); +// +// public TimeWheel(TimerComponent timerComponent, int wheelSize, int tickDuration, TimeWheel upperLevelWheel = null) +// { +// _scene = timerComponent.Scene; +// _wheelSize = wheelSize; +// _tickDuration = tickDuration; +// _upperLevelWheel = upperLevelWheel; +// _scheduledTaskPool = timerComponent.ScheduledTaskPool; +// _wheel = new LinkedList[_wheelSize]; +// for (var i = 0; i < wheelSize; i++) +// { +// _wheel[i] = new LinkedList(); +// } +// } +// +// public long Schedule(Action action, int delay) +// { +// var ticks = delay / _tickDuration; +// var futureIndex = ticks + _currentIndex; +// var rounds = futureIndex / _wheelSize; +// var slot = futureIndex % _wheelSize; +// +// if (slot == 0) +// { +// slot = _wheelSize - 1; +// rounds--; +// } +// else +// { +// slot--; +// } +// +// var taskId = _scene.RuntimeIdFactory.Create; +// var task = _scheduledTaskPool.Rent(action, ref rounds, ref slot); +// task.Node = _wheel[slot].AddLast(task); +// _taskDictionary.Add(taskId, task); +// Console.WriteLine($"Schedule rounds:{rounds} slot:{slot} _currentIndex:{_currentIndex}"); +// return taskId; +// } +// +// public bool Remove(int taskId) +// { +// if (!_taskDictionary.TryGetValue(taskId, out var task)) +// { +// return false; +// } +// +// _taskDictionary.Remove(taskId); +// _wheel[task.FinalSlot].Remove(task.Node); +// _scheduledTaskPool.Return(task); +// Console.WriteLine("找到已经删除了任务"); +// return true; +// } +// +// public void Tick(object? state) +// { +// var currentWheel = _wheel[_currentIndex]; +// +// if (currentWheel.Count == 0) +// { +// AdvanceIndex(); +// return; +// } +// +// var currentNode = currentWheel.First; +// +// while (currentNode != null) +// { +// var nextNode = currentNode.Next; +// var task = currentNode.Value; +// +// if (task.Rounds <= 0 && task.FinalSlot == _currentIndex) +// { +// try +// { +// task.Action.Invoke(); +// } +// catch (Exception ex) +// { +// Log.Error($"Exception during task execution: {ex.Message}"); +// } +// } +// else +// { +// task.Rounds--; +// _tasksToReschedule.Enqueue(task); +// } +// +// currentWheel.Remove(currentNode); +// currentNode = nextNode; +// } +// +// RescheduleTasks(); +// AdvanceIndex(); +// } +// +// [MethodImpl(MethodImplOptions.AggressiveInlining)] +// private void AdvanceIndex() +// { +// _currentIndex = (_currentIndex + 1) % _wheelSize; +// if (_currentIndex == 0 && _upperLevelWheel != null) +// { +// _upperLevelWheel.Tick(null); +// } +// } +// +// [MethodImpl(MethodImplOptions.AggressiveInlining)] +// private void RescheduleTasks() +// { +// while (_tasksToReschedule.TryDequeue(out var task)) +// { +// _wheel[task.FinalSlot].AddLast(task); +// } +// } +// } +// } \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Entitas/Component/TimerComponent/TimerAction.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Entitas/Component/TimerComponent/TimerAction.cs new file mode 100644 index 0000000..2a836ab --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Entitas/Component/TimerComponent/TimerAction.cs @@ -0,0 +1,27 @@ +using System; +using System.Runtime.InteropServices; + +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member +#pragma warning disable CS8625 +#pragma warning disable CS8618 + +namespace Fantasy.Timer +{ + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct TimerAction + { + public long TimerId; + public long StartTime; + public long TriggerTime; + public readonly object Callback; + public readonly TimerType TimerType; + public TimerAction(long timerId, TimerType timerType, long startTime, long triggerTime, object callback) + { + TimerId = timerId; + Callback = callback; + TimerType = timerType; + StartTime = startTime; + TriggerTime = triggerTime; + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Entitas/Component/TimerComponent/TimerComponent.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Entitas/Component/TimerComponent/TimerComponent.cs new file mode 100644 index 0000000..ffa7864 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Entitas/Component/TimerComponent/TimerComponent.cs @@ -0,0 +1,52 @@ +// ReSharper disable ForCanBeConvertedToForeach + +using Fantasy.Entitas; +using Fantasy.Entitas.Interface; + +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. +#if FANTASY_UNITY +using UnityEngine; +#endif +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member +namespace Fantasy.Timer +{ + public sealed class TimerComponentUpdateSystem : UpdateSystem + { + protected override void Update(TimerComponent self) + { + self.Update(); + } + } + + /// + /// 时间调度组件 + /// + public sealed class TimerComponent : Entity + { + /// + /// 使用系统时间创建的计时器核心。 + /// + public TimerSchedulerNet Net { get; private set; } +#if FANTASY_UNITY + /// + /// 使用 Unity 时间创建的计时器核心。 + /// + public TimerSchedulerNetUnity Unity { get; private set; } +#endif + internal TimerComponent Initialize() + { + Net = new TimerSchedulerNet(Scene); +#if FANTASY_UNITY + Unity = new TimerSchedulerNetUnity(Scene); +#endif + return this; + } + public void Update() + { + Net.Update(); +#if FANTASY_UNITY + Unity.Update(); +#endif + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Entitas/Component/TimerComponent/TimerScheduler/TimerSchedulerNet.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Entitas/Component/TimerComponent/TimerScheduler/TimerSchedulerNet.cs new file mode 100644 index 0000000..26581f8 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Entitas/Component/TimerComponent/TimerScheduler/TimerSchedulerNet.cs @@ -0,0 +1,390 @@ +using System; +using System.Collections.Generic; +using Fantasy.Async; +using Fantasy.DataStructure.Collection; +using Fantasy.Helper; +// ReSharper disable UnusedParameter.Global + +#pragma warning disable CS8602 // Dereference of a possibly null reference. +#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. + +namespace Fantasy.Timer +{ + /// + /// 基于系统事件的任务调度系统 + /// + public sealed class TimerSchedulerNet + { + private readonly Scene _scene; + private long _idGenerator; + private long _minTime; // 最小时间 + private readonly Queue _timeOutTime = new Queue(); + private readonly Queue _timeOutTimerIds = new Queue(); + private readonly Dictionary _timerActions = new Dictionary(); + private readonly SortedOneToManyList _timeId = new(); // 时间与计时器ID的有序一对多列表 + private long GetId => ++_idGenerator; + /// + /// 构造函数 + /// + /// 当前的Scene + public TimerSchedulerNet(Scene scene) + { + _scene = scene; + } + + private long Now() + { + return TimeHelper.Now; + } + + /// + /// 驱动方法,只有调用这个方法任务系统才会正常运转。 + /// + public void Update() + { + if (_timeId.Count == 0) + { + return; + } + + var currentTime = Now(); + + if (currentTime < _minTime) + { + return; + } + + // 遍历时间ID列表,查找超时的计时器任务 + foreach (var (key, _) in _timeId) + { + if (key > currentTime) + { + _minTime = key; + break; + } + + _timeOutTime.Enqueue(key); + } + + // 处理超时的计时器任务 + while (_timeOutTime.TryDequeue(out var time)) + { + var timerIds = _timeId[time]; + for (var i = 0; i < timerIds.Count; ++i) + { + _timeOutTimerIds.Enqueue(timerIds[i]); + } + + _timeId.Remove(time); + // _timeId.RemoveKey(time); + } + + if (_timeId.Count == 0) + { + _minTime = long.MaxValue; + } + + // 执行超时的计时器任务的回调操作 + while (_timeOutTimerIds.TryDequeue(out var timerId)) + { + if (!_timerActions.Remove(timerId, out var timerAction)) + { + continue; + } + + // 根据计时器类型执行不同的操作 + switch (timerAction.TimerType) + { + case TimerType.OnceWaitTimer: + { + var tcs = (FTask)timerAction.Callback; + tcs.SetResult(true); + break; + } + case TimerType.OnceTimer: + { + if (timerAction.Callback is not Action action) + { + Log.Error($"timerAction {timerAction.ToJson()}"); + break; + } + + action(); + break; + } + case TimerType.RepeatedTimer: + { + if (timerAction.Callback is not Action action) + { + Log.Error($"timerAction {timerAction.ToJson()}"); + break; + } + + timerAction.StartTime = Now(); + AddTimer(ref timerAction); + action(); + break; + } + } + } + } + + private void AddTimer(ref TimerAction timer) + { + var tillTime = timer.StartTime + timer.TriggerTime; + _timeId.Add(tillTime, timer.TimerId); + _timerActions.Add(timer.TimerId, timer); + + if (tillTime < _minTime) + { + _minTime = tillTime; + } + } + + /// + /// 异步等待指定时间。 + /// + /// 等待的时间长度。 + /// 取消令牌。 + /// 等待是否成功。 + public async FTask WaitAsync(long time, FCancellationToken cancellationToken = null) + { + if (time <= 0) + { + return true; + } + + var now = Now(); + var timerId = GetId; + var tcs = FTask.Create(); + var timerAction = new TimerAction(timerId, TimerType.OnceWaitTimer, now, time, tcs); + + void CancelActionVoid() + { + if (Remove(timerId)) + { + tcs.SetResult(false); + } + } + + bool result; + + try + { + cancellationToken?.Add(CancelActionVoid); + AddTimer(ref timerAction); + result = await tcs; + } + finally + { + cancellationToken?.Remove(CancelActionVoid); + } + + return result; + } + + /// + /// 异步等待直到指定时间。 + /// + /// 等待的目标时间。 + /// 取消令牌。 + /// 等待是否成功。 + public async FTask WaitTillAsync(long tillTime, FCancellationToken cancellationToken = null) + { + var now = Now(); + + if (now >= tillTime) + { + return true; + } + + var timerId = GetId; + var tcs = FTask.Create(); + var timerAction = new TimerAction(timerId, TimerType.OnceWaitTimer, now, tillTime - now, tcs); + + void CancelActionVoid() + { + if (Remove(timerId)) + { + tcs.SetResult(false); + } + } + + bool result; + + try + { + cancellationToken?.Add(CancelActionVoid); + AddTimer(ref timerAction); + result = await tcs; + } + finally + { + cancellationToken?.Remove(CancelActionVoid); + } + + return result; + } + + /// + /// 异步等待一帧时间。 + /// + /// 等待是否成功。 + public async FTask WaitFrameAsync() + { +#if FANTASY_NET + await WaitAsync(100); +#else + await WaitAsync(1); +#endif + } + + /// + /// 创建一个只执行一次的计时器,直到指定时间 + /// + /// 计时器执行的目标时间。 + /// 计时器回调方法。 + /// + public long OnceTimer(long time, Action action) + { + var now = Now(); + var timerId = GetId; + var timerAction = new TimerAction(timerId, TimerType.OnceTimer, now, time, action); + AddTimer(ref timerAction); + return timerId; + } + + /// + /// 创建一个只执行一次的计时器,直到指定时间。 + /// + /// 计时器执行的目标时间。 + /// 计时器回调方法。 + /// 计时器的 ID。 + public long OnceTillTimer(long tillTime, Action action) + { + var now = Now(); + + if (tillTime < now) + { + Log.Error($"new once time too small tillTime:{tillTime} Now:{now}"); + } + + var timerId = GetId; + var timerAction = new TimerAction(timerId, TimerType.OnceTimer, now, tillTime - now, action); + AddTimer(ref timerAction); + return timerId; + } + + /// + /// 创建一个只执行一次的计时器,用于发布指定类型的事件。 + /// + /// 事件类型。 + /// 计时器执行的延迟时间。 + /// 事件处理器类型。 + /// 计时器的 ID。 + public long OnceTimer(long time, T timerHandlerType) where T : struct + { + void OnceTimerVoid() + { + _scene.EventComponent.Publish(timerHandlerType); + } + + return OnceTimer(time, OnceTimerVoid); + } + + /// + /// 创建一个只执行一次的计时器,直到指定时间,用于发布指定类型的事件。 + /// + /// 事件类型。 + /// 计时器执行的目标时间。 + /// 事件处理器类型。 + /// 计时器的 ID。 + public long OnceTillTimer(long tillTime, T timerHandlerType) where T : struct + { + void OnceTillTimerVoid() + { + _scene.EventComponent.Publish(timerHandlerType); + } + + return OnceTillTimer(tillTime, OnceTillTimerVoid); + } + + /// + /// 创建一个帧任务 + /// + /// + /// + public long FrameTimer(Action action) + { +#if FANTASY_NET + return RepeatedTimerInner(100, action); +#else + return RepeatedTimerInner(0, action); +#endif + } + + /// + /// 创建一个重复执行的计时器。 + /// + /// 计时器重复间隔的时间。 + /// 计时器回调方法。 + /// 计时器的 ID。 + public long RepeatedTimer(long time, Action action) + { + if (time < 0) + { + Log.Error($"time too small: {time}"); + return 0; + } + + return RepeatedTimerInner(time, action); + } + + /// + /// 创建一个重复执行的计时器,用于发布指定类型的事件。 + /// + /// 事件类型。 + /// 计时器重复间隔的时间。 + /// 事件处理器类型。 + /// 计时器的 ID。 + public long RepeatedTimer(long time, T timerHandlerType) where T : struct + { + void RepeatedTimerVoid() + { + _scene.EventComponent.Publish(timerHandlerType); + } + + return RepeatedTimer(time, RepeatedTimerVoid); + } + + private long RepeatedTimerInner(long time, Action action) + { + var now = Now(); + var timerId = GetId; + var timerAction = new TimerAction(timerId, TimerType.RepeatedTimer, now, time, action); + AddTimer(ref timerAction); + return timerId; + } + + /// + /// 移除指定 ID 的计时器。 + /// + /// + /// + public bool Remove(ref long timerId) + { + var id = timerId; + timerId = 0; + return Remove(id); + } + + /// + /// 移除指定 ID 的计时器。 + /// + /// 计时器的 ID。 + public bool Remove(long timerId) + { + return timerId != 0 && _timerActions.Remove(timerId, out _); + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Entitas/Component/TimerComponent/TimerScheduler/TimerSchedulerNetUnity.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Entitas/Component/TimerComponent/TimerScheduler/TimerSchedulerNetUnity.cs new file mode 100644 index 0000000..f00bfe4 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Entitas/Component/TimerComponent/TimerScheduler/TimerSchedulerNetUnity.cs @@ -0,0 +1,372 @@ +#if FANTASY_UNITY +using System; +using System.Collections.Generic; +using Fantasy.Async; +using Fantasy.DataStructure.Collection; +using Fantasy.Helper; +using UnityEngine; +namespace Fantasy.Timer +{ + public sealed class TimerSchedulerNetUnity + { + private readonly Scene _scene; + private long _idGenerator; + private long _minTime; // 最小时间 + private readonly Queue _timeOutTime = new Queue(); + private readonly Queue _timeOutTimerIds = new Queue(); + private readonly Dictionary _timerActions = new Dictionary(); + private readonly SortedOneToManyList _timeId = new(); // 时间与计时器ID的有序一对多列表 + private long GetId => ++_idGenerator; + public TimerSchedulerNetUnity(Scene scene) + { + _scene = scene; + } + + private long Now() + { + return (long)(Time.time * 1000); + } + + public void Update() + { + if (_timeId.Count == 0) + { + return; + } + + var currentTime = Now(); + + if (currentTime < _minTime) + { + return; + } + + // 遍历时间ID列表,查找超时的计时器任务 + foreach (var (key, _) in _timeId) + { + if (key > currentTime) + { + _minTime = key; + break; + } + + _timeOutTime.Enqueue(key); + } + + // 处理超时的计时器任务 + while (_timeOutTime.TryDequeue(out var time)) + { + var timerIds = _timeId[time]; + for (var i = 0; i < timerIds.Count; ++i) + { + _timeOutTimerIds.Enqueue(timerIds[i]); + } + + _timeId.Remove(time); + // _timeId.RemoveKey(time); + } + + if (_timeId.Count == 0) + { + _minTime = long.MaxValue; + } + + // 执行超时的计时器任务的回调操作 + while (_timeOutTimerIds.TryDequeue(out var timerId)) + { + if (!_timerActions.Remove(timerId, out var timerAction)) + { + continue; + } + + // 根据计时器类型执行不同的操作 + switch (timerAction.TimerType) + { + case TimerType.OnceWaitTimer: + { + var tcs = (FTask)timerAction.Callback; + tcs.SetResult(true); + break; + } + case TimerType.OnceTimer: + { + if (timerAction.Callback is not Action action) + { + Log.Error($"timerAction {timerAction.ToJson()}"); + break; + } + + action(); + break; + } + case TimerType.RepeatedTimer: + { + if (timerAction.Callback is not Action action) + { + Log.Error($"timerAction {timerAction.ToJson()}"); + break; + } + + timerAction.StartTime = Now(); + AddTimer(ref timerAction); + action(); + break; + } + } + } + } + + private void AddTimer(ref TimerAction timer) + { + var tillTime = timer.StartTime + timer.TriggerTime; + _timeId.Add(tillTime, timer.TimerId); + _timerActions.Add(timer.TimerId, timer); + + if (tillTime < _minTime) + { + _minTime = tillTime; + } + } + + /// + /// 异步等待指定时间。 + /// + /// 等待的时间长度。 + /// 可选的取消令牌。 + /// 等待是否成功。 + public async FTask WaitAsync(long time, FCancellationToken cancellationToken = null) + { + if (time <= 0) + { + return true; + } + + var now = Now(); + var timerId = GetId; + var tcs = FTask.Create(); + var timerAction = new TimerAction(timerId, TimerType.OnceWaitTimer, now, time, tcs); + + + void CancelActionVoid() + { + if (Remove(timerId)) + { + tcs.SetResult(false); + } + } + + bool result; + + try + { + cancellationToken?.Add(CancelActionVoid); + AddTimer(ref timerAction); + result =await tcs; + } + finally + { + cancellationToken?.Remove(CancelActionVoid); + } + + return result; + } + + /// + /// 异步等待直到指定时间。 + /// + /// 等待的目标时间。 + /// 可选的取消令牌。 + /// 等待是否成功。 + public async FTask WaitTillAsync(long tillTime, FCancellationToken cancellationToken = null) + { + var now = Now(); + + if (now >= tillTime) + { + return true; + } + + var timerId = GetId; + var tcs = FTask.Create(); + var timerAction = new TimerAction(timerId, TimerType.OnceWaitTimer, now, tillTime - now, tcs); + + void CancelActionVoid() + { + if (Remove(timerId)) + { + tcs.SetResult(false); + } + } + + bool result; + + try + { + cancellationToken?.Add(CancelActionVoid); + AddTimer(ref timerAction); + result = await tcs; + } + finally + { + cancellationToken?.Remove(CancelActionVoid); + } + + return result; + } + + /// + /// 异步等待一帧时间。 + /// + /// 等待是否成功。 + public async FTask WaitFrameAsync(FCancellationToken cancellationToken = null) + { + await WaitAsync(1, cancellationToken); + } + + /// + /// 创建一个只执行一次的计时器,直到指定时间 + /// + /// 计时器执行的目标时间。 + /// 计时器回调方法。 + /// + public long OnceTimer(long time, Action action) + { + var now = Now(); + var timerId = GetId; + var timerAction = new TimerAction(timerId, TimerType.OnceTimer, now, time, action); + AddTimer(ref timerAction); + return timerId; + } + + /// + /// 创建一个只执行一次的计时器,直到指定时间。 + /// + /// 计时器执行的目标时间。 + /// 计时器回调方法。 + /// 计时器的 ID。 + public long OnceTillTimer(long tillTime, Action action) + { + var now = Now(); + + if (tillTime < now) + { + Log.Error($"new once time too small tillTime:{tillTime} Now:{now}"); + } + + var timerId = GetId; + var timerAction = new TimerAction(timerId, TimerType.OnceTimer, now, tillTime - now, action); + AddTimer(ref timerAction); + return timerId; + } + + /// + /// 创建一个只执行一次的计时器,用于发布指定类型的事件。 + /// + /// 事件类型。 + /// 计时器执行的延迟时间。 + /// 事件处理器类型。 + /// 计时器的 ID。 + public long OnceTimer(long time, T timerHandlerType) where T : struct + { + void OnceTimerVoid() + { + _scene.EventComponent.Publish(timerHandlerType); + } + + return OnceTimer(time, OnceTimerVoid); + } + + /// + /// 创建一个只执行一次的计时器,直到指定时间,用于发布指定类型的事件。 + /// + /// 事件类型。 + /// 计时器执行的目标时间。 + /// 事件处理器类型。 + /// 计时器的 ID。 + public long OnceTillTimer(long tillTime, T timerHandlerType) where T : struct + { + void OnceTillTimerVoid() + { + _scene.EventComponent.Publish(timerHandlerType); + } + + return OnceTillTimer(tillTime, OnceTillTimerVoid); + } + + /// + /// 创建一个帧任务 + /// + /// + /// + public long FrameTimer(Action action) + { + return RepeatedTimerInner(1, action); + } + + /// + /// 创建一个重复执行的计时器。 + /// + /// 计时器重复间隔的时间。 + /// 计时器回调方法。 + /// 计时器的 ID。 + public long RepeatedTimer(long time, Action action) + { + if (time < 0) + { + Log.Error($"time too small: {time}"); + return 0; + } + + return RepeatedTimerInner(time, action); + } + + /// + /// 创建一个重复执行的计时器,用于发布指定类型的事件。 + /// + /// 事件类型。 + /// 计时器重复间隔的时间。 + /// 事件处理器类型。 + /// 计时器的 ID。 + public long RepeatedTimer(long time, T timerHandlerType) where T : struct + { + void RepeatedTimerVoid() + { + _scene.EventComponent.Publish(timerHandlerType); + } + + return RepeatedTimer(time, RepeatedTimerVoid); + } + + private long RepeatedTimerInner(long time, Action action) + { + var now = Now(); + var timerId = GetId; + var timerAction = new TimerAction(timerId, TimerType.RepeatedTimer, now, time, action); + AddTimer(ref timerAction); + return timerId; + } + + /// + /// 移除指定 ID 的计时器。 + /// + /// + /// + public bool Remove(ref long timerId) + { + var id = timerId; + timerId = 0; + return Remove(id); + } + + /// + /// 移除指定 ID 的计时器。 + /// + /// 计时器的 ID。 + public bool Remove(long timerId) + { + return timerId != 0 && _timerActions.Remove(timerId, out _); + } + } +} +#endif + diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Entitas/Component/TimerComponent/TimerType.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Entitas/Component/TimerComponent/TimerType.cs new file mode 100644 index 0000000..6f16f80 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Entitas/Component/TimerComponent/TimerType.cs @@ -0,0 +1,25 @@ +namespace Fantasy.Timer +{ + /// + /// 枚举对象TimerType + /// + public enum TimerType + { + /// + /// None + /// + None, + /// + /// 一次等待定时器 + /// + OnceWaitTimer, + /// + /// 一次性定时器 + /// + OnceTimer, + /// + /// 重复定时器 + /// + RepeatedTimer + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Entitas/Entity.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Entitas/Entity.cs new file mode 100644 index 0000000..0dc46b9 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Entitas/Entity.cs @@ -0,0 +1,1047 @@ +using System; +using System.Collections.Generic; +using System.Runtime.Serialization; +using Fantasy.Entitas.Interface; +using Fantasy.Pool; +using MongoDB.Bson.Serialization.Attributes; +using Newtonsoft.Json; +using ProtoBuf; + +// ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract +// ReSharper disable MergeIntoPattern +// ReSharper disable SuspiciousTypeConversion.Global +// ReSharper disable NullCoalescingConditionIsAlwaysNotNullAccordingToAPIContract +// ReSharper disable CheckNamespace +#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. +#pragma warning disable CS8603 // Possible null reference return. +#pragma warning disable CS8602 // Dereference of a possibly null reference. +#pragma warning disable CS8600 // Converting null literal or possible null value to non-nullable type. +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. + +namespace Fantasy.Entitas +{ + /// + /// 用来表示一个Entity + /// + public interface IEntity : IDisposable, IPool { } + + /// + /// Entity的抽象类,任何Entity必须继承这个接口才可以使用 + /// + public abstract partial class Entity : IEntity + { + #region Members + + /// + /// 获取一个值,表示实体是否支持对象池。 + /// + [BsonIgnore] + [JsonIgnore] + [ProtoIgnore] + [IgnoreDataMember] + private bool _isPool; + /// + /// 实体的Id + /// + [BsonId] + [BsonElement] + [BsonIgnoreIfDefault] + [BsonDefaultValue(0L)] + public long Id { get; protected set; } + /// + /// 实体的RunTimeId,其他系统可以通过这个Id发送Route消息,这个Id也可以理解为RouteId + /// + [BsonIgnore] + [IgnoreDataMember] + [ProtoIgnore] + public long RuntimeId { get; protected set; } + /// + /// 当前实体是否已经被销毁 + /// + [BsonIgnore] + [JsonIgnore] + [IgnoreDataMember] + [ProtoIgnore] + public bool IsDisposed => RuntimeId == 0; + /// + /// 当前实体所归属的Scene + /// + [BsonIgnore] + [JsonIgnore] + [IgnoreDataMember] + [ProtoIgnore] + public Scene Scene { get; protected set; } + /// + /// 实体的父实体 + /// + [BsonIgnore] + [JsonIgnore] + [IgnoreDataMember] + [ProtoIgnore] + public Entity Parent { get; protected set; } + /// + /// 实体的真实Type + /// + [BsonIgnore] + [JsonIgnore] + [IgnoreDataMember] + [ProtoIgnore] + public Type Type { get; protected set; } +#if FANTASY_NET + [BsonElement("t")] [BsonIgnoreIfNull] private EntityList _treeDb; + [BsonElement("m")] [BsonIgnoreIfNull] private EntityList _multiDb; +#endif + [BsonIgnore] [IgnoreDataMember] [ProtoIgnore] private EntitySortedDictionary _tree; + [BsonIgnore] [IgnoreDataMember] [ProtoIgnore] private EntitySortedDictionary _multi; + + /// + /// 获得父Entity + /// + /// 父实体的泛型类型 + /// + public T GetParent() where T : Entity, new() + { + return Parent as T; + } + + #endregion + + #region Create + + /// + /// 创建一个实体 + /// + /// 所属的Scene + /// 实体的Type + /// 是否从对象池创建,如果选择的是,销毁的时候同样会进入对象池 + /// 是否执行实体事件 + /// + public static Entity Create(Scene scene, Type type, bool isPool, bool isRunEvent) + { + return Create(scene, type, scene.EntityIdFactory.Create, isPool, isRunEvent); + } + + /// + /// 创建一个实体 + /// + /// 所属的Scene + /// 实体的Type + /// 指定实体的Id + /// 是否从对象池创建,如果选择的是,销毁的时候同样会进入对象池 + /// 是否执行实体事件 + /// + public static Entity Create(Scene scene, Type type, long id, bool isPool, bool isRunEvent) + { + if (!typeof(Entity).IsAssignableFrom(type)) + { + throw new NotSupportedException($"{type.FullName} Type:{type.FullName} must inherit from Entity"); + } + + Entity entity = null; + + if (isPool) + { + entity = (Entity)scene.EntityPool.Rent(type); + } + else + { + if (!scene.TypeInstance.TryGetValue(type, out var createInstance)) + { + createInstance = CreateInstance.CreateIPool(type); + scene.TypeInstance[type] = createInstance; + } + + entity = (Entity)createInstance(); + } + + entity.Scene = scene; + entity.Type = type; + entity.SetIsPool(isPool); + entity.Id = id; + entity.RuntimeId = scene.RuntimeIdFactory.Create; + scene.AddEntity(entity); + + if (isRunEvent) + { + scene.EntityComponent.Awake(entity); + scene.EntityComponent.StartUpdate(entity); + } + + return entity; + } + + /// + /// 创建一个实体 + /// + /// 所属的Scene + /// 是否从对象池创建,如果选择的是,销毁的时候同样会进入对象池 + /// 是否执行实体事件 + /// 要创建的实体泛型类型 + /// + public static T Create(Scene scene, bool isPool, bool isRunEvent) where T : Entity, new() + { + return Create(scene, scene.EntityIdFactory.Create, isPool, isRunEvent); + } + + /// + /// 创建一个实体 + /// + /// 所属的Scene + /// 指定实体的Id + /// 是否从对象池创建,如果选择的是,销毁的时候同样会进入对象池 + /// 是否执行实体事件 + /// 要创建的实体泛型类型 + /// + public static T Create(Scene scene, long id, bool isPool, bool isRunEvent) where T : Entity, new() + { + var entity = isPool ? scene.EntityPool.Rent() : new T(); + entity.Scene = scene; + entity.Type = typeof(T); + entity.SetIsPool(isPool); + entity.Id = id; + entity.RuntimeId = scene.RuntimeIdFactory.Create; + scene.AddEntity(entity); + + if (isRunEvent) + { + scene.EntityComponent.Awake(entity); + scene.EntityComponent.StartUpdate(entity); + } + + return entity; + } + + #endregion + + #region AddComponent + + /// + /// 添加一个组件到当前实体上 + /// + /// 是否从对象池里创建 + /// 要添加组件的泛型类型 + /// 返回添加到实体上组件的实例 + public T AddComponent(bool isPool = true) where T : Entity, new() + { + var id = SupportedMultiEntityChecker.IsSupported ? Scene.EntityIdFactory.Create : Id; + var entity = Create(Scene, id, isPool, false); + AddComponent(entity); + Scene.EntityComponent.Awake(entity); + Scene.EntityComponent.StartUpdate(entity); + return entity; + } + + /// + /// 添加一个组件到当前实体上 + /// + /// 要添加组件的Id + /// 是否从对象池里创建 + /// 要添加组件的泛型类型 + /// 返回添加到实体上组件的实例 + public T AddComponent(long id, bool isPool = true) where T : Entity, new() + { + var entity = Create(Scene, id, isPool, false); + AddComponent(entity); + Scene.EntityComponent.Awake(entity); + Scene.EntityComponent.StartUpdate(entity); + return entity; + } + + /// + /// 添加一个组件到当前实体上 + /// + /// 要添加的实体实例 + public void AddComponent(Entity component) + { + if (this == component) + { + Log.Error("Cannot add oneself to one's own components"); + return; + } + + if (component.IsDisposed) + { + Log.Error($"component is Disposed {component.Type.FullName}"); + return; + } + + var type = component.Type; + component.Parent?.RemoveComponent(component, false); + + if (component is ISupportedMultiEntity) + { + _multi ??= Scene.EntitySortedDictionaryPool.Rent(); + _multi.Add(component.Id, component); +#if FANTASY_NET + if (component is ISupportedDataBase) + { + _multiDb ??= Scene.EntityListPool.Rent(); + _multiDb.Add(component); + } +#endif + } + else + { +#if FANTASY_NET + if (component is ISupportedSingleCollection && component.Id != Id) + { + Log.Error($"component type :{type.FullName} for implementing ISupportedSingleCollection, it is required that the Id must be the same as the parent"); + } +#endif + var typeHashCode = Scene.EntityComponent.GetHashCode(type);; + + if (_tree == null) + { + _tree = Scene.EntitySortedDictionaryPool.Rent(); + } + else if (_tree.ContainsKey(typeHashCode)) + { + Log.Error($"type:{type.FullName} If you want to add multiple components of the same type, please implement IMultiEntity"); + return; + } + + _tree.Add(typeHashCode, component); +#if FANTASY_NET + if (component is ISupportedDataBase) + { + _treeDb ??= Scene.EntityListPool.Rent(); + _treeDb.Add(component); + } +#endif + } + + component.Parent = this; + component.Scene = Scene; + } + + /// + /// 添加一个组件到当前实体上 + /// + /// 要添加的实体实例 + /// 要添加组件的泛型类型 + public void AddComponent(T component) where T : Entity + { + var type = typeof(T); + + if (type == typeof(Entity)) + { + Log.Error("Cannot add a generic Entity type as a component. Specify a more specific type."); + return; + } + + if (this == component) + { + Log.Error("Cannot add oneself to one's own components"); + return; + } + + if (component.IsDisposed) + { + Log.Error($"component is Disposed {type.FullName}"); + return; + } + + component.Parent?.RemoveComponent(component, false); + + if (SupportedMultiEntityChecker.IsSupported) + { + _multi ??= Scene.EntitySortedDictionaryPool.Rent(); + _multi.Add(component.Id, component); +#if FANTASY_NET + if (SupportedDataBaseChecker.IsSupported) + { + _multiDb ??= Scene.EntityListPool.Rent(); + _multiDb.Add(component); + } +#endif + } + else + { +#if FANTASY_NET + if (SupportedSingleCollectionChecker.IsSupported && component.Id != Id) + { + Log.Error($"component type :{type.FullName} for implementing ISupportedSingleCollection, it is required that the Id must be the same as the parent"); + } +#endif + var typeHashCode = Scene.EntityComponent.GetHashCode(type); + + if (_tree == null) + { + _tree = Scene.EntitySortedDictionaryPool.Rent(); + } + else if (_tree.ContainsKey(typeHashCode)) + { + Log.Error($"type:{type.FullName} If you want to add multiple components of the same type, please implement IMultiEntity"); + return; + } + + _tree.Add(typeHashCode, component); +#if FANTASY_NET + if (SupportedDataBaseChecker.IsSupported) + { + _treeDb ??= Scene.EntityListPool.Rent(); + _treeDb.Add(component); + } +#endif + } + + component.Parent = this; + component.Scene = Scene; + } + + /// + /// 添加一个组件到当前实体上 + /// + /// 组件的类型 + /// 是否在对象池创建 + /// + public Entity AddComponent(Type type, bool isPool = true) + { + var id = typeof(ISupportedMultiEntity).IsAssignableFrom(type) ? Scene.EntityIdFactory.Create : Id; + var entity = Entity.Create(Scene, type, id, isPool, false); + AddComponent(entity); + Scene.EntityComponent.Awake(entity); + Scene.EntityComponent.StartUpdate(entity); + return entity; + } + + #endregion + + #region HasComponent + + /// + /// 当前实体上是否有指定类型的组件 + /// + /// + /// + public bool HasComponent() where T : Entity, new() + { + return HasComponent(typeof(T)); + } + + /// + /// 当前实体上是否有指定类型的组件 + /// + /// + /// + public bool HasComponent(Type type) + { + if (_tree == null) + { + return false; + } + + return _tree.ContainsKey(Scene.EntityComponent.GetHashCode(type)); + } + + /// + /// 当前实体上是否有指定类型的组件 + /// + /// + /// + /// + public bool HasComponent(long id) where T : Entity, ISupportedMultiEntity, new() + { + if (_multi == null) + { + return false; + } + + return _multi.ContainsKey(id); + } + + #endregion + + #region GetComponent + + /// + /// 当前实体上查找一个字实体 + /// + /// 要查找实体泛型类型 + /// 查找的实体实例 + public T GetComponent() where T : Entity, new() + { + if (_tree == null) + { + return null; + } + + var typeHashCode = Scene.EntityComponent.GetHashCode(typeof(T)); + return _tree.TryGetValue(typeHashCode, out var component) ? (T)component : null; + } + + /// + /// 当前实体上查找一个字实体 + /// + /// 要查找实体类型 + /// 查找的实体实例 + public Entity GetComponent(Type type) + { + if (_tree == null) + { + return null; + } + + var typeHashCode = Scene.EntityComponent.GetHashCode(type); + return _tree.TryGetValue(typeHashCode, out var component) ? component : null; + } + + /// + /// 当前实体上查找一个字实体 + /// + /// 要查找实体的Id + /// 要查找实体泛型类型 + /// 查找的实体实例 + public T GetComponent(long id) where T : Entity, ISupportedMultiEntity, new() + { + if (_multi == null) + { + return default; + } + + return _multi.TryGetValue(id, out var entity) ? (T)entity : default; + } + + /// + /// 当前实体上查找一个字实体,如果没有就创建一个新的并添加到当前实体上 + /// + /// 是否从对象池创建 + /// 要查找或添加实体泛型类型 + /// 查找的实体实例 + public T GetOrAddComponent(bool isPool = true) where T : Entity, new() + { + return GetComponent() ?? AddComponent(isPool); + } + + #endregion + + #region RemoveComponent + + /// + /// 当前实体下删除一个实体 + /// + /// 是否执行删除实体的Dispose方法 + /// 实体的泛型类型 + /// + public void RemoveComponent(bool isDispose = true) where T : Entity, new() + { + if (SupportedMultiEntityChecker.IsSupported) + { + throw new NotSupportedException($"{typeof(T).FullName} message:Cannot delete components that implement the ISupportedMultiEntity interface"); + } + + if (_tree == null) + { + return; + } + + var type = typeof(T); + var typeHashCode = Scene.EntityComponent.GetHashCode(type); + if (!_tree.TryGetValue(typeHashCode, out var component)) + { + return; + } +#if FANTASY_NET + if (_treeDb != null && SupportedDataBaseChecker.IsSupported) + { + _treeDb.Remove(component); + + if (_treeDb.Count == 0) + { + Scene.EntityListPool.Return(_treeDb); + _treeDb = null; + } + } +#endif + _tree.Remove(typeHashCode); + + if (_tree.Count == 0) + { + Scene.EntitySortedDictionaryPool.Return(_tree); + _tree = null; + } + + if (isDispose) + { + component.Dispose(); + } + } + + /// + /// 当前实体下删除一个实体 + /// + /// 要删除的实体Id + /// 是否执行删除实体的Dispose方法 + /// 实体的泛型类型 + public void RemoveComponent(long id, bool isDispose = true) where T : Entity, ISupportedMultiEntity, new() + { + if (_multi == null) + { + return; + } + + if (!_multi.TryGetValue(id, out var component)) + { + return; + } +#if FANTASY_NET + if (SupportedDataBaseChecker.IsSupported) + { + _multiDb.Remove(component); + if (_multiDb.Count == 0) + { + Scene.EntityListPool.Return(_multiDb); + _multiDb = null; + } + } +#endif + _multi.Remove(component.Id); + if (_multi.Count == 0) + { + Scene.EntitySortedDictionaryPool.Return(_multi); + _multi = null; + } + + if (isDispose) + { + component.Dispose(); + } + } + + /// + /// 当前实体下删除一个实体 + /// + /// 要删除的实体实例 + /// 是否执行删除实体的Dispose方法 + public void RemoveComponent(Entity component, bool isDispose = true) + { + if (this == component) + { + return; + } + + if (component is ISupportedMultiEntity) + { + if (_multi != null) + { + if (!_multi.ContainsKey(component.Id)) + { + return; + } +#if FANTASY_NET + if (component is ISupportedDataBase) + { + _multiDb.Remove(component); + if (_multiDb.Count == 0) + { + Scene.EntityListPool.Return(_multiDb); + _multiDb = null; + } + } +#endif + _multi.Remove(component.Id); + if (_multi.Count == 0) + { + Scene.EntitySortedDictionaryPool.Return(_multi); + _multi = null; + } + } + } + else if (_tree != null) + { + var typeHashCode = Scene.EntityComponent.GetHashCode(component.Type); + if (!_tree.ContainsKey(typeHashCode)) + { + return; + } +#if FANTASY_NET + if (_treeDb != null && component is ISupportedDataBase) + { + _treeDb.Remove(component); + + if (_treeDb.Count == 0) + { + Scene.EntityListPool.Return(_treeDb); + _treeDb = null; + } + } +#endif + _tree.Remove(typeHashCode); + + if (_tree.Count == 0) + { + Scene.EntitySortedDictionaryPool.Return(_tree); + _tree = null; + } + } + + if (isDispose) + { + component.Dispose(); + } + } + + /// + /// 当前实体下删除一个实体 + /// + /// 要删除的实体实例 + /// 是否执行删除实体的Dispose方法 + /// 实体的泛型类型 + public void RemoveComponent(T component, bool isDispose = true) where T : Entity + { + if (this == component) + { + return; + } + + if (typeof(T) == typeof(Entity)) + { + Log.Error("Cannot remove a generic Entity type as a component. Specify a more specific type."); + return; + } + + if (SupportedMultiEntityChecker.IsSupported) + { + if (_multi != null) + { + if (!_multi.ContainsKey(component.Id)) + { + return; + } +#if FANTASY_NET + if (SupportedDataBaseChecker.IsSupported) + { + _multiDb.Remove(component); + if (_multiDb.Count == 0) + { + Scene.EntityListPool.Return(_multiDb); + _multiDb = null; + } + } +#endif + _multi.Remove(component.Id); + if (_multi.Count == 0) + { + Scene.EntitySortedDictionaryPool.Return(_multi); + _multi = null; + } + } + } + else if (_tree != null) + { + var typeHashCode = Scene.EntityComponent.GetHashCode(typeof(T)); + if (!_tree.ContainsKey(typeHashCode)) + { + return; + } +#if FANTASY_NET + if (_treeDb != null && SupportedDataBaseChecker.IsSupported) + { + _treeDb.Remove(component); + + if (_treeDb.Count == 0) + { + Scene.EntityListPool.Return(_treeDb); + _treeDb = null; + } + } +#endif + _tree.Remove(typeHashCode); + + if (_tree.Count == 0) + { + Scene.EntitySortedDictionaryPool.Return(_tree); + _tree = null; + } + } + + if (isDispose) + { + component.Dispose(); + } + } + + #endregion + + #region Deserialize + + /// + /// 反序列化当前实体,因为在数据库加载过来的或通过协议传送过来的实体并没有跟当前Scene做关联。 + /// 所以必须要执行一下这个反序列化的方法才可以使用。 + /// + /// Scene + /// 是否是重新生成实体的Id,如果是数据库加载过来的一般是不需要的 + public void Deserialize(Scene scene, bool resetId = false) + { + if (RuntimeId != 0) + { + return; + } + + try + { + Scene = scene; + Type ??= GetType(); + RuntimeId = Scene.RuntimeIdFactory.Create; + if (resetId) + { + Id = RuntimeId; + } +#if FANTASY_NET + if (_treeDb != null && _treeDb.Count > 0) + { + _tree = Scene.EntitySortedDictionaryPool.Rent(); + foreach (var entity in _treeDb) + { + entity.Parent = this; + entity.Type = entity.GetType(); + var typeHashCode = Scene.EntityComponent.GetHashCode(entity.Type); + _tree.Add(typeHashCode, entity); + entity.Deserialize(scene, resetId); + } + } + + if (_multiDb != null && _multiDb.Count > 0) + { + _multi = Scene.EntitySortedDictionaryPool.Rent(); + foreach (var entity in _multiDb) + { + entity.Parent = this; + entity.Deserialize(scene, resetId); + _multi.Add(entity.Id, entity); + } + } +#endif + scene.AddEntity(this); + scene.EntityComponent.Deserialize(this); + } + catch (Exception e) + { + if (RuntimeId != 0) + { + scene.RemoveEntity(RuntimeId); + } + + Log.Error(e); + } + } + + #endregion + + #region ForEach +#if FANTASY_NET + /// + /// 查询当前实体下支持数据库分表存储实体 + /// + [BsonIgnore] + [JsonIgnore] + [IgnoreDataMember] + [ProtoIgnore] + public IEnumerable ForEachSingleCollection + { + get + { + foreach (var (_, treeEntity) in _tree) + { + if (treeEntity is not ISupportedSingleCollection) + { + continue; + } + + yield return treeEntity; + } + } + } + /// + /// 查询当前实体下支持传送实体 + /// + [BsonIgnore] + [JsonIgnore] + [IgnoreDataMember] + [ProtoIgnore] + public IEnumerable ForEachTransfer + { + get + { + if (_tree != null) + { + foreach (var (_, treeEntity) in _tree) + { + if (treeEntity is ISupportedTransfer) + { + yield return treeEntity; + } + } + } + + if (_multiDb != null) + { + foreach (var treeEntity in _multiDb) + { + if (treeEntity is not ISupportedTransfer) + { + continue; + } + + yield return treeEntity; + } + } + } + } +#endif + /// + /// 查询当前实体下的实现了ISupportedMultiEntity接口的实体 + /// + [BsonIgnore] + [JsonIgnore] + [IgnoreDataMember] + [ProtoIgnore] + public IEnumerable ForEachMultiEntity + { + get + { + if (_multi == null) + { + yield break; + } + + foreach (var (_, supportedMultiEntity) in _multi) + { + yield return supportedMultiEntity; + } + } + } + /// + /// 查找当前实体下的所有实体,不包括实现ISupportedMultiEntity接口的实体 + /// + [BsonIgnore] + [JsonIgnore] + [IgnoreDataMember] + [ProtoIgnore] + public IEnumerable ForEachEntity + { + get + { + if (_tree == null) + { + yield break; + } + + foreach (var (_, entity) in _tree) + { + yield return entity; + } + } + } + #endregion + + #region Dispose + + /// + /// 销毁当前实体,销毁后会自动销毁当前实体下的所有实体。 + /// + public virtual void Dispose() + { + if (IsDisposed) + { + return; + } + + var scene = Scene; + var runTimeId = RuntimeId; + RuntimeId = 0; + + if (_tree != null) + { + foreach (var (_, entity) in _tree) + { + entity.Dispose(); + } + + _tree.Clear(); + scene.EntitySortedDictionaryPool.Return(_tree); + _tree = null; + } + + if (_multi != null) + { + foreach (var (_, entity) in _multi) + { + entity.Dispose(); + } + + _multi.Clear(); + scene.EntitySortedDictionaryPool.Return(_multi); + _multi = null; + } +#if FANTASY_NET + if (_treeDb != null) + { + foreach (var entity in _treeDb) + { + entity.Dispose(); + } + + _treeDb.Clear(); + scene.EntityListPool.Return(_treeDb); + _treeDb = null; + } + + if (_multiDb != null) + { + foreach (var entity in _multiDb) + { + entity.Dispose(); + } + + _multiDb.Clear(); + scene.EntityListPool.Return(_multiDb); + _multiDb = null; + } +#endif + scene.EntityComponent.Destroy(this); + + if (Parent != null && Parent != this && !Parent.IsDisposed) + { + Parent.RemoveComponent(this, false); + Parent = null; + } + + Id = 0; + Scene = null; + Parent = null; + scene.RemoveEntity(runTimeId); + + if (IsPool()) + { + scene.EntityPool.Return(Type, this); + } + + Type = null; + } + + #endregion + + #region Pool + + /// + /// 获取一个值,该值指示当前实例是否为对象池中的实例。 + /// + /// + public bool IsPool() + { + return _isPool; + } + + /// + /// 设置一个值,该值指示当前实例是否为对象池中的实例。 + /// + /// + public void SetIsPool(bool isPool) + { + _isPool = isPool; + } + + #endregion + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Entitas/EntityPool.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Entitas/EntityPool.cs new file mode 100644 index 0000000..9a6441c --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Entitas/EntityPool.cs @@ -0,0 +1,66 @@ +using System.Collections.Generic; +using Fantasy.Pool; + +#pragma warning disable CS8714 // The type cannot be used as type parameter in the generic type or method. Nullability of type argument doesn't match 'notnull' constraint. + +namespace Fantasy.Entitas +{ + internal sealed class EntityPool : PoolCore + { + public EntityPool() : base(4096) { } + } + + internal sealed class EntityList : List, IPool where T : Entity + { + private bool _isPool; + /// + /// 获取一个值,该值指示当前实例是否为对象池中的实例。 + /// + /// + public bool IsPool() + { + return _isPool; + } + + /// + /// 设置一个值,该值指示当前实例是否为对象池中的实例。 + /// + /// + public void SetIsPool(bool isPool) + { + _isPool = isPool; + } + } + + internal sealed class EntityListPool : PoolCore> where T : Entity + { + public EntityListPool() : base(4096) { } + } + + internal sealed class EntitySortedDictionary : SortedDictionary, IPool where TN : Entity + { + private bool _isPool; + /// + /// 获取一个值,该值指示当前实例是否为对象池中的实例。 + /// + /// + public bool IsPool() + { + return _isPool; + } + + /// + /// 设置一个值,该值指示当前实例是否为对象池中的实例。 + /// + /// + public void SetIsPool(bool isPool) + { + _isPool = isPool; + } + } + + internal sealed class EntitySortedDictionaryPool : PoolCore> where TN : Entity + { + public EntitySortedDictionaryPool() : base(4096) { } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Entitas/EntityReference.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Entitas/EntityReference.cs new file mode 100644 index 0000000..dd1a3fd --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Entitas/EntityReference.cs @@ -0,0 +1,59 @@ +// ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. +#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. +#pragma warning disable CS8603 // Possible null reference return. +namespace Fantasy.Entitas +{ + /// + /// 实体引用检查组件 + /// + /// + public struct EntityReference where T : Entity + { + private T _entity; + private readonly long _runTimeId; + + private EntityReference(T t) + { + if (t == null) + { + _entity = null; + _runTimeId = 0; + return; + } + + _entity = t; + _runTimeId = t.RuntimeId; + } + + /// + /// 将一个实体转换为EntityReference + /// + /// 实体泛型类型 + /// 返回一个EntityReference + public static implicit operator EntityReference(T t) + { + return new EntityReference(t); + } + + /// + /// 将一个EntityReference转换为实体 + /// + /// 实体泛型类型 + /// 当实体已经被销毁过会返回null + public static implicit operator T(EntityReference v) + { + if (v._entity == null) + { + return null; + } + + if (v._entity.RuntimeId != v._runTimeId) + { + v._entity = null; + } + + return v._entity; + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Entitas/Interface/Supported/ISingleCollectionRoot.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Entitas/Interface/Supported/ISingleCollectionRoot.cs new file mode 100644 index 0000000..84de7a4 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Entitas/Interface/Supported/ISingleCollectionRoot.cs @@ -0,0 +1,17 @@ +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member +namespace Fantasy.Entitas.Interface +{ + /// + /// Entity保存到数据库的时候会根据子组件设置分离存储特性分表存储在不同的集合表中 + /// + public interface ISingleCollectionRoot { } + public static class SingleCollectionRootChecker where T : Entity + { + public static bool IsSupported { get; } + + static SingleCollectionRootChecker() + { + IsSupported = typeof(ISingleCollectionRoot).IsAssignableFrom(typeof(T)); + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Entitas/Interface/Supported/ISupportedDataBase.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Entitas/Interface/Supported/ISupportedDataBase.cs new file mode 100644 index 0000000..f505241 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Entitas/Interface/Supported/ISupportedDataBase.cs @@ -0,0 +1,19 @@ +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member +namespace Fantasy.Entitas.Interface +{ + /// + /// Entity支持数据库 + /// + // ReSharper disable once InconsistentNaming + public interface ISupportedDataBase { } + + public static class SupportedDataBaseChecker where T : Entity + { + public static bool IsSupported { get; } + + static SupportedDataBaseChecker() + { + IsSupported = typeof(ISupportedDataBase).IsAssignableFrom(typeof(T)); + } + } +} diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Entitas/Interface/Supported/ISupportedMultiEntity.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Entitas/Interface/Supported/ISupportedMultiEntity.cs new file mode 100644 index 0000000..ee6aeb7 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Entitas/Interface/Supported/ISupportedMultiEntity.cs @@ -0,0 +1,20 @@ +using System; +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member + +namespace Fantasy.Entitas.Interface +{ + /// + /// 支持再一个组件里添加多个同类型组件 + /// + public interface ISupportedMultiEntity : IDisposable { } + + public static class SupportedMultiEntityChecker where T : Entity + { + public static bool IsSupported { get; } + + static SupportedMultiEntityChecker() + { + IsSupported = typeof(ISupportedMultiEntity).IsAssignableFrom(typeof(T)); + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Entitas/Interface/Supported/ISupportedSingleCollection.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Entitas/Interface/Supported/ISupportedSingleCollection.cs new file mode 100644 index 0000000..302e697 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Entitas/Interface/Supported/ISupportedSingleCollection.cs @@ -0,0 +1,47 @@ +using System; +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member +namespace Fantasy.Entitas.Interface +{ + // Entity是单一集合、保存到数据库的时候不会跟随父组件保存在一个集合里、会单独保存在一个集合里 + // 需要配合SingleCollectionAttribute一起使用、如在Entity类头部定义SingleCollectionAttribute(typeOf(Unit)) + // SingleCollectionAttribute用来定义这个Entity是属于哪个Entity的子集 + /// + /// 定义实体支持单一集合存储的接口。当实体需要单独存储在一个集合中,并且在保存到数据库时不会与父组件一起保存在同一个集合中时,应实现此接口。 + /// + public interface ISupportedSingleCollection { } + public static class SupportedSingleCollectionChecker where T : Entity + { + public static bool IsSupported { get; } + + static SupportedSingleCollectionChecker() + { + IsSupported = typeof(ISupportedSingleCollection).IsAssignableFrom(typeof(T)); + } + } + /// + /// 表示用于指定实体的单一集合存储属性。此属性用于配合 接口使用, + /// 用于定义实体属于哪个父实体的子集合,以及在数据库中使用的集合名称。 + /// + [AttributeUsage(AttributeTargets.Class, Inherited = true, AllowMultiple = false)] + public class SingleCollectionAttribute : Attribute + { + /// + /// 获取父实体的类型,指示此实体是属于哪个父实体的子集合。 + /// + public readonly Type RootType; + /// + /// 获取在数据库中使用的集合名称。 + /// + public readonly string CollectionName; + /// + /// 初始化 类的新实例,指定父实体类型和集合名称。 + /// + /// 父实体的类型。 + /// 在数据库中使用的集合名称。 + public SingleCollectionAttribute(Type rootType, string collectionName) + { + RootType = rootType; + CollectionName = collectionName; + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Entitas/Interface/Supported/ISupportedTransfer.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Entitas/Interface/Supported/ISupportedTransfer.cs new file mode 100644 index 0000000..a3ae4a9 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Entitas/Interface/Supported/ISupportedTransfer.cs @@ -0,0 +1,19 @@ +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member +#if FANTASY_NET +namespace Fantasy.Entitas.Interface +{ + /// + /// Entity支持传送 + /// + public interface ISupportedTransfer { } + public static class SupportedTransferChecker where T : Entity + { + public static bool IsSupported { get; } + + static SupportedTransferChecker() + { + IsSupported = typeof(ISupportedTransfer).IsAssignableFrom(typeof(T)); + } + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Entitas/Interface/System/IAwakeSystem.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Entitas/Interface/System/IAwakeSystem.cs new file mode 100644 index 0000000..f651701 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Entitas/Interface/System/IAwakeSystem.cs @@ -0,0 +1,32 @@ +using System; +using Fantasy.Async; + +namespace Fantasy.Entitas.Interface +{ + internal interface IAwakeSystem : IEntitiesSystem { } + /// + /// 实体的Awake事件的抽象接口 + /// + /// 实体的泛型类型 + public abstract class AwakeSystem : IAwakeSystem where T : Entity + { + /// + /// 实体的类型 + /// + /// + public Type EntitiesType() => typeof(T); + /// + /// 事件的抽象方法,需要自己实现这个方法 + /// + /// 触发事件的实体实例 + protected abstract void Awake(T self); + /// + /// 框架内部调用的触发Awake的方法。 + /// + /// 触发事件的实体实例 + public void Invoke(Entity self) + { + Awake((T) self); + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Entitas/Interface/System/IDeserializeSystem.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Entitas/Interface/System/IDeserializeSystem.cs new file mode 100644 index 0000000..9c38ab6 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Entitas/Interface/System/IDeserializeSystem.cs @@ -0,0 +1,32 @@ +using System; +using Fantasy.Async; + +namespace Fantasy.Entitas.Interface +{ + internal interface IDeserializeSystem : IEntitiesSystem { } + /// + /// 实体的反序列化事件的抽象接口 + /// + /// 实体的泛型数据 + public abstract class DeserializeSystem : IDeserializeSystem where T : Entity + { + /// + /// 实体的类型 + /// + /// + public Type EntitiesType() => typeof(T); + /// + /// 事件的抽象方法,需要自己实现这个方法 + /// + /// 触发事件的实体实例 + protected abstract void Deserialize(T self); + /// + /// 框架内部调用的触发Deserialize的方法 + /// + /// 触发事件的实体实例 + public void Invoke(Entity self) + { + Deserialize((T) self); + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Entitas/Interface/System/IDestroySystem.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Entitas/Interface/System/IDestroySystem.cs new file mode 100644 index 0000000..531ebbe --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Entitas/Interface/System/IDestroySystem.cs @@ -0,0 +1,32 @@ +using System; +using Fantasy.Async; + +namespace Fantasy.Entitas.Interface +{ + internal interface IDestroySystem : IEntitiesSystem { } + /// + /// 实体销毁事件的抽象接口 + /// + /// + public abstract class DestroySystem : IDestroySystem where T : Entity + { + /// + /// 实体的类型 + /// + /// + public Type EntitiesType() => typeof(T); + /// + /// 事件的抽象方法,需要自己实现这个方法 + /// + /// 触发事件的实体实例 + protected abstract void Destroy(T self); + /// + /// 框架内部调用的触发Destroy的方法 + /// + /// + public void Invoke(Entity self) + { + Destroy((T) self); + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Entitas/Interface/System/IEntitiesSystem.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Entitas/Interface/System/IEntitiesSystem.cs new file mode 100644 index 0000000..555d21a --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Entitas/Interface/System/IEntitiesSystem.cs @@ -0,0 +1,22 @@ +using System; +using Fantasy.Async; + +namespace Fantasy.Entitas.Interface +{ + /// + /// ECS事件系统的核心接口,任何事件都是要继承这个接口 + /// + public interface IEntitiesSystem + { + /// + /// 实体的类型 + /// + /// + Type EntitiesType(); + /// + /// 框架内部调用的触发事件方法 + /// + /// + void Invoke(Entity entity); + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Entitas/Interface/System/IFrameUpdateSystem.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Entitas/Interface/System/IFrameUpdateSystem.cs new file mode 100644 index 0000000..c50061b --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Entitas/Interface/System/IFrameUpdateSystem.cs @@ -0,0 +1,31 @@ +using System; + +namespace Fantasy.Entitas.Interface +{ + internal interface IFrameUpdateSystem : IEntitiesSystem { } + /// + /// 帧更新时间的抽象接口 + /// + /// + public abstract class FrameUpdateSystem : IFrameUpdateSystem where T : Entity + { + /// + /// 实体的类型 + /// + /// + public Type EntitiesType() => typeof(T); + /// + /// 事件的抽象方法,需要自己实现这个方法 + /// + /// 触发事件的实体实例 + protected abstract void FrameUpdate(T self); + /// + /// 框架内部调用的触发FrameUpdate的方法 + /// + /// + public void Invoke(Entity self) + { + FrameUpdate((T) self); + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Entitas/Interface/System/IUpdateSystem.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Entitas/Interface/System/IUpdateSystem.cs new file mode 100644 index 0000000..4b34ac8 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Entitas/Interface/System/IUpdateSystem.cs @@ -0,0 +1,31 @@ +using System; + +namespace Fantasy.Entitas.Interface +{ + internal interface IUpdateSystem : IEntitiesSystem { } + /// + /// Update事件的抽象接口 + /// + /// + public abstract class UpdateSystem : IUpdateSystem where T : Entity + { + /// + /// 实体的类型 + /// + /// + public Type EntitiesType() => typeof(T); + /// + /// 事件的抽象方法,需要自己实现这个方法 + /// + /// 触发事件的实体实例 + protected abstract void Update(T self); + /// + /// 框架内部调用的触发Update的方法 + /// + /// 触发事件的实体实例 + public void Invoke(Entity self) + { + Update((T) self); + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/FTask/Builder/AsyncFTaskCompletedMethodBuilder.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/FTask/Builder/AsyncFTaskCompletedMethodBuilder.cs new file mode 100644 index 0000000..60b0d08 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/FTask/Builder/AsyncFTaskCompletedMethodBuilder.cs @@ -0,0 +1,52 @@ +using System; +using System.Diagnostics; +using System.Runtime.CompilerServices; +using System.Runtime.ExceptionServices; +using System.Runtime.InteropServices; +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member + +namespace Fantasy.Async +{ + [StructLayout(LayoutKind.Auto)] + public struct AsyncFTaskCompletedMethodBuilder + { + public FTaskCompleted Task => default; + + [DebuggerHidden] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static AsyncFTaskCompletedMethodBuilder Create() + { + return new AsyncFTaskCompletedMethodBuilder(); + } + [DebuggerHidden] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Start(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine + { + stateMachine.MoveNext(); + } + [DebuggerHidden] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void SetException(Exception exception) + { + ExceptionDispatchInfo.Capture(exception).Throw(); + } + [DebuggerHidden] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void SetResult() { } + [DebuggerHidden] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void AwaitOnCompleted(ref TAwaiter awaiter, ref TStateMachine stateMachine) where TAwaiter : INotifyCompletion where TStateMachine : IAsyncStateMachine + { + awaiter.OnCompleted(stateMachine.MoveNext); + } + [DebuggerHidden] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void AwaitUnsafeOnCompleted(ref TAwaiter awaiter, ref TStateMachine stateMachine) where TAwaiter : ICriticalNotifyCompletion where TStateMachine : IAsyncStateMachine + { + awaiter.UnsafeOnCompleted(stateMachine.MoveNext); + } + [DebuggerHidden] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void SetStateMachine(IAsyncStateMachine stateMachine) { } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/FTask/Builder/AsyncFTaskMethodBuilder.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/FTask/Builder/AsyncFTaskMethodBuilder.cs new file mode 100644 index 0000000..6c072cd --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/FTask/Builder/AsyncFTaskMethodBuilder.cs @@ -0,0 +1,140 @@ +using System; +using System.Collections.Concurrent; +using System.Diagnostics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +// ReSharper disable MemberCanBePrivate.Global +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member +#pragma warning disable CS8604 // Possible null reference argument. + +namespace Fantasy.Async +{ + [StructLayout(LayoutKind.Auto)] + public readonly struct AsyncFTaskMethodBuilder + { + public FTask Task + { + [DebuggerHidden] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get; + } + + [DebuggerHidden] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static AsyncFTaskMethodBuilder Create() + { + return new AsyncFTaskMethodBuilder(FTask.Create()); + } + + public AsyncFTaskMethodBuilder(FTask fTask) + { + Task = fTask; + } + + [DebuggerHidden] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Start(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine + { + stateMachine.MoveNext(); + } + + [DebuggerHidden] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void SetResult() + { + Task.SetResult(); + } + + [DebuggerHidden] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void SetException(Exception exception) + { + Task.SetException(exception); + } + + [DebuggerHidden] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void AwaitOnCompleted(ref TAwaiter awaiter, ref TStateMachine stateMachine) where TAwaiter : INotifyCompletion where TStateMachine : IAsyncStateMachine + { + // 通常在异步方法中遇到 await 关键字时调用,并且需要将执行恢复到调用 await 之前的同步上下文。 + awaiter.OnCompleted(stateMachine.MoveNext); + } + + [DebuggerHidden] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void AwaitUnsafeOnCompleted(ref TAwaiter awaiter, ref TStateMachine stateMachine) where TAwaiter : ICriticalNotifyCompletion where TStateMachine : IAsyncStateMachine + { + // 通常在你不需要恢复到原始同步上下文时调用,这意味着你不关心在什么线程上恢复执行。 + awaiter.UnsafeOnCompleted(stateMachine.MoveNext); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void SetStateMachine(IAsyncStateMachine stateMachine) + { + // 用于设置和保存异步方法的状态机实例。 + // 编译器在生成异步方法时要求其存在。 + // 编译器生成的代码已经足够处理状态机的管理,所以这里没有什么特殊要求所以保持空实现。 + } + } + + [StructLayout(LayoutKind.Auto)] + public readonly struct AsyncFTaskMethodBuilder + { + public FTask Task + { + [DebuggerHidden] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get; + } + + [DebuggerHidden] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static AsyncFTaskMethodBuilder Create() + { + return new AsyncFTaskMethodBuilder(FTask.Create()); + } + + public AsyncFTaskMethodBuilder(FTask fTask) + { + Task = fTask; + } + + [DebuggerHidden] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Start(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine + { + stateMachine.MoveNext(); + } + + [DebuggerHidden] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void SetResult(T value) + { + Task.SetResult(value); + } + + [DebuggerHidden] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void SetException(Exception exception) + { + Task.SetException(exception); + } + + [DebuggerHidden] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void AwaitOnCompleted(ref TAwaiter awaiter, ref TStateMachine stateMachine) where TAwaiter : INotifyCompletion where TStateMachine : IAsyncStateMachine + { + awaiter.OnCompleted(stateMachine.MoveNext); + } + + [DebuggerHidden] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void AwaitUnsafeOnCompleted(ref TAwaiter awaiter, ref TStateMachine stateMachine) where TAwaiter : ICriticalNotifyCompletion where TStateMachine : IAsyncStateMachine + { + awaiter.UnsafeOnCompleted(stateMachine.MoveNext); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void SetStateMachine(IAsyncStateMachine stateMachine) { } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/FTask/Builder/AsyncFVoidMethodBuilder.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/FTask/Builder/AsyncFVoidMethodBuilder.cs new file mode 100644 index 0000000..b9f7bc0 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/FTask/Builder/AsyncFVoidMethodBuilder.cs @@ -0,0 +1,62 @@ +using System; +using System.Diagnostics; +using System.Runtime.CompilerServices; +using System.Runtime.ExceptionServices; +using System.Runtime.InteropServices; +#pragma warning disable CS8603 // Possible null reference return. + +namespace Fantasy.Async +{ + [StructLayout(LayoutKind.Auto)] + internal struct AsyncFVoidMethodBuilder + { + public FVoid Task + { + [DebuggerHidden] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => default; + } + + [DebuggerHidden] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static AsyncFVoidMethodBuilder Create() + { + return default; + } + + [DebuggerHidden] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Start(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine + { + stateMachine.MoveNext(); + } + + [DebuggerHidden] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void SetResult() { } + + [DebuggerHidden] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void SetException(Exception exception) + { + ExceptionDispatchInfo.Capture(exception).Throw(); + } + + [DebuggerHidden] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void AwaitOnCompleted(ref TAwaiter awaiter, ref TStateMachine stateMachine) where TAwaiter : INotifyCompletion where TStateMachine : IAsyncStateMachine + { + awaiter.OnCompleted(stateMachine.MoveNext); + } + + [DebuggerHidden] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void AwaitUnsafeOnCompleted(ref TAwaiter awaiter, ref TStateMachine stateMachine) where TAwaiter : ICriticalNotifyCompletion where TStateMachine : IAsyncStateMachine + { + awaiter.UnsafeOnCompleted(stateMachine.MoveNext); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void SetStateMachine(IAsyncStateMachine stateMachine) { } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/FTask/FCancellationToken/FCancellationToken.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/FTask/FCancellationToken/FCancellationToken.cs new file mode 100644 index 0000000..90913e3 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/FTask/FCancellationToken/FCancellationToken.cs @@ -0,0 +1,121 @@ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; + +namespace Fantasy.Async +{ + /// + /// 用于FTask取消的CancellationToken + /// + public sealed class FCancellationToken : IDisposable + { + private bool _isDispose; + private bool _isCancel; + private readonly HashSet _actions = new HashSet(); + /// + /// 当前CancellationToken是否已经取消过了 + /// + public bool IsCancel => _isDispose || _isCancel; + /// + /// 添加一个取消要执行的Action + /// + /// + public void Add(Action action) + { + if (_isDispose) + { + return; + } + + _actions.Add(action); + } + /// + /// 移除一个取消要执行的Action + /// + /// + public void Remove(Action action) + { + if (_isDispose) + { + return; + } + + _actions.Remove(action); + } + /// + /// 取消CancellationToken + /// + public void Cancel() + { + if (IsCancel) + { + return; + } + + _isCancel = true; + + foreach (var action in _actions) + { + try + { + action.Invoke(); + } + catch (Exception e) + { + Console.WriteLine(e); + } + } + + _actions.Clear(); + } + /// + /// 销毁掉CancellationToken,会执行Cancel方法。 + /// + public void Dispose() + { + if (_isDispose) + { + return; + } + + if (!IsCancel) + { + Cancel(); + _isCancel = true; + } + + _isDispose = true; + + if (Caches.Count > 2000) + { + return; + } + + Caches.Enqueue(this); + } + + #region Static + + private static readonly ConcurrentQueue Caches = new ConcurrentQueue(); + + /// + /// 获取一个新的CancellationToken + /// + public static FCancellationToken ToKen + { + get + { + if (!Caches.TryDequeue(out var fCancellationToken)) + { + fCancellationToken = new FCancellationToken(); + } + + fCancellationToken._isCancel = false; + fCancellationToken._isDispose = false; + return fCancellationToken; + } + } + + #endregion + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/FTask/FTask.Extension/FTask.Factory.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/FTask/FTask.Extension/FTask.Factory.cs new file mode 100644 index 0000000..80c7fc8 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/FTask/FTask.Extension/FTask.Factory.cs @@ -0,0 +1,115 @@ +#if !FANTASY_WEBGL +using System.Collections.Concurrent; +#endif +using System.Collections.Generic; +using System.Diagnostics; +using System.Runtime.CompilerServices; +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. +#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. + +namespace Fantasy.Async +{ + /// + /// 一个异步任务 + /// + public partial class FTask + { + private bool _isPool; +#if FANTASY_WEBGL + private static readonly Queue Caches = new Queue(); +#else + private static readonly ConcurrentQueue Caches = new ConcurrentQueue(); +#endif + /// + /// 创建一个空的任务 + /// + public static FTaskCompleted CompletedTask => new FTaskCompleted(); + + private FTask() { } + + /// + /// 创建一个任务 + /// + /// 是否从对象池中创建 + /// + [DebuggerHidden] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static FTask Create(bool isPool = true) + { + if (!isPool) + { + return new FTask(); + } + + if (!Caches.TryDequeue(out var fTask)) + { + fTask = new FTask(); + } + + fTask._isPool = true; + return fTask; + } + + private void Return() + { + if (!_isPool || Caches.Count > 2000) + { + return; + } + + _callBack = null; + _status = STaskStatus.Pending; + Caches.Enqueue(this); + } + } + + /// + /// 一个异步任务 + /// + /// 任务的泛型类型 + public partial class FTask + { + private bool _isPool; +#if FANTASY_WEBGL + private static readonly Queue> Caches = new Queue>(); +#else + private static readonly ConcurrentQueue> Caches = new ConcurrentQueue>(); +#endif + /// + /// 创建一个任务 + /// + /// 是否从对象池中创建 + /// + [DebuggerHidden] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static FTask Create(bool isPool = true) + { + if (!isPool) + { + return new FTask(); + } + + if (!Caches.TryDequeue(out var fTask)) + { + fTask = new FTask(); + } + + fTask._isPool = true; + return fTask; + } + + private FTask() { } + + private void Return() + { + if (!_isPool || Caches.Count > 2000) + { + return; + } + + _callBack = null; + _status = STaskStatus.Pending; + Caches.Enqueue(this); + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/FTask/FTask.Extension/FTask.Tools.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/FTask/FTask.Extension/FTask.Tools.cs new file mode 100644 index 0000000..a42edec --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/FTask/FTask.Extension/FTask.Tools.cs @@ -0,0 +1,345 @@ +// ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract + +using System; +using System.Collections.Generic; +#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. +namespace Fantasy.Async +{ + public partial class FTask + { + #region NetTimer + + /// + /// 异步等待指定时间 + /// + /// + /// + /// + /// + public static FTask Wait(Scene scene, long time, FCancellationToken cancellationToken = null) + { + return scene.TimerComponent.Net.WaitAsync(time, cancellationToken); + } + + /// + /// 异步等待直到指定时间 + /// + /// + /// + /// + /// + public static FTask WaitTill(Scene scene, long time, FCancellationToken cancellationToken = null) + { + return scene.TimerComponent.Net.WaitTillAsync(time, cancellationToken); + } + + /// + /// 异步等待一帧时间 + /// + /// + /// + public static FTask WaitFrame(Scene scene) + { + return scene.TimerComponent.Net.WaitFrameAsync(); + } + + /// + /// 创建一个只执行一次的计时器,直到指定时间 + /// + /// + /// + /// + /// + public static long OnceTimer(Scene scene, long time, Action action) + { + return scene.TimerComponent.Net.OnceTimer(time, action); + } + + /// + /// 创建一个只执行一次的计时器,直到指定时间。 + /// + /// + /// + /// + /// + public static long OnceTillTimer(Scene scene, long time, Action action) + { + return scene.TimerComponent.Net.OnceTillTimer(time, action); + } + + /// + /// 创建一个只执行一次的计时器,用于发布指定类型的事件。 + /// + /// + /// + /// + /// + /// + public static long OnceTimer(Scene scene, long time, T timerHandlerType) where T : struct + { + return scene.TimerComponent.Net.OnceTimer(time, timerHandlerType); + } + + /// + /// 创建一个只执行一次的计时器,直到指定时间,用于发布指定类型的事件。 + /// + /// + /// + /// + /// + /// + public static long OnceTillTimer(Scene scene, long tillTime, T timerHandlerType) where T : struct + { + return scene.TimerComponent.Net.OnceTillTimer(tillTime, timerHandlerType); + } + + /// + /// 创建一个重复执行的计时器。 + /// + /// + /// + /// + /// + public static long RepeatedTimer(Scene scene, long time, Action action) + { + return scene.TimerComponent.Net.RepeatedTimer(time, action); + } + + /// + /// 创建一个重复执行的计时器,用于发布指定类型的事件。 + /// + /// + /// + /// + /// + /// + public static long RepeatedTimer(Scene scene, long time, T timerHandlerType) where T : struct + { + return scene.TimerComponent.Net.RepeatedTimer(time, timerHandlerType); + } + + /// + /// 移除指定 ID 的计时器。 + /// + /// + /// + /// + public static bool RemoveTimer(Scene scene, ref long timerId) + { + return scene.TimerComponent.Net.Remove(ref timerId); + } + + #endregion + + #region Unity + +#if FANTASY_UNITY + /// + /// 异步等待指定时间。(使用Unity的Time时间) + /// + /// + /// + /// + /// + public static FTask UnityWait(Scene scene, long time, FCancellationToken cancellationToken = null) + { + return scene.TimerComponent.Unity.WaitAsync(time, cancellationToken); + } + + /// + /// 异步等待直到指定时间。(使用Unity的Time时间) + /// + /// + /// + /// + /// + public static FTask UnityWaitTill(Scene scene, long time, FCancellationToken cancellationToken = null) + { + return scene.TimerComponent.Unity.WaitTillAsync(time, cancellationToken); + } + + /// + /// 异步等待一帧时间。(使用Unity的Time时间) + /// + /// + /// + public static FTask UnityWaitFrame(Scene scene) + { + return scene.TimerComponent.Unity.WaitFrameAsync(); + } + + /// + /// 创建一个只执行一次的计时器,直到指定时间。(使用Unity的Time时间) + /// + /// + /// + /// + /// + public static long UnityOnceTimer(Scene scene, long time, Action action) + { + return scene.TimerComponent.Unity.OnceTimer(time, action); + } + + /// + /// 创建一个只执行一次的计时器,直到指定时间。(使用Unity的Time时间) + /// + /// + /// + /// + /// + public static long UnityOnceTillTimer(Scene scene, long time, Action action) + { + return scene.TimerComponent.Unity.OnceTillTimer(time, action); + } + + /// + /// 创建一个只执行一次的计时器,用于发布指定类型的事件。(使用Unity的Time时间) + /// + /// + /// + /// + /// + /// + public static long UnityOnceTimer(Scene scene, long time, T timerHandlerType) where T : struct + { + return scene.TimerComponent.Unity.OnceTimer(time, timerHandlerType); + } + + /// + /// 创建一个只执行一次的计时器,直到指定时间,用于发布指定类型的事件。(使用Unity的Time时间) + /// + /// + /// + /// + /// + /// + public static long UnityOnceTillTimer(Scene scene, long tillTime, T timerHandlerType) where T : struct + { + return scene.TimerComponent.Unity.OnceTillTimer(tillTime, timerHandlerType); + } + + /// + /// 创建一个重复执行的计时器。(使用Unity的Time时间) + /// + /// + /// + /// + /// + public static long UnityRepeatedTimer(Scene scene, long time, Action action) + { + return scene.TimerComponent.Unity.RepeatedTimer(time, action); + } + + /// + /// 创建一个重复执行的计时器,用于发布指定类型的事件。(使用Unity的Time时间) + /// + /// + /// + /// + /// + /// + public static long UnityRepeatedTimer(Scene scene, long time, T timerHandlerType) where T : struct + { + return scene.TimerComponent.Unity.RepeatedTimer(time, timerHandlerType); + } + + /// + /// 移除指定 ID 的计时器。(使用Unity的Time时间) + /// + /// + /// + /// + public static bool UnityRemoveTimer(Scene scene, ref long timerId) + { + return scene.TimerComponent.Unity.Remove(ref timerId); + } +#endif + + #endregion + + /// + /// 创建并运行一个异步任务 + /// + /// + /// + public static FTask Run(Func factory) + { + return factory(); + } + + /// + /// 创建并运行一个带有结果的异步任务 + /// + /// + /// + /// + public static FTask Run(Func> factory) + { + return factory(); + } + + /// + /// 等待所有任务完成 + /// + /// + public static async FTask WaitAll(List tasks) + { + if (tasks.Count <= 0) + { + return; + } + + var count = tasks.Count; + var sTaskCompletionSource = Create(); + + foreach (var task in tasks) + { + RunSTask(task).Coroutine(); + } + + await sTaskCompletionSource; + + async FVoid RunSTask(FTask task) + { + await task; + count--; + if (count <= 0) + { + sTaskCompletionSource.SetResult(); + } + } + } + /// + /// 等待其中一个任务完成 + /// + /// + public static async FTask WaitAny(List tasks) + { + if (tasks.Count <= 0) + { + return; + } + + var count = 1; + var sTaskCompletionSource = Create(); + + foreach (var task in tasks) + { + RunSTask(task).Coroutine(); + } + + await sTaskCompletionSource; + + async FVoid RunSTask(FTask task) + { + await task; + count--; + if (count == 0) + { + sTaskCompletionSource.SetResult(); + } + } + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/FTask/Task/FTask.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/FTask/Task/FTask.cs new file mode 100644 index 0000000..ce925f2 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/FTask/Task/FTask.cs @@ -0,0 +1,263 @@ +using System; +using System.Diagnostics; +using System.Runtime.CompilerServices; +using System.Runtime.ExceptionServices; +// ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract +// ReSharper disable ConditionalAccessQualifierIsNonNullableAccordingToAPIContract +// ReSharper disable CheckNamespace +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member +#pragma warning disable CS8602 // Dereference of a possibly null reference. +#pragma warning disable CS8603 // Possible null reference return. +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. +#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. + +namespace Fantasy.Async +{ + public enum STaskStatus : byte + { + Pending = 0, // The operation has not yet completed. + Succeeded = 1, // The operation completed successfully. + Faulted = 2 // The operation completed with an error. + } + + [AsyncMethodBuilder(typeof(AsyncFTaskMethodBuilder))] + public sealed partial class FTask : ICriticalNotifyCompletion + { + private Action _callBack; + private ExceptionDispatchInfo _exception; + private STaskStatus _status = STaskStatus.Pending; + public bool IsCompleted + { + [DebuggerHidden] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _status != STaskStatus.Pending; + } + + [DebuggerHidden] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public FTask GetAwaiter() => this; + + [DebuggerHidden] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private async FVoid InnerCoroutine() + { + await this; + } + + [DebuggerHidden] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Coroutine() + { + InnerCoroutine().Coroutine(); + } + + [DebuggerHidden] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void GetResult() + { + switch (_status) + { + case STaskStatus.Succeeded: + { + Return(); + return; + } + case STaskStatus.Faulted: + { + Return(); + + if (_exception == null) + { + return; + } + + var exception = _exception; + _exception = null; + exception.Throw(); + return; + } + default: + { + throw new NotSupportedException("Direct call to getResult is not allowed"); + } + } + } + + [DebuggerHidden] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void SetResult() + { + if (_status != STaskStatus.Pending) + { + throw new InvalidOperationException("The task has been completed"); + } + + _status = STaskStatus.Succeeded; + + if (_callBack == null) + { + return; + } + + var callBack = _callBack; + _callBack = null; + callBack.Invoke(); + } + + [DebuggerHidden] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void OnCompleted(Action action) + { + UnsafeOnCompleted(action); + } + + [DebuggerHidden] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void UnsafeOnCompleted(Action action) + { + if (_status != STaskStatus.Pending) + { + action?.Invoke(); + return; + } + + _callBack = action; + } + + [DebuggerHidden] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void SetException(Exception exception) + { + if (_status != STaskStatus.Pending) + { + throw new InvalidOperationException("The task has been completed"); + } + + _status = STaskStatus.Faulted; + _exception = ExceptionDispatchInfo.Capture(exception); + _callBack?.Invoke(); + } + } + + [AsyncMethodBuilder(typeof(AsyncFTaskMethodBuilder<>))] + public sealed partial class FTask : ICriticalNotifyCompletion + { + private T _value; + private Action _callBack; + private ExceptionDispatchInfo _exception; + private STaskStatus _status = STaskStatus.Pending; + public bool IsCompleted + { + [DebuggerHidden] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _status != STaskStatus.Pending; + } + + [DebuggerHidden] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public FTask GetAwaiter() => this; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + [DebuggerHidden] + private async FVoid InnerCoroutine() + { + await this; + } + + [DebuggerHidden] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Coroutine() + { + InnerCoroutine().Coroutine(); + } + + [DebuggerHidden] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public T GetResult() + { + switch (_status) + { + case STaskStatus.Succeeded: + { + var value = _value; + Return(); + return value; + } + case STaskStatus.Faulted: + { + Return(); + + if (_exception == null) + { + return default; + } + + var exception = _exception; + _exception = null; + exception.Throw(); + return default; + } + default: + { + throw new NotSupportedException("Direct call to getResult is not allowed"); + } + } + } + + [DebuggerHidden] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void SetResult(T value) + { + if (_status != STaskStatus.Pending) + { + throw new InvalidOperationException("The task has been completed"); + } + + _value = value; + _status = STaskStatus.Succeeded; + + if (_callBack == null) + { + return; + } + + var callBack = _callBack; + _callBack = null; + callBack.Invoke(); + } + + [DebuggerHidden] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void OnCompleted(Action action) + { + UnsafeOnCompleted(action); + } + + [DebuggerHidden] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void UnsafeOnCompleted(Action action) + { + if (_status != STaskStatus.Pending) + { + action?.Invoke(); + return; + } + + _callBack = action; + } + + [DebuggerHidden] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void SetException(Exception exception) + { + if (_status != STaskStatus.Pending) + { + throw new InvalidOperationException("The task has been completed"); + } + + _status = STaskStatus.Faulted; + _exception = ExceptionDispatchInfo.Capture(exception); + _callBack?.Invoke(); + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/FTask/Task/FTaskCompleted.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/FTask/Task/FTaskCompleted.cs new file mode 100644 index 0000000..48b9e36 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/FTask/Task/FTaskCompleted.cs @@ -0,0 +1,31 @@ +using System; +using System.Diagnostics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member + +namespace Fantasy.Async +{ + [StructLayout(LayoutKind.Auto)] + [AsyncMethodBuilder(typeof(AsyncFTaskCompletedMethodBuilder))] + public struct FTaskCompleted : ICriticalNotifyCompletion + { + [DebuggerHidden] + public bool IsCompleted => true; + [DebuggerHidden] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public FTaskCompleted GetAwaiter() + { + return this; + } + [DebuggerHidden] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void GetResult() { } + [DebuggerHidden] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void OnCompleted(Action continuation) { } + [DebuggerHidden] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void UnsafeOnCompleted(Action continuation) { } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/FTask/Task/FVoid.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/FTask/Task/FVoid.cs new file mode 100644 index 0000000..f10ca7c --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/FTask/Task/FVoid.cs @@ -0,0 +1,29 @@ +using System; +using System.Diagnostics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace Fantasy.Async +{ + [StructLayout(LayoutKind.Auto)] + [AsyncMethodBuilder(typeof(AsyncFVoidMethodBuilder))] + internal struct FVoid : ICriticalNotifyCompletion + { + public bool IsCompleted + { + [DebuggerHidden] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => true; + } + [DebuggerHidden] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Coroutine() { } + [DebuggerHidden] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void OnCompleted(Action continuation) { } + + [DebuggerHidden] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void UnsafeOnCompleted(Action continuation) { } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Helper/ByteHelper.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Helper/ByteHelper.cs new file mode 100644 index 0000000..9d3d6e0 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Helper/ByteHelper.cs @@ -0,0 +1,388 @@ +using System; +using System.Buffers; +using System.IO; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Text; +using Fantasy.Async; + +namespace Fantasy.Helper +{ + /// + /// 提供字节操作辅助方法的静态类。 + /// + public static class ByteHelper + { + private static readonly string[] Suffix = { "Byte", "KB", "MB", "GB", "TB" }; + + /// + /// 从指定的文件流中读取一个 64 位整数。 + /// + public static long ReadInt64(FileStream stream) + { + var buffer = new byte[8]; +#if FANTASY_NET + stream.ReadExactly(buffer, 0, 8); +#else + stream.Read(buffer, 0, 8); +#endif + return BitConverter.ToInt64(buffer, 0); + } + + /// + /// 从指定的文件流中读取一个 32 位整数。 + /// + public static int ReadInt32(FileStream stream) + { + var buffer = new byte[4]; +#if FANTASY_NET + stream.ReadExactly(buffer, 0, 4); +#else + stream.Read(buffer, 0, 4); +#endif + return BitConverter.ToInt32(buffer, 0); + } + + /// + /// 从指定的内存流中读取一个 64 位整数。 + /// + public static long ReadInt64(MemoryStream stream) + { + var buffer = new byte[8]; +#if FANTASY_NET + stream.ReadExactly(buffer, 0, 8); +#else + stream.Read(buffer, 0, 8); +#endif + return BitConverter.ToInt64(buffer, 0); + } + + /// + /// 从指定的内存流中读取一个 32 位整数。 + /// + public static int ReadInt32(MemoryStream stream) + { + var buffer = new byte[4]; +#if FANTASY_NET + stream.ReadExactly(buffer, 0, 4); +#else + stream.Read(buffer, 0, 4); +#endif + return BitConverter.ToInt32(buffer, 0); + } + + /// + /// 将字节转换为十六进制字符串表示。 + /// + public static string ToHex(this byte b) + { + return b.ToString("X2"); + } + + /// + /// 将字节数组转换为十六进制字符串表示。 + /// + public static string ToHex(this byte[] bytes) + { + var stringBuilder = new StringBuilder(); + foreach (var b in bytes) + { + stringBuilder.Append(b.ToString("X2")); + } + + return stringBuilder.ToString(); + } + + /// + /// 将字节数组按指定格式转换为十六进制字符串表示。 + /// + public static string ToHex(this byte[] bytes, string format) + { + var stringBuilder = new StringBuilder(); + foreach (var b in bytes) + { + stringBuilder.Append(b.ToString(format)); + } + + return stringBuilder.ToString(); + } + + /// + /// 将字节数组的指定范围按十六进制格式转换为字符串表示。 + /// + public static string ToHex(this byte[] bytes, int offset, int count) + { + var stringBuilder = new StringBuilder(); + for (var i = offset; i < offset + count; ++i) + { + stringBuilder.Append(bytes[i].ToString("X2")); + } + + return stringBuilder.ToString(); + } + + /// + /// 将字节数组转换为默认编码的字符串表示。 + /// + public static string ToStr(this byte[] bytes) + { + return Encoding.Default.GetString(bytes); + } + + /// + /// 将字节数组的指定范围按默认编码转换为字符串表示。 + /// + public static string ToStr(this byte[] bytes, int index, int count) + { + return Encoding.Default.GetString(bytes, index, count); + } + + /// + /// 将字节数组转换为 UTF-8 编码的字符串表示。 + /// + public static string Utf8ToStr(this byte[] bytes) + { + return Encoding.UTF8.GetString(bytes); + } + + /// + /// 将字节数组的指定范围按 UTF-8 编码转换为字符串表示。 + /// + public static string Utf8ToStr(this byte[] bytes, int index, int count) + { + return Encoding.UTF8.GetString(bytes, index, count); + } + + /// + /// 将无符号整数写入字节数组的指定偏移位置。 + /// + public static void WriteTo(this byte[] bytes, int offset, uint num) + { + bytes[offset] = (byte)(num & 0xff); + bytes[offset + 1] = (byte)((num & 0xff00) >> 8); + bytes[offset + 2] = (byte)((num & 0xff0000) >> 16); + bytes[offset + 3] = (byte)((num & 0xff000000) >> 24); + } + + /// + /// 将有符号整数写入字节数组的指定偏移位置。 + /// + public static void WriteTo(this byte[] bytes, int offset, int num) + { + bytes[offset] = (byte)(num & 0xff); + bytes[offset + 1] = (byte)((num & 0xff00) >> 8); + bytes[offset + 2] = (byte)((num & 0xff0000) >> 16); + bytes[offset + 3] = (byte)((num & 0xff000000) >> 24); + } + + /// + /// 将字节写入字节数组的指定偏移位置。 + /// + public static void WriteTo(this byte[] bytes, int offset, byte num) + { + bytes[offset] = num; + } + + /// + /// 将有符号短整数写入字节数组的指定偏移位置。 + /// + public static void WriteTo(this byte[] bytes, int offset, short num) + { + bytes[offset] = (byte)(num & 0xff); + bytes[offset + 1] = (byte)((num & 0xff00) >> 8); + } + + /// + /// 将无符号短整数写入字节数组的指定偏移位置。 + /// + public static void WriteTo(this byte[] bytes, int offset, ushort num) + { + bytes[offset] = (byte)(num & 0xff); + bytes[offset + 1] = (byte)((num & 0xff00) >> 8); + } + + /// + /// 将字节数转换为可读的速度表示。 + /// + /// 字节数 + /// 可读的速度表示 + public static string ToReadableSpeed(this long byteCount) + { + var i = 0; + double dblSByte = byteCount; + if (byteCount <= 1024) + { + return $"{dblSByte:0.##}{Suffix[i]}"; + } + + for (i = 0; byteCount / 1024 > 0; i++, byteCount /= 1024) + { + dblSByte = byteCount / 1024.0; + } + + return $"{dblSByte:0.##}{Suffix[i]}"; + } + + /// + /// 将字节数转换为可读的速度表示。 + /// + /// 字节数 + /// 可读的速度表示 + public static string ToReadableSpeed(this ulong byteCount) + { + var i = 0; + double dblSByte = byteCount; + + if (byteCount <= 1024) + { + return $"{dblSByte:0.##}{Suffix[i]}"; + } + + for (i = 0; byteCount / 1024 > 0; i++, byteCount /= 1024) + { + dblSByte = byteCount / 1024.0; + } + + return $"{dblSByte:0.##}{Suffix[i]}"; + } + + /// + /// 合并两个字节数组。 + /// + /// 第一个字节数组 + /// 第二个字节数组 + /// 合并后的字节数组 + public static byte[] MergeBytes(byte[] bytes, byte[] otherBytes) + { + var result = new byte[bytes.Length + otherBytes.Length]; + bytes.CopyTo(result, 0); + otherBytes.CopyTo(result, bytes.Length); + return result; + } + + /// + /// 根据int值获取字节数组。 + /// + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void GetBytes(this int value, byte[] buffer) + { + if (buffer.Length < 4) + { + throw new ArgumentException("Buffer too small."); + } + +#if FANTASY_NET || FANTASY_CONSOLE + MemoryMarshal.Write(buffer.AsSpan(), in value); +#endif +#if FANTASY_UNITY + MemoryMarshal.Write(buffer.AsSpan(), ref value); +#endif + } + + /// + /// 根据int值获取字节数组。 + /// + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void WriteBytes(this MemoryStream memoryStream, int value) + { + using var memoryOwner = MemoryPool.Shared.Rent(4); + var memorySpan = memoryOwner.Memory.Span; +#if FANTASY_NET + MemoryMarshal.Write(memorySpan, in value); +#endif +#if FANTASY_UNITY + MemoryMarshal.Write(memorySpan, ref value); +#endif + memoryStream.Write(memorySpan); + } + + /// + /// 根据uint值获取字节数组。 + /// + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void GetBytes(ref this uint value, byte[] buffer) + { + if (buffer.Length < 4) + { + throw new ArgumentException("Buffer too small."); + } + +#if FANTASY_NET + MemoryMarshal.Write(buffer.AsSpan(), in value); +#endif +#if FANTASY_UNITY + MemoryMarshal.Write(buffer.AsSpan(), ref value); +#endif + } + + /// + /// 根据uint值获取字节数组。 + /// + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void WriteBytes(this MemoryStream memoryStream, uint value) + { + using var memoryOwner = MemoryPool.Shared.Rent(4); + var memorySpan = memoryOwner.Memory.Span; +#if FANTASY_NET + MemoryMarshal.Write(memorySpan, in value); +#endif +#if FANTASY_UNITY + MemoryMarshal.Write(memorySpan, ref value); +#endif + memoryStream.Write(memorySpan); + } + + /// + /// 根据int值获取字节数组。 + /// + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void GetBytes(this long value, byte[] buffer) + { + if (buffer.Length < 8) + { + throw new ArgumentException("Buffer too small."); + } +#if FANTASY_NET + MemoryMarshal.Write(buffer.AsSpan(), in value); +#endif +#if FANTASY_UNITY + MemoryMarshal.Write(buffer.AsSpan(), ref value); +#endif + } + + /// + /// 根据uint值获取字节数组。 + /// + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void WriteBytes(this MemoryStream memoryStream, long value) + { + using var memoryOwner = MemoryPool.Shared.Rent(8); + var memorySpan = memoryOwner.Memory.Span; +#if FANTASY_NET + MemoryMarshal.Write(memorySpan, in value); +#endif +#if FANTASY_UNITY + MemoryMarshal.Write(memorySpan, ref value); +#endif + memoryStream.Write(memorySpan); + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Helper/Download/ADownload.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Helper/Download/ADownload.cs new file mode 100644 index 0000000..4846d51 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Helper/Download/ADownload.cs @@ -0,0 +1,50 @@ +#if FANTASY_UNITY +using System; +using Fantasy.Async; +using UnityEngine.Networking; + +namespace Fantasy.Unity.Download +{ + public abstract class AUnityDownload : IDisposable + { + private long _timeId; + private ulong _totalDownloadedBytes; + private Download _download; + protected UnityWebRequest UnityWebRequest; + private FCancellationToken _cancellationToken; + private Scene Scene; + + protected AUnityDownload(Scene scene,Download download) + { + Scene = scene; + _download = download; + _download.Tasks.Add(this); + } + + protected UnityWebRequestAsyncOperation Start(UnityWebRequest unityWebRequest, bool monitor) + { + UnityWebRequest = unityWebRequest; + _timeId = Scene.TimerComponent.Unity.RepeatedTimer(33, Update); + return UnityWebRequest.SendWebRequest(); + } + + private void Update() + { + var downloadSpeed = UnityWebRequest.downloadedBytes - _totalDownloadedBytes; + _download.DownloadSpeed += downloadSpeed; + _download.TotalDownloadedBytes += downloadSpeed; + _totalDownloadedBytes = UnityWebRequest.downloadedBytes; + } + + public virtual void Dispose() + { + Update(); + _totalDownloadedBytes = 0; + UnityWebRequest?.Dispose(); + _download.Tasks.Remove(this); + Scene.TimerComponent.Unity.Remove(ref _timeId); + _download = null; + } + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Helper/Download/ADownload.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Helper/Download/ADownload.cs.meta new file mode 100644 index 0000000..70e1e3c --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Helper/Download/ADownload.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: c5743903d34d474a818b5c2bafa31459 +timeCreated: 1726021902 \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Helper/Download/Download.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Helper/Download/Download.cs new file mode 100644 index 0000000..a53a42a --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Helper/Download/Download.cs @@ -0,0 +1,72 @@ +#if FANTASY_UNITY +using System.Collections.Generic; +using System.Linq; +using Fantasy.Async; +using UnityEngine; + +namespace Fantasy.Unity.Download +{ + public sealed class Download + { + public Scene Scene; + public ulong DownloadSpeed; + public ulong TotalDownloadedBytes; + public readonly HashSet Tasks = new(); + + public static Download Create(Scene scene) => new Download(scene); + + private Download(Scene scene) + { + Scene = scene; + } + + public void Clear() + { + DownloadSpeed = 0; + TotalDownloadedBytes = 0; + + if (Tasks.Count <= 0) + { + return; + } + + foreach (var aUnityDownload in Tasks.ToArray()) + { + aUnityDownload.Dispose(); + } + + Tasks.Clear(); + } + + public FTask DownloadAssetBundle(string url, bool monitor = false, FCancellationToken cancellationToken = null) + { + return new DownloadAssetBundle(Scene, this).StartDownload(url, monitor, cancellationToken); + } + + public FTask DownloadAudioClip(string url, AudioType audioType, bool monitor = false, FCancellationToken cancellationToken = null) + { + return new DownloadAudioClip(Scene, this).StartDownload(url, audioType, monitor, cancellationToken); + } + + public FTask DownloadSprite(string url, bool monitor = false, FCancellationToken cancellationToken = null) + { + return new DownloadSprite(Scene, this).StartDownload(url, monitor, cancellationToken); + } + + public FTask DownloadTexture(string url, bool monitor = false, FCancellationToken cancellationToken = null) + { + return new DownloadTexture(Scene, this).StartDownload(url, monitor, cancellationToken); + } + + public FTask DownloadText(string url, bool monitor = false, FCancellationToken cancellationToken = null) + { + return new DownloadText(Scene, this).StartDownload(url, monitor, cancellationToken); + } + + public FTask DownloadByte(string url, bool monitor = false, FCancellationToken cancellationToken = null) + { + return new DownloadByte(Scene, this).StartDownload(url, monitor, cancellationToken); + } + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Helper/Download/Download.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Helper/Download/Download.cs.meta new file mode 100644 index 0000000..41e84be --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Helper/Download/Download.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 5715816370e84842aaab799c9776a5e4 +timeCreated: 1726023436 \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Helper/Download/DownloadAssetBundle.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Helper/Download/DownloadAssetBundle.cs new file mode 100644 index 0000000..9d8f5a4 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Helper/Download/DownloadAssetBundle.cs @@ -0,0 +1,54 @@ +#if FANTASY_UNITY +using System; +using Fantasy.Async; +using UnityEngine; +using UnityEngine.Networking; + +namespace Fantasy.Unity.Download +{ + public sealed class DownloadAssetBundle : AUnityDownload + { + public DownloadAssetBundle(Scene scene, Download download) : base(scene, download) + { + } + + public FTask StartDownload(string url, bool monitor, FCancellationToken cancellationToken = null) + { + var task = FTask.Create(false); + var unityWebRequestAsyncOperation = Start(UnityWebRequestAssetBundle.GetAssetBundle(Uri.EscapeUriString(url)), monitor); + + if (cancellationToken != null) + { + cancellationToken.Add(() => + { + Dispose(); + task.SetResult(null); + }); + } + + unityWebRequestAsyncOperation.completed += operation => + { + try + { + if (UnityWebRequest.result == UnityWebRequest.Result.Success) + { + var assetBundle = DownloadHandlerAssetBundle.GetContent(UnityWebRequest); + task.SetResult(assetBundle); + } + else + { + Log.Error(UnityWebRequest.error); + task.SetResult(null); + } + } + finally + { + Dispose(); + } + }; + + return task; + } + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Helper/Download/DownloadAssetBundle.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Helper/Download/DownloadAssetBundle.cs.meta new file mode 100644 index 0000000..c6bf29a --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Helper/Download/DownloadAssetBundle.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 07cbb9a010ed4fe1b90919f81847b9ea +timeCreated: 1726023471 \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Helper/Download/DownloadAudioClip.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Helper/Download/DownloadAudioClip.cs new file mode 100644 index 0000000..29b3dc5 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Helper/Download/DownloadAudioClip.cs @@ -0,0 +1,54 @@ +#if FANTASY_UNITY +using System; +using Fantasy.Async; +using UnityEngine; +using UnityEngine.Networking; + +namespace Fantasy.Unity.Download +{ + public sealed class DownloadAudioClip : AUnityDownload + { + public DownloadAudioClip(Scene scene, Download download) : base(scene, download) + { + } + + public FTask StartDownload(string url, AudioType audioType, bool monitor, FCancellationToken cancellationToken = null) + { + var task = FTask.Create(false); + var unityWebRequestAsyncOperation = Start(UnityWebRequestMultimedia.GetAudioClip(Uri.EscapeUriString(url), audioType), monitor); + + if (cancellationToken != null) + { + cancellationToken.Add(() => + { + Dispose(); + task.SetResult(null); + }); + } + + unityWebRequestAsyncOperation.completed += operation => + { + try + { + if (UnityWebRequest.result == UnityWebRequest.Result.Success) + { + var audioClip = DownloadHandlerAudioClip.GetContent(UnityWebRequest); + task.SetResult(audioClip); + } + else + { + Log.Error(UnityWebRequest.error); + task.SetResult(null); + } + } + finally + { + Dispose(); + } + }; + + return task; + } + } +} +#endif diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Helper/Download/DownloadAudioClip.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Helper/Download/DownloadAudioClip.cs.meta new file mode 100644 index 0000000..6440f22 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Helper/Download/DownloadAudioClip.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 66d3739ec33845148534e6ecaf134b73 +timeCreated: 1726023476 \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Helper/Download/DownloadByte.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Helper/Download/DownloadByte.cs new file mode 100644 index 0000000..6c934d9 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Helper/Download/DownloadByte.cs @@ -0,0 +1,52 @@ +#if FANTASY_UNITY +using Fantasy.Async; +using UnityEngine.Networking; + +namespace Fantasy.Unity.Download +{ + public sealed class DownloadByte : AUnityDownload + { + public DownloadByte(Scene scene, Download download) : base(scene, download) + { + } + + public FTask StartDownload(string url, bool monitor, FCancellationToken cancellationToken = null) + { + var task = FTask.Create(false); + var unityWebRequestAsyncOperation = Start(UnityWebRequest.Get(url), monitor); + + if (cancellationToken != null) + { + cancellationToken.Add(() => + { + Dispose(); + task.SetResult(null); + }); + } + + unityWebRequestAsyncOperation.completed += operation => + { + try + { + if (UnityWebRequest.result == UnityWebRequest.Result.Success) + { + var bytes = UnityWebRequest.downloadHandler.data; + task.SetResult(bytes); + } + else + { + Log.Error(UnityWebRequest.error); + task.SetResult(null); + } + } + finally + { + Dispose(); + } + }; + + return task; + } + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Helper/Download/DownloadByte.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Helper/Download/DownloadByte.cs.meta new file mode 100644 index 0000000..0aa0487 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Helper/Download/DownloadByte.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: ae87f3ea9f4e4c9ebabedf45b0bb83b1 +timeCreated: 1726023481 \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Helper/Download/DownloadSprite.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Helper/Download/DownloadSprite.cs new file mode 100644 index 0000000..802a967 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Helper/Download/DownloadSprite.cs @@ -0,0 +1,55 @@ +#if FANTASY_UNITY +using System; +using Fantasy.Async; +using UnityEngine; +using UnityEngine.Networking; + +namespace Fantasy.Unity.Download +{ + public sealed class DownloadSprite : AUnityDownload + { + public DownloadSprite(Scene scene, Download download) : base(scene, download) + { + } + + public FTask StartDownload(string url, bool monitor, FCancellationToken cancellationToken = null) + { + var task = FTask.Create(false); + var unityWebRequestAsyncOperation = Start(UnityWebRequestTexture.GetTexture(Uri.EscapeUriString(url)), monitor); + + if (cancellationToken != null) + { + cancellationToken.Add(() => + { + Dispose(); + task.SetResult(null); + }); + } + + unityWebRequestAsyncOperation.completed += operation => + { + try + { + if (UnityWebRequest.result == UnityWebRequest.Result.Success) + { + var texture = DownloadHandlerTexture.GetContent(UnityWebRequest); + var sprite = Sprite.Create(texture, new Rect(0, 0, texture.width, texture.height), Vector2.one * 5, 1f); + task.SetResult(sprite); + } + else + { + Log.Error(UnityWebRequest.error); + task.SetResult(null); + } + } + finally + { + Dispose(); + } + }; + + return task; + } + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Helper/Download/DownloadSprite.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Helper/Download/DownloadSprite.cs.meta new file mode 100644 index 0000000..354e3e3 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Helper/Download/DownloadSprite.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 0c2a0f442e974169b7d8b7a5878fe0e6 +timeCreated: 1726023487 \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Helper/Download/DownloadText.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Helper/Download/DownloadText.cs new file mode 100644 index 0000000..50d8329 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Helper/Download/DownloadText.cs @@ -0,0 +1,52 @@ +#if FANTASY_UNITY +using Fantasy.Async; +using UnityEngine.Networking; + +namespace Fantasy.Unity.Download +{ + public sealed class DownloadText : AUnityDownload + { + public DownloadText(Scene scene, Download download) : base(scene, download) + { + } + + public FTask StartDownload(string url, bool monitor, FCancellationToken cancellationToken = null) + { + var task = FTask.Create(false); + var unityWebRequestAsyncOperation = Start(UnityWebRequest.Get(url), monitor); + + if (cancellationToken != null) + { + cancellationToken.Add(() => + { + Dispose(); + task.SetResult(null); + }); + } + + unityWebRequestAsyncOperation.completed += operation => + { + try + { + if (UnityWebRequest.result == UnityWebRequest.Result.Success) + { + var text = UnityWebRequest.downloadHandler.text; + task.SetResult(text); + } + else + { + Log.Error(UnityWebRequest.error); + task.SetResult(null); + } + } + finally + { + Dispose(); + } + }; + + return task; + } + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Helper/Download/DownloadText.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Helper/Download/DownloadText.cs.meta new file mode 100644 index 0000000..35892a9 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Helper/Download/DownloadText.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 4284aafa8572453cb75920d2d58e9c50 +timeCreated: 1726023491 \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Helper/Download/DownloadTexture.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Helper/Download/DownloadTexture.cs new file mode 100644 index 0000000..f66533d --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Helper/Download/DownloadTexture.cs @@ -0,0 +1,54 @@ +#if FANTASY_UNITY +using System; +using Fantasy.Async; +using UnityEngine; +using UnityEngine.Networking; + +namespace Fantasy.Unity.Download +{ + public sealed class DownloadTexture : AUnityDownload + { + public DownloadTexture(Scene scene, Download download) : base(scene, download) + { + } + + public FTask StartDownload(string url, bool monitor, FCancellationToken cancellationToken = null) + { + var task = FTask.Create(false); + var unityWebRequestAsyncOperation = Start(UnityWebRequestTexture.GetTexture(Uri.EscapeUriString(url)), monitor); + + if (cancellationToken != null) + { + cancellationToken.Add(() => + { + Dispose(); + task.SetResult(null); + }); + } + + unityWebRequestAsyncOperation.completed += operation => + { + try + { + if (UnityWebRequest.result == UnityWebRequest.Result.Success) + { + var texture = DownloadHandlerTexture.GetContent(UnityWebRequest); + task.SetResult(texture); + } + else + { + Log.Error(UnityWebRequest.error); + task.SetResult(null); + } + } + finally + { + Dispose(); + } + }; + + return task; + } + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Helper/Download/DownloadTexture.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Helper/Download/DownloadTexture.cs.meta new file mode 100644 index 0000000..7b48ea6 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Helper/Download/DownloadTexture.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 5eaa6023378844ebb51e4b80425d8a4e +timeCreated: 1726023496 \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Helper/EncryptHelper.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Helper/EncryptHelper.cs new file mode 100644 index 0000000..be950bc --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Helper/EncryptHelper.cs @@ -0,0 +1,63 @@ +using System.IO; +using System.Security.Cryptography; +using System.Text; + +namespace Fantasy.Helper +{ + /// + /// 提供计算 MD5 散列值的辅助方法。 + /// + public static partial class EncryptHelper + { + private static readonly SHA256 Sha256Hash = SHA256.Create(); + + /// + /// 计算指定字节数组的Sha256。 + /// + /// + /// + public static byte[] ComputeSha256Hash(byte[] bytes) + { +#if FANTASY_UNITY + using var sha256Hash = SHA256.Create(); + return sha256Hash.ComputeHash(bytes); +#else + return SHA256.HashData(bytes); +#endif + } + + /// + /// 计算指定文件的 MD5 散列值。 + /// + /// 要计算散列值的文件路径。 + /// 表示文件的 MD5 散列值的字符串。 + public static string FileMD5(string filePath) + { + using var file = new FileStream(filePath, FileMode.Open); + return FileMD5(file); + } + + /// + /// 计算给定文件流的 MD5 散列值。 + /// + /// 要计算散列值的文件流。 + /// 表示文件流的 MD5 散列值的字符串。 + public static string FileMD5(FileStream fileStream) + { + var md5 = MD5.Create(); + return md5.ComputeHash(fileStream).ToHex("x2"); + } + + /// + /// 计算给定字节数组的 MD5 散列值。 + /// + /// 要计算散列值的字节数组。 + /// 表示字节数组的 MD5 散列值的字符串。 + public static string BytesMD5(byte[] bytes) + { + var md5 = MD5.Create(); + bytes = md5.ComputeHash(bytes); + return bytes.ToHex("x2"); + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Helper/FileHelper.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Helper/FileHelper.cs new file mode 100644 index 0000000..058db82 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Helper/FileHelper.cs @@ -0,0 +1,175 @@ +using System.Collections.Generic; +using System.IO; +using System.Text; +using System.Threading.Tasks; + +namespace Fantasy.Helper +{ + /// + /// 文件操作助手类,提供了各种文件操作方法。 + /// + public static partial class FileHelper + { + /// + /// 获取相对路径的完整路径。 + /// + /// 相对路径。 + /// 完整路径。 + public static string GetFullPath(string relativePath) + { + return Path.GetFullPath(Path.Combine(Directory.GetCurrentDirectory(), relativePath)); + } + + /// + /// 获取相对路径的的文本信息。 + /// + /// + /// + public static async Task GetTextByRelativePath(string relativePath) + { + var fullPath = GetFullPath(relativePath); + return await File.ReadAllTextAsync(fullPath, Encoding.UTF8); + } + + /// + /// 获取绝对路径的的文本信息。 + /// + /// + /// + public static async Task GetText(string fullPath) + { + return await File.ReadAllTextAsync(fullPath, Encoding.UTF8); + } + + /// + /// 根据文件夹路径创建文件夹,如果文件夹不存在会自动创建文件夹。 + /// + /// + public static void CreateDirectory(string directoryPath) + { + if (directoryPath.LastIndexOf('/') != directoryPath.Length - 1) + { + directoryPath += "/"; + } + + var directoriesByFilePath = GetDirectoriesByFilePath(directoryPath); + + foreach (var dir in directoriesByFilePath) + { + if (Directory.Exists(dir)) + { + continue; + } + + Directory.CreateDirectory(dir); + } + } + + /// + /// 将文件复制到目标路径,如果目标目录不存在会自动创建目录。 + /// + /// 源文件路径。 + /// 目标文件路径。 + /// 是否覆盖已存在的目标文件。 + public static void Copy(string sourceFile, string destinationFile, bool overwrite) + { + CreateDirectory(destinationFile); + File.Copy(sourceFile, destinationFile, overwrite); + } + + /// + /// 获取文件路径内的所有文件夹路径。 + /// + /// 文件路径。 + /// 文件夹路径列表。 + public static IEnumerable GetDirectoriesByFilePath(string filePath) + { + var dir = ""; + var fileDirectories = filePath.Split('/'); + + for (var i = 0; i < fileDirectories.Length - 1; i++) + { + dir = $"{dir}{fileDirectories[i]}/"; + yield return dir; + } + + if (fileDirectories.Length == 1) + { + yield return filePath; + } + } + + /// + /// 将文件夹内的所有内容复制到目标位置。 + /// + /// 源文件夹路径。 + /// 目标文件夹路径。 + /// 是否覆盖已存在的文件。 + public static void CopyDirectory(string sourceDirectory, string destinationDirectory, bool overwrite) + { + // 创建目标文件夹 + + if (!Directory.Exists(destinationDirectory)) + { + Directory.CreateDirectory(destinationDirectory); + } + + // 获取当前文件夹中的所有文件 + + var files = Directory.GetFiles(sourceDirectory); + + // 拷贝文件到目标文件夹 + + foreach (var file in files) + { + var fileName = Path.GetFileName(file); + var destinationPath = Path.Combine(destinationDirectory, fileName); + File.Copy(file, destinationPath, overwrite); + } + + // 获取源文件夹中的所有子文件夹 + + var directories = Directory.GetDirectories(sourceDirectory); + + // 递归方式拷贝文件夹 + + foreach (var directory in directories) + { + var directoryName = Path.GetFileName(directory); + var destinationPath = Path.Combine(destinationDirectory, directoryName); + CopyDirectory(directory, destinationPath, overwrite); + } + } + + /// + /// 获取目录下的所有文件 + /// + /// 文件夹路径。 + /// 需要查找的文件通配符 + /// 查找的类型 + /// + public static string[] GetDirectoryFile(string folderPath, string searchPattern, SearchOption searchOption) + { + return Directory.GetFiles(folderPath, searchPattern, searchOption); + } + + /// + /// 清空文件夹内的所有文件。 + /// + /// 文件夹路径。 + public static void ClearDirectoryFile(string folderPath) + { + if (!Directory.Exists(folderPath)) + { + return; + } + + var files = Directory.GetFiles(folderPath); + + foreach (var file in files) + { + File.Delete(file); + } + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Helper/HashCodeHelper.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Helper/HashCodeHelper.cs new file mode 100644 index 0000000..42be4e4 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Helper/HashCodeHelper.cs @@ -0,0 +1,129 @@ +using System.Security.Cryptography; +using System.Text; +// ReSharper disable InconsistentNaming + +namespace Fantasy.Helper +{ + /// + /// HashCode算法帮助类 + /// + public static partial class HashCodeHelper + { + private static readonly SHA256 Sha256Hash = SHA256.Create(); + + /// + /// 使用bkdr算法生成一个long的值 + /// + /// + /// + public static unsafe long GetBKDRHashCode(string str) + { + ulong hash = 0; + // 如果要修改这个种子、建议选择一个质数来做种子 + const uint seed = 13131; // 31 131 1313 13131 131313 etc.. + fixed (char* p = str) + { + for (var i = 0; i < str.Length; i++) + { + var c = p[i]; + var high = (byte)(c >> 8); + var low = (byte)(c & byte.MaxValue); + hash = hash * seed + high; + hash = hash * seed + low; + } + } + return (long)hash; + } + + /// + /// 使用MurmurHash3算法生成一个uint的值 + /// + /// + /// + public static unsafe uint MurmurHash3(string str) + { + const uint seed = 0xc58f1a7b; + uint hash = seed; + uint c1 = 0xcc9e2d51; + uint c2 = 0x1b873593; + + fixed (char* p = str) + { + var current = p; + + for (var i = 0; i < str.Length; i++) + { + var k1 = (uint)(*current); + k1 *= c1; + k1 = (k1 << 15) | (k1 >> (32 - 15)); + k1 *= c2; + + hash ^= k1; + hash = (hash << 13) | (hash >> (32 - 13)); + hash = hash * 5 + 0xe6546b64; + + current++; + } + } + + hash ^= (uint)str.Length; + hash ^= hash >> 16; + hash *= 0x85ebca6b; + hash ^= hash >> 13; + hash *= 0xc2b2ae35; + hash ^= hash >> 16; + return hash; + } + + /// + /// 使用MurmurHash3算法生成一个long的值 + /// + /// + /// + public static unsafe long ComputeHash64(string str) + { + const ulong seed = 0xc58f1a7bc58f1a7bUL; // 64-bit seed + var hash = seed; + var c1 = 0x87c37b91114253d5UL; + var c2 = 0x4cf5ad432745937fUL; + + fixed (char* p = str) + { + var current = p; + + for (var i = 0; i < str.Length; i++) + { + var k1 = (ulong)(*current); + k1 *= c1; + k1 = (k1 << 31) | (k1 >> (64 - 31)); + k1 *= c2; + + hash ^= k1; + hash = (hash << 27) | (hash >> (64 - 27)); + hash = hash * 5 + 0x52dce729; + + current++; + } + } + + hash ^= (ulong)str.Length; + hash ^= hash >> 33; + hash *= 0xff51afd7ed558ccdUL; + hash ^= hash >> 33; + hash *= 0xc4ceb9fe1a85ec53UL; + hash ^= hash >> 33; + return (long)hash; + } + + /// + /// 根据字符串计算一个Hash值 + /// + /// + /// + public static int ComputeSha256HashAsInt(string rawData) + { + var bytes = Sha256Hash.ComputeHash(Encoding.UTF8.GetBytes(rawData)); + return (bytes[0] << 24) | (bytes[1] << 16) | (bytes[2] << 8) | bytes[3]; + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Helper/HttpClient/HttpClientHelper.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Helper/HttpClient/HttpClientHelper.cs new file mode 100644 index 0000000..3954a8c --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Helper/HttpClient/HttpClientHelper.cs @@ -0,0 +1,144 @@ +#if !FANTASY_WEBGL +using System; +using System.Net; +using System.Net.Http; +using System.Net.Http.Headers; +using System.Text; +using Fantasy.Async; +using Fantasy.Helper; +using Fantasy.Pool; +#pragma warning disable CS8603 // Possible null reference return. + +namespace Fantasy.Http +{ + /// + /// HTTP帮助类 + /// + public static partial class HttpClientHelper + { + private static readonly HttpClient Client = new HttpClient(new HttpClientHandler + { + ServerCertificateCustomValidationCallback = (sender, cert, chain, sslPolicyErrors) => true + }); + + /// + /// 用Post方式请求string数据 + /// + /// + /// + /// + /// + public static async FTask CallNotDeserializeByPost(string url, HttpContent content) + { + var response = await Client.PostAsync(url, content); + + if (response.StatusCode != HttpStatusCode.OK) + { + throw new Exception($"Unable to connect to server url {(object)url} HttpStatusCode:{(object)response.StatusCode}"); + } + + return await response.Content.ReadAsStringAsync(); + } + + /// + /// 用Get方式请求string数据 + /// + /// + /// + /// + public static async FTask CallNotDeserializeByGet(string url) + { + var response = await Client.GetAsync(url); + + if (response.StatusCode != HttpStatusCode.OK) + { + throw new Exception($"Unable to connect to server url {(object)url} HttpStatusCode:{(object)response.StatusCode}"); + } + + return await response.Content.ReadAsStringAsync(); + } + + /// + /// 用Post方式请求JSON数据,并自动把JSON转换为对象。 + /// + /// + /// + /// + /// + public static async FTask CallByPost(string url, HttpContent content) + { + return await Deserialize(url, await Client.PostAsync(url, content)); + } + + /// + /// 用Post方式请求JSON数据,并自动把JSON转换为对象。 + /// + /// + /// + /// + /// + public static async FTask CallByPost(string url, HttpMethod method) + { + return await Deserialize(url, await Client.SendAsync(new HttpRequestMessage(method, url))); + } + + /// + /// 用Get方式请求JSON数据,并自动把JSON转换为对象。 + /// + /// + /// + /// + public static async FTask CallByGet(string url) + { + return await Deserialize(url, await Client.GetAsync(url)); + } + + /// + /// 用Post方式请求JSON数据,并自动把JSON转换为对象。 + /// + /// + /// + /// + /// + /// + /// + /// + /// + public static async FTask Call(string url, int id, AuthenticationHeaderValue authentication, string method, params object[] @params) where TRequest : class, IJsonRpcRequest, new() + { + var request = Pool.Rent(); + using var httpClientPool = HttpClientPool.Create(); + var client = httpClientPool.Client; + client.DefaultRequestHeaders.Authorization = authentication; + + try + { + request.Init(method, id, @params); + var content = new StringContent(request.ToJson(), Encoding.UTF8, "application/json"); + var response = await Deserialize(url, await client.PostAsync(url, content)); + return response; + } + catch (Exception e) + { + Log.Error(e); + } + finally + { + Pool.Return(request); + } + + return default; + } + + private static async FTask Deserialize(string url, HttpResponseMessage response) + { + if (response.StatusCode != HttpStatusCode.OK) + { + throw new Exception($"Unable to connect to server url {(object)url} HttpStatusCode:{(object)response.StatusCode}"); + } + + return (await response.Content.ReadAsStringAsync()).Deserialize(); + } + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Helper/HttpClient/HttpClientHelper.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Helper/HttpClient/HttpClientHelper.cs.meta new file mode 100644 index 0000000..70e3bd5 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Helper/HttpClient/HttpClientHelper.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: f8005f3a1a1945a2929442f82832e765 +timeCreated: 1726023741 \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Helper/HttpClient/HttpClientPool.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Helper/HttpClient/HttpClientPool.cs new file mode 100644 index 0000000..de421ff --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Helper/HttpClient/HttpClientPool.cs @@ -0,0 +1,44 @@ +#if !FANTASY_WEBGL +using System; +using System.Collections.Generic; +using System.Net.Http; +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. + +namespace Fantasy.Http +{ + internal class HttpClientPool : IDisposable + { + private bool IsDispose { get; set; } + public HttpClient Client { get; private set; } + private static readonly Queue Pools = new Queue(); + private static readonly HttpClientHandler ClientHandler = new HttpClientHandler + { + ServerCertificateCustomValidationCallback = (sender, cert, chain, sslPolicyErrors) => true + }; + + public static HttpClientPool Create() + { + if (Pools.TryDequeue(out var httpClientPool)) + { + httpClientPool.IsDispose = false; + return httpClientPool; + } + + httpClientPool = new HttpClientPool(); + httpClientPool.Client = new HttpClient(ClientHandler); + return httpClientPool; + } + + public void Dispose() + { + if (IsDispose) + { + return; + } + + IsDispose = true; + Pools.Enqueue(this); + } + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Helper/HttpClient/HttpClientPool.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Helper/HttpClient/HttpClientPool.cs.meta new file mode 100644 index 0000000..a1ac3bf --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Helper/HttpClient/HttpClientPool.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: a78c441357d244d5ba490a13c89e1c50 +timeCreated: 1726023895 \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Helper/HttpClient/IJsonRpcRequest.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Helper/HttpClient/IJsonRpcRequest.cs new file mode 100644 index 0000000..ae756c5 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Helper/HttpClient/IJsonRpcRequest.cs @@ -0,0 +1,20 @@ +using Fantasy.Pool; + +#if !FANTASY_WEBGL +namespace Fantasy.Http +{ + /// + /// 一个JsonRPC的接口 + /// + public interface IJsonRpcRequest : IPool + { + /// + /// 用于初始化这个Json对象 + /// + /// + /// + /// + void Init(string method, int id, params object[] @params); + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Helper/HttpClient/IJsonRpcRequest.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Helper/HttpClient/IJsonRpcRequest.cs.meta new file mode 100644 index 0000000..9e01783 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Helper/HttpClient/IJsonRpcRequest.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 72a03580c619417b9f8f92d99938e371 +timeCreated: 1726023900 \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Helper/JsonHelper.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Helper/JsonHelper.cs new file mode 100644 index 0000000..2b10fab --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Helper/JsonHelper.cs @@ -0,0 +1,57 @@ +using System; +using Newtonsoft.Json; +#pragma warning disable CS8603 + +namespace Fantasy.Helper +{ + /// + /// 提供操作 JSON 数据的辅助方法。 + /// + public static partial class JsonHelper + { + /// + /// 将对象序列化为 JSON 字符串。 + /// + /// 要序列化的对象类型。 + /// 要序列化的对象。 + /// 表示序列化对象的 JSON 字符串。 + public static string ToJson(this T t) + { + return JsonConvert.SerializeObject(t); + } + + /// + /// 反序列化 JSON 字符串为指定类型的对象。 + /// + /// 要反序列化的 JSON 字符串。 + /// 目标对象的类型。 + /// 是否使用反射进行反序列化(默认为 true)。 + /// 反序列化后的对象。 + public static object Deserialize(this string json, Type type, bool reflection = true) + { + return JsonConvert.DeserializeObject(json, type); + } + + /// + /// 反序列化 JSON 字符串为指定类型的对象。 + /// + /// 目标对象的类型。 + /// 要反序列化的 JSON 字符串。 + /// 反序列化后的对象。 + public static T Deserialize(this string json) + { + return JsonConvert.DeserializeObject(json); + } + + /// + /// 克隆对象,通过将对象序列化为 JSON,然后再进行反序列化。 + /// + /// 要克隆的对象类型。 + /// 要克隆的对象。 + /// 克隆后的对象。 + public static T Clone(T t) + { + return t.ToJson().Deserialize(); + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Helper/NetworkHelper.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Helper/NetworkHelper.cs new file mode 100644 index 0000000..6a35a61 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Helper/NetworkHelper.cs @@ -0,0 +1,443 @@ +#if !FANTASY_WEBGL +using System; +using System.Collections.Generic; +using System.Net; +using System.Net.NetworkInformation; +using System.Net.Sockets; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +#pragma warning disable CS8603 // Possible null reference return. + +// ReSharper disable InconsistentNaming + +namespace Fantasy.Helper +{ + /// + /// 提供网络操作相关的帮助方法。 + /// + public static partial class NetworkHelper + { + /// + /// 根据字符串获取一个IPEndPoint + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static IPEndPoint GetIPEndPoint(string address) + { + try + { + var addressSplit = address.Split(':'); + if (addressSplit.Length != 2) + { + throw new FormatException("Invalid format"); + } + + var ipString = addressSplit[0]; + var portString = addressSplit[1]; + + if (!IPAddress.TryParse(ipString, out var ipAddress)) + { + throw new FormatException("Invalid IP address"); + } + + if (!int.TryParse(portString, out var port) || port < 0 || port > 65535) + { + throw new FormatException("Invalid port number"); + } + + return new IPEndPoint(ipAddress, port); + } + catch (Exception e) + { + Log.Error($"Error parsing IP and Port:{e.Message}"); + return null; + } + } + + /// + /// 克隆一个IPEndPoint + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static IPEndPoint Clone(this EndPoint endPoint) + { + var ip = (IPEndPoint)endPoint; + return new IPEndPoint(ip.Address, ip.Port); + } + + /// + /// 比较两个IPEndPoint是否相等 + /// + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool IPEndPointEquals(this EndPoint endPoint, IPEndPoint ipEndPoint) + { + var ip = (IPEndPoint)endPoint; + return ip.Address.Equals(ipEndPoint.Address) && ip.Port == ipEndPoint.Port; + } + + /// + /// 比较两个IPEndPoint是否相等 + /// + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool IPEndPointEquals(this IPEndPoint endPoint, IPEndPoint ipEndPoint) + { + return endPoint.Address.Equals(ipEndPoint.Address) && endPoint.Port == ipEndPoint.Port; + } + +#if !FANTASY_WEBGL + /// + /// 将SocketAddress写入到Byte[]中 + /// + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe void SocketAddressToByte(this SocketAddress socketAddress, byte[] buffer, int offset) + { + if (socketAddress == null) + { + throw new ArgumentNullException(nameof(socketAddress), "The SocketAddress cannot be null."); + } + + if (buffer == null) + { + throw new ArgumentNullException(nameof(buffer), "The buffer cannot be null."); + } + + if (buffer.Length < socketAddress.Size + offset + 8) + { + throw new ArgumentException("The buffer length is insufficient. It must be at least the size of the SocketAddress plus 8 bytes.", nameof(buffer)); + } + + fixed (byte* pBuffer = buffer) + { + var pOffsetBuffer = pBuffer + offset; + var addressFamilyValue = (int)socketAddress.Family; + var socketAddressSizeValue = socketAddress.Size; + Buffer.MemoryCopy(&addressFamilyValue, pOffsetBuffer, buffer.Length - offset, sizeof(int)); + Buffer.MemoryCopy(&socketAddressSizeValue, pOffsetBuffer + 4, buffer.Length - offset -4, sizeof(int)); + for (var i = 0; i < socketAddress.Size - 2; i++) + { + pOffsetBuffer[8 + i] = socketAddress[i + 2]; + } + } + } + + /// + /// 将byre[]转换为SocketAddress + /// + /// + /// + /// + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe int ByteToSocketAddress(byte[] buffer, int offset, out SocketAddress socketAddress) + { + if (buffer == null) + { + throw new ArgumentNullException(nameof(buffer), "The buffer cannot be null."); + } + + if (buffer.Length < 8) + { + throw new ArgumentException("Buffer length is insufficient. It must be at least 8 bytes.", nameof(buffer)); + } + + try + { + fixed (byte* pBuffer = buffer) + { + var pOffsetBuffer = pBuffer + offset; + var addressFamily = (AddressFamily)Marshal.ReadInt32((IntPtr)pOffsetBuffer); + var socketAddressSize = Marshal.ReadInt32((IntPtr)(pOffsetBuffer + 4)); + + if (buffer.Length < offset + 8 + socketAddressSize) + { + throw new ArgumentException("Buffer length is insufficient for the given SocketAddress size.", nameof(buffer)); + } + + socketAddress = new SocketAddress(addressFamily, socketAddressSize); + + for (var i = 0; i < socketAddressSize - 2; i++) + { + socketAddress[i + 2] = *(pOffsetBuffer + 8 + i); + } + + return 8 + offset + socketAddressSize; + } + } + catch (ArgumentNullException ex) + { + throw new InvalidOperationException("An argument provided to the method is null.", ex); + } + catch (ArgumentException ex) + { + throw new InvalidOperationException("An argument provided to the method is invalid.", ex); + } + catch (Exception ex) + { + throw new InvalidOperationException("An unexpected error occurred while processing the buffer.", ex); + } + } + + /// + /// 将ReadOnlyMemory转换为SocketAddress + /// + /// + /// + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe int ByteToSocketAddress(ReadOnlyMemory buffer, int offset, out SocketAddress socketAddress) + { + if (buffer.Length < 8) + { + throw new ArgumentException("Buffer length is insufficient. It must be at least 8 bytes.", nameof(buffer)); + } + + try + { + fixed (byte* pBuffer = buffer.Span) + { + var pOffsetBuffer = pBuffer + offset; + var addressFamily = (AddressFamily)Marshal.ReadInt32((IntPtr)pOffsetBuffer); + var socketAddressSize = Marshal.ReadInt32((IntPtr)(pOffsetBuffer + 4)); + + if (buffer.Length < offset + 8 + socketAddressSize) + { + throw new ArgumentException("Buffer length is insufficient for the given SocketAddress size.", nameof(buffer)); + } + + socketAddress = new SocketAddress(addressFamily, socketAddressSize); + + for (var i = 0; i < socketAddressSize - 2; i++) + { + socketAddress[i + 2] = *(pOffsetBuffer + 8 + i); + } + + return 8 + offset + socketAddressSize; + } + } + catch (ArgumentNullException ex) + { + throw new InvalidOperationException("An argument provided to the method is null.", ex); + } + catch (ArgumentException ex) + { + throw new InvalidOperationException("An argument provided to the method is invalid.", ex); + } + catch (Exception ex) + { + throw new InvalidOperationException("An unexpected error occurred while processing the buffer.", ex); + } + } + + /// + /// 根据SocketAddress获得IPEndPoint + /// + /// + /// + /// + public static unsafe IPEndPoint GetIPEndPoint(this SocketAddress socketAddress) + { + switch (socketAddress.Family) + { + case AddressFamily.InterNetwork: + { + var ipBytes = new byte[4]; + for (var i = 0; i < 4; i++) + { + ipBytes[i] = socketAddress[4 + i]; + } + var port = (socketAddress[2] << 8) + socketAddress[3]; + var ip = new IPAddress(ipBytes); + return new IPEndPoint(ip, port); + } + case AddressFamily.InterNetworkV6: + { + var ipBytes = new byte[16]; + Span socketAddressSpan = stackalloc byte[28]; + + for (var i = 0; i < 28; i++) + { + socketAddressSpan[i] = socketAddress[i]; + } + + fixed (byte* pSocketAddress = socketAddressSpan) + { + for (var i = 0; i < 16; i++) + { + ipBytes[i] = *(pSocketAddress + 8 + i); + } + + var port = (*(pSocketAddress + 2) << 8) + *(pSocketAddress + 3); + var scopeId = Marshal.ReadInt64((IntPtr)(pSocketAddress + 24)); + var ip = new IPAddress(ipBytes, scopeId); + return new IPEndPoint(ip, port); + } + } + default: + { + throw new NotSupportedException("Address family not supported."); + } + } + } +#endif + /// + /// 获取本机所有网络适配器的IP地址。 + /// + /// IP地址数组。 + public static string[] GetAddressIPs() + { + var list = new List(); + foreach (var networkInterface in NetworkInterface.GetAllNetworkInterfaces()) + { + // 仅考虑以太网类型的网络适配器 + if (networkInterface.NetworkInterfaceType != NetworkInterfaceType.Ethernet) + { + continue; + } + + foreach (var add in networkInterface.GetIPProperties().UnicastAddresses) + { + list.Add(add.Address.ToString()); + } + } + + return list.ToArray(); + } + + /// + /// 将主机名和端口号转换为 实例。 + /// + /// 主机名。 + /// 端口号。 + /// 实例。 + public static IPEndPoint ToIPEndPoint(string host, int port) + { + return new IPEndPoint(IPAddress.Parse(host), port); + } + + /// + /// 将地址字符串转换为 实例。 + /// + /// 地址字符串,格式为 "主机名:端口号"。 + /// 实例。 + public static IPEndPoint ToIPEndPoint(string address) + { + var index = address.LastIndexOf(':'); + var host = address.Substring(0, index); + var p = address.Substring(index + 1); + var port = int.Parse(p); + return ToIPEndPoint(host, port); + } + + /// + /// 将 实例转换为字符串表示形式。 + /// + /// 实例。 + /// 表示 的字符串。 + public static string IPEndPointToStr(this IPEndPoint self) + { + return $"{self.Address}:{self.Port}"; + } + + /// + /// 针对 Windows 平台设置UDP连接重置选项。 + /// + /// 要设置选项的 实例。 + public static void SetSioUdpConnReset(this Socket socket) + { + if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + return; + } + + /* + 目前这个问题只有Windows下才会出现。 + 服务器端在发送数据时捕获到了一个异常, + 这个异常导致原因应该是远程客户端的UDP监听已停止导致数据发送出错。 + 按理说UDP是无连接的,报这个异常是不合理的 + 这个异常让整UDP的服务监听也停止了。 + 这样就因为一个客户端的数据发送无法到达而导致了服务挂了,所有客户端都无法与服务器通信了 + 想详细了解看下https://blog.csdn.net/sunzhen6251/article/details/124168805*/ + const uint IOC_IN = 0x80000000; + const uint IOC_VENDOR = 0x18000000; + const int SIO_UDP_CONNRESET = unchecked((int) (IOC_IN | IOC_VENDOR | 12)); + + socket.IOControl(SIO_UDP_CONNRESET, new[] {Convert.ToByte(false)}, null); + } + + /// + /// 将 Socket 缓冲区大小设置为操作系统限制。 + /// + /// 要设置缓冲区大小的 Socket。 + public static void SetSocketBufferToOsLimit(this Socket socket) + { + socket.SetReceiveBufferToOSLimit(); + socket.SetSendBufferToOSLimit(); + } + + /// + /// 将 Socket 接收缓冲区大小设置为操作系统限制。 + /// 尝试增加接收缓冲区大小的次数 = 默认 + 最大增加 100 MB。 + /// + /// 要设置接收缓冲区大小的 Socket。 + /// 每次增加的步长大小。 + /// 尝试增加缓冲区大小的次数。 + public static void SetReceiveBufferToOSLimit(this Socket socket, int stepSize = 1024, int attempts = 100_000) + { + // setting a too large size throws a socket exception. + // so let's keep increasing until we encounter it. + for (int i = 0; i < attempts; ++i) + { + // increase in 1 KB steps + try + { + socket.ReceiveBufferSize += stepSize; + } + catch (SocketException) + { + break; + } + } + } + + /// + /// 将 Socket 发送缓冲区大小设置为操作系统限制。 + /// 尝试增加发送缓冲区大小的次数 = 默认 + 最大增加 100 MB。 + /// + /// 要设置发送缓冲区大小的 Socket。 + /// 每次增加的步长大小。 + /// 尝试增加缓冲区大小的次数。 + public static void SetSendBufferToOSLimit(this Socket socket, int stepSize = 1024, int attempts = 100_000) + { + // setting a too large size throws a socket exception. + // so let's keep increasing until we encounter it. + for (var i = 0; i < attempts; ++i) + { + // increase in 1 KB steps + try + { + socket.SendBufferSize += stepSize; + } + catch (SocketException) + { + break; + } + } + } + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Helper/RandomHelper.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Helper/RandomHelper.cs new file mode 100644 index 0000000..a91b360 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Helper/RandomHelper.cs @@ -0,0 +1,293 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Numerics; + +namespace Fantasy.Helper +{ + /// + /// 随机数操作助手类,提供各种随机数生成和操作方法。 + /// + public static partial class RandomHelper + { + private static readonly Random Random = new Random(); + private static readonly byte[] Byte8 = new byte[8]; + private static readonly byte[] Byte2 = new byte[2]; + + /// + /// 生成一个随机的无符号 64 位整数。 + /// + /// 无符号 64 位整数。 + public static ulong RandUInt64() + { + Random.NextBytes(Byte8); + return BitConverter.ToUInt64(Byte8, 0); + } + + /// + /// 生成一个随机的 64 位整数。 + /// + /// 64 位整数。 + public static long RandInt64() + { + Random.NextBytes(Byte8); + return BitConverter.ToInt64(Byte8, 0); + } + + /// + /// 生成一个随机的无符号 32 位整数。 + /// + /// 无符号 32 位整数。 + public static uint RandUInt32() + { + return (uint) Random.Next(); + } + + /// + /// 生成一个随机的无符号 16 位整数。 + /// + /// 无符号 16 位整数。 + public static ushort RandUInt16() + { + Random.NextBytes(Byte2); + return BitConverter.ToUInt16(Byte2, 0); + } + + /// + /// 在指定范围内生成一个随机整数(包含下限,不包含上限)。 + /// + /// 下限。 + /// 上限。 + /// 生成的随机整数。 + public static int RandomNumber(int lower, int upper) + { + return Random.Next(lower, upper); + } + + /// + /// 生成一个随机的布尔值。 + /// + /// 随机的布尔值。 + public static bool RandomBool() + { + return Random.Next(2) == 0; + } + + /// + /// 从数组中随机选择一个元素。 + /// + /// 数组元素的类型。 + /// 要选择的数组。 + /// 随机选择的数组元素。 + public static T RandomArray(this T[] array) + { + return array[RandomNumber(0, array.Count())]; + } + + /// + /// 从列表中随机选择一个元素。 + /// + /// 列表元素的类型。 + /// 要选择的列表。 + /// 随机选择的列表元素。 + public static T RandomArray(this List array) + { + return array[RandomNumber(0, array.Count())]; + } + + /// + /// 打乱列表中元素的顺序。 + /// + /// 列表元素的类型。 + /// 要打乱顺序的列表。 + public static void BreakRank(List arr) + { + if (arr == null || arr.Count < 2) + { + return; + } + + for (var i = 0; i < arr.Count / 2; i++) + { + var index = Random.Next(0, arr.Count); + (arr[index], arr[arr.Count - index - 1]) = (arr[arr.Count - index - 1], arr[index]); + } + } + + /// + /// 生成一个介于 0 和 1 之间的随机单精度浮点数。 + /// + /// 随机单精度浮点数。 + public static float RandFloat01() + { + var value = Random.NextDouble(); + return (float) value; + } + + private static int Rand(int n) + { + var rd = new Random(); + // 注意,返回值是左闭右开,所以maxValue要加1 + return rd.Next(1, n + 1); + } + + /// + /// 根据权重随机选择一个索引。 + /// + /// 权重数组,每个元素表示相应索引的权重。 + /// 随机选择的索引值。 + public static int RandomByWeight(int[] weights) + { + var sum = weights.Sum(); + var numberRand = Rand(sum); + var sumTemp = 0; + for (var i = 0; i < weights.Length; i++) + { + sumTemp += weights[i]; + if (numberRand <= sumTemp) + { + return i; + } + } + + return -1; + } + + /// + /// 根据固定概率随机选择一个索引,即某个数值上限内随机多少次。 + /// + /// 概率数组,每个元素表示相应索引的概率。 + /// 随机选择的索引值。 + public static int RandomByFixedProbability(int[] args) + { + var argCount = args.Length; + var sum = args.Sum(); + var random = Random.NextDouble() * sum; + while (sum > random) + { + sum -= args[argCount - 1]; + argCount--; + } + + return argCount; + } + + /// + /// 返回随机数。 + /// + /// 是否包含负数。 + /// 返回一个随机的单精度浮点数。 + public static float NextFloat(bool containNegative = false) + { + float f; + var buffer = new byte[4]; + if (containNegative) + { + do + { + Random.NextBytes(buffer); + f = BitConverter.ToSingle(buffer, 0); + } while ((f >= float.MinValue && f < float.MaxValue) == false); + + return f; + } + + do + { + Random.NextBytes(buffer); + f = BitConverter.ToSingle(buffer, 0); + } while ((f >= 0 && f < float.MaxValue) == false); + + return f; + } + + /// + /// 返回一个小于所指定最大值的非负随机数。 + /// + /// 要生成的随机数的上限(随机数不能取该上限值)。 maxValue 必须大于或等于零。 + /// 大于等于零且小于 maxValue 的单精度浮点数,即:返回值的范围通常包括零但不包括 maxValue。 不过,如果 maxValue 等于零,则返回 maxValue。 + public static float NextFloat(float maxValue) + { + if (maxValue.Equals(0)) + { + return maxValue; + } + + if (maxValue < 0) + { + throw new ArgumentOutOfRangeException("“maxValue”必须大于 0。", "maxValue"); + } + + float f; + var buffer = new byte[4]; + + do + { + Random.NextBytes(buffer); + f = BitConverter.ToSingle(buffer, 0); + } while ((f >= 0 && f < maxValue) == false); + + return f; + } + + /// + /// 返回一个指定范围内的随机数。 + /// + /// 返回的随机数的下界(随机数可取该下界值)。 + /// 返回的随机数的上界(随机数不能取该上界值)。 maxValue 必须大于或等于 minValue。 + /// 一个大于等于 minValue 且小于 maxValue 的单精度浮点数,即:返回的值范围包括 minValue 但不包括 maxValue。 如果 minValue 等于 maxValue,则返回 minValue。 + public static float NextFloat(float minValue, float maxValue) + { + if (minValue.Equals(maxValue)) + { + return minValue; + } + + if (minValue > maxValue) + { + throw new ArgumentOutOfRangeException("“minValue”不能大于 maxValue。", "minValue"); + } + + float f; + var buffer = new byte[4]; + + do + { + Random.NextBytes(buffer); + f = BitConverter.ToSingle(buffer, 0); + } while ((f >= minValue && f < maxValue) == false); + + return f; + } + + /// + /// 在指定的矩形区域内随机生成一个二维向量位置。 + /// + /// X轴最小值。 + /// X轴最大值。 + /// Y轴最小值。 + /// Y轴最大值。 + /// 随机生成的二维向量位置。 + public static Vector2 NextVector2(float minX, float maxX, float minY, float maxY) + { + return new Vector2(NextFloat(minX, maxX), NextFloat(minY, maxY)); + } + + /// + /// 生成指定长度的随机数字代码。 + /// + /// 数字代码的长度。 + /// 生成的随机数字代码。 + public static string RandomNumberCode(int len = 6) + { + int num = 0; + for (int i = 0; i < len; i++) + { + int number = RandomNumber(0, 10); + num = num * 10 + number; + } + + return num.ToString(); + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Helper/SocketHelper.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Helper/SocketHelper.cs new file mode 100644 index 0000000..15027c5 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Helper/SocketHelper.cs @@ -0,0 +1,74 @@ +#if !FANTASY_WEBGL +using System.Net; +using System.Net.Sockets; +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member +namespace Fantasy.Helper +{ + /// + /// Socket帮助类 + /// + public static partial class SocketHelper + { + // always pass the same IPEndPointNonAlloc instead of allocating a new + // one each time. + // + // use IPEndPointNonAlloc.temp to get the latest SocketAdddress written + // by ReceiveFrom_Internal! + // + // IMPORTANT: .temp will be overwritten in next call! + // hash or manually copy it if you need to store it, e.g. + // when adding a new connection. + public static int ReceiveFrom_NonAlloc( + this Socket socket, + byte[] buffer, + int offset, + int size, + SocketFlags socketFlags, + EndPoint remoteEndPoint) + { + // call ReceiveFrom with IPEndPointNonAlloc. + // need to wrap this in ReceiveFrom_NonAlloc because it's not + // obvious that IPEndPointNonAlloc.Create does NOT create a new + // IPEndPoint. it saves the result in IPEndPointNonAlloc.temp! +#if FANTASY_UNITY + EndPoint casted = remoteEndPoint; + return socket.ReceiveFrom(buffer, offset, size, socketFlags, ref casted); +#else + return socket.ReceiveFrom(buffer, offset, size, socketFlags, ref remoteEndPoint); +#endif + } + + // same as above, different parameters + public static int ReceiveFrom_NonAlloc(this Socket socket, byte[] buffer, ref EndPoint remoteEndPoint) + { +#if UNITY + EndPoint casted = remoteEndPoint; + return socket.ReceiveFrom(buffer, ref casted); +#else + return socket.ReceiveFrom(buffer, ref remoteEndPoint); +#endif + + } + + // SendTo allocates too: + // https://github.com/mono/mono/blob/f74eed4b09790a0929889ad7fc2cf96c9b6e3757/mcs/class/System/System.Net.Sockets/Socket.cs#L2240 + // -> the allocation is in EndPoint.Serialize() + // NOTE: technically this function isn't necessary. + // could just pass IPEndPointNonAlloc. + // still good for strong typing. + //public static int SendTo_NonAlloc( + // this Socket socket, + // byte[] buffer, + // int offset, + // int size, + // SocketFlags socketFlags, + // IPEndPointNonAlloc remoteEndPoint) + //{ + // EndPoint casted = remoteEndPoint; + // return socket.SendTo(buffer, offset, size, socketFlags, casted); + //} + } +} +#endif + + diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Helper/TimeHelper.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Helper/TimeHelper.cs new file mode 100644 index 0000000..fa52e0d --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Helper/TimeHelper.cs @@ -0,0 +1,84 @@ +using System; +#if FANTASY_UNITY +using UnityEngine; +#endif + +namespace Fantasy.Helper +{ + /// + /// 提供与时间相关的帮助方法。 + /// + public static partial class TimeHelper + { + /// + /// 一小时的毫秒值。 + /// + public const long Hour = 3600000; + /// + /// 一分钟的毫秒值。 + /// + public const long Minute = 60000; + /// + /// 一天的毫秒值。 + /// + public const long OneDay = 86400000; + // 1970年1月1日的Ticks + private const long Epoch = 621355968000000000L; + private static readonly DateTime Dt1970 = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); + /// + /// 获取当前时间的毫秒数,从1970年1月1日开始计算。 + /// + public static long Now => (DateTime.UtcNow.Ticks - Epoch) / 10000; +#if FANTASY_UNITY || FANTASY_CONSOLE + /// + /// 与服务器时间的偏差。 + /// + public static long TimeDiff; + /// + /// 获取当前服务器时间的毫秒数,加上与服务器时间的偏差。 + /// + public static long ServerNow => Now + TimeDiff; +#if FANTASY_UNITY + /// + /// 获取当前Unity运行的总时间的毫秒数。 + /// + public static long UnityNow => (long) (Time.time * 1000); +#endif +#endif + /// + /// 根据时间获取时间戳 + /// + public static long Transition(DateTime dateTime) + { + return (dateTime.ToUniversalTime().Ticks - Epoch) / 10000; + } + + /// + /// 根据时间获取 时间戳 + /// + public static long TransitionToSeconds(DateTime dateTime) + { + return (dateTime.ToUniversalTime().Ticks - Epoch) / 10000000; + } + + /// + /// 将毫秒数转换为日期时间。 + /// + /// 要转换的毫秒数。 + /// 转换后的日期时间。 + public static DateTime Transition(this long timeStamp) + { + return new DateTime(Epoch + timeStamp * 10000, DateTimeKind.Utc).ToUniversalTime(); + } + + /// + /// 将毫秒数转换为本地时间的日期时间。 + /// + /// 要转换的毫秒数。 + /// 转换后的本地时间的日期时间。 + public static DateTime TransitionLocal(this long timeStamp) + { + return new DateTime(Epoch + timeStamp * 10000, DateTimeKind.Utc).ToLocalTime(); + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Helper/UnityWebRequest/UnityWebRequestHelper.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Helper/UnityWebRequest/UnityWebRequestHelper.cs new file mode 100644 index 0000000..dbc0334 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Helper/UnityWebRequest/UnityWebRequestHelper.cs @@ -0,0 +1,244 @@ +#if FANTASY_UNITY +using System; +using Fantasy.Async; +using UnityEngine; +using UnityEngine.Networking; + +namespace Fantasy.Unity +{ + /// + /// UnityWebRequest的帮助类 + /// + public static class UnityWebRequestHelper + { + /// + /// 获取一个文本 + /// + /// + /// + /// + public static FTask GetText(string url, FCancellationToken cancellationToken = null) + { + var task = FTask.Create(false); + var unityWebRequest = UnityWebRequest.Get(url); + var unityWebRequestAsyncOperation = unityWebRequest.SendWebRequest(); + + if (cancellationToken != null) + { + cancellationToken.Add(() => + { + unityWebRequest.Abort(); + task.SetResult(null); + }); + } + + unityWebRequestAsyncOperation.completed += operation => + { + if (unityWebRequest.result == UnityWebRequest.Result.Success) + { + var text = unityWebRequest.downloadHandler.text; + task.SetResult(text); + } + else + { + Log.Error(unityWebRequest.error); + task.SetResult(null); + } + }; + + return task; + } + + /// + /// 获取一个Sprite + /// + /// + /// + /// + public static FTask GetSprite(string url, FCancellationToken cancellationToken = null) + { + var task = FTask.Create(false); + var unityWebRequest = UnityWebRequestTexture.GetTexture(Uri.EscapeUriString(url)); + var unityWebRequestAsyncOperation = unityWebRequest.SendWebRequest(); + + if (cancellationToken != null) + { + cancellationToken.Add(() => + { + unityWebRequest.Abort(); + task.SetResult(null); + }); + } + + unityWebRequestAsyncOperation.completed += operation => + { + if (unityWebRequest.result == UnityWebRequest.Result.Success) + { + var texture = DownloadHandlerTexture.GetContent(unityWebRequest); + var sprite = Sprite.Create(texture, new Rect(0, 0, texture.width, texture.height), Vector2.one * 5, 1f); + task.SetResult(sprite); + } + else + { + Log.Error(unityWebRequest.error); + task.SetResult(null); + } + }; + + return task; + } + + /// + /// 获取一个Texture + /// + /// + /// + /// + public static FTask GetTexture(string url, FCancellationToken cancellationToken = null) + { + var task = FTask.Create(false); + var unityWebRequest = UnityWebRequestTexture.GetTexture(Uri.EscapeUriString(url)); + var unityWebRequestAsyncOperation = unityWebRequest.SendWebRequest(); + + if (cancellationToken != null) + { + cancellationToken.Add(() => + { + unityWebRequest.Abort(); + task.SetResult(null); + }); + } + + unityWebRequestAsyncOperation.completed += operation => + { + if (unityWebRequest.result == UnityWebRequest.Result.Success) + { + var texture = DownloadHandlerTexture.GetContent(unityWebRequest); + task.SetResult(texture); + } + else + { + Log.Error(unityWebRequest.error); + task.SetResult(null); + } + }; + + return task; + } + + /// + /// 获取Bytes + /// + /// + /// + /// + public static FTask GetBytes(string url, FCancellationToken cancellationToken = null) + { + var task = FTask.Create(false); + var unityWebRequest = UnityWebRequest.Get(url); + var unityWebRequestAsyncOperation = unityWebRequest.SendWebRequest(); + + if (cancellationToken != null) + { + cancellationToken.Add(() => + { + unityWebRequest.Abort(); + task.SetResult(null); + }); + } + + unityWebRequestAsyncOperation.completed += operation => + { + if (unityWebRequest.result == UnityWebRequest.Result.Success) + { + var bytes = unityWebRequest.downloadHandler.data; + task.SetResult(bytes); + } + else + { + Log.Error(unityWebRequest.error); + task.SetResult(null); + } + }; + + return task; + } + + /// + /// 获取AssetBundle + /// + /// + /// + /// + public static FTask GetAssetBundle(string url, FCancellationToken cancellationToken = null) + { + var task = FTask.Create(false); + var unityWebRequest = UnityWebRequestAssetBundle.GetAssetBundle(Uri.EscapeUriString(url)); + var unityWebRequestAsyncOperation = unityWebRequest.SendWebRequest(); + + if (cancellationToken != null) + { + cancellationToken.Add(() => + { + unityWebRequest.Abort(); + task.SetResult(null); + }); + } + + unityWebRequestAsyncOperation.completed += operation => + { + if (unityWebRequest.result == UnityWebRequest.Result.Success) + { + var assetBundle = DownloadHandlerAssetBundle.GetContent(unityWebRequest); + task.SetResult(assetBundle); + return; + } + + Log.Error(unityWebRequest.error); + task.SetResult(null); + }; + + return task; + } + + /// + /// 获取AudioClip + /// + /// + /// + /// + /// + public static FTask GetAudioClip(string url, AudioType audioType, FCancellationToken cancellationToken = null) + { + var task = FTask.Create(false); + var unityWebRequest = UnityWebRequestMultimedia.GetAudioClip(Uri.EscapeUriString(url), audioType); + var unityWebRequestAsyncOperation = unityWebRequest.SendWebRequest(); + + if (cancellationToken != null) + { + cancellationToken.Add(() => + { + unityWebRequest.Abort(); + task.SetResult(null); + }); + } + + unityWebRequestAsyncOperation.completed += operation => + { + if (unityWebRequest.result == UnityWebRequest.Result.Success) + { + var audioClip = DownloadHandlerAudioClip.GetContent(unityWebRequest); + task.SetResult(audioClip); + } + else + { + Log.Error(unityWebRequest.error); + task.SetResult(null); + } + }; + + return task; + } + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Helper/UnityWebRequest/UnityWebRequestHelper.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Helper/UnityWebRequest/UnityWebRequestHelper.cs.meta new file mode 100644 index 0000000..53b7c3c --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Helper/UnityWebRequest/UnityWebRequestHelper.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 4a679bf05117455388666f6d8cc35d7d +timeCreated: 1726022012 \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Helper/WebSocketHelper.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Helper/WebSocketHelper.cs new file mode 100644 index 0000000..822db06 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Helper/WebSocketHelper.cs @@ -0,0 +1,38 @@ +using System; +using System.Runtime.CompilerServices; + +namespace Fantasy.Helper +{ + /// + /// WebSocket帮助类 + /// + public static partial class WebSocketHelper + { + /// + /// 根据字符串获取WebSocket的连接地址 + /// + /// 目标服务器地址格式为:127.0.0.1:2000 + /// 目标服务器是否为加密连接也就是https + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static string GetWebSocketAddress(string address, bool isHttps) + { + var addressSplit = address.Split(':'); + if (addressSplit.Length != 2) + { + throw new FormatException("Invalid format"); + } + + var ipString = addressSplit[0]; + var portString = addressSplit[1]; + + if (!int.TryParse(portString, out var port) || port < 0 || port > 65535) + { + throw new FormatException("Invalid port number"); + } + + return isHttps ? $"wss://{ipString}:{portString}" : $"ws://{ipString}:{portString}"; + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Helper/WinPeriod.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Helper/WinPeriod.cs new file mode 100644 index 0000000..a1a5aca --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Helper/WinPeriod.cs @@ -0,0 +1,24 @@ +using System.Runtime.InteropServices; + +namespace Fantasy.Helper +{ + /// + /// 精度设置 + /// + public static partial class WinPeriod + { + // 一般默认的精度不止1毫秒(不同操作系统有所不同),需要调用timeBeginPeriod与timeEndPeriod来设置精度 + [DllImport("winmm")] + private static extern void timeBeginPeriod(int t); + /// + /// 针对Windows平台设置精度 + /// + public static void Initialize() + { + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + timeBeginPeriod(1); + } + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/IdFactory/Default/EntityIdStruct.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/IdFactory/Default/EntityIdStruct.cs new file mode 100644 index 0000000..2eb393b --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/IdFactory/Default/EntityIdStruct.cs @@ -0,0 +1,136 @@ +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using Fantasy.Helper; + +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member + +namespace Fantasy.IdFactory +{ + /// + /// 表示一个唯一实体的ID。 + /// + [StructLayout(LayoutKind.Sequential, Pack = 1)] + internal struct EntityIdStruct + { + // EntityId:39 + 16 + 18 = 64 + // +-------------------+-----------------------------+------------------------------------+ + // | time(30) 最大34年 | SceneId(16) 最多65535个Scene | sequence(18) 每秒每个进程能生产262143个 + // +-------------------+-----------------------------+------------------------------------+ + public uint Time { get; set; } + public uint SceneId { get; set; } + public uint Sequence { get; set; } + + public const uint MaskSequence = 0x3FFFF; + public const uint MaskSceneId = 0xFFFF; + public const uint MaskTime = 0x3FFFFFFF; + + /// + /// WorldEntityIdStruct(如果超过下面参数的设定该ID会失效)。 + /// + /// time不能超过1073741823 + /// sceneId不能超过65535 + /// sequence不能超过262143 + public EntityIdStruct(uint time, uint sceneId, uint sequence) + { + // 因为都是在配置表里拿到参数、所以这个不做边界判定、能节省一点点性能。 + Time = time; + SceneId = sceneId; + Sequence = sequence; + } + + public static implicit operator long(EntityIdStruct entityIdStruct) + { + ulong result = 0; + result |= entityIdStruct.Sequence; + result |= (ulong)entityIdStruct.SceneId << 18; + result |= (ulong)entityIdStruct.Time << 34; + return (long)result; + } + + public static implicit operator EntityIdStruct(long entityId) + { + var result = (ulong) entityId; + var entityIdStruct = new EntityIdStruct + { + Sequence = (uint)(result & MaskSequence) + }; + result >>= 18; + entityIdStruct.SceneId = (uint)(result & MaskSceneId); + result >>= 16; + entityIdStruct.Time = (uint)(result & MaskTime); + return entityIdStruct; + } + } + + public sealed class EntityIdFactory : IEntityIdFactory + { + private readonly ushort _sceneId; + + private uint _lastTime; + private uint _lastSequence; + private static readonly long Epoch1970 = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).Ticks / 10000; + private static readonly long EpochThisYear = new DateTime(DateTime.Now.Year, 1, 1, 0, 0, 0, DateTimeKind.Utc).Ticks / 10000 - Epoch1970; + + private EntityIdFactory() { } + + public EntityIdFactory(uint sceneId) + { + switch (sceneId) + { + case > 65535: + { + throw new NotSupportedException($"sceneId:{sceneId} cannot be greater than 255255"); + } + default: + { + _sceneId = (ushort)sceneId; + break; + } + } + } + + public long Create + { + get + { + var time = (uint)((TimeHelper.Now - EpochThisYear) / 1000); + + if (time > _lastTime) + { + _lastTime = time; + _lastSequence = 0; + } + else if (++_lastSequence > EntityIdStruct.MaskSequence - 1) + { + _lastTime++; + _lastSequence = 0; + } + + return new EntityIdStruct(time, _sceneId, _lastSequence); + } + } + } + + public sealed class EntityIdFactoryTool : IIdFactoryTool + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public uint GetTime(ref long entityId) + { + var result = (ulong)entityId >> 34; + return (uint)(result & EntityIdStruct.MaskTime); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public uint GetSceneId(ref long entityId) + { + var result = (ulong)entityId >> 18; + return (uint)(result & EntityIdStruct.MaskSceneId); + } + + public byte GetWorldId(ref long entityId) + { + throw new NotImplementedException(); + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/IdFactory/Default/RuntimeIdStruct.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/IdFactory/Default/RuntimeIdStruct.cs new file mode 100644 index 0000000..a5d5e10 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/IdFactory/Default/RuntimeIdStruct.cs @@ -0,0 +1,137 @@ +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using Fantasy.Helper; +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member + +namespace Fantasy.IdFactory +{ + /// + /// 表示一个运行时的ID。 + /// + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct RuntimeIdStruct + { + // RuntimeId:23 + 8 + 8 + 25 = 64 + // +-------------------+-----------------------------+--------------------------------------+ + // | time(23) 最大60天 | SceneId(16) 最多65535个Scene | sequence(25) 每秒每个进程能生产33554431个 + // +-------------------+-----------------------------+--------------------------------------+ + public uint Time { get; private set; } + public uint SceneId { get; private set; } + public uint Sequence { get; private set; } + + public const uint MaskSequence = 0x1FFFFFF; + public const uint MaskSceneId = 0xFFFF; + public const uint MaskTime = 0x7FFFFF; + + /// + /// RuntimeIdStruct(如果超过下面参数的设定该ID会失效)。 + /// + /// time不能超过8388607 + /// sceneId不能超过65535 + /// sequence不能超过33554431 + public RuntimeIdStruct(uint time, uint sceneId, uint sequence) + { + // 因为都是在配置表里拿到参数、所以这个不做边界判定、能节省一点点性能。 + Time = time; + SceneId = sceneId; + Sequence = sequence; + } + + public static implicit operator long(RuntimeIdStruct runtimeIdStruct) + { + ulong result = runtimeIdStruct.Sequence; + result |= (ulong)runtimeIdStruct.SceneId << 25; + result |= (ulong)runtimeIdStruct.Time << 41; + return (long)result; + } + + public static implicit operator RuntimeIdStruct(long runtimeId) + { + var result = (ulong)runtimeId; + var runtimeIdStruct = new RuntimeIdStruct + { + Sequence = (uint)(result & MaskSequence) + }; + result >>= 25; + runtimeIdStruct.SceneId = (byte)(result & MaskSceneId); + result >>= 16; + runtimeIdStruct.Time = (uint)(result & MaskTime); + return runtimeIdStruct; + } + } + + public sealed class RuntimeIdFactory : IRuntimeIdFactory + { + private readonly uint _sceneId; + + private uint _lastTime; + private uint _lastSequence; + private readonly long _epochNow; + private readonly long _epoch1970 = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).Ticks / 10000; + + private RuntimeIdFactory() { } + + public RuntimeIdFactory(uint sceneId) : this(TimeHelper.Now, sceneId) { } + + public RuntimeIdFactory(long epochNow, uint sceneId) + { + switch (sceneId) + { + case > 65535: + { + throw new NotSupportedException($"sceneId:{sceneId} cannot be greater than 255255"); + } + default: + { + _sceneId = (ushort)sceneId; + _epochNow = epochNow - _epoch1970; + break; + } + } + } + + public long Create + { + get + { + var time = (uint)((TimeHelper.Now - _epochNow) / 1000); + + if (time > _lastTime) + { + _lastTime = time; + _lastSequence = 0; + } + else if (++_lastSequence > RuntimeIdStruct.MaskSequence - 1) + { + _lastTime++; + _lastSequence = 0; + } + + return new RuntimeIdStruct(time, _sceneId, _lastSequence); + } + } + } + + public sealed class RuntimeIdFactoryTool : IIdFactoryTool + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public uint GetTime(ref long runtimeId) + { + var result = (ulong)runtimeId >> 41; + return (uint)(result & RuntimeIdStruct.MaskTime); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public uint GetSceneId(ref long runtimeId) + { + var result = (ulong)runtimeId >> 25; + return (uint)(result & RuntimeIdStruct.MaskSceneId); + } + + public byte GetWorldId(ref long entityId) + { + throw new NotImplementedException(); + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/IdFactory/IdFactoryHelper.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/IdFactory/IdFactoryHelper.cs new file mode 100644 index 0000000..4251d53 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/IdFactory/IdFactoryHelper.cs @@ -0,0 +1,132 @@ +using System; +using System.Runtime.CompilerServices; +using Fantasy.Helper; +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring as nullable. + +namespace Fantasy.IdFactory +{ + /// + /// Id生成器帮助类 + /// + public static class IdFactoryHelper + { + private static IdFactoryType _idFactoryType = IdFactoryType.World; + + /// + /// EntityId工具 + /// + public static IIdFactoryTool EntityIdTool { get; private set; } = new WorldEntityIdFactoryTool(); + + /// + /// RuntimeId工具 + /// + public static IIdFactoryTool RuntimeIdTool { get; private set; } = new WorldRuntimeIdFactoryTool(); + + /// + /// 初始化 + /// + /// + public static void Initialize(IdFactoryType idFactoryType) + { + _idFactoryType = idFactoryType; + + switch (_idFactoryType) + { + case IdFactoryType.Default: + { + EntityIdTool = new EntityIdFactoryTool(); + RuntimeIdTool = new RuntimeIdFactoryTool(); + return; + } + case IdFactoryType.World: + { + EntityIdTool = new WorldEntityIdFactoryTool(); + RuntimeIdTool = new WorldRuntimeIdFactoryTool(); + return; + } + } + } + + internal static IEntityIdFactory EntityIdFactory(uint sceneId, byte worldId) + { + switch (_idFactoryType) + { + case IdFactoryType.Default: + { + return new EntityIdFactory(sceneId); + } + case IdFactoryType.World: + { + return new WorldEntityIdFactory(sceneId, worldId); + } + default: + { + throw new NotSupportedException($"IdFactoryType {_idFactoryType} is not supported."); + } + } + } + + internal static IRuntimeIdFactory RuntimeIdFactory(long epochNow, uint sceneId, byte worldId) + { + switch (_idFactoryType) + { + case IdFactoryType.Default: + { + return new RuntimeIdFactory(sceneId); + } + case IdFactoryType.World: + { + if (epochNow == 0) + { + epochNow = TimeHelper.Now; + } + + return new WorldRuntimeIdFactory(epochNow, sceneId, worldId); + } + default: + { + throw new NotSupportedException($"IdFactoryType {_idFactoryType} is not supported."); + } + } + } + + internal static long EntityId(uint time, uint sceneId, byte wordId, uint sequence) + { + switch (_idFactoryType) + { + case IdFactoryType.Default: + { + return new EntityIdStruct(time, sceneId, sequence); + } + case IdFactoryType.World: + { + return new WorldEntityIdStruct(time, sceneId, wordId, sequence); + } + default: + { + throw new NotSupportedException($"IdFactoryType {_idFactoryType} is not supported."); + } + } + } + + internal static long RuntimeId(uint time, uint sceneId, byte wordId, uint sequence) + { + switch (_idFactoryType) + { + case IdFactoryType.Default: + { + return new RuntimeIdStruct(time, sceneId, sequence); + } + case IdFactoryType.World: + { + return new WorldRuntimeIdStruct(time, sceneId, wordId, sequence); + } + default: + { + throw new NotSupportedException($"IdFactoryType {_idFactoryType} is not supported."); + } + } + } + } +} + diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/IdFactory/IdFactoryType.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/IdFactory/IdFactoryType.cs new file mode 100644 index 0000000..d465b5b --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/IdFactory/IdFactoryType.cs @@ -0,0 +1,23 @@ +namespace Fantasy.IdFactory +{ + /// + /// ID生成器规则 + /// + public enum IdFactoryType + { + /// + /// 空。 + /// + None = 0, + /// + /// 默认生成器 + /// Scene最大为65535个。 + /// + Default = 1, + /// + /// ID中包含World,使用这种方式可以不用管理合区的ID重复的问题。 + /// 但Scene的数量也会限制到255个。 + /// + World = 2 + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/IdFactory/Interface/IIdFactory.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/IdFactory/Interface/IIdFactory.cs new file mode 100644 index 0000000..d71c15b --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/IdFactory/Interface/IIdFactory.cs @@ -0,0 +1,24 @@ +namespace Fantasy.IdFactory +{ + /// + /// EntityId生成器接口类 + /// + public interface IEntityIdFactory + { + /// + /// 创建一个新的Id + /// + public long Create { get; } + } + + /// + /// RuntimeId生成器接口类 + /// + public interface IRuntimeIdFactory + { + /// + /// 创建一个新的Id + /// + public long Create { get; } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/IdFactory/Interface/IIdFactoryTool.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/IdFactory/Interface/IIdFactoryTool.cs new file mode 100644 index 0000000..8dd1e99 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/IdFactory/Interface/IIdFactoryTool.cs @@ -0,0 +1,27 @@ +namespace Fantasy.IdFactory +{ + /// + /// Id扩展工具接口 + /// + public interface IIdFactoryTool + { + /// + /// 获得创建时间 + /// + /// + /// + public uint GetTime(ref long entityId); + /// + /// 获得SceneId + /// + /// + /// + public uint GetSceneId(ref long entityId); + /// + /// 获得WorldId + /// + /// + /// + public byte GetWorldId(ref long entityId); + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/IdFactory/World/WorldEntityIdFactory.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/IdFactory/World/WorldEntityIdFactory.cs new file mode 100644 index 0000000..a4aafba --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/IdFactory/World/WorldEntityIdFactory.cs @@ -0,0 +1,153 @@ +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using Fantasy.Helper; + +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member + +namespace Fantasy.IdFactory +{ + /// + /// 表示一个唯一实体的ID。 + /// + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct WorldEntityIdStruct + { + // EntityId:39 + 8 + 8 + 18 = 64 + // +-------------------+--------------------------+-----------------------+------------------------------------+ + // | time(30) 最大34年 | SceneId(8) 最多255个Scene | WordId(8) 最多255个世界 | sequence(18) 每秒每个进程能生产262143个 + // +-------------------+--------------------------+-----------------------+------------------------------------+ + public uint Time { get; private set; } + public uint SceneId { get; private set; } + public byte WordId { get; private set; } + public uint Sequence { get; private set; } + + public const uint MaskSequence = 0x3FFFF; + public const uint MaskSceneId = 0xFF; + public const uint MaskWordId = 0xFF; + public const uint MaskTime = 0x3FFFFFFF; + + /// + /// WorldEntityIdStruct(如果超过下面参数的设定该ID会失效)。 + /// + /// time不能超过1073741823 + /// sceneId不能超过255 + /// wordId不能超过255 + /// sequence不能超过262143 + public WorldEntityIdStruct(uint time, uint sceneId, byte wordId, uint sequence) + { + // 因为都是在配置表里拿到参数、所以这个不做边界判定、能节省一点点性能。 + Time = time; + SceneId = sceneId; + WordId = wordId; + Sequence = sequence; + } + + public static implicit operator long(WorldEntityIdStruct entityIdStruct) + { + ulong result = 0; + result |= entityIdStruct.Sequence; + result |= (ulong)entityIdStruct.WordId << 18; + result |= (ulong)(entityIdStruct.SceneId % (entityIdStruct.WordId * 1000)) << 26; + result |= (ulong)entityIdStruct.Time << 34; + return (long)result; + } + + public static implicit operator WorldEntityIdStruct(long entityId) + { + var result = (ulong) entityId; + var entityIdStruct = new WorldEntityIdStruct + { + Sequence = (uint)(result & MaskSequence) + }; + result >>= 18; + entityIdStruct.WordId = (byte)(result & MaskWordId); + result >>= 8; + entityIdStruct.SceneId = (uint)(result & MaskSceneId) + (uint)entityIdStruct.WordId * 1000; + result >>= 8; + entityIdStruct.Time = (uint)(result & MaskTime); + return entityIdStruct; + } + } + + public sealed class WorldEntityIdFactory : IEntityIdFactory + { + private readonly uint _sceneId; + private readonly byte _worldId; + + private uint _lastTime; + private uint _lastSequence; + private static readonly long Epoch1970 = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).Ticks / 10000; + private static readonly long EpochThisYear = new DateTime(DateTime.Now.Year, 1, 1, 0, 0, 0, DateTimeKind.Utc).Ticks / 10000 - Epoch1970; + + private WorldEntityIdFactory() { } + + public WorldEntityIdFactory(uint sceneId, byte worldId) + { + switch (sceneId) + { + case > 255255: + { + throw new NotSupportedException($"sceneId:{sceneId} cannot be greater than 255255"); + } + case < 1001: + { + throw new NotSupportedException($"sceneId:{sceneId} cannot be less than 1001"); + } + default: + { + _sceneId = sceneId; + _worldId = worldId; + break; + } + } + } + + public long Create + { + get + { + var time = (uint)((TimeHelper.Now - EpochThisYear) / 1000); + + if (time > _lastTime) + { + _lastTime = time; + _lastSequence = 0; + } + else if (++_lastSequence > WorldEntityIdStruct.MaskSequence - 1) + { + _lastTime++; + _lastSequence = 0; + } + + return new WorldEntityIdStruct(time, _sceneId, _worldId, _lastSequence); + } + } + } + + public sealed class WorldEntityIdFactoryTool : IIdFactoryTool + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public uint GetTime(ref long entityId) + { + var result = (ulong)entityId >> 34; + return (uint)(result & WorldEntityIdStruct.MaskTime); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public uint GetSceneId(ref long entityId) + { + var result = (ulong)entityId >> 18; + var worldId = (uint)(result & WorldEntityIdStruct.MaskWordId) * 1000; + result >>= 8; + return (uint)(result & WorldEntityIdStruct.MaskSceneId) + worldId; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public byte GetWorldId(ref long entityId) + { + var result = (ulong)entityId >> 18; + return (byte)(result & WorldEntityIdStruct.MaskWordId); + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/IdFactory/World/WorldRuntimeIdFactory.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/IdFactory/World/WorldRuntimeIdFactory.cs new file mode 100644 index 0000000..a5d582b --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/IdFactory/World/WorldRuntimeIdFactory.cs @@ -0,0 +1,155 @@ +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using Fantasy.Helper; + +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member + +namespace Fantasy.IdFactory +{ + /// + /// 表示一个运行时的ID。 + /// + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct WorldRuntimeIdStruct + { + // RuntimeId:23 + 8 + 8 + 25 = 64 + // +-------------------+--------------------------+-----------------------+--------------------------------------+ + // | time(23) 最大60天 | SceneId(8) 最多255个Scene | WordId(8) 最多255个世界 | sequence(25) 每秒每个进程能生产33554431个 + // +-------------------+--------------------------+-----------------------+--------------------------------------+ + public uint Time { get; private set; } + public uint SceneId { get; private set; } + public byte WordId { get; private set; } + public uint Sequence { get; private set; } + + public const uint MaskSequence = 0x1FFFFFF; + public const uint MaskSceneId = 0xFF; + public const uint MaskWordId = 0xFF; + public const uint MaskTime = 0x7FFFFF; + + /// + /// WorldRuntimeIdStruct(如果超过下面参数的设定该ID会失效)。 + /// + /// time不能超过8388607 + /// sceneId不能超过255 + /// wordId不能超过255 + /// sequence不能超过33554431 + public WorldRuntimeIdStruct(uint time, uint sceneId, byte wordId, uint sequence) + { + // 因为都是在配置表里拿到参数、所以这个不做边界判定、能节省一点点性能。 + Time = time; + SceneId = sceneId; + WordId = wordId; + Sequence = sequence; + } + + public static implicit operator long(WorldRuntimeIdStruct runtimeIdStruct) + { + ulong result = runtimeIdStruct.Sequence; + result |= (ulong)runtimeIdStruct.WordId << 25; + result |= (ulong)(runtimeIdStruct.SceneId % (runtimeIdStruct.WordId * 1000)) << 33; + result |= (ulong)runtimeIdStruct.Time << 41; + return (long)result; + } + + public static implicit operator WorldRuntimeIdStruct(long runtimeId) + { + var result = (ulong)runtimeId; + var runtimeIdStruct = new WorldRuntimeIdStruct + { + Sequence = (uint)(result & MaskSequence) + }; + result >>= 25; + runtimeIdStruct.WordId = (byte)(result & MaskWordId); + result >>= 8; + runtimeIdStruct.SceneId = (uint)(result & MaskSceneId) + (uint)runtimeIdStruct.WordId * 1000; + result >>= 8; + runtimeIdStruct.Time = (uint)(result & MaskTime); + return runtimeIdStruct; + } + } + + public sealed class WorldRuntimeIdFactory : IRuntimeIdFactory + { + private readonly uint _sceneId; + private readonly byte _worldId; + + private uint _lastTime; + private uint _lastSequence; + private readonly long _epochNow; + private readonly long _epoch1970 = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).Ticks / 10000; + + private WorldRuntimeIdFactory() { } + + public WorldRuntimeIdFactory(uint sceneId, byte worldId) : this(TimeHelper.Now, sceneId, worldId) { } + + public WorldRuntimeIdFactory(long epochNow, uint sceneId, byte worldId) + { + switch (sceneId) + { + case > 255255: + { + throw new NotSupportedException($"sceneId:{sceneId} cannot be greater than 255255"); + } + case < 1001: + { + throw new NotSupportedException($"sceneId:{sceneId} cannot be less than 1001"); + } + default: + { + _sceneId = sceneId; + _worldId = worldId; + _epochNow = epochNow - _epoch1970; + break; + } + } + } + + public long Create + { + get + { + var time = (uint)((TimeHelper.Now - _epochNow) / 1000); + + if (time > _lastTime) + { + _lastTime = time; + _lastSequence = 0; + } + else if (++_lastSequence > WorldRuntimeIdStruct.MaskSequence - 1) + { + _lastTime++; + _lastSequence = 0; + } + + return new WorldRuntimeIdStruct(time, _sceneId, _worldId, _lastSequence); + } + } + } + + public sealed class WorldRuntimeIdFactoryTool : IIdFactoryTool + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public uint GetTime(ref long runtimeId) + { + var result = (ulong)runtimeId >> 41; + return (uint)(result & WorldRuntimeIdStruct.MaskTime); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public uint GetSceneId(ref long runtimeId) + { + var result = (ulong)runtimeId >> 25; + var worldId = (uint)(result & WorldRuntimeIdStruct.MaskWordId) * 1000; + result >>= 8; + return (uint)(result & WorldRuntimeIdStruct.MaskSceneId) + worldId; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public byte GetWorldId(ref long runtimeId) + { + var result = (ulong)runtimeId >> 25; + return (byte)(result & WorldRuntimeIdStruct.MaskWordId); + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/InnerErrorCode.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/InnerErrorCode.cs new file mode 100644 index 0000000..3510b76 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/InnerErrorCode.cs @@ -0,0 +1,31 @@ +namespace Fantasy.Network +{ + /// + /// 定义 Fantasy 框架中的内部错误代码。 + /// + public class InnerErrorCode + { + private InnerErrorCode() { } + /// + /// 表示 Rpc 消息发送失败的错误代码。 + /// + public const uint ErrRpcFail = 100000002; + /// + /// 表示未找到 Route 消息的错误代码。 + /// + public const uint ErrNotFoundRoute = 100000003; + + /// + /// 表示发送 Route 消息超时的错误代码。 + /// + public const uint ErrRouteTimeout = 100000004; + /// + /// 表示未找到实体的错误代码。 + /// + public const uint ErrEntityNotFound = 100000008; + /// + /// 表示传送过程中发生错误的错误代码。 + /// + public const uint ErrTransfer = 100000009; + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Log/ConsoleLog.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Log/ConsoleLog.cs new file mode 100644 index 0000000..0d57e22 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Log/ConsoleLog.cs @@ -0,0 +1,144 @@ +#if FANTASY_NET +using Fantasy.Platform.Net; +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member + +namespace Fantasy; + +/// +/// 标准的控制台Log +/// +public sealed class ConsoleLog : ILog +{ + /// + /// 初始化方法 + /// + /// + public void Initialize(ProcessMode processMode) { } + + /// + /// 记录跟踪级别的日志消息。 + /// + /// 日志消息。 + public void Trace(string message) + { + Console.ForegroundColor = ConsoleColor.White; + Console.WriteLine(message); + } + + /// + /// 记录警告级别的日志消息。 + /// + /// 日志消息。 + public void Warning(string message) + { + Console.ForegroundColor = ConsoleColor.Yellow; + Console.WriteLine(message); + } + + /// + /// 记录信息级别的日志消息。 + /// + /// 日志消息。 + public void Info(string message) + { + Console.ForegroundColor = ConsoleColor.Gray; + Console.WriteLine(message); + } + + /// + /// 记录调试级别的日志消息。 + /// + /// 日志消息。 + public void Debug(string message) + { + Console.ForegroundColor = ConsoleColor.DarkGreen; + Console.WriteLine(message); + } + + /// + /// 记录错误级别的日志消息。 + /// + /// 日志消息。 + public void Error(string message) + { + Console.ForegroundColor = ConsoleColor.DarkRed; + Console.WriteLine(message); + } + + /// + /// 记录严重错误级别的日志消息。 + /// + /// 日志消息。 + public void Fatal(string message) + { + Console.ForegroundColor = ConsoleColor.Red; + Console.WriteLine(message); + } + + /// + /// 记录跟踪级别的格式化日志消息。 + /// + /// 日志消息模板。 + /// 格式化参数。 + public void Trace(string message, params object[] args) + { + Console.ForegroundColor = ConsoleColor.White; + Console.WriteLine(message, args); + } + + /// + /// 记录警告级别的格式化日志消息。 + /// + /// 日志消息模板。 + /// 格式化参数。 + public void Warning(string message, params object[] args) + { + Console.ForegroundColor = ConsoleColor.Yellow; + Console.WriteLine(message, args); + } + + /// + /// 记录信息级别的格式化日志消息。 + /// + /// 日志消息模板。 + /// 格式化参数。 + public void Info(string message, params object[] args) + { + Console.ForegroundColor = ConsoleColor.Gray; + Console.WriteLine(message, args); + } + + /// + /// 记录调试级别的格式化日志消息。 + /// + /// 日志消息模板。 + /// 格式化参数。 + public void Debug(string message, params object[] args) + { + Console.ForegroundColor = ConsoleColor.DarkGreen; + Console.WriteLine(message, args); + } + + /// + /// 记录错误级别的格式化日志消息。 + /// + /// 日志消息模板。 + /// 格式化参数。 + public void Error(string message, params object[] args) + { + Console.ForegroundColor = ConsoleColor.DarkRed; + Console.WriteLine(message, args); + } + + /// + /// 记录严重错误级别的格式化日志消息。 + /// + /// 日志消息模板。 + /// 格式化参数。 + public void Fatal(string message, params object[] args) + { + Console.ForegroundColor = ConsoleColor.Red; + Console.WriteLine(message, args); + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Log/ILog.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Log/ILog.cs new file mode 100644 index 0000000..b01e857 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Log/ILog.cs @@ -0,0 +1,74 @@ +#if FANTASY_NET +using Fantasy.Platform.Net; +#endif +namespace Fantasy +{ + /// + /// 定义日志记录功能的接口。 + /// + public interface ILog + { +#if FANTASY_NET + /// + /// 初始化 + /// + /// + void Initialize(ProcessMode processMode); +#endif + /// + /// 记录跟踪级别的日志消息。 + /// + /// 日志消息。 + void Trace(string message); + /// + /// 记录警告级别的日志消息。 + /// + /// 日志消息。 + void Warning(string message); + /// + /// 记录信息级别的日志消息。 + /// + /// 日志消息。 + void Info(string message); + /// + /// 记录调试级别的日志消息。 + /// + /// 日志消息。 + void Debug(string message); + /// + /// 记录错误级别的日志消息。 + /// + /// 日志消息。 + void Error(string message); + /// + /// 记录跟踪级别的格式化日志消息。 + /// + /// 日志消息模板。 + /// 格式化参数。 + void Trace(string message, params object[] args); + /// + /// 记录警告级别的格式化日志消息。 + /// + /// 日志消息模板。 + /// 格式化参数。 + void Warning(string message, params object[] args); + /// + /// 记录信息级别的格式化日志消息。 + /// + /// 日志消息模板。 + /// 格式化参数。 + void Info(string message, params object[] args); + /// + /// 记录调试级别的格式化日志消息。 + /// + /// 日志消息模板。 + /// 格式化参数。 + void Debug(string message, params object[] args); + /// + /// 记录错误级别的格式化日志消息。 + /// + /// 日志消息模板。 + /// 格式化参数。 + void Error(string message, params object[] args); + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Log/Log.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Log/Log.cs new file mode 100644 index 0000000..8069fff --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Log/Log.cs @@ -0,0 +1,189 @@ +using System; +using System.Diagnostics; +#if FANTASY_NET +using Fantasy.Platform.Net; +#endif + +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. + +namespace Fantasy +{ + /// + /// 提供日志记录功能的静态类。 + /// + public static class Log + { + private static ILog _logCore; + private static bool _isRegister; +#if FANTASY_NET + /// + /// 初始化Log系统 + /// + public static void Initialize() + { + if (!_isRegister) + { + Register(new ConsoleLog()); + return; + } + + var processMode = ProcessMode.None; + + switch (ProcessDefine.Options.Mode) + { + case "Develop": + { + processMode = ProcessMode.Develop; + break; + } + case "Release": + { + processMode = ProcessMode.Release; + break; + } + } + + _logCore.Initialize(processMode); + } +#endif + /// + /// 注册一个日志系统 + /// + /// + public static void Register(ILog log) + { + if (_isRegister) + { + return; + } + + _logCore = log; + _isRegister = true; + } + + /// + /// 记录跟踪级别的日志消息。 + /// + /// 日志消息。 + public static void Trace(string msg) + { + var st = new StackTrace(1, true); + _logCore.Trace($"{msg}\n{st}"); + } + + /// + /// 记录调试级别的日志消息。 + /// + /// 日志消息。 + public static void Debug(string msg) + { + _logCore.Debug(msg); + } + + /// + /// 记录信息级别的日志消息。 + /// + /// 日志消息。 + public static void Info(string msg) + { + _logCore.Info(msg); + } + + /// + /// 记录跟踪级别的日志消息,并附带调用栈信息。 + /// + /// 日志消息。 + public static void TraceInfo(string msg) + { + var st = new StackTrace(1, true); + _logCore.Trace($"{msg}\n{st}"); + } + + /// + /// 记录警告级别的日志消息。 + /// + /// 日志消息。 + public static void Warning(string msg) + { + _logCore.Warning(msg); + } + + /// + /// 记录错误级别的日志消息,并附带调用栈信息。 + /// + /// 日志消息。 + public static void Error(string msg) + { + var st = new StackTrace(1, true); + _logCore.Error($"{msg}\n{st}"); + } + + /// + /// 记录异常的错误级别的日志消息,并附带调用栈信息。 + /// + /// 异常对象。 + public static void Error(Exception e) + { + if (e.Data.Contains("StackTrace")) + { + _logCore.Error($"{e.Data["StackTrace"]}\n{e}"); + return; + } + var str = e.ToString(); + _logCore.Error(str); + } + + /// + /// 记录跟踪级别的格式化日志消息,并附带调用栈信息。 + /// + /// 日志消息模板。 + /// 格式化参数。 + public static void Trace(string message, params object[] args) + { + var st = new StackTrace(1, true); + _logCore.Trace($"{string.Format(message, args)}\n{st}"); + } + + /// + /// 记录警告级别的格式化日志消息。 + /// + /// 日志消息模板。 + /// 格式化参数。 + public static void Warning(string message, params object[] args) + { + _logCore.Warning(string.Format(message, args)); + } + + /// + /// 记录信息级别的格式化日志消息。 + /// + /// 日志消息模板。 + /// 格式化参数。 + public static void Info(string message, params object[] args) + { + _logCore.Info(string.Format(message, args)); + } + + /// + /// 记录调试级别的格式化日志消息。 + /// + /// 日志消息模板。 + /// 格式化参数。 + public static void Debug(string message, params object[] args) + { + _logCore.Debug(string.Format(message, args)); + } + + /// + /// 记录错误级别的格式化日志消息,并附带调用栈信息。 + /// + /// 日志消息模板。 + /// 格式化参数。 + public static void Error(string message, params object[] args) + { + var st = new StackTrace(1, true); + var s = string.Format(message, args) + '\n' + st; + _logCore.Error(s); + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Log/UnityLog.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Log/UnityLog.cs new file mode 100644 index 0000000..c381528 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Log/UnityLog.cs @@ -0,0 +1,182 @@ +#if UNITY_EDITOR +using System; +using System.Reflection; +using System.Text.RegularExpressions; +using UnityEditor; +using UnityEditor.Callbacks; +using UnityEditorInternal; +#else +using System; +#endif + +#if FANTASY_UNITY +namespace Fantasy +{ + public class UnityLog : ILog + { + public void Trace(string msg) + { + UnityEngine.Debug.Log(msg); + } + + public void Debug(string msg) + { + UnityEngine.Debug.Log(msg); + } + + public void Info(string msg) + { + UnityEngine.Debug.Log(msg); + } + + public void Warning(string msg) + { + UnityEngine.Debug.LogWarning(msg); + } + + public void Error(string msg) + { + UnityEngine.Debug.LogError(msg); + } + + public void Error(Exception e) + { + UnityEngine.Debug.LogException(e); + } + + public void Trace(string message, params object[] args) + { + UnityEngine.Debug.LogFormat(message, args); + } + + public void Warning(string message, params object[] args) + { + UnityEngine.Debug.LogWarningFormat(message, args); + } + + public void Info(string message, params object[] args) + { + UnityEngine.Debug.LogFormat(message, args); + } + + public void Debug(string message, params object[] args) + { + UnityEngine.Debug.LogFormat(message, args); + } + + public void Error(string message, params object[] args) + { + UnityEngine.Debug.LogErrorFormat(message, args); + } + } +} +#endif + +#if UNITY_EDITOR +namespace Fantasy +{ + /// + /// 日志重定向相关的实用函数。 + /// + internal static class LogRedirection + { + [OnOpenAsset(0)] + private static bool OnOpenAsset(int instanceID, int line) + { + if (line <= 0) + { + return false; + } + + // 获取资源路径 + string assetPath = AssetDatabase.GetAssetPath(instanceID); + + // 判断资源类型 + if (!assetPath.EndsWith(".cs")) + { + return false; + } + + bool autoFirstMatch = assetPath.Contains("Log.cs") || + assetPath.Contains("UnityLog.cs"); + + var stackTrace = GetStackTrace(); + if (!string.IsNullOrEmpty(stackTrace)) + + { + if (!autoFirstMatch) + { + var fullPath = UnityEngine.Application.dataPath.Substring(0, UnityEngine.Application.dataPath.LastIndexOf("Assets", StringComparison.Ordinal)); + fullPath = $"{fullPath}{assetPath}"; + // 跳转到目标代码的特定行 + InternalEditorUtility.OpenFileAtLineExternal(fullPath.Replace('/', '\\'), line); + return true; + } + + // 使用正则表达式匹配at的哪个脚本的哪一行 + var matches = Regex.Match(stackTrace, @"\(at (.+)\)", + RegexOptions.IgnoreCase); + while (matches.Success) + { + var pathLine = matches.Groups[1].Value; + + if (!pathLine.Contains("Log.cs") && + !pathLine.Contains("UnityLog.cs")) + { + var splitIndex = pathLine.LastIndexOf(":", StringComparison.Ordinal); + // 脚本路径 + var path = pathLine.Substring(0, splitIndex); + // 行号 + line = Convert.ToInt32(pathLine.Substring(splitIndex + 1)); + var fullPath = UnityEngine.Application.dataPath.Substring(0, UnityEngine.Application.dataPath.LastIndexOf("Assets", StringComparison.Ordinal)); + fullPath = $"{fullPath}{path}"; + // 跳转到目标代码的特定行 + InternalEditorUtility.OpenFileAtLineExternal(fullPath.Replace('/', '\\'), line); + break; + } + + matches = matches.NextMatch(); + } + + return true; + } + + return false; + } + + /// + /// 获取当前日志窗口选中的日志的堆栈信息。 + /// + /// 选中日志的堆栈信息实例。 + private static string GetStackTrace() + { + // 通过反射获取ConsoleWindow类 + var consoleWindowType = typeof(EditorWindow).Assembly.GetType("UnityEditor.ConsoleWindow"); + // 获取窗口实例 + var fieldInfo = consoleWindowType.GetField("ms_ConsoleWindow", + BindingFlags.Static | + BindingFlags.NonPublic); + if (fieldInfo != null) + { + var consoleInstance = fieldInfo.GetValue(null); + if (consoleInstance != null) + if (EditorWindow.focusedWindow == (EditorWindow)consoleInstance) + { + // 获取m_ActiveText成员 + fieldInfo = consoleWindowType.GetField("m_ActiveText", + BindingFlags.Instance | + BindingFlags.NonPublic); + // 获取m_ActiveText的值 + if (fieldInfo != null) + { + var activeText = fieldInfo.GetValue(consoleInstance).ToString(); + return activeText; + } + } + } + + return null; + } + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Addressable/AddressableHelper.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Addressable/AddressableHelper.cs new file mode 100644 index 0000000..098ba8a --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Addressable/AddressableHelper.cs @@ -0,0 +1,141 @@ +#if FANTASY_NET +using Fantasy.Async; +using Fantasy.InnerMessage; +using Fantasy.Platform.Net; +namespace Fantasy.Network.Route +{ + /// + /// 提供操作地址映射的辅助方法。 + /// + public static class AddressableHelper + { + // 声明一个私有静态只读列表 AddressableScenes,用于存储地址映射的场景配置信息 + private static readonly List AddressableScenes = new List(); + + static AddressableHelper() + { + // 遍历场景配置信息,筛选出地址映射类型的场景,并添加到 AddressableScenes 列表中 + foreach (var sceneConfig in SceneConfigData.Instance.List) + { + if (sceneConfig.SceneTypeString == "Addressable") + { + AddressableScenes.Add(new AddressableScene(sceneConfig)); + } + } + } + + /// + /// 添加地址映射并返回操作结果。 + /// + /// 场景实例。 + /// 地址映射的唯一标识。 + /// 路由 ID。 + /// 是否锁定。 + public static async FTask AddAddressable(Scene scene, long addressableId, long routeId, bool isLock = true) + { + // 获取指定索引的地址映射场景配置信息 + var addressableScene = AddressableScenes[(int)addressableId % AddressableScenes.Count]; + // 调用内部路由方法,发送添加地址映射的请求并等待响应 + var response = await scene.NetworkMessagingComponent.CallInnerRoute(addressableScene.RunTimeId, + new I_AddressableAdd_Request + { + AddressableId = addressableId, RouteId = routeId, IsLock = isLock + }); + if (response.ErrorCode != 0) + { + Log.Error($"AddAddressable error is {response.ErrorCode}"); + } + } + + /// + /// 获取地址映射的路由 ID。 + /// + /// 场景实例。 + /// 地址映射的唯一标识。 + /// 地址映射的路由 ID。 + public static async FTask GetAddressableRouteId(Scene scene, long addressableId) + { + // 获取指定索引的地址映射场景配置信息 + var addressableScene = AddressableScenes[(int)addressableId % AddressableScenes.Count]; + // 调用内部路由方法,发送获取地址映射路由 ID 的请求并等待响应 + var response = (I_AddressableGet_Response) await scene.NetworkMessagingComponent.CallInnerRoute(addressableScene.RunTimeId, + new I_AddressableGet_Request + { + AddressableId = addressableId + }); + // 检查响应错误码,如果为零,返回路由 ID;否则,输出错误信息并返回 0 + if (response.ErrorCode == 0) + { + return response.RouteId; + } + + Log.Error($"GetAddressable error is {response.ErrorCode} addressableId:{addressableId}"); + return 0; + } + + /// + /// 移除指定地址映射。 + /// + /// 场景实例。 + /// 地址映射的唯一标识。 + public static async FTask RemoveAddressable(Scene scene, long addressableId) + { + var addressableScene = AddressableScenes[(int)addressableId % AddressableScenes.Count]; + var response = await scene.NetworkMessagingComponent.CallInnerRoute(addressableScene.RunTimeId, + new I_AddressableRemove_Request + { + AddressableId = addressableId + }); + + if (response.ErrorCode != 0) + { + Log.Error($"RemoveAddressable error is {response.ErrorCode}"); + } + } + + /// + /// 锁定指定地址映射。 + /// + /// 场景实例。 + /// 地址映射的唯一标识。 + public static async FTask LockAddressable(Scene scene, long addressableId) + { + var addressableScene = AddressableScenes[(int)addressableId % AddressableScenes.Count]; + var response = await scene.NetworkMessagingComponent.CallInnerRoute(addressableScene.RunTimeId, + new I_AddressableLock_Request + { + AddressableId = addressableId + }); + + if (response.ErrorCode != 0) + { + Log.Error($"LockAddressable error is {response.ErrorCode}"); + } + } + + /// + /// 解锁指定地址映射。 + /// + /// 场景实例。 + /// 地址映射的唯一标识。 + /// 路由 ID。 + /// 解锁来源。 + public static async FTask UnLockAddressable(Scene scene, long addressableId, long routeId, string source) + { + var addressableScene = AddressableScenes[(int)addressableId % AddressableScenes.Count]; + var response = await scene.NetworkMessagingComponent.CallInnerRoute(addressableScene.RunTimeId, + new I_AddressableUnLock_Request + { + AddressableId = addressableId, + RouteId = routeId, + Source = source + }); + + if (response.ErrorCode != 0) + { + Log.Error($"UnLockAddressable error is {response.ErrorCode}"); + } + } + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Addressable/AddressableManageComponent.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Addressable/AddressableManageComponent.cs new file mode 100644 index 0000000..8d08f08 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Addressable/AddressableManageComponent.cs @@ -0,0 +1,144 @@ +#if FANTASY_NET +using System; +using System.Collections.Generic; +using Fantasy.Async; +using Fantasy.Entitas; +using Fantasy.Entitas.Interface; + +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. +#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. +#pragma warning disable CS8600 // Converting null literal or possible null value to non-nullable type. + +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member +namespace Fantasy.Network.Route +{ + public class AddressableManageComponentAwakeSystem : AwakeSystem + { + protected override void Awake(AddressableManageComponent self) + { + self.AddressableLock = self.Scene.CoroutineLockComponent.Create(self.GetType().TypeHandle.Value.ToInt64()); + } + } + + public class AddressableManageComponentDestroySystem : DestroySystem + { + protected override void Destroy(AddressableManageComponent self) + { + foreach (var (_, waitCoroutineLock) in self.Locks) + { + waitCoroutineLock.Dispose(); + } + + self.Locks.Clear(); + self.Addressable.Clear(); + self.AddressableLock.Dispose(); + self.AddressableLock = null; + } + } + + public sealed class AddressableManageComponent : Entity + { + public CoroutineLock AddressableLock; + public readonly Dictionary Addressable = new(); + public readonly Dictionary Locks = new(); + + /// + /// 添加地址映射。 + /// + /// 地址映射的唯一标识。 + /// 路由 ID。 + /// 是否进行锁定。 + public async FTask Add(long addressableId, long routeId, bool isLock) + { + WaitCoroutineLock waitCoroutineLock = null; + + try + { + if (isLock) + { + waitCoroutineLock = await AddressableLock.Wait(addressableId); + } + + Addressable[addressableId] = routeId; +#if FANTASY_DEVELOP + Log.Debug($"AddressableManageComponent Add addressableId:{addressableId} routeId:{routeId}"); +#endif + } + catch (Exception e) + { + Log.Error(e); + } + finally + { + waitCoroutineLock?.Dispose(); + } + } + + /// + /// 获取地址映射的路由 ID。 + /// + /// 地址映射的唯一标识。 + /// 地址映射的路由 ID。 + public async FTask Get(long addressableId) + { + using (await AddressableLock.Wait(addressableId)) + { + Addressable.TryGetValue(addressableId, out var routeId); + return routeId; + } + } + + /// + /// 移除地址映射。 + /// + /// 地址映射的唯一标识。 + public async FTask Remove(long addressableId) + { + using (await AddressableLock.Wait(addressableId)) + { + Addressable.Remove(addressableId); +#if FANTASY_DEVELOP + Log.Debug($"Addressable Remove addressableId: {addressableId} _addressable:{Addressable.Count}"); +#endif + } + } + + /// + /// 锁定地址映射。 + /// + /// 地址映射的唯一标识。 + public async FTask Lock(long addressableId) + { + var waitCoroutineLock = await AddressableLock.Wait(addressableId); + Locks.Add(addressableId, waitCoroutineLock); + } + + /// + /// 解锁地址映射。 + /// + /// 地址映射的唯一标识。 + /// 新的路由 ID。 + /// 解锁来源。 + public void UnLock(long addressableId, long routeId, string source) + { + if (!Locks.Remove(addressableId, out var coroutineLock)) + { + Log.Error($"Addressable unlock not found addressableId: {addressableId} Source:{source}"); + return; + } + + Addressable.TryGetValue(addressableId, out var oldAddressableId); + + if (routeId != 0) + { + Addressable[addressableId] = routeId; + } + + coroutineLock.Dispose(); +#if FANTASY_DEVELOP + Log.Debug($"Addressable UnLock key: {addressableId} oldAddressableId : {oldAddressableId} routeId: {routeId} Source:{source}"); +#endif + } + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Addressable/AddressableMessageComponent.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Addressable/AddressableMessageComponent.cs new file mode 100644 index 0000000..9227374 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Addressable/AddressableMessageComponent.cs @@ -0,0 +1,91 @@ +using Fantasy.Async; +using Fantasy.Entitas; +using Fantasy.Entitas.Interface; + +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member +#if FANTASY_NET +namespace Fantasy.Network.Route +{ + public class AddressableMessageComponentDestroySystem : DestroySystem + { + protected override void Destroy(AddressableMessageComponent self) + { + if (self.AddressableId != 0) + { + AddressableHelper.RemoveAddressable(self.Scene, self.AddressableId).Coroutine(); + self.AddressableId = 0; + } + } + } + + /// + /// 可寻址消息组件、挂载了这个组件可以接收Addressable消息 + /// + public sealed class AddressableMessageComponent : Entity + { + /// + /// 可寻址消息组件的唯一标识。 + /// + public long AddressableId; + + /// + /// 注册可寻址消息组件。 + /// + /// 是否进行锁定。 + public FTask Register(bool isLock = true) + { + if (Parent == null) + { + throw new Exception("AddressableRouteComponent must be mounted under a component"); + } + + AddressableId = Parent.Id; + + if (AddressableId == 0) + { + throw new Exception("AddressableRouteComponent.Parent.Id is null"); + } + +#if FANTASY_DEVELOP + Log.Debug($"AddressableMessageComponent Register addressableId:{AddressableId} RouteId:{Parent.RuntimeId}"); +#endif + return AddressableHelper.AddAddressable(Scene, AddressableId, Parent.RuntimeId, isLock); + } + + /// + /// 锁定可寻址消息组件。 + /// + public FTask Lock() + { +#if FANTASY_DEVELOP + Log.Debug($"AddressableMessageComponent Lock {Parent.Id}"); +#endif + return AddressableHelper.LockAddressable(Scene, Parent.Id); + } + + /// + /// 解锁可寻址消息组件。 + /// + /// 解锁来源。 + public FTask UnLock(string source) + { +#if FANTASY_DEVELOP + Log.Debug($"AddressableMessageComponent UnLock {Parent.Id} {Parent.RuntimeId}"); +#endif + return AddressableHelper.UnLockAddressable(Scene, Parent.Id, Parent.RuntimeId, source); + } + + /// + /// 锁定可寻址消息并且释放掉AddressableMessageComponent组件。 + /// 该方法不会自动取Addressable中心删除自己的信息。 + /// 用于传送或转移到其他服务器时使用 + /// + public async FTask LockAndRelease() + { + await Lock(); + AddressableId = 0; + Dispose(); + } + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Addressable/AddressableRouteComponent.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Addressable/AddressableRouteComponent.cs new file mode 100644 index 0000000..d7914a1 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Addressable/AddressableRouteComponent.cs @@ -0,0 +1,216 @@ +using Fantasy.Async; +using Fantasy.Entitas; +using Fantasy.Entitas.Interface; +using Fantasy.Helper; +using Fantasy.Network.Interface; +using Fantasy.PacketParser.Interface; +using Fantasy.Scheduler; +using Fantasy.Timer; + +#pragma warning disable CS8603 // Possible null reference return. +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. +#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. +#pragma warning disable CS8600 // Converting null literal or possible null value to non-nullable type. +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member +#if FANTASY_NET +namespace Fantasy.Network.Route +{ + public class AddressableRouteComponentAwakeSystem : AwakeSystem + { + protected override void Awake(AddressableRouteComponent self) + { + var selfScene = self.Scene; + self.TimerComponent = selfScene.TimerComponent; + self.NetworkMessagingComponent = selfScene.NetworkMessagingComponent; + self.MessageDispatcherComponent = selfScene.MessageDispatcherComponent; + self.AddressableRouteLock = + selfScene.CoroutineLockComponent.Create(self.GetType().TypeHandle.Value.ToInt64()); + } + } + + public class AddressableRouteComponentDestroySystem : DestroySystem + { + protected override void Destroy(AddressableRouteComponent self) + { + self.AddressableRouteLock.Dispose(); + + self.RouteId = 0; + self.AddressableId = 0; + self.TimerComponent = null; + self.AddressableRouteLock = null; + self.NetworkMessagingComponent = null; + self.MessageDispatcherComponent = null; + } + } + + /// + /// 可寻址路由消息组件,挂载了这个组件可以接收和发送 Addressable 消息。 + /// + public sealed class AddressableRouteComponent : Entity + { + public long RouteId; + public long AddressableId; + public CoroutineLock AddressableRouteLock; + public TimerComponent TimerComponent; + public NetworkMessagingComponent NetworkMessagingComponent; + public MessageDispatcherComponent MessageDispatcherComponent; + + internal void Send(IAddressableRouteMessage message) + { + Call(message).Coroutine(); + } + + internal async FTask Send(Type requestType, APackInfo packInfo) + { + await Call(requestType, packInfo); + } + + internal async FTask Call(Type requestType, APackInfo packInfo) + { + if (IsDisposed) + { + return MessageDispatcherComponent.CreateResponse(requestType, InnerErrorCode.ErrNotFoundRoute); + } + + packInfo.IsDisposed = true; + var failCount = 0; + var runtimeId = RuntimeId; + IResponse iRouteResponse = null; + + try + { + using (await AddressableRouteLock.Wait(AddressableId, "AddressableRouteComponent Call MemoryStream")) + { + while (!IsDisposed) + { + if (RouteId == 0) + { + RouteId = await AddressableHelper.GetAddressableRouteId(Scene, AddressableId); + } + + if (RouteId == 0) + { + return MessageDispatcherComponent.CreateResponse(requestType, + InnerErrorCode.ErrNotFoundRoute); + } + + iRouteResponse = await NetworkMessagingComponent.CallInnerRoute(RouteId, requestType, packInfo); + + if (runtimeId != RuntimeId) + { + iRouteResponse.ErrorCode = InnerErrorCode.ErrRouteTimeout; + } + + switch (iRouteResponse.ErrorCode) + { + case InnerErrorCode.ErrRouteTimeout: + { + return iRouteResponse; + } + case InnerErrorCode.ErrNotFoundRoute: + { + if (++failCount > 20) + { + Log.Error($"AddressableComponent.Call failCount > 20 route send message fail, routeId: {RouteId} AddressableRouteComponent:{Id}"); + return iRouteResponse; + } + + await TimerComponent.Net.WaitAsync(100); + + if (runtimeId != RuntimeId) + { + iRouteResponse.ErrorCode = InnerErrorCode.ErrRouteTimeout; + } + + RouteId = 0; + continue; + } + default: + { + return iRouteResponse; // 对于其他情况,直接返回响应,无需额外处理 + } + } + } + } + } + finally + { + packInfo.Dispose(); + } + + + return iRouteResponse; + } + + /// + /// 调用可寻址路由消息并等待响应。 + /// + /// 可寻址路由请求。 + private async FTask Call(IAddressableRouteMessage request) + { + if (IsDisposed) + { + return MessageDispatcherComponent.CreateResponse(request.GetType(), InnerErrorCode.ErrNotFoundRoute); + } + + var failCount = 0; + var runtimeId = RuntimeId; + + using (await AddressableRouteLock.Wait(AddressableId, "AddressableRouteComponent Call")) + { + while (true) + { + if (RouteId == 0) + { + RouteId = await AddressableHelper.GetAddressableRouteId(Scene, AddressableId); + } + + if (RouteId == 0) + { + return MessageDispatcherComponent.CreateResponse(request.GetType(), + InnerErrorCode.ErrNotFoundRoute); + } + + var iRouteResponse = await NetworkMessagingComponent.CallInnerRoute(RouteId, request); + + if (runtimeId != RuntimeId) + { + iRouteResponse.ErrorCode = InnerErrorCode.ErrRouteTimeout; + } + + switch (iRouteResponse.ErrorCode) + { + case InnerErrorCode.ErrNotFoundRoute: + { + if (++failCount > 20) + { + Log.Error( + $"AddressableRouteComponent.Call failCount > 20 route send message fail, routeId: {RouteId} AddressableRouteComponent:{Id}"); + return iRouteResponse; + } + + await TimerComponent.Net.WaitAsync(500); + + if (runtimeId != RuntimeId) + { + iRouteResponse.ErrorCode = InnerErrorCode.ErrRouteTimeout; + } + + RouteId = 0; + continue; + } + case InnerErrorCode.ErrRouteTimeout: + { + return iRouteResponse; + } + default: + { + return iRouteResponse; + } + } + } + } + } + } +} +#endif diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Addressable/AddressableScene.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Addressable/AddressableScene.cs new file mode 100644 index 0000000..3105fca --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Addressable/AddressableScene.cs @@ -0,0 +1,31 @@ +#if FANTASY_NET +using Fantasy.IdFactory; +using Fantasy.Platform.Net; + +namespace Fantasy.Network.Route +{ + /// + /// AddressableScene + /// + public sealed class AddressableScene + { + /// + /// Id + /// + public readonly long Id; + /// + /// RunTimeId + /// + public readonly long RunTimeId; + /// + /// 构造方法 + /// + /// sceneConfig + public AddressableScene(SceneConfig sceneConfig) + { + Id = IdFactoryHelper.EntityId(0, sceneConfig.Id, (byte)sceneConfig.WorldConfigId, 0); + RunTimeId = IdFactoryHelper.RuntimeId(0, sceneConfig.Id, (byte)sceneConfig.WorldConfigId, 0); + } + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Addressable/Handler/I_AddressableAddHandler.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Addressable/Handler/I_AddressableAddHandler.cs new file mode 100644 index 0000000..847625b --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Addressable/Handler/I_AddressableAddHandler.cs @@ -0,0 +1,26 @@ +using Fantasy.Async; +using Fantasy.InnerMessage; +using Fantasy.Network.Interface; + +#if FANTASY_NET +namespace Fantasy.Network.Route +{ + /// + /// 声明一个 sealed 类 I_AddressableAddHandler,继承自 RouteRPC 类,并指定泛型参数 + /// + public sealed class I_AddressableAddHandler : RouteRPC + { + /// + /// 在收到地址映射添加请求时执行的逻辑。 + /// + /// 当前场景实例。 + /// 包含请求信息的 I_AddressableAdd_Request 实例。 + /// 用于构建响应的 I_AddressableAdd_Response 实例。 + /// 执行响应的回调操作。 + protected override async FTask Run(Scene scene, I_AddressableAdd_Request request, I_AddressableAdd_Response response, Action reply) + { + await scene.GetComponent().Add(request.AddressableId, request.RouteId, request.IsLock); + } + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Addressable/Handler/I_AddressableGetHandler.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Addressable/Handler/I_AddressableGetHandler.cs new file mode 100644 index 0000000..f53c1f1 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Addressable/Handler/I_AddressableGetHandler.cs @@ -0,0 +1,26 @@ +using Fantasy.Async; +using Fantasy.InnerMessage; +using Fantasy.Network.Interface; + +#if FANTASY_NET +namespace Fantasy.Network.Route +{ + /// + /// 声明一个 sealed 类 I_AddressableGetHandler,继承自 RouteRPC 类,并指定泛型参数 + /// + public sealed class I_AddressableGetHandler : RouteRPC + { + /// + /// 在收到地址映射获取请求时执行的逻辑。 + /// + /// 当前场景实例。 + /// 包含请求信息的 I_AddressableGet_Request 实例。 + /// 用于构建响应的 I_AddressableGet_Response 实例。 + /// 执行响应的回调操作。 + protected override async FTask Run(Scene scene, I_AddressableGet_Request request, I_AddressableGet_Response response, Action reply) + { + response.RouteId = await scene.GetComponent().Get(request.AddressableId); + } + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Addressable/Handler/I_AddressableLockHandler.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Addressable/Handler/I_AddressableLockHandler.cs new file mode 100644 index 0000000..b964274 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Addressable/Handler/I_AddressableLockHandler.cs @@ -0,0 +1,26 @@ +using Fantasy.Async; +using Fantasy.InnerMessage; +using Fantasy.Network.Interface; + +#if FANTASY_NET +namespace Fantasy.Network.Route +{ + /// + /// 声明一个 sealed 类 I_AddressableLockHandler,继承自 RouteRPC 类,并指定泛型参数 + /// + public sealed class I_AddressableLockHandler : RouteRPC + { + /// + /// 在收到地址映射锁定请求时执行的逻辑。 + /// + /// 当前场景实例。 + /// 包含请求信息的 I_AddressableLock_Request 实例。 + /// 用于构建响应的 I_AddressableLock_Response 实例。 + /// 执行响应的回调操作。 + protected override async FTask Run(Scene scene, I_AddressableLock_Request request, I_AddressableLock_Response response, Action reply) + { + await scene.GetComponent().Lock(request.AddressableId); + } + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Addressable/Handler/I_AddressableRemoveHandler.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Addressable/Handler/I_AddressableRemoveHandler.cs new file mode 100644 index 0000000..c4e9654 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Addressable/Handler/I_AddressableRemoveHandler.cs @@ -0,0 +1,26 @@ +using Fantasy.Async; +using Fantasy.InnerMessage; +using Fantasy.Network.Interface; + +#if FANTASY_NET +namespace Fantasy.Network.Route +{ + /// + /// 声明一个 sealed 类 I_AddressableRemoveHandler,继承自 RouteRPC 类,并指定泛型参数 + /// + public sealed class I_AddressableRemoveHandler : RouteRPC + { + /// + /// 在收到地址映射移除请求时执行的逻辑。 + /// + /// 当前场景实例。 + /// 包含请求信息的 I_AddressableRemove_Request 实例。 + /// 用于构建响应的 I_AddressableRemove_Response 实例。 + /// 执行响应的回调操作。 + protected override async FTask Run(Scene scene, I_AddressableRemove_Request request, I_AddressableRemove_Response response, Action reply) + { + await scene.GetComponent().Remove(request.AddressableId); + } + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Addressable/Handler/I_AddressableUnLockHandler.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Addressable/Handler/I_AddressableUnLockHandler.cs new file mode 100644 index 0000000..1ab3937 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Addressable/Handler/I_AddressableUnLockHandler.cs @@ -0,0 +1,27 @@ +using Fantasy.Async; +using Fantasy.InnerMessage; +using Fantasy.Network.Interface; + +#if FANTASY_NET +namespace Fantasy.Network.Route +{ + /// + /// 声明一个 sealed 类 I_AddressableUnLockHandler,继承自 RouteRPC 类,并指定泛型参数 + /// + public sealed class I_AddressableUnLockHandler : RouteRPC + { + /// + /// 在收到地址映射解锁请求时执行的逻辑。 + /// + /// 当前场景实例。 + /// 包含请求信息的 I_AddressableUnLock_Request 实例。 + /// 用于构建响应的 I_AddressableUnLock_Response 实例。 + /// 执行响应的回调操作。 + protected override async FTask Run(Scene scene, I_AddressableUnLock_Request request, I_AddressableUnLock_Response response, Action reply) + { + scene.GetComponent().UnLock(request.AddressableId, request.RouteId, request.Source); + await FTask.CompletedTask; + } + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/MemoryStreamBufferPool.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/MemoryStreamBufferPool.cs new file mode 100644 index 0000000..6e6d4f7 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/MemoryStreamBufferPool.cs @@ -0,0 +1,96 @@ +using System; +using System.Collections.Generic; +using Fantasy.Serialize; +#pragma warning disable CS8603 // Possible null reference return. + +namespace Fantasy.Network +{ + /// + /// MemoryStreamBuffer对象池类 + /// + public sealed class MemoryStreamBufferPool : IDisposable + { + private readonly int _poolSize; + private readonly int _maxMemoryStreamSize; + private readonly Queue _memoryStreamPool = new Queue(); + + /// + /// 构造方法 + /// + /// + /// + public MemoryStreamBufferPool(int maxMemoryStreamSize = 2048, int poolSize = 512) + { + _poolSize = poolSize; + _maxMemoryStreamSize = maxMemoryStreamSize; + } + + /// + /// 租借MemoryStream + /// + /// + /// + /// + public MemoryStreamBuffer RentMemoryStream(MemoryStreamBufferSource memoryStreamBufferSource, int size = 0) + { + if (size > _maxMemoryStreamSize) + { + return new MemoryStreamBuffer(memoryStreamBufferSource, size); + } + + if (size < _maxMemoryStreamSize) + { + size = _maxMemoryStreamSize; + } + + if (_memoryStreamPool.Count == 0) + { + return new MemoryStreamBuffer(memoryStreamBufferSource, size); + } + + if (_memoryStreamPool.TryDequeue(out var memoryStream)) + { + memoryStream.MemoryStreamBufferSource = memoryStreamBufferSource; + return memoryStream; + } + + return new MemoryStreamBuffer(memoryStreamBufferSource, size); + } + + /// + /// 归还ReturnMemoryStream + /// + /// + public void ReturnMemoryStream(MemoryStreamBuffer memoryStreamBuffer) + { + if (memoryStreamBuffer.Capacity > _maxMemoryStreamSize) + { + return; + } + + if (_memoryStreamPool.Count > _poolSize) + { + // 设置该值只能是内网或服务器转发的时候可能在连接之前发送的数据过多的情况下可以修改。 + // 设置过大会导致内存占用过大,所以要谨慎设置。 + return; + } + + memoryStreamBuffer.SetLength(0); + memoryStreamBuffer.MemoryStreamBufferSource = MemoryStreamBufferSource.None; + _memoryStreamPool.Enqueue(memoryStreamBuffer); + } + + /// + /// 销毁方法 + /// + public void Dispose() + { + foreach (var memoryStreamBuffer in _memoryStreamPool) + { + memoryStreamBuffer.MemoryStreamBufferSource = MemoryStreamBufferSource.None; + memoryStreamBuffer.Dispose(); + } + _memoryStreamPool.Clear(); + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Message/Dispatcher/Interface/IMessageHandler.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Message/Dispatcher/Interface/IMessageHandler.cs new file mode 100644 index 0000000..d8f928e --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Message/Dispatcher/Interface/IMessageHandler.cs @@ -0,0 +1,220 @@ +// ReSharper disable InconsistentNaming + +using System; +using System.Collections.Generic; +using Fantasy.Async; +using Fantasy.Network; +using Fantasy.Serialize; + +namespace Fantasy.Network.Interface +{ + /// + /// 表示消息处理器的接口,处理特定类型的消息。 + /// + public interface IMessageHandler + { + /// + /// 获取处理的消息类型。 + /// + /// 消息类型。 + public Type Type(); + /// + /// 处理消息的方法。 + /// + /// 会话对象。 + /// RPC标识。 + /// 消息类型代码。 + /// 要处理的消息。 + /// 异步任务。 + FTask Handle(Session session, uint rpcId, uint messageTypeCode, object message); + } + + /// + /// 泛型消息基类,实现了 接口。 + /// + public abstract class Message : IMessageHandler + { + /// + /// 获取处理的消息类型。 + /// + /// 消息类型。 + public Type Type() + { + return typeof(T); + } + + /// + /// 处理消息的方法。 + /// + /// 会话对象。 + /// RPC标识。 + /// 消息类型代码。 + /// 要处理的消息。 + /// 异步任务。 + public async FTask Handle(Session session, uint rpcId, uint messageTypeCode, object message) + { + try + { + await Run(session, (T) message); + } + catch (Exception e) + { + Log.Error(e); + } + } + + /// + /// 运行消息处理逻辑。 + /// + /// 会话对象。 + /// 要处理的消息。 + /// 异步任务。 + protected abstract FTask Run(Session session, T message); + } + + /// + /// 泛型消息RPC基类,实现了 接口,用于处理请求和响应类型的消息。 + /// + public abstract class MessageRPC : IMessageHandler where TRequest : IRequest where TResponse : AMessage, IResponse, new() + { + /// + /// 获取处理的消息类型。 + /// + /// 消息类型。 + public Type Type() + { + return typeof(TRequest); + } + + /// + /// 处理消息的方法。 + /// + /// 会话对象。 + /// RPC标识。 + /// 消息类型代码。 + /// 要处理的消息。 + /// 异步任务。 + public async FTask Handle(Session session, uint rpcId, uint messageTypeCode, object message) + { + if (message is not TRequest request) + { + Log.Error($"消息类型转换错误: {message.GetType().Name} to {typeof(TRequest).Name}"); + return; + } + + var response = new TResponse(); + var isReply = false; + + void Reply() + { + if (isReply) + { + return; + } + + isReply = true; + + if (session.IsDisposed) + { + return; + } + + session.Send(response, rpcId); + } + + try + { + await Run(session, request, response, Reply); + } + catch (Exception e) + { + Log.Error(e); + response.ErrorCode = InnerErrorCode.ErrRpcFail; + } + finally + { + Reply(); + } + } + + /// + /// 运行消息处理逻辑。 + /// + /// 会话对象。 + /// 请求消息。 + /// 响应消息。 + /// 发送响应的方法。 + /// 异步任务。 + protected abstract FTask Run(Session session, TRequest request, TResponse response, Action reply); + } +#if FANTASY_UNITY + public interface IMessageDelegateHandler + { + /// + /// 注册消息处理器。 + /// + /// + public void Register(object @delegate); + /// + /// 取消注册消息处理器。 + /// + /// + public int UnRegister(object @delegate); + /// + /// 处理消息的方法。 + /// + /// + /// + public void Handle(Session session, object message); + } + public delegate FTask MessageDelegate(Session session, T msg) where T : IMessage; + public sealed class MessageDelegateHandler : IMessageDelegateHandler, IDisposable where T : IMessage + { + private readonly List> _delegates = new List>(); + + public Type Type() + { + return typeof(T); + } + + public void Register(object @delegate) + { + var a = (MessageDelegate)@delegate; + + if (_delegates.Contains(a)) + { + Log.Error($"{typeof(T).Name} already register action delegateName:{a.Method.Name}"); + return; + } + + _delegates.Add(a); + } + + public int UnRegister(object @delegate) + { + _delegates.Remove((MessageDelegate)@delegate); + return _delegates.Count; + } + + public void Handle(Session session, object message) + { + foreach (var registerDelegate in _delegates) + { + try + { + registerDelegate(session, (T)message).Coroutine(); + } + catch (Exception e) + { + Log.Error(e); + } + } + } + + public void Dispose() + { + _delegates.Clear(); + } + } +#endif +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Message/Dispatcher/Interface/IRouteMessageHandler.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Message/Dispatcher/Interface/IRouteMessageHandler.cs new file mode 100644 index 0000000..f027aec --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Message/Dispatcher/Interface/IRouteMessageHandler.cs @@ -0,0 +1,338 @@ +using Fantasy.Async; +using Fantasy.Entitas; +using Fantasy.InnerMessage; +using Fantasy.Network; +using Fantasy.Serialize; + +#if FANTASY_NET +// ReSharper disable InconsistentNaming + +namespace Fantasy.Network.Interface +{ + /// + /// 表示路由消息处理器的接口,处理特定类型的路由消息。 + /// + public interface IRouteMessageHandler + { + /// + /// 获取处理的消息类型。 + /// + /// 消息类型。 + public Type Type(); + + /// + /// 处理路由消息的方法。 + /// + /// 会话对象。 + /// 实体对象。 + /// RPC标识。 + /// 要处理的路由消息。 + /// 异步任务。 + FTask Handle(Session session, Entity entity, uint rpcId, object routeMessage); + } + + /// + /// 泛型路由基类,实现了 接口,用于处理特定实体和路由消息类型的路由。 + /// + /// 实体类型。 + /// 路由消息类型。 + public abstract class Route : IRouteMessageHandler where TEntity : Entity where TMessage : IRouteMessage + { + /// + /// 获取处理的消息类型。 + /// + /// 消息类型。 + public Type Type() + { + return typeof(TMessage); + } + + /// + /// 处理路由消息的方法。 + /// + /// 会话对象。 + /// 实体对象。 + /// RPC标识。 + /// 要处理的路由消息。 + /// 异步任务。 + public async FTask Handle(Session session, Entity entity, uint rpcId, object routeMessage) + { + if (routeMessage is not TMessage ruteMessage) + { + Log.Error($"Message type conversion error: {routeMessage.GetType().FullName} to {typeof(TMessage).Name}"); + return; + } + + if (entity is not TEntity tEntity) + { + Log.Error($"Route type conversion error: {entity.GetType().Name} to {nameof(TEntity)}"); + return; + } + + try + { + await Run(tEntity, ruteMessage); + } + catch (Exception e) + { + if (entity is not Scene scene) + { + scene = entity.Scene; + } + + Log.Error($"SceneConfigId:{session.Scene.SceneConfigId} ProcessConfigId:{scene.Process.Id} SceneType:{scene.SceneType} EntityId {tEntity.Id} : Error {e}"); + } + } + + /// + /// 运行路由消息处理逻辑。 + /// + /// 实体对象。 + /// 要处理的路由消息。 + /// 异步任务。 + protected abstract FTask Run(TEntity entity, TMessage message); + } + + /// + /// 泛型路由RPC基类,实现了 接口,用于处理请求和响应类型的路由。 + /// + /// 实体类型。 + /// 路由请求类型。 + /// 路由响应类型。 + public abstract class RouteRPC : IRouteMessageHandler where TEntity : Entity where TRouteRequest : IRouteRequest where TRouteResponse : AMessage, IRouteResponse, new() + { + /// + /// 获取处理的消息类型。 + /// + /// 消息类型。 + public Type Type() + { + return typeof(TRouteRequest); + } + + /// + /// 处理路由消息的方法。 + /// + /// 会话对象。 + /// 实体对象。 + /// RPC标识。 + /// 要处理的路由消息。 + /// 异步任务。 + public async FTask Handle(Session session, Entity entity, uint rpcId, object routeMessage) + { + if (routeMessage is not TRouteRequest tRouteRequest) + { + Log.Error($"Message type conversion error: {routeMessage.GetType().FullName} to {typeof(TRouteRequest).Name}"); + return; + } + + if (entity is not TEntity tEntity) + { + Log.Error($"Route type conversion error: {entity.GetType().Name} to {nameof(TEntity)}"); + return; + } + + var isReply = false; + var response = new TRouteResponse(); + + void Reply() + { + if (isReply) + { + return; + } + + isReply = true; + + if (session.IsDisposed) + { + return; + } + + session.Send(response, rpcId); + } + + try + { + await Run(tEntity, tRouteRequest, response, Reply); + } + catch (Exception e) + { + if (entity is not Scene scene) + { + scene = entity.Scene; + } + + Log.Error($"SceneConfigId:{session.Scene.SceneConfigId} ProcessConfigId:{scene.Process.Id} SceneType:{scene.SceneType} EntityId {tEntity.Id} : Error {e}"); + response.ErrorCode = InnerErrorCode.ErrRpcFail; + } + finally + { + Reply(); + } + } + + /// + /// 运行路由消息处理逻辑。 + /// + /// 实体对象。 + /// 请求路由消息。 + /// 响应路由消息。 + /// 发送响应的方法。 + /// 异步任务。 + protected abstract FTask Run(TEntity entity, TRouteRequest request, TRouteResponse response, Action reply); + } + + /// + /// 泛型可寻址路由基类,实现了 接口,用于处理特定实体和可寻址路由消息类型的路由。 + /// + /// 实体类型。 + /// 可寻址路由消息类型。 + public abstract class Addressable : IRouteMessageHandler where TEntity : Entity where TMessage : IAddressableRouteMessage + { + /// + /// 获取消息类型。 + /// + /// 消息类型。 + public Type Type() + { + return typeof(TMessage); + } + + /// + /// 处理可寻址路由消息。 + /// + /// 会话。 + /// 实体。 + /// RPC标识。 + /// 可寻址路由消息。 + public async FTask Handle(Session session, Entity entity, uint rpcId, object routeMessage) + { + if (routeMessage is not TMessage ruteMessage) + { + Log.Error($"Message type conversion error: {routeMessage.GetType().FullName} to {typeof(TMessage).Name}"); + return; + } + + if (entity is not TEntity tEntity) + { + Log.Error($"Route type conversion error: {entity.GetType().Name} to {nameof(TEntity)}"); + return; + } + + try + { + await Run(tEntity, ruteMessage); + } + catch (Exception e) + { + if (entity is not Scene scene) + { + scene = entity.Scene; + } + + Log.Error($"SceneConfigId:{session.Scene.SceneConfigId} ProcessConfigId:{scene.Process.Id} SceneType:{scene.SceneType} EntityId {tEntity.Id} : Error {e}"); + } + finally + { + session.Send(new RouteResponse(), rpcId); + } + } + + /// + /// 运行处理可寻址路由消息。 + /// + /// 实体。 + /// 可寻址路由消息。 + protected abstract FTask Run(TEntity entity, TMessage message); + } + + /// + /// 泛型可寻址RPC路由基类,实现了 接口,用于处理特定实体和可寻址RPC路由请求类型的路由。 + /// + /// 实体类型。 + /// 可寻址RPC路由请求类型。 + /// 可寻址RPC路由响应类型。 + public abstract class AddressableRPC : IRouteMessageHandler where TEntity : Entity where TRouteRequest : IAddressableRouteRequest where TRouteResponse : IAddressableRouteResponse, new() + { + /// + /// 获取消息类型。 + /// + /// 消息类型。 + public Type Type() + { + return typeof(TRouteRequest); + } + + /// + /// 处理可寻址RPC路由请求。 + /// + /// 会话。 + /// 实体。 + /// RPC标识。 + /// 可寻址RPC路由请求。 + public async FTask Handle(Session session, Entity entity, uint rpcId, object routeMessage) + { + if (routeMessage is not TRouteRequest tRouteRequest) + { + Log.Error($"Message type conversion error: {routeMessage.GetType().FullName} to {typeof(TRouteRequest).Name}"); + return; + } + + if (entity is not TEntity tEntity) + { + Log.Error($"Route type conversion error: {entity.GetType().Name} to {nameof(TEntity)}"); + return; + } + + var isReply = false; + var response = new TRouteResponse(); + + void Reply() + { + if (isReply) + { + return; + } + + isReply = true; + + if (session.IsDisposed) + { + return; + } + + session.Send(response, rpcId); + } + + try + { + await Run(tEntity, tRouteRequest, response, Reply); + } + catch (Exception e) + { + if (entity is not Scene scene) + { + scene = entity.Scene; + } + + Log.Error($"SceneConfigId:{session.Scene.SceneConfigId} ProcessConfigId:{scene.Process.Id} SceneType:{scene.SceneType} EntityId {tEntity.Id} : Error {e}"); + response.ErrorCode = InnerErrorCode.ErrRpcFail; + } + finally + { + Reply(); + } + } + + /// + /// 运行处理可寻址RPC路由请求。 + /// + /// 实体。 + /// 可寻址RPC路由请求。 + /// 可寻址RPC路由响应。 + /// 回复操作。 + protected abstract FTask Run(TEntity entity, TRouteRequest request, TRouteResponse response, Action reply); + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Message/Dispatcher/MessageDispatcherComponent.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Message/Dispatcher/MessageDispatcherComponent.cs new file mode 100644 index 0000000..c3462d6 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Message/Dispatcher/MessageDispatcherComponent.cs @@ -0,0 +1,427 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Fantasy.Assembly; +using Fantasy.Async; +using Fantasy.DataStructure.Collection; +using Fantasy.DataStructure.Dictionary; +using Fantasy.Entitas; +using Fantasy.InnerMessage; +using Fantasy.Network; + +#pragma warning disable CS8602 // Dereference of a possibly null reference. +#pragma warning disable CS8600 // Converting null literal or possible null value to non-nullable type. +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. + +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member +namespace Fantasy.Network.Interface +{ + /// + /// 用于存储消息处理器的信息,包括类型和对象实例。 + /// + /// 消息处理器的类型 + internal sealed class HandlerInfo + { + /// + /// 获取或设置消息处理器对象。 + /// + public T Obj; + /// + /// 获取或设置消息处理器的类型。 + /// + public Type Type; + } + + /// + /// 网络消息分发组件。 + /// + public sealed class MessageDispatcherComponent : Entity, IAssembly + { + public long AssemblyIdentity { get; set; } + private readonly Dictionary _responseTypes = new Dictionary(); + private readonly DoubleMapDictionary _networkProtocols = new DoubleMapDictionary(); + private readonly Dictionary _messageHandlers = new Dictionary(); + private readonly OneToManyList _assemblyResponseTypes = new OneToManyList(); + private readonly OneToManyList _assemblyNetworkProtocols = new OneToManyList(); + private readonly OneToManyList> _assemblyMessageHandlers = new OneToManyList>(); +#if FANTASY_UNITY + + private readonly Dictionary _messageDelegateHandlers = new Dictionary(); +#endif +#if FANTASY_NET + private readonly Dictionary _customRouteMap = new Dictionary(); + private readonly OneToManyList _assemblyCustomRouteMap = new OneToManyList(); + private readonly Dictionary _routeMessageHandlers = new Dictionary(); + private readonly OneToManyList> _assemblyRouteMessageHandlers = new OneToManyList>(); +#endif + private CoroutineLock _receiveRouteMessageLock; + + #region Initialize + + internal async FTask Initialize() + { + _receiveRouteMessageLock = Scene.CoroutineLockComponent.Create(GetType().TypeHandle.Value.ToInt64()); + await AssemblySystem.Register(this); + return this; + } + + public async FTask Load(long assemblyIdentity) + { + var tcs = FTask.Create(false); + Scene.ThreadSynchronizationContext.Post(() => + { + LoadInner(assemblyIdentity); + tcs.SetResult(); + }); + await tcs; + } + + private void LoadInner(long assemblyIdentity) + { + // 遍历所有实现了IMessage接口的类型,获取OpCode并添加到_networkProtocols字典中 + foreach (var type in AssemblySystem.ForEach(assemblyIdentity, typeof(IMessage))) + { + var obj = (IMessage) Activator.CreateInstance(type); + var opCode = obj.OpCode(); + + _networkProtocols.Add(opCode, type); + + var responseType = type.GetProperty("ResponseType"); + + // 如果类型具有ResponseType属性,将其添加到_responseTypes字典中 + if (responseType != null) + { + _responseTypes.Add(type, responseType.PropertyType); + _assemblyResponseTypes.Add(assemblyIdentity, type); + } + + _assemblyNetworkProtocols.Add(assemblyIdentity, opCode); + } + + // 遍历所有实现了IMessageHandler接口的类型,创建实例并添加到_messageHandlers字典中 + foreach (var type in AssemblySystem.ForEach(assemblyIdentity, typeof(IMessageHandler))) + { + var obj = (IMessageHandler) Activator.CreateInstance(type); + + if (obj == null) + { + throw new Exception($"message handle {type.Name} is null"); + } + + var key = obj.Type(); + _messageHandlers.Add(key, obj); + _assemblyMessageHandlers.Add(assemblyIdentity, new HandlerInfo() + { + Obj = obj, Type = key + }); + } + + // 如果编译符号FANTASY_NET存在,遍历所有实现了IRouteMessageHandler接口的类型,创建实例并添加到_routeMessageHandlers字典中 +#if FANTASY_NET + foreach (var type in AssemblySystem.ForEach(assemblyIdentity, typeof(IRouteMessageHandler))) + { + var obj = (IRouteMessageHandler) Activator.CreateInstance(type); + + if (obj == null) + { + throw new Exception($"message handle {type.Name} is null"); + } + + var key = obj.Type(); + _routeMessageHandlers.Add(key, obj); + _assemblyRouteMessageHandlers.Add(assemblyIdentity, new HandlerInfo() + { + Obj = obj, Type = key + }); + } + + foreach (var type in AssemblySystem.ForEach(assemblyIdentity, typeof(ICustomRoute))) + { + var obj = (ICustomRoute) Activator.CreateInstance(type); + + if (obj == null) + { + throw new Exception($"message handle {type.Name} is null"); + } + + var opCode = obj.OpCode(); + _customRouteMap[opCode] = obj.RouteType; + _assemblyCustomRouteMap.Add(assemblyIdentity, opCode); + } +#endif + } + + public async FTask ReLoad(long assemblyIdentity) + { + var tcs = FTask.Create(false); + Scene.ThreadSynchronizationContext.Post(() => + { + OnUnLoadInner(assemblyIdentity); + LoadInner(assemblyIdentity); + tcs.SetResult(); + }); + await tcs; + } + + public async FTask OnUnLoad(long assemblyIdentity) + { + var tcs = FTask.Create(false); + Scene.ThreadSynchronizationContext.Post(() => + { + OnUnLoadInner(assemblyIdentity); + tcs.SetResult(); + }); + await tcs; + } + + private void OnUnLoadInner(long assemblyIdentity) + { + // 移除程序集对应的ResponseType类型和OpCode信息 + if (_assemblyResponseTypes.TryGetValue(assemblyIdentity, out var removeResponseTypes)) + { + foreach (var removeResponseType in removeResponseTypes) + { + _responseTypes.Remove(removeResponseType); + } + + _assemblyResponseTypes.RemoveByKey(assemblyIdentity); + } + + if (_assemblyNetworkProtocols.TryGetValue(assemblyIdentity, out var removeNetworkProtocols)) + { + foreach (var removeNetworkProtocol in removeNetworkProtocols) + { + _networkProtocols.RemoveByKey(removeNetworkProtocol); + } + + _assemblyNetworkProtocols.RemoveByKey(assemblyIdentity); + } + + // 移除程序集对应的消息处理器信息 + if (_assemblyMessageHandlers.TryGetValue(assemblyIdentity, out var removeMessageHandlers)) + { + foreach (var removeMessageHandler in removeMessageHandlers) + { + _messageHandlers.Remove(removeMessageHandler.Type); + } + + _assemblyMessageHandlers.RemoveByKey(assemblyIdentity); + } + + // 如果编译符号FANTASY_NET存在,移除程序集对应的路由消息处理器信息 +#if FANTASY_NET + if (_assemblyRouteMessageHandlers.TryGetValue(assemblyIdentity, out var removeRouteMessageHandlers)) + { + foreach (var removeRouteMessageHandler in removeRouteMessageHandlers) + { + _routeMessageHandlers.Remove(removeRouteMessageHandler.Type); + } + + _assemblyRouteMessageHandlers.RemoveByKey(assemblyIdentity); + } + + if (_assemblyCustomRouteMap.TryGetValue(assemblyIdentity, out var removeCustomRouteMap)) + { + foreach (var removeCustom in removeCustomRouteMap) + { + _customRouteMap.Remove(removeCustom); + } + + _assemblyCustomRouteMap.RemoveByKey(assemblyIdentity); + } +#endif + } + +#if FANTASY_UNITY + /// + /// 手动注册一个消息处理器。 + /// + /// + /// + public void RegisterHandler(MessageDelegate @delegate) where T : IMessage + { + var type = typeof(T); + + if (!_messageDelegateHandlers.TryGetValue(type, out var messageDelegate)) + { + messageDelegate = new MessageDelegateHandler(); + _messageDelegateHandlers.Add(type,messageDelegate); + } + + messageDelegate.Register(@delegate); + } + + /// + /// 手动卸载一个消息处理器,必须是通过RegisterHandler方法注册的消息处理器。 + /// + /// + /// + public void UnRegisterHandler(MessageDelegate @delegate) where T : IMessage + { + var type = typeof(T); + + if (!_messageDelegateHandlers.TryGetValue(type, out var messageDelegate)) + { + return; + } + + if (messageDelegate.UnRegister(@delegate) != 0) + { + return; + } + + _messageDelegateHandlers.Remove(type); + } +#endif + + #endregion + + /// + /// 处理普通消息,将消息分发给相应的消息处理器。 + /// + /// 会话对象 + /// 消息类型 + /// 消息对象 + /// RPC标识 + /// 协议码 + public void MessageHandler(Session session, Type type, object message, uint rpcId, uint protocolCode) + { +#if FANTASY_UNITY + if(_messageDelegateHandlers.TryGetValue(type,out var messageDelegateHandler)) + { + messageDelegateHandler.Handle(session, message); + return; + } +#endif + if (!_messageHandlers.TryGetValue(type, out var messageHandler)) + { + Log.Warning($"Scene:{session.Scene.Id} Found Unhandled Message: {message.GetType()}"); + return; + } + + // 调用消息处理器的Handle方法并启动协程执行处理逻辑 + messageHandler.Handle(session, rpcId, protocolCode, message).Coroutine(); + } + + // 如果编译符号FANTASY_NET存在,定义处理路由消息的方法 +#if FANTASY_NET + /// + /// 处理路由消息,将消息分发给相应的路由消息处理器。 + /// + /// 会话对象 + /// 消息类型 + /// 实体对象 + /// 消息对象 + /// RPC标识 + public async FTask RouteMessageHandler(Session session, Type type, Entity entity, object message, uint rpcId) + { + if (!_routeMessageHandlers.TryGetValue(type, out var routeMessageHandler)) + { + Log.Warning($"Scene:{session.Scene.Id} Found Unhandled RouteMessage: {message.GetType()}"); + + if (message is IRouteRequest request) + { + FailRouteResponse(session, request.GetType(), InnerErrorCode.ErrEntityNotFound, rpcId); + } + + return; + } + + var runtimeId = entity.RuntimeId; + var sessionRuntimeId = session.RuntimeId; + + if (entity is Scene) + { + // 如果是Scene的话、就不要加锁了、如果加锁很一不小心就可能会造成死锁 + await routeMessageHandler.Handle(session, entity, rpcId, message); + return; + } + + // 使用协程锁来确保多线程安全 + using (await _receiveRouteMessageLock.Wait(runtimeId)) + { + if (sessionRuntimeId != session.RuntimeId) + { + return; + } + + if (runtimeId != entity.RuntimeId) + { + if (message is IRouteRequest request) + { + FailRouteResponse(session, request.GetType(), InnerErrorCode.ErrEntityNotFound, rpcId); + } + + return; + } + + await routeMessageHandler.Handle(session, entity, rpcId, message); + } + } + + internal bool GetCustomRouteType(long protocolCode,out int routeType) + { + return _customRouteMap.TryGetValue(protocolCode, out routeType); + } +#endif + internal void FailRouteResponse(Session session, Type requestType, uint error, uint rpcId) + { + var response = CreateRouteResponse(requestType, error); + session.Send(response, rpcId); + } + + internal IResponse CreateResponse(Type requestType, uint error) + { + IResponse response; + + if (_responseTypes.TryGetValue(requestType, out var responseType)) + { + response = (IResponse) Activator.CreateInstance(responseType); + } + else + { + response = new Response(); + } + + response.ErrorCode = error; + return response; + } + + internal IRouteResponse CreateRouteResponse(Type requestType, uint error) + { + IRouteResponse response; + + if (_responseTypes.TryGetValue(requestType, out var responseType)) + { + response = (IRouteResponse) Activator.CreateInstance(responseType); + } + else + { + response = new RouteResponse(); + } + + response.ErrorCode = error; + return response; + } + + /// + /// 根据消息类型获取对应的OpCode。 + /// + /// 消息类型 + /// 消息对应的OpCode + public uint GetOpCode(Type type) + { + return _networkProtocols.GetKeyByValue(type); + } + + /// + /// 根据OpCode获取对应的消息类型。 + /// + /// OpCode + /// OpCode对应的消息类型 + public Type GetOpCodeType(uint code) + { + return _networkProtocols.GetValueByKey(code); + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Message/IMessage.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Message/IMessage.cs new file mode 100644 index 0000000..704b736 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Message/IMessage.cs @@ -0,0 +1,83 @@ +using System; +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member + +namespace Fantasy.Network.Interface +{ + /// + /// 表示通用消息接口。 + /// + public interface IMessage + { + /// + /// 获取消息的操作代码。 + /// + /// 操作代码。 + uint OpCode(); + } + + /// + /// 表示请求消息接口。 + /// + public interface IRequest : IMessage + { + + } + + /// + /// 表示响应消息接口。 + /// + public interface IResponse : IMessage + { + /// + /// 获取或设置错误代码。 + /// + uint ErrorCode { get; set; } + } + // 普通路由消息 + /// + /// 表示普通路由消息的接口,继承自请求接口。 + /// + public interface IRouteMessage : IRequest + { + + } + + /// + /// 普通路由请求接口,继承自普通路由消息接口。 + /// + public interface IRouteRequest : IRouteMessage { } + /// + /// 普通路由响应接口,继承自响应接口。 + /// + public interface IRouteResponse : IResponse { } + // 可寻址协议 + /// + /// 表示可寻址协议的普通路由消息接口,继承自普通路由消息接口。 + /// + public interface IAddressableRouteMessage : IRouteMessage { } + /// + /// 可寻址协议的普通路由请求接口,继承自可寻址协议的普通路由消息接口。 + /// + public interface IAddressableRouteRequest : IRouteRequest { } + /// + /// 可寻址协议的普通路由响应接口,继承自普通路由响应接口。 + /// + public interface IAddressableRouteResponse : IRouteResponse { } + // 自定义Route协议 + public interface ICustomRoute : IMessage + { + int RouteType { get; } + } + /// + /// 表示自定义Route协议的普通路由消息接口,继承自普通路由消息接口。 + /// + public interface ICustomRouteMessage : IRouteMessage, ICustomRoute { } + /// + /// 自定义Route协议的普通路由请求接口,继承自自定义Route协议的普通路由消息接口。 + /// + public interface ICustomRouteRequest : IRouteRequest, ICustomRoute { } + /// + /// 自定义Route协议的普通路由响应接口,继承自普通路由响应接口。 + /// + public interface ICustomRouteResponse : IRouteResponse { } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Message/InnerMessage.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Message/InnerMessage.cs new file mode 100644 index 0000000..8910a34 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Message/InnerMessage.cs @@ -0,0 +1,209 @@ +using Fantasy.Network.Interface; +using Fantasy.Serialize; +using ProtoBuf; + +// ReSharper disable InconsistentNaming +// ReSharper disable PropertyCanBeMadeInitOnly.Global +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member + +namespace Fantasy.InnerMessage +{ + [ProtoContract] + public sealed partial class BenchmarkMessage : AMessage, IMessage + { + public uint OpCode() + { + return Fantasy.Network.OpCode.BenchmarkMessage; + } + } + [ProtoContract] + public partial class BenchmarkRequest : AMessage, IRequest + { + public uint OpCode() + { + return Fantasy.Network.OpCode.BenchmarkRequest; + } + [ProtoIgnore] + public BenchmarkResponse ResponseType { get; set; } + [ProtoMember(1)] + public long RpcId { get; set; } + } + + [ProtoContract] + public partial class BenchmarkResponse : AMessage, IResponse + { + public uint OpCode() + { + return Fantasy.Network.OpCode.BenchmarkResponse; + } + [ProtoMember(1)] + public long RpcId { get; set; } + [ProtoMember(2)] + public uint ErrorCode { get; set; } + } + public sealed partial class Response : AMessage, IResponse + { + public uint OpCode() + { + return Fantasy.Network.OpCode.DefaultResponse; + } + [ProtoMember(1)] + public long RpcId { get; set; } + [ProtoMember(2)] + public uint ErrorCode { get; set; } + } + [ProtoContract] + public sealed partial class RouteResponse : AMessage, IRouteResponse + { + public uint OpCode() + { + return Fantasy.Network.OpCode.DefaultRouteResponse; + } + [ProtoMember(1)] + public long RpcId { get; set; } + [ProtoMember(2)] + public uint ErrorCode { get; set; } + } + [ProtoContract] + public partial class PingRequest : AMessage, IRequest + { + public uint OpCode() + { + return Fantasy.Network.OpCode.PingRequest; + } + [ProtoIgnore] + public PingResponse ResponseType { get; set; } + [ProtoMember(1)] + public long RpcId { get; set; } + } + + [ProtoContract] + public partial class PingResponse : AMessage, IResponse + { + public uint OpCode() + { + return Fantasy.Network.OpCode.PingResponse; + } + [ProtoMember(1)] + public long RpcId { get; set; } + [ProtoMember(2)] + public uint ErrorCode { get; set; } + [ProtoMember(3)] + public long Now; + } + [ProtoContract] + public partial class I_AddressableAdd_Request : AMessage, IRouteRequest + { + [ProtoIgnore] + public I_AddressableAdd_Response ResponseType { get; set; } + public uint OpCode() { return Fantasy.Network.OpCode.AddressableAddRequest; } + public long RouteTypeOpCode() { return 1; } + [ProtoMember(1)] + public long AddressableId { get; set; } + [ProtoMember(2)] + public long RouteId { get; set; } + [ProtoMember(3)] + public bool IsLock { get; set; } + } + [ProtoContract] + public partial class I_AddressableAdd_Response : AMessage, IRouteResponse + { + public uint OpCode() { return Fantasy.Network.OpCode.AddressableAddResponse; } + [ProtoMember(1)] + public uint ErrorCode { get; set; } + } + [ProtoContract] + public partial class I_AddressableGet_Request : AMessage, IRouteRequest + { + [ProtoIgnore] + public I_AddressableGet_Response ResponseType { get; set; } + public uint OpCode() { return Fantasy.Network.OpCode.AddressableGetRequest; } + public long RouteTypeOpCode() { return 1; } + [ProtoMember(1)] + public long AddressableId { get; set; } + } + [ProtoContract] + public partial class I_AddressableGet_Response : AMessage, IRouteResponse + { + public uint OpCode() { return Fantasy.Network.OpCode.AddressableGetResponse; } + [ProtoMember(2)] + public uint ErrorCode { get; set; } + [ProtoMember(1)] + public long RouteId { get; set; } + } + [ProtoContract] + public partial class I_AddressableRemove_Request : AMessage, IRouteRequest + { + [ProtoIgnore] + public I_AddressableRemove_Response ResponseType { get; set; } + public uint OpCode() { return Fantasy.Network.OpCode.AddressableRemoveRequest; } + public long RouteTypeOpCode() { return 1; } + [ProtoMember(1)] + public long AddressableId { get; set; } + } + [ProtoContract] + public partial class I_AddressableRemove_Response : AMessage, IRouteResponse + { + public uint OpCode() { return Fantasy.Network.OpCode.AddressableRemoveResponse; } + [ProtoMember(1)] + public uint ErrorCode { get; set; } + } + [ProtoContract] + public partial class I_AddressableLock_Request : AMessage, IRouteRequest + { + [ProtoIgnore] + public I_AddressableLock_Response ResponseType { get; set; } + public uint OpCode() { return Fantasy.Network.OpCode.AddressableLockRequest; } + public long RouteTypeOpCode() { return 1; } + [ProtoMember(1)] + public long AddressableId { get; set; } + } + [ProtoContract] + public partial class I_AddressableLock_Response : AMessage, IRouteResponse + { + public uint OpCode() { return Fantasy.Network.OpCode.AddressableLockResponse; } + [ProtoMember(1)] + public uint ErrorCode { get; set; } + } + [ProtoContract] + public partial class I_AddressableUnLock_Request : AMessage, IRouteRequest + { + [ProtoIgnore] + public I_AddressableUnLock_Response ResponseType { get; set; } + public uint OpCode() { return Fantasy.Network.OpCode.AddressableUnLockRequest; } + public long RouteTypeOpCode() { return 1; } + [ProtoMember(1)] + public long AddressableId { get; set; } + [ProtoMember(2)] + public long RouteId { get; set; } + [ProtoMember(3)] + public string Source { get; set; } + } + [ProtoContract] + public partial class I_AddressableUnLock_Response : AMessage, IRouteResponse + { + public uint OpCode() { return Fantasy.Network.OpCode.AddressableUnLockResponse; } + [ProtoMember(1)] + public uint ErrorCode { get; set; } + } + [ProtoContract] + public partial class LinkEntity_Request : AMessage, IRouteRequest + { + public uint OpCode() { return Fantasy.Network.OpCode.LinkEntityRequest; } + public long RouteTypeOpCode() { return 1; } + [ProtoMember(1)] + public int EntityType { get; set; } + [ProtoMember(2)] + public long RuntimeId { get; set; } + [ProtoMember(3)] + public long LinkGateSessionRuntimeId { get; set; } + } + [ProtoContract] + public partial class LinkEntity_Response : AMessage, IRouteResponse + { + public uint OpCode() { return Fantasy.Network.OpCode.LinkEntityResponse; } + [ProtoMember(1)] + public uint ErrorCode { get; set; } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Message/PacketParser/Handler/BufferPacketParser.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Message/PacketParser/Handler/BufferPacketParser.cs new file mode 100644 index 0000000..e4d1540 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Message/PacketParser/Handler/BufferPacketParser.cs @@ -0,0 +1,386 @@ +using System; +using System.Buffers; +using System.IO; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using Fantasy.Helper; +using Fantasy.Network; +using Fantasy.Network.Interface; +using Fantasy.PacketParser.Interface; +using Fantasy.Serialize; + +// ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member + +#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. +namespace Fantasy.PacketParser +{ + /// + /// BufferPacketParser消息格式化器抽象类 + /// 这个不会用在TCP协议中、因此不用考虑分包和粘包的问题。 + /// 目前这个只会用在KCP协议中、因为KCP出来的就是一个完整的包、所以可以一次性全部解析出来。 + /// 如果是用在其他协议上可能会出现问题。 + /// + public abstract class BufferPacketParser : APacketParser + { + protected uint RpcId; + protected long RouteId; + protected uint ProtocolCode; + protected int MessagePacketLength; + public override void Dispose() + { + RpcId = 0; + RouteId = 0; + ProtocolCode = 0; + MessagePacketLength = 0; + base.Dispose(); + } + /// + /// 解包方法 + /// + /// buffer + /// count + /// packInfo + /// + public abstract bool UnPack(byte[] buffer, ref int count, out APackInfo packInfo); + } +#if FANTASY_NET + /// + /// 服务器之间专用的BufferPacketParser消息格式化器 + /// + public sealed class InnerBufferPacketParser : BufferPacketParser + { + /// + /// + /// + /// + /// + /// + /// + /// + public override unsafe bool UnPack(byte[] buffer, ref int count, out APackInfo packInfo) + { + packInfo = null; + + if (buffer.Length < count) + { + throw new ScanException($"The buffer length is less than the specified count. buffer.Length={buffer.Length} count={count}"); + } + + if (count < Packet.InnerPacketHeadLength) + { + // 如果内存资源中的数据长度小于内部消息头的长度,无法解析 + return false; + } + + fixed (byte* bufferPtr = buffer) + { + MessagePacketLength = *(int*)bufferPtr; + + if (MessagePacketLength > Packet.PacketBodyMaxLength || count < MessagePacketLength) + { + // 检查消息体长度是否超出限制 + throw new ScanException($"The received information exceeds the maximum limit = {MessagePacketLength}"); + } + + ProtocolCode = *(uint*)(bufferPtr + Packet.PacketLength); + RpcId = *(uint*)(bufferPtr + Packet.InnerPacketRpcIdLocation); + RouteId = *(long*)(bufferPtr + Packet.InnerPacketRouteRouteIdLocation); + } + + packInfo = InnerPackInfo.Create(Network); + packInfo.RpcId = RpcId; + packInfo.RouteId = RouteId; + packInfo.ProtocolCode = ProtocolCode; + packInfo.RentMemoryStream(MemoryStreamBufferSource.UnPack, count).Write(buffer, 0, count); + return true; + } + + public override MemoryStreamBuffer Pack(ref uint rpcId, ref long routeId, MemoryStreamBuffer memoryStream, IMessage message) + { + return memoryStream == null ? Pack(ref rpcId, ref routeId, message) : Pack(ref rpcId, ref routeId, memoryStream); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private unsafe MemoryStreamBuffer Pack(ref uint rpcId, ref long routeId, MemoryStreamBuffer memoryStream) + { + fixed (byte* bufferPtr = memoryStream.GetBuffer()) + { + *(uint*)(bufferPtr + Packet.InnerPacketRpcIdLocation) = rpcId; + *(long*)(bufferPtr + Packet.InnerPacketRouteRouteIdLocation) = routeId; + } + + return memoryStream; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private unsafe MemoryStreamBuffer Pack(ref uint rpcId, ref long routeId, IMessage message) + { + var memoryStreamLength = 0; + var messageType = message.GetType(); + var memoryStream = Network.MemoryStreamBufferPool.RentMemoryStream(MemoryStreamBufferSource.Pack); + OpCodeIdStruct opCodeIdStruct = message.OpCode(); + memoryStream.Seek(Packet.InnerPacketHeadLength, SeekOrigin.Begin); + + if (SerializerManager.TryGetSerializer(opCodeIdStruct.OpCodeProtocolType, out var serializer)) + { + serializer.Serialize(messageType, message, memoryStream); + memoryStreamLength = (int)memoryStream.Position; + } + else + { + Log.Error($"type:{messageType} Does not support processing protocol"); + } + + var opCode = Scene.MessageDispatcherComponent.GetOpCode(messageType); + var packetBodyCount = memoryStreamLength - Packet.InnerPacketHeadLength; + + if (packetBodyCount == 0) + { + // protoBuf做了一个优化、就是当序列化的对象里的属性和字段都为默认值的时候就不会序列化任何东西。 + // 为了TCP的分包和粘包、需要判定下是当前包数据不完整还是本应该如此、所以用-1代表。 + packetBodyCount = -1; + } + + if (packetBodyCount > Packet.PacketBodyMaxLength) + { + // 检查消息体长度是否超出限制 + throw new Exception($"Message content exceeds {Packet.PacketBodyMaxLength} bytes"); + } + + fixed (byte* bufferPtr = memoryStream.GetBuffer()) + { + *(int*)bufferPtr = packetBodyCount; + *(uint*)(bufferPtr + Packet.PacketLength) = opCode; + *(uint*)(bufferPtr + Packet.InnerPacketRpcIdLocation) = rpcId; + *(long*)(bufferPtr + Packet.InnerPacketRouteRouteIdLocation) = routeId; + } + + return memoryStream; + } + } +#endif + /// + /// 客户端和服务器之间专用的BufferPacketParser消息格式化器 + /// + public sealed class OuterBufferPacketParser : BufferPacketParser + { + /// + /// + /// + /// + /// + /// + /// + /// + public override unsafe bool UnPack(byte[] buffer, ref int count, out APackInfo packInfo) + { + packInfo = null; + + if (buffer.Length < count) + { + throw new ScanException($"The buffer length is less than the specified count. buffer.Length={buffer.Length} count={count}"); + } + + if (count < Packet.OuterPacketHeadLength) + { + // 如果内存资源中的数据长度小于内部消息头的长度,无法解析 + return false; + } + + fixed (byte* bufferPtr = buffer) + { + MessagePacketLength = *(int*)bufferPtr; + + if (MessagePacketLength > Packet.PacketBodyMaxLength || count < MessagePacketLength) + { + // 检查消息体长度是否超出限制 + throw new ScanException($"The received information exceeds the maximum limit = {MessagePacketLength}"); + } + + ProtocolCode = *(uint*)(bufferPtr + Packet.PacketLength); + RpcId = *(uint*)(bufferPtr + Packet.OuterPacketRpcIdLocation); + } + + packInfo = OuterPackInfo.Create(Network); + packInfo.RpcId = RpcId; + packInfo.ProtocolCode = ProtocolCode; + packInfo.RentMemoryStream(MemoryStreamBufferSource.UnPack, count).Write(buffer, 0, count); + return true; + } + + public override MemoryStreamBuffer Pack(ref uint rpcId, ref long routeId, MemoryStreamBuffer memoryStream, IMessage message) + { + return memoryStream == null ? Pack(ref rpcId, message) : Pack(ref rpcId, memoryStream); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private unsafe MemoryStreamBuffer Pack(ref uint rpcId, MemoryStreamBuffer memoryStream) + { + fixed (byte* bufferPtr = memoryStream.GetBuffer()) + { + *(uint*)(bufferPtr + Packet.InnerPacketRpcIdLocation) = rpcId; + } + + return memoryStream; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private unsafe MemoryStreamBuffer Pack(ref uint rpcId, IMessage message) + { + var memoryStreamLength = 0; + var messageType = message.GetType(); + var memoryStream = Network.MemoryStreamBufferPool.RentMemoryStream(MemoryStreamBufferSource.Pack); + OpCodeIdStruct opCodeIdStruct = message.OpCode(); + memoryStream.Seek(Packet.OuterPacketHeadLength, SeekOrigin.Begin); + + if (SerializerManager.TryGetSerializer(opCodeIdStruct.OpCodeProtocolType, out var serializer)) + { + serializer.Serialize(messageType, message, memoryStream); + memoryStreamLength = (int)memoryStream.Position; + } + else + { + Log.Error($"type:{messageType} Does not support processing protocol"); + } + + var opCode = Scene.MessageDispatcherComponent.GetOpCode(messageType); + var packetBodyCount = memoryStreamLength - Packet.OuterPacketHeadLength; + + if (packetBodyCount == 0) + { + // protoBuf做了一个优化、就是当序列化的对象里的属性和字段都为默认值的时候就不会序列化任何东西。 + // 为了TCP的分包和粘包、需要判定下是当前包数据不完整还是本应该如此、所以用-1代表。 + packetBodyCount = -1; + } + + if (packetBodyCount > Packet.PacketBodyMaxLength) + { + // 检查消息体长度是否超出限制 + throw new Exception($"Message content exceeds {Packet.PacketBodyMaxLength} bytes"); + } + + fixed (byte* bufferPtr = memoryStream.GetBuffer()) + { + *(int*)bufferPtr = packetBodyCount; + *(uint*)(bufferPtr + Packet.PacketLength) = opCode; + *(uint*)(bufferPtr + Packet.OuterPacketRpcIdLocation) = rpcId; + } + + return memoryStream; + } + } + /// + /// Webgl专用的客户端和服务器之间专用的BufferPacketParser消息格式化器 + /// + public sealed class OuterWebglBufferPacketParser : BufferPacketParser + { + /// + /// + /// + /// + /// + /// + /// + /// + public override bool UnPack(byte[] buffer, ref int count, out APackInfo packInfo) + { + packInfo = null; + + if (buffer.Length < count) + { + throw new ScanException($"The buffer length is less than the specified count. buffer.Length={buffer.Length} count={count}"); + } + + if (count < Packet.OuterPacketHeadLength) + { + // 如果内存资源中的数据长度小于内部消息头的长度,无法解析 + return false; + } + + MessagePacketLength = BitConverter.ToInt32(buffer, 0); + + if (MessagePacketLength > Packet.PacketBodyMaxLength || count < MessagePacketLength) + { + // 检查消息体长度是否超出限制 + throw new ScanException($"The received information exceeds the maximum limit = {MessagePacketLength}"); + } + + ProtocolCode = BitConverter.ToUInt32(buffer, Packet.PacketLength); + RpcId = BitConverter.ToUInt32(buffer, Packet.OuterPacketRpcIdLocation); + + packInfo = OuterPackInfo.Create(Network); + packInfo.RpcId = RpcId; + packInfo.ProtocolCode = ProtocolCode; + packInfo.RentMemoryStream(MemoryStreamBufferSource.UnPack, count).Write(buffer, 0, count); + return true; + } + + public override MemoryStreamBuffer Pack(ref uint rpcId, ref long routeId, MemoryStreamBuffer memoryStream, IMessage message) + { + return memoryStream == null ? Pack(ref rpcId, message) : Pack(ref rpcId, memoryStream); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private MemoryStreamBuffer Pack(ref uint rpcId, MemoryStreamBuffer memoryStream) + { + var buffer = memoryStream.GetBuffer().AsSpan(); +#if FANTASY_NET + MemoryMarshal.Write(buffer.Slice(Packet.OuterPacketRpcIdLocation, sizeof(uint)), in rpcId); +#endif +#if FANTASY_UNITY + MemoryMarshal.Write(buffer.Slice(Packet.OuterPacketRpcIdLocation, sizeof(uint)), ref rpcId); +#endif + return memoryStream; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private MemoryStreamBuffer Pack(ref uint rpcId, IMessage message) + { + var memoryStreamLength = 0; + var messageType = message.GetType(); + var memoryStream = Network.MemoryStreamBufferPool.RentMemoryStream(MemoryStreamBufferSource.UnPack); + OpCodeIdStruct opCodeIdStruct = message.OpCode(); + memoryStream.Seek(Packet.OuterPacketHeadLength, SeekOrigin.Begin); + + if (SerializerManager.TryGetSerializer(opCodeIdStruct.OpCodeProtocolType, out var serializer)) + { + serializer.Serialize(messageType, message, memoryStream); + memoryStreamLength = (int)memoryStream.Position; + } + else + { + Log.Error($"type:{messageType} Does not support processing protocol"); + } + + var opCode = Scene.MessageDispatcherComponent.GetOpCode(messageType); + var packetBodyCount = memoryStreamLength - Packet.OuterPacketHeadLength; + + if (packetBodyCount == 0) + { + // protoBuf做了一个优化、就是当序列化的对象里的属性和字段都为默认值的时候就不会序列化任何东西。 + // 为了TCP的分包和粘包、需要判定下是当前包数据不完整还是本应该如此、所以用-1代表。 + packetBodyCount = -1; + } + + if (packetBodyCount > Packet.PacketBodyMaxLength) + { + // 检查消息体长度是否超出限制 + throw new Exception($"Message content exceeds {Packet.PacketBodyMaxLength} bytes"); + } + + var buffer = memoryStream.GetBuffer().AsSpan(); +#if FANTASY_NET + MemoryMarshal.Write(buffer, in packetBodyCount); + MemoryMarshal.Write(buffer.Slice(Packet.PacketLength, sizeof(uint)), in opCode); + MemoryMarshal.Write(buffer.Slice(Packet.OuterPacketRpcIdLocation, sizeof(uint)), in rpcId); +#endif +#if FANTASY_UNITY + MemoryMarshal.Write(buffer, ref packetBodyCount); + MemoryMarshal.Write(buffer.Slice(Packet.PacketLength, sizeof(uint)), ref opCode); + MemoryMarshal.Write(buffer.Slice(Packet.OuterPacketRpcIdLocation, sizeof(uint)), ref rpcId); +#endif + return memoryStream; + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Message/PacketParser/Handler/CircularBufferPacketParser.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Message/PacketParser/Handler/CircularBufferPacketParser.cs new file mode 100644 index 0000000..24c368b --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Message/PacketParser/Handler/CircularBufferPacketParser.cs @@ -0,0 +1,170 @@ +// using System.Runtime.CompilerServices; +// // ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract +// #pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. +// +// namespace Fantasy +// { +// // 这个对处理分包和粘包逻辑不完整、考虑现在没有任何地方使用了、就先不修改了。 +// // 后面用到了再修改、现在这个只是留做备份、万一以后用到了呢。 +// public abstract class CircularBufferPacketParser : APacketParser +// { +// protected uint RpcId; +// protected long RouteId; +// protected uint ProtocolCode; +// protected int MessagePacketLength; +// protected bool IsUnPackHead = true; +// protected readonly byte[] MessageHead = new byte[Packet.InnerPacketHeadLength]; +// public abstract bool UnPack(CircularBuffer buffer, out APackInfo packInfo); +// } +// +// #if FANTASY_NET +// public sealed class InnerCircularBufferPacketParser : CircularBufferPacketParser, IInnerPacketParser +// { +// public override bool UnPack(CircularBuffer buffer, out APackInfo packInfo) +// { +// packInfo = null; +// +// // 在对象没有被释放的情况下循环解析数据 +// while (!IsDisposed) +// { +// if (IsUnPackHead) +// { +// // 如果缓冲区中的数据长度小于内部消息头的长度,无法解析 +// if (buffer.Length < Packet.InnerPacketHeadLength) +// { +// return false; +// } +// +// // 从缓冲区中读取内部消息头的数据 +// _ = buffer.Read(MessageHead, 0, Packet.InnerPacketHeadLength); +// MessagePacketLength = BitConverter.ToInt32(MessageHead, 0); +// +// // 检查消息体长度是否超出限制 +// if (MessagePacketLength > Packet.PacketBodyMaxLength) +// { +// throw new ScanException( +// $"The received information exceeds the maximum limit = {MessagePacketLength}"); +// } +// +// // 解析协议编号、RPC ID 和 Route ID +// ProtocolCode = BitConverter.ToUInt32(MessageHead, Packet.PacketLength); +// RpcId = BitConverter.ToUInt32(MessageHead, Packet.InnerPacketRpcIdLocation); +// RouteId = BitConverter.ToInt64(MessageHead, Packet.InnerPacketRouteRouteIdLocation); +// IsUnPackHead = false; +// } +// +// try +// { +// // 如果缓冲区中的数据长度小于消息体的长度,无法解析 +// if (MessagePacketLength < 0 || buffer.Length < MessagePacketLength) +// { +// return false; +// } +// +// IsUnPackHead = true; +// packInfo = InnerPackInfo.Create(Network); +// var memoryStream = packInfo.RentMemoryStream(MessagePacketLength); +// memoryStream.SetLength(MessagePacketLength); +// buffer.Read(memoryStream, MessagePacketLength); +// packInfo.RpcId = RpcId; +// packInfo.RouteId = RouteId; +// packInfo.ProtocolCode = ProtocolCode; +// packInfo.MessagePacketLength = MessagePacketLength; +// return true; +// } +// catch (Exception e) +// { +// // 在发生异常时,释放 packInfo 并记录日志 +// packInfo?.Dispose(); +// Log.Error(e); +// return false; +// } +// } +// +// return false; +// } +// +// public override MemoryStream Pack(ref uint rpcId, ref long routeTypeOpCode, ref long routeId, +// MemoryStream memoryStream, object message) +// { +// return memoryStream == null +// ? Pack(ref rpcId, ref routeId, message) +// : Pack(ref rpcId, ref routeId, memoryStream); +// } +// +// [MethodImpl(MethodImplOptions.AggressiveInlining)] +// private unsafe MemoryStream Pack(ref uint rpcId, ref long routeId, MemoryStream memoryStream) +// { +// var buffer = memoryStream.GetBuffer(); +// +// fixed (byte* bufferPtr = buffer) +// { +// var rpcIdPtr = bufferPtr + Packet.InnerPacketRpcIdLocation; +// var routeIdPtr = bufferPtr + Packet.InnerPacketRouteRouteIdLocation; +// *(uint*)rpcIdPtr = rpcId; +// *(long*)routeIdPtr = routeId; +// } +// +// memoryStream.Seek(0, SeekOrigin.Begin); +// return memoryStream; +// } +// +// [MethodImpl(MethodImplOptions.AggressiveInlining)] +// private unsafe MemoryStream Pack(ref uint rpcId, ref long routeId, object message) +// { +// var memoryStream = Network.RentMemoryStream(); +// memoryStream.Seek(Packet.InnerPacketHeadLength, SeekOrigin.Begin); +// +// switch (message) +// { +// case IBsonMessage: +// { +// MongoHelper.SerializeTo(message, memoryStream); +// break; +// } +// default: +// { +// ProtoBuffHelper.ToStream(message, memoryStream); +// break; +// } +// } +// +// var opCode = Scene.MessageDispatcherComponent.GetOpCode(message.GetType()); +// var packetBodyCount = (int)(memoryStream.Position - Packet.InnerPacketHeadLength); +// +// if (packetBodyCount == 0) +// { +// // protoBuf做了一个优化、就是当序列化的对象里的属性和字段都为默认值的时候就不会序列化任何东西。 +// // 为了TCP的分包和粘包、需要判定下是当前包数据不完整还是本应该如此、所以用-1代表。 +// packetBodyCount = -1; +// } +// +// // 检查消息体长度是否超出限制 +// if (packetBodyCount > Packet.PacketBodyMaxLength) +// { +// throw new Exception($"Message content exceeds {Packet.PacketBodyMaxLength} bytes"); +// } +// +// var buffer = memoryStream.GetBuffer(); +// +// fixed (byte* bufferPtr = buffer) +// { +// var opCodePtr = bufferPtr + Packet.PacketLength; +// var rpcIdPtr = bufferPtr + Packet.InnerPacketRpcIdLocation; +// var routeIdPtr = bufferPtr + Packet.InnerPacketRouteRouteIdLocation; +// *(int*)bufferPtr = packetBodyCount; +// *(uint*)opCodePtr = opCode; +// *(uint*)rpcIdPtr = rpcId; +// *(long*)routeIdPtr = routeId; +// } +// +// memoryStream.Seek(0, SeekOrigin.Begin); +// return memoryStream; +// } +// } +// #endif +// } +// +// +// +// diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Message/PacketParser/Handler/OuterBufferPacketParserHelper.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Message/PacketParser/Handler/OuterBufferPacketParserHelper.cs new file mode 100644 index 0000000..a6e66ca --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Message/PacketParser/Handler/OuterBufferPacketParserHelper.cs @@ -0,0 +1,72 @@ +#if FANTASY_NET +using System.Runtime.CompilerServices; +using Fantasy.Helper; +using Fantasy.Network; +using Fantasy.Network.Interface; +using Fantasy.Serialize; + +namespace Fantasy.PacketParser +{ + /// + /// 打包Outer消息的帮助类 + /// + public static class OuterBufferPacketParserHelper + { + /// + /// 打包一个网络消息 + /// + /// scene + /// 如果是RPC消息需要传递一个rpcId + /// 打包的网络消息 + /// 序列化后流的长度 + /// 打包完成会返回一个MemoryStreamBuffer + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe MemoryStreamBuffer Pack(Scene scene, uint rpcId, IMessage message, out int memoryStreamLength) + { + memoryStreamLength = 0; + var messageType = message.GetType(); + var memoryStream = new MemoryStreamBuffer(); + memoryStream.MemoryStreamBufferSource = MemoryStreamBufferSource.Pack; + OpCodeIdStruct opCodeIdStruct = message.OpCode(); + memoryStream.Seek(Packet.OuterPacketHeadLength, SeekOrigin.Begin); + + if (SerializerManager.TryGetSerializer(opCodeIdStruct.OpCodeProtocolType, out var serializer)) + { + serializer.Serialize(messageType, message, memoryStream); + memoryStreamLength = (int)memoryStream.Position; + } + else + { + Log.Error($"type:{messageType} Does not support processing protocol"); + } + + var opCode = scene.MessageDispatcherComponent.GetOpCode(messageType); + var packetBodyCount = memoryStreamLength - Packet.OuterPacketHeadLength; + + if (packetBodyCount == 0) + { + // protoBuf做了一个优化、就是当序列化的对象里的属性和字段都为默认值的时候就不会序列化任何东西。 + // 为了TCP的分包和粘包、需要判定下是当前包数据不完整还是本应该如此、所以用-1代表。 + packetBodyCount = -1; + } + + if (packetBodyCount > Packet.PacketBodyMaxLength) + { + // 检查消息体长度是否超出限制 + throw new Exception($"Message content exceeds {Packet.PacketBodyMaxLength} bytes"); + } + + fixed (byte* bufferPtr = memoryStream.GetBuffer()) + { + *(int*)bufferPtr = packetBodyCount; + *(uint*)(bufferPtr + Packet.PacketLength) = opCode; + *(uint*)(bufferPtr + Packet.OuterPacketRpcIdLocation) = rpcId; + } + + return memoryStream; + } + } +} + +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Message/PacketParser/Handler/ReadOnlyMemoryPacketParser.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Message/PacketParser/Handler/ReadOnlyMemoryPacketParser.cs new file mode 100644 index 0000000..758ec17 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Message/PacketParser/Handler/ReadOnlyMemoryPacketParser.cs @@ -0,0 +1,357 @@ +using System; +using System.IO; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using Fantasy.Helper; +using Fantasy.Network; +using Fantasy.Network.Interface; +using Fantasy.PacketParser.Interface; +using Fantasy.Serialize; + +// ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. +#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. + +namespace Fantasy.PacketParser +{ + internal abstract class ReadOnlyMemoryPacketParser : APacketParser + { + /// + /// 一个网络消息包 + /// + protected APackInfo PackInfo; + + protected int Offset; + protected int MessageHeadOffset; + protected int MessageBodyOffset; + protected int MessagePacketLength; + protected bool IsUnPackHead = true; + protected readonly byte[] MessageHead = new byte[20]; + public ReadOnlyMemoryPacketParser() { } + + public abstract bool UnPack(ref ReadOnlyMemory buffer, out APackInfo packInfo); + + public override void Dispose() + { + Offset = 0; + MessageHeadOffset = 0; + MessageBodyOffset = 0; + MessagePacketLength = 0; + IsUnPackHead = true; + PackInfo = null; + Array.Clear(MessageHead, 0, 20); + base.Dispose(); + } + } + +#if FANTASY_NET + internal sealed class InnerReadOnlyMemoryPacketParser : ReadOnlyMemoryPacketParser + { + public override unsafe bool UnPack(ref ReadOnlyMemory buffer, out APackInfo packInfo) + { + packInfo = null; + var readOnlySpan = buffer.Span; + var bufferLength = buffer.Length - Offset; + + if (bufferLength == 0) + { + // 没有剩余的数据需要处理、等待下一个包再处理。 + Offset = 0; + return false; + } + + if (IsUnPackHead) + { + fixed (byte* bufferPtr = readOnlySpan) + fixed (byte* messagePtr = MessageHead) + { + // 在当前buffer中拿到包头的数据 + var innerPacketHeadLength = Packet.InnerPacketHeadLength - MessageHeadOffset; + var copyLength = Math.Min(bufferLength, innerPacketHeadLength); + Buffer.MemoryCopy(bufferPtr + Offset, messagePtr + MessageHeadOffset, innerPacketHeadLength, copyLength); + Offset += copyLength; + MessageHeadOffset += copyLength; + // 检查是否有完整包头 + if (MessageHeadOffset == Packet.InnerPacketHeadLength) + { + // 通过指针直接读取协议编号、messagePacketLength protocolCode rpcId routeId + MessagePacketLength = *(int*)messagePtr; + // 检查消息体长度是否超出限制 + if (MessagePacketLength > Packet.PacketBodyMaxLength) + { + throw new ScanException($"The received information exceeds the maximum limit = {MessagePacketLength}"); + } + + PackInfo = InnerPackInfo.Create(Network); + var memoryStream = PackInfo.RentMemoryStream(MemoryStreamBufferSource.UnPack, Packet.InnerPacketHeadLength + MessagePacketLength); + PackInfo.RpcId = *(uint*)(messagePtr + Packet.InnerPacketRpcIdLocation); + PackInfo.ProtocolCode = *(uint*)(messagePtr + Packet.PacketLength); + PackInfo.RouteId = *(long*)(messagePtr + Packet.InnerPacketRouteRouteIdLocation); + memoryStream.Write(MessageHead); + IsUnPackHead = false; + bufferLength -= copyLength; + MessageHeadOffset = 0; + } + else + { + Offset = 0; + return false; + } + } + } + + if (MessagePacketLength == -1) + { + // protoBuf做了一个优化、就是当序列化的对象里的属性和字段都为默认值的时候就不会序列化任何东西。 + // 为了TCP的分包和粘包、需要判定下是当前包数据不完整还是本应该如此、所以用-1代表。 + packInfo = PackInfo; + PackInfo = null; + IsUnPackHead = true; + return true; + } + + if (bufferLength == 0) + { + // 没有剩余的数据需要处理、等待下一个包再处理。 + Offset = 0; + return false; + } + + // 处理包消息体 + var innerPacketBodyLength = MessagePacketLength - MessageBodyOffset; + var copyBodyLength = Math.Min(bufferLength, innerPacketBodyLength); + // 写入数据到消息体中 + PackInfo.MemoryStream.Write(readOnlySpan.Slice(Offset, copyBodyLength)); + Offset += copyBodyLength; + MessageBodyOffset += copyBodyLength; + // 检查是否是完整的消息体 + if (MessageBodyOffset == MessagePacketLength) + { + packInfo = PackInfo; + PackInfo = null; + IsUnPackHead = true; + MessageBodyOffset = 0; + return true; + } + Offset = 0; + return false; + } + + public override MemoryStreamBuffer Pack(ref uint rpcId, ref long routeId, MemoryStreamBuffer memoryStream, IMessage message) + { + return memoryStream == null ? Pack(ref rpcId, ref routeId, message) : Pack(ref rpcId, ref routeId, memoryStream); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private unsafe MemoryStreamBuffer Pack(ref uint rpcId, ref long routeId, MemoryStreamBuffer memoryStream) + { + fixed (byte* bufferPtr = memoryStream.GetBuffer()) + { + *(uint*)(bufferPtr + Packet.InnerPacketRpcIdLocation) = rpcId; + *(long*)(bufferPtr + Packet.InnerPacketRouteRouteIdLocation) = routeId; + } + + return memoryStream; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private unsafe MemoryStreamBuffer Pack(ref uint rpcId, ref long routeId, IMessage message) + { + var memoryStreamLength = 0; + var messageType = message.GetType(); + var memoryStream = Network.MemoryStreamBufferPool.RentMemoryStream(MemoryStreamBufferSource.Pack); + OpCodeIdStruct opCodeIdStruct = message.OpCode(); + memoryStream.Seek(Packet.InnerPacketHeadLength, SeekOrigin.Begin); + + if (SerializerManager.TryGetSerializer(opCodeIdStruct.OpCodeProtocolType, out var serializer)) + { + serializer.Serialize(messageType, message, memoryStream); + memoryStreamLength = (int)memoryStream.Position; + } + else + { + Log.Error($"type:{messageType} Does not support processing protocol"); + } + + var opCode = Scene.MessageDispatcherComponent.GetOpCode(messageType); + var packetBodyCount = memoryStreamLength - Packet.InnerPacketHeadLength; + + if (packetBodyCount == 0) + { + // protoBuf做了一个优化、就是当序列化的对象里的属性和字段都为默认值的时候就不会序列化任何东西。 + // 为了TCP的分包和粘包、需要判定下是当前包数据不完整还是本应该如此、所以用-1代表。 + // 其实可以不用设置-1、解包的时候判断如果是0也可以、但我仔细想了下,还是用-1代表更加清晰。 + packetBodyCount = -1; + } + + if (packetBodyCount > Packet.PacketBodyMaxLength) + { + // 检查消息体长度是否超出限制 + throw new Exception($"Message content exceeds {Packet.PacketBodyMaxLength} bytes"); + } + + fixed (byte* bufferPtr = memoryStream.GetBuffer()) + { + *(int*)bufferPtr = packetBodyCount; + *(uint*)(bufferPtr + Packet.PacketLength) = opCode; + *(uint*)(bufferPtr + Packet.InnerPacketRpcIdLocation) = rpcId; + *(long*)(bufferPtr + Packet.InnerPacketRouteRouteIdLocation) = routeId; + } + + return memoryStream; + } + } +#endif + internal sealed class OuterReadOnlyMemoryPacketParser : ReadOnlyMemoryPacketParser + { + public override unsafe bool UnPack(ref ReadOnlyMemory buffer, out APackInfo packInfo) + { + packInfo = null; + var readOnlySpan = buffer.Span; + var bufferLength = buffer.Length - Offset; + + if (bufferLength == 0) + { + // 没有剩余的数据需要处理、等待下一个包再处理。 + Offset = 0; + return false; + } + + if (IsUnPackHead) + { + fixed (byte* bufferPtr = readOnlySpan) + fixed (byte* messagePtr = MessageHead) + { + // 在当前buffer中拿到包头的数据 + var outerPacketHeadLength = Packet.OuterPacketHeadLength - MessageHeadOffset; + var copyLength = Math.Min(bufferLength, outerPacketHeadLength); + Buffer.MemoryCopy(bufferPtr + Offset, messagePtr + MessageHeadOffset, outerPacketHeadLength, copyLength); + Offset += copyLength; + MessageHeadOffset += copyLength; + // 检查是否有完整包头 + if (MessageHeadOffset == Packet.OuterPacketHeadLength) + { + // 通过指针直接读取协议编号、messagePacketLength protocolCode rpcId routeId + MessagePacketLength = *(int*)messagePtr; + // 检查消息体长度是否超出限制 + if (MessagePacketLength > Packet.PacketBodyMaxLength) + { + throw new ScanException($"The received information exceeds the maximum limit = {MessagePacketLength}"); + } + + PackInfo = OuterPackInfo.Create(Network); + PackInfo.ProtocolCode = *(uint*)(messagePtr + Packet.PacketLength); + PackInfo.RpcId = *(uint*)(messagePtr + Packet.OuterPacketRpcIdLocation); + var memoryStream = PackInfo.RentMemoryStream(MemoryStreamBufferSource.UnPack, Packet.OuterPacketHeadLength + MessagePacketLength); + memoryStream.Write(MessageHead); + IsUnPackHead = false; + bufferLength -= copyLength; + MessageHeadOffset = 0; + } + else + { + Offset = 0; + return false; + } + } + } + + if (MessagePacketLength == -1) + { + // protoBuf做了一个优化、就是当序列化的对象里的属性和字段都为默认值的时候就不会序列化任何东西。 + // 为了TCP的分包和粘包、需要判定下是当前包数据不完整还是本应该如此、所以用-1代表。 + packInfo = PackInfo; + PackInfo = null; + IsUnPackHead = true; + return true; + } + + if (bufferLength == 0) + { + // 没有剩余的数据需要处理、等待下一个包再处理。 + Offset = 0; + return false; + } + // 处理包消息体 + var outerPacketBodyLength = MessagePacketLength - MessageBodyOffset; + var copyBodyLength = Math.Min(bufferLength, outerPacketBodyLength); + // 写入数据到消息体中 + PackInfo.MemoryStream.Write(readOnlySpan.Slice(Offset, copyBodyLength)); + Offset += copyBodyLength; + MessageBodyOffset += copyBodyLength; + // 检查是否是完整的消息体 + if (MessageBodyOffset == MessagePacketLength) + { + packInfo = PackInfo; + PackInfo = null; + IsUnPackHead = true; + MessageBodyOffset = 0; + return true; + } + + Offset = 0; + return false; + } + + public override MemoryStreamBuffer Pack(ref uint rpcId, ref long routeId, MemoryStreamBuffer memoryStream, IMessage message) + { + return memoryStream == null ? Pack(ref rpcId, message) : Pack(ref rpcId, memoryStream); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private unsafe MemoryStreamBuffer Pack(ref uint rpcId, MemoryStreamBuffer memoryStream) + { + fixed (byte* bufferPtr = memoryStream.GetBuffer()) + { + *(uint*)(bufferPtr + Packet.OuterPacketRpcIdLocation) = rpcId; + } + + return memoryStream; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private unsafe MemoryStreamBuffer Pack(ref uint rpcId, IMessage message) + { + var memoryStreamLength = 0; + var messageType = message.GetType(); + var memoryStream = Network.MemoryStreamBufferPool.RentMemoryStream(MemoryStreamBufferSource.Pack); + OpCodeIdStruct opCodeIdStruct = message.OpCode(); + memoryStream.Seek(Packet.OuterPacketHeadLength, SeekOrigin.Begin); + + if (SerializerManager.TryGetSerializer(opCodeIdStruct.OpCodeProtocolType, out var serializer)) + { + serializer.Serialize(messageType, message, memoryStream); + memoryStreamLength = (int)memoryStream.Position; + } + else + { + Log.Error($"type:{messageType} Does not support processing protocol"); + } + + var opCode = Scene.MessageDispatcherComponent.GetOpCode(messageType); + var packetBodyCount = memoryStreamLength - Packet.OuterPacketHeadLength; + + if (packetBodyCount == 0) + { + // protoBuf做了一个优化、就是当序列化的对象里的属性和字段都为默认值的时候就不会序列化任何东西。 + // 为了TCP的分包和粘包、需要判定下是当前包数据不完整还是本应该如此、所以用-1代表。 + packetBodyCount = -1; + } + + if (packetBodyCount > Packet.PacketBodyMaxLength) + { + // 检查消息体长度是否超出限制 + throw new Exception($"Message content exceeds {Packet.PacketBodyMaxLength} bytes"); + } + + fixed (byte* bufferPtr = memoryStream.GetBuffer()) + { + *(int*)bufferPtr = packetBodyCount; + *(uint*)(bufferPtr + Packet.PacketLength) = opCode; + *(uint*)(bufferPtr + Packet.OuterPacketRpcIdLocation) = rpcId; + } + + return memoryStream; + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Message/PacketParser/Interface/APackInfo.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Message/PacketParser/Interface/APackInfo.cs new file mode 100644 index 0000000..1ea6d6b --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Message/PacketParser/Interface/APackInfo.cs @@ -0,0 +1,61 @@ +using System; +using System.IO; +using Fantasy.Network; +using Fantasy.Network.Interface; +using Fantasy.Serialize; + +// ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. +#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member + +namespace Fantasy.PacketParser.Interface +{ + public abstract class APackInfo : IDisposable + { + internal ANetwork Network; + + public uint RpcId; + public long RouteId; + public long PackInfoId; + public bool IsDisposed; + private uint _protocolCode; + + public uint ProtocolCode + { + get => _protocolCode; + set + { + _protocolCode = value; + OpCodeIdStruct = value; + } + } + public OpCodeIdStruct OpCodeIdStruct { get; private set; } + public MemoryStreamBuffer MemoryStream { get; protected set; } + public abstract object Deserialize(Type messageType); + public abstract MemoryStreamBuffer RentMemoryStream(MemoryStreamBufferSource memoryStreamBufferSource, int size = 0); + public virtual void Dispose() + { + if (IsDisposed) + { + return; + } + + RpcId = 0; + RouteId = 0; + PackInfoId = 0; + ProtocolCode = 0; + _protocolCode = 0; + OpCodeIdStruct = default; + + if (MemoryStream != null) + { + Network.MemoryStreamBufferPool.ReturnMemoryStream(MemoryStream); + MemoryStream = null; + } + + IsDisposed = true; + Network = null; + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Message/PacketParser/Interface/APacketParser.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Message/PacketParser/Interface/APacketParser.cs new file mode 100644 index 0000000..579cf6f --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Message/PacketParser/Interface/APacketParser.cs @@ -0,0 +1,30 @@ +using System; +using System.Buffers; +using System.IO; +using Fantasy.Network.Interface; +using Fantasy.Serialize; + +#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member + +namespace Fantasy.PacketParser.Interface +{ + /// + /// 抽象的包解析器基类,用于解析网络通信数据包。 + /// + public abstract class APacketParser : IDisposable + { + internal Scene Scene; + internal ANetwork Network; + internal MessageDispatcherComponent MessageDispatcherComponent; + protected bool IsDisposed { get; private set; } + public abstract MemoryStreamBuffer Pack(ref uint rpcId, ref long routeId, MemoryStreamBuffer memoryStream, IMessage message); + public virtual void Dispose() + { + IsDisposed = true; + Scene = null; + MessageDispatcherComponent = null; + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Message/PacketParser/OpCode.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Message/PacketParser/OpCode.cs new file mode 100644 index 0000000..d02105d --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Message/PacketParser/OpCode.cs @@ -0,0 +1,106 @@ +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member +namespace Fantasy.Network +{ + public struct OpCodeIdStruct + { + // OpCodeIdStruct:5 + 4 + 23 = 32 + // +---------------------------+---------------------------------+-----------------------------+ + // | OpCodeType(5) 最多31种类型 | Protocol(4) 最多15种不同的网络协议 | Index(23) 最多8388607个协议 | + // +---------------------------+---------------------------------+-----------------------------+ + public uint OpCodeProtocolType { get; private set; } + public uint Protocol { get; private set; } + public uint Index { get; private set; } + + public OpCodeIdStruct(uint opCodeProtocolType, uint protocol, uint index) + { + OpCodeProtocolType = opCodeProtocolType; + Protocol = protocol; + Index = index; + } + + public static implicit operator uint(OpCodeIdStruct opCodeIdStruct) + { + var result = opCodeIdStruct.Index; + result |= opCodeIdStruct.OpCodeProtocolType << 23; + result |= opCodeIdStruct.Protocol << 27; + return result; + } + + public static implicit operator OpCodeIdStruct(uint opCodeId) + { + var opCodeIdStruct = new OpCodeIdStruct() + { + Index = opCodeId & 0x7FFFFF + }; + opCodeId >>= 23; + opCodeIdStruct.OpCodeProtocolType = opCodeId & 0xF; + opCodeId >>= 4; + opCodeIdStruct.Protocol = opCodeId & 0x1F; + return opCodeIdStruct; + } + } + + public static class OpCodeProtocolType + { + public const uint Bson = 1; + public const uint ProtoBuf = 0; + } + + public static class OpCodeType + { + public const uint OuterMessage = 1; + public const uint OuterRequest = 2; + public const uint OuterResponse = 3; + + public const uint InnerMessage = 4; + public const uint InnerRequest = 5; + public const uint InnerResponse = 6; + + public const uint InnerRouteMessage = 7; + public const uint InnerRouteRequest = 8; + public const uint InnerRouteResponse = 9; + + public const uint OuterAddressableMessage = 10; + public const uint OuterAddressableRequest = 11; + public const uint OuterAddressableResponse = 12; + + public const uint InnerAddressableMessage = 13; + public const uint InnerAddressableRequest = 14; + public const uint InnerAddressableResponse = 15; + + public const uint OuterCustomRouteMessage = 16; + public const uint OuterCustomRouteRequest = 17; + public const uint OuterCustomRouteResponse = 18; + + public const uint OuterPingRequest = 19; + public const uint OuterPingResponse = 20; + } + + public static class OpCode + { + public static readonly uint BenchmarkMessage = Create(OpCodeProtocolType.ProtoBuf, OpCodeType.OuterMessage, 8388607); + public static readonly uint BenchmarkRequest = Create(OpCodeProtocolType.ProtoBuf, OpCodeType.OuterRequest, 8388607); + public static readonly uint BenchmarkResponse = Create(OpCodeProtocolType.ProtoBuf, OpCodeType.OuterResponse, 8388607); + public static readonly uint PingRequest = Create(OpCodeProtocolType.ProtoBuf, OpCodeType.OuterPingRequest, 1); + public static readonly uint PingResponse = Create(OpCodeProtocolType.ProtoBuf, OpCodeType.OuterPingResponse, 1); + public static readonly uint DefaultResponse = Create(OpCodeProtocolType.ProtoBuf, OpCodeType.InnerResponse, 1); + public static readonly uint DefaultRouteResponse = Create(OpCodeProtocolType.ProtoBuf, OpCodeType.InnerRouteResponse, 7); + public static readonly uint AddressableAddRequest = Create(OpCodeProtocolType.ProtoBuf, OpCodeType.InnerRouteRequest, 1); + public static readonly uint AddressableAddResponse = Create(OpCodeProtocolType.ProtoBuf, OpCodeType.InnerRouteResponse, 1); + public static readonly uint AddressableGetRequest = Create(OpCodeProtocolType.ProtoBuf, OpCodeType.InnerRouteRequest, 2); + public static readonly uint AddressableGetResponse = Create(OpCodeProtocolType.ProtoBuf,OpCodeType.InnerRouteResponse,2); + public static readonly uint AddressableRemoveRequest = Create(OpCodeProtocolType.ProtoBuf, OpCodeType.InnerRouteRequest, 3); + public static readonly uint AddressableRemoveResponse = Create(OpCodeProtocolType.ProtoBuf, OpCodeType.InnerRouteResponse, 3); + public static readonly uint AddressableLockRequest = Create(OpCodeProtocolType.ProtoBuf, OpCodeType.InnerRouteRequest, 4); + public static readonly uint AddressableLockResponse = Create(OpCodeProtocolType.ProtoBuf, OpCodeType.InnerRouteResponse, 4); + public static readonly uint AddressableUnLockRequest = Create(OpCodeProtocolType.ProtoBuf, OpCodeType.InnerRouteRequest, 5); + public static readonly uint AddressableUnLockResponse = Create(OpCodeProtocolType.ProtoBuf, OpCodeType.InnerRouteResponse, 5); + public static readonly uint LinkEntityRequest = Create(OpCodeProtocolType.ProtoBuf, OpCodeType.InnerRouteRequest, 6); + public static readonly uint LinkEntityResponse = Create(OpCodeProtocolType.ProtoBuf, OpCodeType.InnerRouteResponse, 6); + + public static uint Create(uint opCodeProtocolType, uint protocol, uint index) + { + return new OpCodeIdStruct(opCodeProtocolType, protocol, index); + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Message/PacketParser/Pack/InnerPackInfo.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Message/PacketParser/Pack/InnerPackInfo.cs new file mode 100644 index 0000000..e9870e7 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Message/PacketParser/Pack/InnerPackInfo.cs @@ -0,0 +1,79 @@ +// ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract + +using Fantasy.Network; +using Fantasy.Network.Interface; +using Fantasy.PacketParser.Interface; +using Fantasy.Pool; +using Fantasy.Serialize; + +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member +#pragma warning disable CS8600 // Converting null literal or possible null value to non-nullable type. +#pragma warning disable CS8603 // Possible null reference return. +#if FANTASY_NET +namespace Fantasy.PacketParser +{ + public sealed class InnerPackInfo : APackInfo + { + private readonly Dictionary> _createInstances = new Dictionary>(); + + public override void Dispose() + { + if (IsDisposed) + { + return; + } + + var network = Network; + base.Dispose(); + network.ReturnInnerPackInfo(this); + } + + public static InnerPackInfo Create(ANetwork network) + { + var innerPackInfo = network.RentInnerPackInfo(); + innerPackInfo.Network = network; + innerPackInfo.IsDisposed = false; + return innerPackInfo; + } + + public override MemoryStreamBuffer RentMemoryStream(MemoryStreamBufferSource memoryStreamBufferSource, int size = 0) + { + return MemoryStream ??= Network.MemoryStreamBufferPool.RentMemoryStream(memoryStreamBufferSource, size); + } + + public override object Deserialize(Type messageType) + { + if (MemoryStream == null) + { + Log.Debug("Deserialize MemoryStream is null"); + return null; + } + + MemoryStream.Seek(Packet.InnerPacketHeadLength, SeekOrigin.Begin); + + if (MemoryStream.Length == 0) + { + if (_createInstances.TryGetValue(messageType, out var createInstance)) + { + return createInstance(); + } + + createInstance = CreateInstance.CreateObject(messageType); + _createInstances.Add(messageType, createInstance); + return createInstance(); + } + + if (SerializerManager.TryGetSerializer(OpCodeIdStruct.OpCodeProtocolType, out var serializer)) + { + var obj = serializer.Deserialize(messageType, MemoryStream); + MemoryStream.Seek(0, SeekOrigin.Begin); + return obj; + } + + MemoryStream.Seek(0, SeekOrigin.Begin); + Log.Error($"protocolCode:{ProtocolCode} Does not support processing protocol"); + return null; + } + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Message/PacketParser/Pack/OuterPackInfo.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Message/PacketParser/Pack/OuterPackInfo.cs new file mode 100644 index 0000000..8ce08b7 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Message/PacketParser/Pack/OuterPackInfo.cs @@ -0,0 +1,73 @@ +// ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract +using System; +using System.IO; +using Fantasy.Network; +using Fantasy.Network.Interface; +using Fantasy.PacketParser.Interface; +using Fantasy.Serialize; + +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member +#pragma warning disable CS8603 // Possible null reference return. +#pragma warning disable CS8600 // Converting null literal or possible null value to non-nullable type. +#pragma warning disable CS8602 // Dereference of a possibly null reference. +namespace Fantasy.PacketParser +{ + public sealed class OuterPackInfo : APackInfo + { + public override void Dispose() + { + if (IsDisposed) + { + return; + } + var network = Network; + base.Dispose(); + network.ReturnOuterPackInfo(this); + } + + public static OuterPackInfo Create(ANetwork network) + { + var outerPackInfo = network.RentOuterPackInfo(); + outerPackInfo.Network = network; + outerPackInfo.IsDisposed = false; + return outerPackInfo; + } + + public override MemoryStreamBuffer RentMemoryStream(MemoryStreamBufferSource memoryStreamBufferSource, int size = 0) + { + if (MemoryStream == null) + { + MemoryStream = Network.MemoryStreamBufferPool.RentMemoryStream(memoryStreamBufferSource, size); + } + + return MemoryStream; + } + + /// + /// 将消息数据从内存反序列化为指定的消息类型实例。 + /// + /// 目标消息类型。 + /// 反序列化后的消息类型实例。 + public override object Deserialize(Type messageType) + { + if (MemoryStream == null) + { + Log.Debug("Deserialize MemoryStream is null"); + return null; + } + + MemoryStream.Seek(Packet.OuterPacketHeadLength, SeekOrigin.Begin); + + if (SerializerManager.TryGetSerializer(OpCodeIdStruct.OpCodeProtocolType, out var serializer)) + { + var obj = serializer.Deserialize(messageType, MemoryStream); + MemoryStream.Seek(0, SeekOrigin.Begin); + return obj; + } + + MemoryStream.Seek(0, SeekOrigin.Begin); + Log.Error($"protocolCode:{ProtocolCode} Does not support processing protocol"); + return null; + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Message/PacketParser/Pack/ProcessPackInfo.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Message/PacketParser/Pack/ProcessPackInfo.cs new file mode 100644 index 0000000..f010858 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Message/PacketParser/Pack/ProcessPackInfo.cs @@ -0,0 +1,160 @@ +#if FANTASY_NET +using System.Collections.Concurrent; +using Fantasy.Network; +using Fantasy.Network.Interface; +using Fantasy.PacketParser.Interface; +using Fantasy.Pool; +using Fantasy.Serialize; + +// ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member +#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. +#pragma warning disable CS8600 // Converting null literal or possible null value to non-nullable type. +#pragma warning disable CS8603 // Possible null reference return. +namespace Fantasy.PacketParser +{ + public sealed class ProcessPackInfo : APackInfo + { + private int _disposeCount; + public Type MessageType { get; private set; } + private static readonly ConcurrentQueue Caches = new ConcurrentQueue(); + private readonly ConcurrentDictionary> _createInstances = new ConcurrentDictionary>(); + + public override void Dispose() + { + if (--_disposeCount > 0 || IsDisposed) + { + return; + } + + _disposeCount = 0; + MessageType = null; + base.Dispose(); + + if (Caches.Count > 2000) + { + return; + } + + Caches.Enqueue(this); + } + + public static unsafe ProcessPackInfo Create(Scene scene, T message, int disposeCount, uint rpcId = 0, long routeId = 0) where T : IRouteMessage + { + if (!Caches.TryDequeue(out var packInfo)) + { + packInfo = new ProcessPackInfo(); + } + + var type = typeof(T); + var memoryStreamLength = 0; + packInfo._disposeCount = disposeCount; + packInfo.MessageType = type; + packInfo.IsDisposed = false; + var memoryStream = new MemoryStreamBuffer(); + memoryStream.MemoryStreamBufferSource = MemoryStreamBufferSource.Pack; + OpCodeIdStruct opCodeIdStruct = message.OpCode(); + memoryStream.Seek(Packet.InnerPacketHeadLength, SeekOrigin.Begin); + + if (SerializerManager.TryGetSerializer(opCodeIdStruct.OpCodeProtocolType, out var serializer)) + { + serializer.Serialize(type, message, memoryStream); + memoryStreamLength = (int)memoryStream.Position; + } + else + { + Log.Error($"type:{type} Does not support processing protocol"); + } + + var opCode = scene.MessageDispatcherComponent.GetOpCode(packInfo.MessageType); + var packetBodyCount = memoryStreamLength - Packet.InnerPacketHeadLength; + + if (packetBodyCount == 0) + { + // protoBuf做了一个优化、就是当序列化的对象里的属性和字段都为默认值的时候就不会序列化任何东西。 + // 为了TCP的分包和粘包、需要判定下是当前包数据不完整还是本应该如此、所以用-1代表。 + packetBodyCount = -1; + } + + if (packetBodyCount > Packet.PacketBodyMaxLength) + { + // 检查消息体长度是否超出限制 + throw new Exception($"Message content exceeds {Packet.PacketBodyMaxLength} bytes"); + } + + var buffer = memoryStream.GetBuffer(); + + fixed (byte* bufferPtr = buffer) + { + var opCodePtr = bufferPtr + Packet.PacketLength; + var rpcIdPtr = bufferPtr + Packet.InnerPacketRpcIdLocation; + var routeIdPtr = bufferPtr + Packet.InnerPacketRouteRouteIdLocation; + *(int*)bufferPtr = packetBodyCount; + *(uint*)opCodePtr = opCode; + *(uint*)rpcIdPtr = rpcId; + *(long*)routeIdPtr = routeId; + } + + memoryStream.Seek(0, SeekOrigin.Begin); + packInfo.MemoryStream = memoryStream; + return packInfo; + } + + public unsafe void Set(uint rpcId, long routeId) + { + var buffer = MemoryStream.GetBuffer(); + + fixed (byte* bufferPtr = buffer) + { + var rpcIdPtr = bufferPtr + Packet.InnerPacketRpcIdLocation; + var routeIdPtr = bufferPtr + Packet.InnerPacketRouteRouteIdLocation; + *(uint*)rpcIdPtr = rpcId; + *(long*)routeIdPtr = routeId; + } + + MemoryStream.Seek(0, SeekOrigin.Begin); + } + + public override MemoryStreamBuffer RentMemoryStream(MemoryStreamBufferSource memoryStreamBufferSource, int size = 0) + { + throw new NotImplementedException(); + } + + public override object Deserialize(Type messageType) + { + if (MemoryStream == null) + { + Log.Debug("Deserialize MemoryStream is null"); + return null; + } + + object obj = null; + MemoryStream.Seek(Packet.InnerPacketHeadLength, SeekOrigin.Begin); + + if (MemoryStream.Length == 0) + { + if (_createInstances.TryGetValue(messageType, out var createInstance)) + { + return createInstance(); + } + + createInstance = CreateInstance.CreateObject(messageType); + _createInstances.TryAdd(messageType, createInstance); + return createInstance(); + } + + if (SerializerManager.TryGetSerializer(OpCodeIdStruct.OpCodeProtocolType, out var serializer)) + { + obj = serializer.Deserialize(messageType, MemoryStream); + MemoryStream.Seek(0, SeekOrigin.Begin); + return obj; + } + + MemoryStream.Seek(0, SeekOrigin.Begin); + Log.Error($"protocolCode:{ProtocolCode} Does not support processing protocol"); + return null; + } + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Message/PacketParser/Packet.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Message/PacketParser/Packet.cs new file mode 100644 index 0000000..7198af7 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Message/PacketParser/Packet.cs @@ -0,0 +1,49 @@ +namespace Fantasy.PacketParser +{ + /// + /// 提供关于消息包的常量定义。 + /// + public struct Packet + { + /// + /// 消息体最大长度 + /// + public const int PacketBodyMaxLength = ushort.MaxValue * 16; + /// + /// 消息体长度在消息头占用的长度 + /// + public const int PacketLength = sizeof(int); + /// + /// 协议编号在消息头占用的长度 + /// + public const int ProtocolCodeLength = sizeof(uint); + /// + /// RouteId长度 + /// + public const int PacketRouteIdLength = sizeof(long); + /// + /// RpcId在消息头占用的长度 + /// + public const int RpcIdLength = sizeof(uint); + /// + /// OuterRPCId所在的位置 + /// + public const int OuterPacketRpcIdLocation = PacketLength + ProtocolCodeLength; + /// + /// InnerRPCId所在的位置 + /// + public const int InnerPacketRpcIdLocation = PacketLength + ProtocolCodeLength; + /// + /// RouteId所在的位置 + /// + public const int InnerPacketRouteRouteIdLocation = PacketLength + ProtocolCodeLength + RpcIdLength; + /// + /// 外网消息头长度(消息体长度在消息头占用的长度 + 协议编号在消息头占用的长度 + RPCId长度 + RouteId长度) + /// + public const int OuterPacketHeadLength = PacketLength + ProtocolCodeLength + RpcIdLength + PacketRouteIdLength; + /// + /// 内网消息头长度(消息体长度在消息头占用的长度 + 协议编号在消息头占用的长度 + RPCId长度 + RouteId长度) + /// + public const int InnerPacketHeadLength = PacketLength + ProtocolCodeLength + RpcIdLength + PacketRouteIdLength; + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Message/PacketParser/PacketParserFactory.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Message/PacketParser/PacketParserFactory.cs new file mode 100644 index 0000000..679f95d --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Message/PacketParser/PacketParserFactory.cs @@ -0,0 +1,173 @@ +using System; +using Fantasy.Network; +using Fantasy.Network.Interface; +using Fantasy.PacketParser.Interface; + +// ReSharper disable PossibleNullReferenceException +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member +#pragma warning disable CS8602 // Dereference of a possibly null reference. +#pragma warning disable CS8600 // Converting null literal or possible null value to non-nullable type. +#pragma warning disable CS8603 // Possible null reference return. +namespace Fantasy.PacketParser +{ + internal static class PacketParserFactory + { +#if FANTASY_NET + internal static ReadOnlyMemoryPacketParser CreateServerReadOnlyMemoryPacket(ANetwork network) + { + ReadOnlyMemoryPacketParser readOnlyMemoryPacketParser = null; + + switch (network.NetworkTarget) + { + case NetworkTarget.Inner: + { + readOnlyMemoryPacketParser = new InnerReadOnlyMemoryPacketParser(); + break; + } + case NetworkTarget.Outer: + { + readOnlyMemoryPacketParser = new OuterReadOnlyMemoryPacketParser(); + break; + } + } + + readOnlyMemoryPacketParser.Scene = network.Scene; + readOnlyMemoryPacketParser.Network = network; + readOnlyMemoryPacketParser.MessageDispatcherComponent = network.Scene.MessageDispatcherComponent; + return readOnlyMemoryPacketParser; + } + + public static BufferPacketParser CreateServerBufferPacket(ANetwork network) + { + BufferPacketParser bufferPacketParser = null; + + switch (network.NetworkTarget) + { + case NetworkTarget.Inner: + { + bufferPacketParser = new InnerBufferPacketParser(); + break; + } + case NetworkTarget.Outer: + { + bufferPacketParser = new OuterBufferPacketParser(); + break; + } + } + + bufferPacketParser.Scene = network.Scene; + bufferPacketParser.Network = network; + bufferPacketParser.MessageDispatcherComponent = network.Scene.MessageDispatcherComponent; + return bufferPacketParser; + } +#endif + internal static ReadOnlyMemoryPacketParser CreateClientReadOnlyMemoryPacket(ANetwork network) + { + ReadOnlyMemoryPacketParser readOnlyMemoryPacketParser = null; + + switch (network.NetworkTarget) + { +#if FANTASY_NET + case NetworkTarget.Inner: + { + readOnlyMemoryPacketParser = new InnerReadOnlyMemoryPacketParser(); + break; + } +#endif + case NetworkTarget.Outer: + { + readOnlyMemoryPacketParser = new OuterReadOnlyMemoryPacketParser(); + break; + } + } + + readOnlyMemoryPacketParser.Scene = network.Scene; + readOnlyMemoryPacketParser.Network = network; + readOnlyMemoryPacketParser.MessageDispatcherComponent = network.Scene.MessageDispatcherComponent; + return readOnlyMemoryPacketParser; + } + +#if !FANTASY_WEBGL + public static BufferPacketParser CreateClientBufferPacket(ANetwork network) + { + BufferPacketParser bufferPacketParser = null; + + switch (network.NetworkTarget) + { +#if FANTASY_NET + case NetworkTarget.Inner: + { + bufferPacketParser = new InnerBufferPacketParser(); + break; + } +#endif + case NetworkTarget.Outer: + { + bufferPacketParser = new OuterBufferPacketParser(); + break; + } + } + + bufferPacketParser.Scene = network.Scene; + bufferPacketParser.Network = network; + bufferPacketParser.MessageDispatcherComponent = network.Scene.MessageDispatcherComponent; + return bufferPacketParser; + } +#endif + public static T CreateClient(ANetwork network) where T : APacketParser + { + var packetParserType = typeof(T); + + switch (network.NetworkTarget) + { +#if FANTASY_NET + case NetworkTarget.Inner: + { + APacketParser innerPacketParser = null; + + if (packetParserType == typeof(ReadOnlyMemoryPacketParser)) + { + innerPacketParser = new InnerReadOnlyMemoryPacketParser(); + } + else if (packetParserType == typeof(BufferPacketParser)) + { + innerPacketParser = new InnerBufferPacketParser(); + } + // else if(packetParserType == typeof(CircularBufferPacketParser)) + // { + // innerPacketParser = new InnerCircularBufferPacketParser(); + // } + + innerPacketParser.Scene = network.Scene; + innerPacketParser.Network = network; + innerPacketParser.MessageDispatcherComponent = network.Scene.MessageDispatcherComponent; + return (T)innerPacketParser; + } +#endif + case NetworkTarget.Outer: + { + APacketParser outerPacketParser = null; + + if (packetParserType == typeof(ReadOnlyMemoryPacketParser)) + { + outerPacketParser = new OuterReadOnlyMemoryPacketParser(); + } + else if (packetParserType == typeof(BufferPacketParser)) + { +#if FANTASY_WEBGL + outerPacketParser = new OuterWebglBufferPacketParser(); +#else + outerPacketParser = new OuterBufferPacketParser(); +#endif + } + outerPacketParser.Scene = network.Scene; + outerPacketParser.Network = network; + outerPacketParser.MessageDispatcherComponent = network.Scene.MessageDispatcherComponent; + return (T)outerPacketParser; + } + default: + throw new ArgumentOutOfRangeException(); + } + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Message/Scheduler/ClientMessageScheduler.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Message/Scheduler/ClientMessageScheduler.cs new file mode 100644 index 0000000..baa7a59 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Message/Scheduler/ClientMessageScheduler.cs @@ -0,0 +1,93 @@ +using System; +using Fantasy.Async; +using Fantasy.Network; +using Fantasy.Network.Interface; +using Fantasy.PacketParser.Interface; + +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member + +namespace Fantasy.Scheduler +{ +#if FANTASY_UNITY || FANTASY_CONSOLE + /// + /// 提供了一个用于客户端网络消息调度和处理的抽象基类。 + /// + public sealed class ClientMessageScheduler : ANetworkMessageScheduler + { + public ClientMessageScheduler(Scene scene) : base(scene) { } + + public override async FTask Scheduler(Session session, APackInfo packInfo) + { + await FTask.CompletedTask; + switch (packInfo.OpCodeIdStruct.Protocol) + { + case OpCodeType.OuterMessage: + case OpCodeType.OuterRequest: + case OpCodeType.OuterAddressableMessage: + case OpCodeType.OuterAddressableRequest: + case OpCodeType.OuterCustomRouteMessage: + case OpCodeType.OuterCustomRouteRequest: + { + using (packInfo) + { + var messageType = MessageDispatcherComponent.GetOpCodeType(packInfo.ProtocolCode); + + if (messageType == null) + { + throw new Exception($"可能遭受到恶意发包或没有协议定义ProtocolCode ProtocolCode:{packInfo.ProtocolCode}"); + } + + var message = packInfo.Deserialize(messageType); + MessageDispatcherComponent.MessageHandler(session, messageType, message, packInfo.RpcId, packInfo.ProtocolCode); + } + + return; + } + case OpCodeType.OuterResponse: + case OpCodeType.OuterPingResponse: + case OpCodeType.OuterAddressableResponse: + case OpCodeType.OuterCustomRouteResponse: + { + using (packInfo) + { + var messageType = MessageDispatcherComponent.GetOpCodeType(packInfo.ProtocolCode); + + if (messageType == null) + { + throw new Exception($"可能遭受到恶意发包或没有协议定义ProtocolCode ProtocolCode:{packInfo.ProtocolCode}"); + } + + // 这个一般是客户端Session.Call发送时使用的、目前这个逻辑只有Unity客户端时使用 + + var aResponse = (IResponse)packInfo.Deserialize(messageType); + + if (!session.RequestCallback.Remove(packInfo.RpcId, out var action)) + { + Log.Error($"not found rpc {packInfo.RpcId}, response message: {aResponse.GetType().Name}"); + return; + } + + action.SetResult(aResponse); + } + + return; + } + default: + { + packInfo.Dispose(); + throw new NotSupportedException($"Received unsupported message protocolCode:{packInfo.ProtocolCode}"); + } + } + } + } +#endif +#if FANTASY_NET + internal sealed class ClientMessageScheduler(Scene scene) : ANetworkMessageScheduler(scene) + { + public override FTask Scheduler(Session session, APackInfo packInfo) + { + throw new NotSupportedException($"ClientMessageScheduler Received unsupported message protocolCode:{packInfo.ProtocolCode}"); + } + } +#endif +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Message/Scheduler/InnerMessageScheduler.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Message/Scheduler/InnerMessageScheduler.cs new file mode 100644 index 0000000..806ce63 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Message/Scheduler/InnerMessageScheduler.cs @@ -0,0 +1,204 @@ +#if FANTASY_NET +// ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract +using System.Runtime.CompilerServices; +using Fantasy.Async; +using Fantasy.Network; +using Fantasy.Network.Interface; +using Fantasy.PacketParser; +using Fantasy.PacketParser.Interface; +#pragma warning disable CS8604 // Possible null reference argument. + +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member +namespace Fantasy.Scheduler +{ + /// + /// 提供了一个机制来调度和处理内部网络消息。 + /// + internal sealed class InnerMessageScheduler(Scene scene) : ANetworkMessageScheduler(scene) + { + public override async FTask Scheduler(Session session, APackInfo packInfo) + { + var protocol = packInfo.OpCodeIdStruct.Protocol; + + switch (protocol) + { + case OpCodeType.InnerMessage: + case OpCodeType.InnerRequest: + { + var messageType = MessageDispatcherComponent.GetOpCodeType(packInfo.ProtocolCode); + + try + { + if (messageType == null) + { + throw new Exception($"可能遭受到恶意发包或没有协议定义ProtocolCode ProtocolCode:{packInfo.ProtocolCode}"); + } + + var message = packInfo.Deserialize(messageType); + MessageDispatcherComponent.MessageHandler(session, messageType, message, packInfo.RpcId, packInfo.ProtocolCode); + } + catch (Exception e) + { + Log.Error($"ANetworkMessageScheduler OuterResponse error messageProtocolCode:{packInfo.ProtocolCode} messageType:{messageType} SessionId {session.Id} IsDispose {session.IsDisposed} {e}"); + } + finally + { + packInfo.Dispose(); + } + + return; + } + case OpCodeType.InnerResponse: + case OpCodeType.InnerRouteResponse: + case OpCodeType.InnerAddressableResponse: + case OpCodeType.OuterAddressableResponse: + case OpCodeType.OuterCustomRouteResponse: + { + using (packInfo) + { + var messageType = MessageDispatcherComponent.GetOpCodeType(packInfo.ProtocolCode); + + if (messageType == null) + { + throw new Exception($"可能遭受到恶意发包或没有协议定义ProtocolCode ProtocolCode:{packInfo.ProtocolCode}"); + } + + NetworkMessagingComponent.ResponseHandler(packInfo.RpcId, (IResponse)packInfo.Deserialize(messageType)); + } + + return; + } + case OpCodeType.InnerRouteMessage: + case OpCodeType.InnerAddressableMessage: + { + using (packInfo) + { + var messageType = MessageDispatcherComponent.GetOpCodeType(packInfo.ProtocolCode); + + if (messageType == null) + { + throw new Exception($"InnerMessageScheduler error 可能遭受到恶意发包或没有协议定义ProtocolCode ProtocolCode:{packInfo.ProtocolCode}"); + } + + if (!Scene.TryGetEntity(packInfo.RouteId, out var entity)) + { + throw new Exception($"The Entity associated with RouteId = {packInfo.RouteId} was not found! messageType = {messageType.FullName}"); + } + + var obj = packInfo.Deserialize(messageType); + await Scene.MessageDispatcherComponent.RouteMessageHandler(session, messageType, entity, (IMessage)obj, packInfo.RpcId); + } + + return; + } + case OpCodeType.InnerRouteRequest: + case OpCodeType.InnerAddressableRequest: + { + using (packInfo) + { + var messageType = MessageDispatcherComponent.GetOpCodeType(packInfo.ProtocolCode); + + if (messageType == null) + { + throw new Exception($"InnerMessageScheduler error 可能遭受到恶意发包或没有协议定义ProtocolCode ProtocolCode:{packInfo.ProtocolCode}"); + } + + if (!Scene.TryGetEntity(packInfo.RouteId, out var entity)) + { + Scene.MessageDispatcherComponent.FailRouteResponse(session, messageType, InnerErrorCode.ErrNotFoundRoute, packInfo.RpcId); + return; + } + + var obj = packInfo.Deserialize(messageType); + await Scene.MessageDispatcherComponent.RouteMessageHandler(session, messageType, entity, (IMessage)obj, packInfo.RpcId); + } + + return; + } + case OpCodeType.OuterCustomRouteRequest: + case OpCodeType.OuterAddressableRequest: + case OpCodeType.OuterAddressableMessage: + case OpCodeType.OuterCustomRouteMessage: + { + var entity = Scene.GetEntity(packInfo.RouteId); + + switch (entity) + { + case null: + { + // 执行到这里有两种情况: + using (packInfo) + { + switch (Scene.SceneConfig.SceneTypeString) + { + case "Gate": + { + // 1、当前是Gate进行,需要转发消息给客户端,但当前这个Session已经断开了。 + // 这种情况不需要做任何处理。 + return; + } + default: + { + // 2、当前是其他Scene、消息通过Gate发送到这个Scene上面,但这个Scene上面没有这个Entity。 + // 因为这个是Gate转发消息到这个Scene的,如果没有找到Entity要返回错误给Gate。 + // 出现这个情况一定要打印日志,因为出现这个问题肯定是上层逻辑导致的,不应该出现这样的问题。 + var packInfoRouteId = packInfo.RouteId; + var messageType = MessageDispatcherComponent.GetOpCodeType(packInfo.ProtocolCode); + + switch (protocol) + { + case OpCodeType.OuterCustomRouteRequest: + case OpCodeType.OuterAddressableRequest: + case OpCodeType.OuterAddressableMessage: + { + Scene.MessageDispatcherComponent.FailRouteResponse(session, messageType, InnerErrorCode.ErrNotFoundRoute, packInfo.RpcId); + return; + } + } + + throw new Exception($"The Entity associated with RouteId = {packInfoRouteId} was not found! messageType = {messageType.FullName} protocol = {protocol}"); + } + } + } + } + case Session gateSession: + { + using (packInfo) + { + // 这里如果是Session只可能是Gate的Session、如果是的话、肯定是转发消息 + gateSession.Send(packInfo.MemoryStream, packInfo.RpcId); + } + + return; + } + default: + { + using (packInfo) + { + var messageType = MessageDispatcherComponent.GetOpCodeType(packInfo.ProtocolCode); + + if (messageType == null) + { + throw new Exception($"InnerMessageScheduler error 可能遭受到恶意发包或没有协议定义ProtocolCode ProtocolCode:{packInfo.ProtocolCode}"); + } + + var obj = packInfo.Deserialize(messageType); + await Scene.MessageDispatcherComponent.RouteMessageHandler(session, messageType, entity, (IMessage)obj, packInfo.RpcId); + } + + return; + } + } + } + default: + { + var infoProtocolCode = packInfo.ProtocolCode; + packInfo.Dispose(); + throw new NotSupportedException($"InnerMessageScheduler Received unsupported message protocolCode:{infoProtocolCode}"); + } + } + } + } +} +#endif + diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Message/Scheduler/Interface/ANetworkMessageScheduler.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Message/Scheduler/Interface/ANetworkMessageScheduler.cs new file mode 100644 index 0000000..b296cff --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Message/Scheduler/Interface/ANetworkMessageScheduler.cs @@ -0,0 +1,30 @@ +using System; +using System.IO; +using Fantasy.Async; +using Fantasy.Network; +using Fantasy.Network.Interface; +using Fantasy.PacketParser.Interface; +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member +// ReSharper disable UnassignedField.Global +#pragma warning disable CS8600 // Converting null literal or possible null value to non-nullable type. + +namespace Fantasy.Scheduler +{ + public abstract class ANetworkMessageScheduler + { + protected readonly Scene Scene; + protected readonly MessageDispatcherComponent MessageDispatcherComponent; +#if FANTASY_NET + protected readonly NetworkMessagingComponent NetworkMessagingComponent; +#endif + protected ANetworkMessageScheduler(Scene scene) + { + Scene = scene; + MessageDispatcherComponent = scene.MessageDispatcherComponent; +#if FANTASY_NET + NetworkMessagingComponent = scene.NetworkMessagingComponent; +#endif + } + public abstract FTask Scheduler(Session session, APackInfo packInfo); + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Message/Scheduler/MessageHelper/MessageSender.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Message/Scheduler/MessageHelper/MessageSender.cs new file mode 100644 index 0000000..c645183 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Message/Scheduler/MessageHelper/MessageSender.cs @@ -0,0 +1,107 @@ +using System; +using Fantasy.Async; +using Fantasy.Helper; +using Fantasy.Network.Interface; + +#pragma warning disable CS8625 +#pragma warning disable CS8618 + +namespace Fantasy.Scheduler +{ + /// + /// 网络消息发送者的类。 + /// + public struct MessageSender : IDisposable + { + /// + /// 获取或设置 RPC ID。 + /// + public uint RpcId { get; private set; } + /// + /// 获取或设置路由 ID。 + /// + public long RouteId { get; private set; } + /// + /// 获取或设置创建时间。 + /// + public long CreateTime { get; private set; } + /// + /// 获取或设置消息类型。 + /// + public Type MessageType { get; private set; } + /// + /// 获取或设置请求消息。 + /// + public IMessage Request { get; private set; } + /// + /// 获取或设置任务。 + /// + public FTask Tcs { get; private set; } + + /// + /// 释放资源。 + /// + public void Dispose() + { + RpcId = 0; + RouteId = 0; + CreateTime = 0; + Tcs = null; + Request = null; + MessageType = null; + } + + /// + /// 创建一个 实例。 + /// + /// RPC ID。 + /// 请求消息类型。 + /// 任务。 + /// 创建的 实例。 + public static MessageSender Create(uint rpcId, Type requestType, FTask tcs) + { + var routeMessageSender = new MessageSender(); + routeMessageSender.Tcs = tcs; + routeMessageSender.RpcId = rpcId; + routeMessageSender.MessageType = requestType; + routeMessageSender.CreateTime = TimeHelper.Now; + return routeMessageSender; + } + + /// + /// 创建一个 实例。 + /// + /// RPC ID。 + /// 请求消息。 + /// 任务。 + /// 创建的 实例。 + public static MessageSender Create(uint rpcId, IRequest request, FTask tcs) + { + var routeMessageSender = new MessageSender(); + routeMessageSender.Tcs = tcs; + routeMessageSender.RpcId = rpcId; + routeMessageSender.Request = request; + routeMessageSender.CreateTime = TimeHelper.Now; + return routeMessageSender; + } + + /// + /// 创建一个 实例。 + /// + /// RPC ID。 + /// 路由 ID。 + /// 路由消息请求。 + /// 任务。 + /// 创建的 实例。 + public static MessageSender Create(uint rpcId, long routeId, IRouteMessage request, FTask tcs) + { + var routeMessageSender = new MessageSender(); + routeMessageSender.Tcs = tcs; + routeMessageSender.RpcId = rpcId; + routeMessageSender.RouteId = routeId; + routeMessageSender.Request = request; + routeMessageSender.CreateTime = TimeHelper.Now; + return routeMessageSender; + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Message/Scheduler/MessageHelper/NetworkMessagingComponent.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Message/Scheduler/MessageHelper/NetworkMessagingComponent.cs new file mode 100644 index 0000000..7580dd9 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Message/Scheduler/MessageHelper/NetworkMessagingComponent.cs @@ -0,0 +1,273 @@ +#if FANTASY_NET +using Fantasy.Entitas; +using System.Runtime.CompilerServices; +using Fantasy.Async; +using Fantasy.Entitas.Interface; +using Fantasy.Helper; +using Fantasy.Network; +using Fantasy.Network.Interface; +using Fantasy.Network.Route; +using Fantasy.PacketParser; +using Fantasy.PacketParser.Interface; +using Fantasy.Timer; +// ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract +#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. +#pragma warning disable CS8603 // Possible null reference return. +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member +namespace Fantasy.Scheduler +{ + public struct NetworkMessageUpdate + { + public NetworkMessagingComponent NetworkMessagingComponent; + } + + public class NetworkMessagingComponentAwakeSystem : AwakeSystem + { + protected override void Awake(NetworkMessagingComponent self) + { + var selfScene = self.Scene; + self.TimerComponent = selfScene.TimerComponent; + self.MessageDispatcherComponent = selfScene.MessageDispatcherComponent; + self.AddressableRouteMessageLock = selfScene.CoroutineLockComponent.Create(self.GetType().TypeHandle.Value.ToInt64()); + + self.TimerId = self.TimerComponent.Net.RepeatedTimer(10000, new NetworkMessageUpdate() + { + NetworkMessagingComponent = self + }); + } + } + + public class NetworkMessagingComponentDestroySystem : DestroySystem + { + protected override void Destroy(NetworkMessagingComponent self) + { + if (self.TimerId != 0) + { + self.TimerComponent.Net.Remove(ref self.TimerId); + } + + foreach (var (rpcId, messageSender) in self.RequestCallback.ToDictionary()) + { + self.ReturnMessageSender(rpcId, messageSender); + } + + self.AddressableRouteMessageLock.Dispose(); + + self.RequestCallback.Clear(); + self.TimeoutRouteMessageSenders.Clear(); + self.TimerComponent = null; + self.MessageDispatcherComponent = null; + self.AddressableRouteMessageLock = null; + } + } + public sealed class NetworkMessagingComponent : Entity + { + public long TimerId; + private uint _rpcId; + public CoroutineLock AddressableRouteMessageLock; + public TimerComponent TimerComponent; + public MessageDispatcherComponent MessageDispatcherComponent; + public readonly SortedDictionary RequestCallback = new(); + public readonly Dictionary TimeoutRouteMessageSenders = new(); + + public void SendInnerRoute(long routeId, IRouteMessage message) + { + if (routeId == 0) + { + Log.Error($"SendInnerRoute appId == 0"); + return; + } + + Scene.GetSession(routeId).Send(message, 0, routeId); + } + + internal void SendInnerRoute(long routeId, Type messageType, APackInfo packInfo) + { + if (routeId == 0) + { + Log.Error($"SendInnerRoute routeId == 0"); + return; + } + + Scene.GetSession(routeId).Send(0, routeId, messageType, packInfo); + } + + public void SendInnerRoute(ICollection routeIdCollection, IRouteMessage message) + { + if (routeIdCollection.Count <= 0) + { + Log.Error("SendInnerRoute routeIdCollection.Count <= 0"); + return; + } + + using var processPackInfo = ProcessPackInfo.Create(Scene, message, routeIdCollection.Count); + foreach (var routeId in routeIdCollection) + { + processPackInfo.Set(0, routeId); + Scene.GetSession(routeId).Send(processPackInfo, 0, routeId); + } + } + + public async FTask SendAddressable(long addressableId, IRouteMessage message) + { + await CallAddressable(addressableId, message); + } + + internal async FTask CallInnerRoute(long routeId, Type requestType, APackInfo packInfo) + { + if (routeId == 0) + { + Log.Error($"CallInnerRoute routeId == 0"); + return null; + } + + var rpcId = ++_rpcId; + var session = Scene.GetSession(routeId); + var requestCallback = FTask.Create(false); + RequestCallback.Add(rpcId, MessageSender.Create(rpcId, requestType, requestCallback)); + session.Send(rpcId, routeId, requestType, packInfo); + return await requestCallback; + } + + public async FTask CallInnerRouteBySession(Session session, long routeId, IRouteMessage request) + { + var rpcId = ++_rpcId; + var requestCallback = FTask.Create(false); + RequestCallback.Add(rpcId, MessageSender.Create(rpcId, request, requestCallback)); + session.Send(request, rpcId, routeId); + return await requestCallback; + } + + public async FTask CallInnerRoute(long routeId, IRouteMessage request) + { + if (routeId == 0) + { + Log.Error($"CallInnerRoute routeId == 0"); + return null; + } + + var rpcId = ++_rpcId; + var session = Scene.GetSession(routeId); + var requestCallback = FTask.Create(false); + RequestCallback.Add(rpcId, MessageSender.Create(rpcId, request, requestCallback)); + session.Send(request, rpcId, routeId); + return await requestCallback; + } + + public async FTask CallAddressable(long addressableId, IRouteMessage request) + { + var failCount = 0; + + using (await AddressableRouteMessageLock.Wait(addressableId, "CallAddressable")) + { + var addressableRouteId = await AddressableHelper.GetAddressableRouteId(Scene, addressableId); + + while (true) + { + if (addressableRouteId == 0) + { + addressableRouteId = await AddressableHelper.GetAddressableRouteId(Scene, addressableId); + } + + if (addressableRouteId == 0) + { + return MessageDispatcherComponent.CreateResponse(request.GetType(), InnerErrorCode.ErrNotFoundRoute); + } + + var iRouteResponse = await CallInnerRoute(addressableRouteId, request); + + switch (iRouteResponse.ErrorCode) + { + case InnerErrorCode.ErrNotFoundRoute: + { + if (++failCount > 20) + { + Log.Error($"AddressableComponent.Call failCount > 20 route send message fail, routeId: {addressableRouteId} AddressableMessageComponent:{addressableId}"); + return iRouteResponse; + } + + await TimerComponent.Net.WaitAsync(500); + addressableRouteId = 0; + continue; + } + case InnerErrorCode.ErrRouteTimeout: + { + Log.Error($"CallAddressableRoute ErrorCode.ErrRouteTimeout Error:{iRouteResponse.ErrorCode} Message:{request}"); + return iRouteResponse; + } + default: + { + return iRouteResponse; + } + } + } + } + } + + public void ResponseHandler(uint rpcId, IResponse response) + { + if (!RequestCallback.Remove(rpcId, out var routeMessageSender)) + { + throw new Exception($"not found rpc, response.RpcId:{rpcId} response message: {response.GetType().Name} Process:{Scene.Process.Id} Scene:{Scene.SceneConfigId}"); + } + + ResponseHandler(routeMessageSender, response); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static void ResponseHandler(MessageSender messageSender, IResponse response) + { + if (response.ErrorCode == InnerErrorCode.ErrRouteTimeout) + { +#if FANTASY_DEVELOP + messageSender.Tcs.SetException(new Exception($"Rpc error: request, 注意RouteId消息超时,请注意查看是否死锁或者没有reply: RouteId: {messageSender.RouteId} {messageSender.Request.ToJson()}, response: {response}")); +#else + messageSender.Tcs.SetException(new Exception($"Rpc error: request, 注意RouteId消息超时,请注意查看是否死锁或者没有reply: RouteId: {messageSender.RouteId} {messageSender.Request}, response: {response}")); +#endif + messageSender.Dispose(); + return; + } + + messageSender.Tcs.SetResult(response); + messageSender.Dispose(); + } + + public void ReturnMessageSender(uint rpcId, MessageSender messageSender) + { + try + { + switch (messageSender.Request) + { + case IRouteMessage iRouteMessage: + { + // IRouteMessage是个特殊的RPC协议、这里不处理就可以了。 + break; + } + case IRequest iRequest: + { + var response = MessageDispatcherComponent.CreateResponse(iRequest.GetType(), InnerErrorCode.ErrRpcFail); + var responseRpcId = messageSender.RpcId; + ResponseHandler(responseRpcId, response); + Log.Warning($"timeout rpcId:{rpcId} responseRpcId:{responseRpcId} {iRequest.ToJson()}"); + break; + } + default: + { + Log.Error(messageSender.Request != null + ? $"Unsupported protocol type {messageSender.Request.GetType()} rpcId:{rpcId} messageSender.Request != null" + : $"Unsupported protocol type:{messageSender.MessageType.FullName} rpcId:{rpcId}"); + RequestCallback.Remove(rpcId); + break; + } + } + } + catch (Exception e) + { + Console.WriteLine(e); + throw; + } + } + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Message/Scheduler/MessageHelper/OnNetworkMessageUpdateCheckTimeout.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Message/Scheduler/MessageHelper/OnNetworkMessageUpdateCheckTimeout.cs new file mode 100644 index 0000000..7dd2ea3 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Message/Scheduler/MessageHelper/OnNetworkMessageUpdateCheckTimeout.cs @@ -0,0 +1,60 @@ +using Fantasy.Helper; +using Fantasy.Timer; + +#if FANTASY_NET +// ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract +namespace Fantasy.Scheduler +{ + /// + /// 网络消息更新检查超时。 + /// + public sealed class OnNetworkMessageUpdateCheckTimeout : TimerHandler + { + /// + /// 超时时间(毫秒)。 + /// + private const long Timeout = 40000; + + /// + /// 处理网络消息更新检查超时。 + /// + /// + /// + protected override void Handler(NetworkMessageUpdate self) + { + var timeNow = TimeHelper.Now; + var selfNetworkMessagingComponent = self.NetworkMessagingComponent; + + // 遍历请求回调字典,检查是否有超时的请求,将超时请求添加到超时消息发送列表中。 + + foreach (var (rpcId, value) in selfNetworkMessagingComponent.RequestCallback) + { + if (timeNow < value.CreateTime + Timeout) + { + break; + } + + selfNetworkMessagingComponent.TimeoutRouteMessageSenders.Add(rpcId, value); + } + + // 如果没有超时的请求,直接返回。 + + if (selfNetworkMessagingComponent.TimeoutRouteMessageSenders.Count == 0) + { + return; + } + + // 处理超时的请求,根据请求类型生成相应的响应消息,并进行处理。 + + foreach (var (rpcId, routeMessageSender) in selfNetworkMessagingComponent.TimeoutRouteMessageSenders) + { + selfNetworkMessagingComponent.ReturnMessageSender(rpcId, routeMessageSender); + } + + // 清空超时消息发送列表。 + + selfNetworkMessagingComponent.TimeoutRouteMessageSenders.Clear(); + } + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Message/Scheduler/OuterMessageScheduler.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Message/Scheduler/OuterMessageScheduler.cs new file mode 100644 index 0000000..58ac0a8 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Message/Scheduler/OuterMessageScheduler.cs @@ -0,0 +1,282 @@ +using System; +using Fantasy.Async; +using Fantasy.Network; +using Fantasy.PacketParser.Interface; +#if FANTASY_NET +using System.Text; +using Fantasy.Network.Interface; +using Fantasy.Network.Route; +using Fantasy.PacketParser; +using Fantasy.Helper; +using Fantasy.InnerMessage; +#endif + +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member + +// ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract + +namespace Fantasy.Scheduler +{ + /// + /// 提供了一个机制来调度和处理外部网络消息。 + /// +#if FANTASY_UNITY + public sealed class OuterMessageScheduler : ANetworkMessageScheduler + { + public OuterMessageScheduler(Scene scene) : base(scene) { } + + /// + /// 在Unity环境下,处理外部消息的方法。 + /// + /// 网络会话。 + /// 消息封包信息。 + public override FTask Scheduler(Session session, APackInfo packInfo) + { + throw new NotSupportedException($"Received unsupported message protocolCode:{packInfo.ProtocolCode}"); + } + } +#endif +#if FANTASY_NET + internal sealed class OuterMessageScheduler(Scene scene) : ANetworkMessageScheduler(scene) + { + private readonly PingResponse _pingResponse = new PingResponse(); + public override async FTask Scheduler(Session session, APackInfo packInfo) + { + if (session.IsDisposed) + { + return; + } + + switch (packInfo.OpCodeIdStruct.Protocol) + { + case OpCodeType.OuterPingRequest: + { + // 注意心跳目前只有外网才才会有、内网之间不需要心跳。 + + session.LastReceiveTime = TimeHelper.Now; + _pingResponse.Now = session.LastReceiveTime; + + using (packInfo) + { + session.Send(_pingResponse, packInfo.RpcId); + } + + return; + } + case OpCodeType.OuterMessage: + case OpCodeType.OuterRequest: + { + var messageType = MessageDispatcherComponent.GetOpCodeType(packInfo.ProtocolCode); + + try + { + if (messageType == null) + { + throw new Exception($"可能遭受到恶意发包或没有协议定义ProtocolCode ProtocolCode:{packInfo.ProtocolCode}"); + } + + var message = packInfo.Deserialize(messageType); + MessageDispatcherComponent.MessageHandler(session, messageType, message, packInfo.RpcId, packInfo.ProtocolCode); + } + catch (Exception e) + { + Log.Error($"ANetworkMessageScheduler OuterResponse error messageProtocolCode:{packInfo.ProtocolCode} messageType:{messageType} SessionId {session.Id} IsDispose {session.IsDisposed} {e}"); + } + finally + { + packInfo.Dispose(); + } + + return; + } + case OpCodeType.OuterResponse: + { + using (packInfo) + { + var messageType = MessageDispatcherComponent.GetOpCodeType(packInfo.ProtocolCode); + + if (messageType == null) + { + throw new Exception($"可能遭受到恶意发包或没有协议定义ProtocolCode ProtocolCode:{packInfo.ProtocolCode}"); + } + + NetworkMessagingComponent.ResponseHandler(packInfo.RpcId, (IResponse)packInfo.Deserialize(messageType)); + } + + return; + } + case OpCodeType.OuterAddressableMessage: + { + var packInfoPackInfoId = packInfo.PackInfoId; + + try + { + var messageType = MessageDispatcherComponent.GetOpCodeType(packInfo.ProtocolCode); + + if (messageType == null) + { + throw new Exception($"OuterMessageScheduler error 可能遭受到恶意发包或没有协议定义ProtocolCode ProtocolCode:{packInfo.ProtocolCode}"); + } + + var addressableRouteComponent = session.GetComponent(); + + if (addressableRouteComponent == null) + { + throw new Exception("OuterMessageScheduler error session does not have an AddressableRouteComponent component"); + } + + await addressableRouteComponent.Send(messageType, packInfo); + } + finally + { + if (packInfo.PackInfoId == packInfoPackInfoId) + { + packInfo.Dispose(); + } + } + + return; + } + case OpCodeType.OuterAddressableRequest: + { + var packInfoPackInfoId = packInfo.PackInfoId; + + try + { + var messageType = MessageDispatcherComponent.GetOpCodeType(packInfo.ProtocolCode); + + if (messageType == null) + { + throw new Exception($"OuterMessageScheduler error 可能遭受到恶意发包或没有协议定义ProtocolCode ProtocolCode:{packInfo.ProtocolCode}"); + } + + var addressableRouteComponent = session.GetComponent(); + + if (addressableRouteComponent == null) + { + throw new Exception("OuterMessageScheduler error session does not have an AddressableRouteComponent component"); + } + + var rpcId = packInfo.RpcId; + var runtimeId = session.RuntimeId; + var response = await addressableRouteComponent.Call(messageType, packInfo); + // session可能已经断开了,所以这里需要判断 + if (session.RuntimeId == runtimeId) + { + session.Send(response, rpcId); + } + } + finally + { + if (packInfo.PackInfoId == packInfoPackInfoId) + { + packInfo.Dispose(); + } + } + + return; + } + case OpCodeType.OuterCustomRouteMessage: + { + var packInfoProtocolCode = packInfo.ProtocolCode; + var packInfoPackInfoId = packInfo.PackInfoId; + + try + { + if (!MessageDispatcherComponent.GetCustomRouteType(packInfoProtocolCode, out var routeType)) + { + throw new Exception($"OuterMessageScheduler error 可能遭受到恶意发包或没有协议定义ProtocolCode ProtocolCode:{packInfo.ProtocolCode}"); + } + + var messageType = MessageDispatcherComponent.GetOpCodeType(packInfo.ProtocolCode); + + if (messageType == null) + { + throw new Exception($"OuterMessageScheduler error 可能遭受到恶意发包或没有协议定义ProtocolCode ProtocolCode:{packInfo.ProtocolCode}"); + } + + var routeComponent = session.GetComponent(); + + if (routeComponent == null) + { + throw new Exception($"OuterMessageScheduler CustomRouteType session does not have an routeComponent component messageType:{messageType.FullName} ProtocolCode:{packInfo.ProtocolCode}"); + } + + if (!routeComponent.TryGetRouteId(routeType, out var routeId)) + { + throw new Exception($"OuterMessageScheduler RouteComponent cannot find RouteId with RouteType {routeType}"); + } + + NetworkMessagingComponent.SendInnerRoute(routeId, messageType, packInfo); + } + finally + { + if (packInfo.PackInfoId == packInfoPackInfoId) + { + packInfo.Dispose(); + } + } + + return; + } + case OpCodeType.OuterCustomRouteRequest: + { + var packInfoProtocolCode = packInfo.ProtocolCode; + var packInfoPackInfoId = packInfo.PackInfoId; + + try + { + if (!MessageDispatcherComponent.GetCustomRouteType(packInfoProtocolCode, out var routeType)) + { + throw new Exception($"OuterMessageScheduler error 可能遭受到恶意发包或没有协议定义ProtocolCode ProtocolCode:{packInfo.ProtocolCode}"); + } + + var messageType = MessageDispatcherComponent.GetOpCodeType(packInfo.ProtocolCode); + + if (messageType == null) + { + throw new Exception($"OuterMessageScheduler error 可能遭受到恶意发包或没有协议定义ProtocolCode ProtocolCode:{packInfo.ProtocolCode}"); + } + + var routeComponent = session.GetComponent(); + + if (routeComponent == null) + { + throw new Exception("OuterMessageScheduler CustomRouteType session does not have an routeComponent component"); + } + + if (!routeComponent.TryGetRouteId(routeType, out var routeId)) + { + throw new Exception($"OuterMessageScheduler RouteComponent cannot find RouteId with RouteType {routeType}"); + } + + var rpcId = packInfo.RpcId; + var runtimeId = session.RuntimeId; + var response = await NetworkMessagingComponent.CallInnerRoute(routeId, messageType, packInfo); + // session可能已经断开了,所以这里需要判断 + if (session.RuntimeId == runtimeId) + { + session.Send(response, rpcId); + } + } + finally + { + if (packInfo.PackInfoId == packInfoPackInfoId) + { + packInfo.Dispose(); + } + } + + return; + } + default: + { + var ipAddress = session.IsDisposed ? "null" : session.RemoteEndPoint.ToString(); + packInfo.Dispose(); + throw new NotSupportedException($"OuterMessageScheduler Received unsupported message protocolCode:{packInfo.ProtocolCode}\n1、请检查该协议所在的程序集是否在框架初始化的时候添加到框架中。\n2、如果看到这个消息表示你有可能用的老版本的导出工具,请更换为最新的导出工具。\n IP地址:{ipAddress}"); + } + } + } + } +#endif +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Protocol/Exception/ScanException.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Protocol/Exception/ScanException.cs new file mode 100644 index 0000000..43c695a --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Protocol/Exception/ScanException.cs @@ -0,0 +1,21 @@ +using System; + +namespace Fantasy.Network +{ + /// + /// 在扫描过程中发生的异常。 + /// + public class ScanException : Exception + { + /// + /// 初始化 类的新实例。 + /// + public ScanException() { } + + /// + /// 使用指定的错误消息初始化 类的新实例。 + /// + /// 错误消息。 + public ScanException(string msg) : base(msg) { } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Protocol/HTTP/HTTPServerNetwork.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Protocol/HTTP/HTTPServerNetwork.cs new file mode 100644 index 0000000..9ca4eba --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Protocol/HTTP/HTTPServerNetwork.cs @@ -0,0 +1,128 @@ +#if FANTASY_NET +using System.IO; +using System.Net; +using System.Security.Cryptography.X509Certificates; +using System.Text; +using Fantasy.Assembly; +using Fantasy.Async; +using Fantasy.Network.Interface; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Server.Kestrel.Core; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; + +#pragma warning disable CS8604 // Possible null reference argument. + +// ReSharper disable PossibleMultipleEnumeration + +namespace Fantasy.Network.HTTP +{ + /// + /// HTTP服务器 + /// + public sealed class HTTPServerNetwork : ANetwork + { + /// + /// 初始化入口 + /// + /// + /// + /// + public void Initialize(NetworkTarget networkTarget, string bindIp, int port) + { + base.Initialize(NetworkType.Server, NetworkProtocolType.HTTP, networkTarget); + + try + { + StartAsync(bindIp, port); + } + catch (HttpListenerException e) + { + if (e.ErrorCode == 5) + { + var sb = new StringBuilder(); + sb.AppendLine("CMD管理员中输入下面其中一个命令,具体根据您是HTTPS或HTTP决定:"); + sb.AppendLine($"HTTP请输入如下:netsh http add urlacl url=http://{bindIp}:{port}/ user=Everyone"); + sb.AppendLine($"HTTPS请输入如下:netsh http add urlacl url=https://{bindIp}:{port}/ user=Everyone"); + throw new Exception(sb.ToString(), e); + } + + Log.Error(e); + } + catch (Exception e) + { + Log.Error(e); + } + } + + private void StartAsync(string bindIp, int port) + { + var builder = WebApplication.CreateBuilder(); + // 配置日志级别为 Warning 或更高 + builder.Logging.ClearProviders(); + builder.Logging.AddConsole(); + builder.Logging.SetMinimumLevel(LogLevel.Warning); + // 将Scene注册到 DI 容器中,传递给控制器 + builder.Services.AddSingleton(Scene); + // 注册Scene同步过滤器 + builder.Services.AddScoped(); + // 注册控制器服务 + var addControllers = builder.Services.AddControllers() + .AddJsonOptions(options => { options.JsonSerializerOptions.PropertyNamingPolicy = null; }); + foreach (var assembly in AssemblySystem.ForEachAssembly) + { + addControllers.AddApplicationPart(assembly); + } + var listenUrl = ""; + var app = builder.Build(); + // 检测当前路径下是否有证书文件 + var certificatePath = Path.Combine(AppContext.BaseDirectory, $"certificate{bindIp}{port}"); + if (Directory.Exists(certificatePath)) + { + // 加载包含证书链的 PEM 文件 + var pemCertChain = File.ReadAllText(Path.Combine(certificatePath, "chain.pem")); + var pemPrivateKey = File.ReadAllText(Path.Combine(certificatePath, "private-key.pem")); + // 配置 HTTPS 监听并使用证书 + builder.WebHost.ConfigureKestrel(kestrelServerOptions => + { + kestrelServerOptions.ConfigureHttpsDefaults(https => + { + https.ServerCertificate = X509Certificate2.CreateFromPem(pemCertChain, pemPrivateKey); + }); + }); + listenUrl = $"https://{bindIp}:{port}/"; + app.Urls.Add(listenUrl); + app.UseHttpsRedirection(); + } + else + { + // 不安全的HTTP地址 + listenUrl = $"http://{bindIp}:{port}/"; + app.Urls.Add(listenUrl); + } + // 启用开发者工具 + if (app.Environment.IsDevelopment()) + { + app.UseDeveloperExceptionPage(); + } + // 路由注册 + app.MapControllers(); + // 开启监听 + app.RunAsync(); + Log.Info($"SceneConfigId = {Scene.SceneConfigId} HTTPServer Listen {listenUrl}"); + } + + /// + /// 移除Channel + /// + /// + /// + public override void RemoveChannel(uint channelId) + { + throw new NotImplementedException(); + } + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Protocol/HTTP/SceneContextFilter.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Protocol/HTTP/SceneContextFilter.cs new file mode 100644 index 0000000..2688bdc --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Protocol/HTTP/SceneContextFilter.cs @@ -0,0 +1,54 @@ +#if FANTASY_NET +using Fantasy.Async; +using Microsoft.AspNetCore.Mvc.Filters; + +namespace Fantasy.Network.HTTP; + +/// +/// 让所有实现SceneContextFilter的控制器,都在执行的Scene下执行 +/// +public sealed class SceneContextFilter : IAsyncActionFilter +{ + private readonly Scene _scene; + + /// + /// 构造函数 + /// + /// + public SceneContextFilter(Scene scene) + { + _scene = scene; + } + + /// + /// OnActionExecutionAsync + /// + /// + /// + /// + public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next) + { + var tcs = FTask.Create(); + + _scene.ThreadSynchronizationContext.Post(() => + { + Action().Coroutine(); + }); + + await tcs; + return; + + async FTask Action() + { + try + { + await next(); + } + finally + { + tcs.SetResult(); + } + } + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Protocol/Interface/AClientNetwork.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Protocol/Interface/AClientNetwork.cs new file mode 100644 index 0000000..322c811 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Protocol/Interface/AClientNetwork.cs @@ -0,0 +1,38 @@ +using System; +using System.IO; +using Fantasy.Serialize; + +// ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract +#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member + +namespace Fantasy.Network.Interface +{ + /// + /// 抽象客户端网络基类。 + /// + public abstract class AClientNetwork : ANetwork, INetworkChannel + { + protected bool IsInit; + public Session Session { get; protected set; } + public abstract Session Connect(string remoteAddress, Action onConnectComplete, Action onConnectFail, Action onConnectDisconnect, bool isHttps, int connectTimeout = 5000); + public abstract void Send(uint rpcId, long routeId, MemoryStreamBuffer memoryStream, IMessage message); + public override void Dispose() + { + IsInit = false; + + if (Session != null) + { + if (!Session.IsDisposed) + { + Session.Dispose(); + } + + Session = null; + } + + base.Dispose(); + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Protocol/Interface/ANetwork.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Protocol/Interface/ANetwork.cs new file mode 100644 index 0000000..fdb85f2 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Protocol/Interface/ANetwork.cs @@ -0,0 +1,149 @@ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.IO; +using Fantasy.Entitas; +using Fantasy.PacketParser; +using Fantasy.Scheduler; +using Fantasy.Serialize; + +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member + +namespace Fantasy.Network.Interface +{ + /// + /// 抽象网络基类。 + /// + public abstract class ANetwork : Entity + { + private long _outerPackInfoId; + private Queue _outerPackInfoPool; + public readonly MemoryStreamBufferPool MemoryStreamBufferPool = new MemoryStreamBufferPool(); + + public NetworkType NetworkType { get; private set; } + public NetworkTarget NetworkTarget { get; private set; } + public NetworkProtocolType NetworkProtocolType { get; private set; } + public ANetworkMessageScheduler NetworkMessageScheduler { get; private set; } + + protected void Initialize(NetworkType networkType, NetworkProtocolType networkProtocolType, NetworkTarget networkTarget) + { + NetworkType = networkType; + NetworkTarget = networkTarget; + NetworkProtocolType = networkProtocolType; +#if FANTASY_NET + if (networkProtocolType == NetworkProtocolType.HTTP) + { + return; + } + if (networkTarget == NetworkTarget.Inner) + { + _innerPackInfoPool = new Queue(); + NetworkMessageScheduler = new InnerMessageScheduler(Scene); + return; + } +#endif + switch (networkType) + { + case NetworkType.Client: + { + _outerPackInfoPool = new Queue(); + NetworkMessageScheduler = new ClientMessageScheduler(Scene); + break; + } +#if FANTASY_NET + case NetworkType.Server: + { + _outerPackInfoPool = new Queue(); + NetworkMessageScheduler = new OuterMessageScheduler(Scene); + break; + } +#endif + } + } + + public abstract void RemoveChannel(uint channelId); + public OuterPackInfo RentOuterPackInfo() + { + if (_outerPackInfoPool.Count == 0) + { + return new OuterPackInfo() + { + PackInfoId = ++_outerPackInfoId + }; + } + + if (!_outerPackInfoPool.TryDequeue(out var outerPackInfo)) + { + return new OuterPackInfo() + { + PackInfoId = ++_outerPackInfoId + }; + } + + outerPackInfo.PackInfoId = ++_outerPackInfoId; + return outerPackInfo; + } + + public void ReturnOuterPackInfo(OuterPackInfo outerPackInfo) + { + if (_outerPackInfoPool.Count > 512) + { + // 池子里最多缓存256个、其实这样设置有点多了、其实用不了512个。 + // 反而设置越大内存会占用越多。 + return; + } + + _outerPackInfoPool.Enqueue(outerPackInfo); + } +#if FANTASY_NET + private long _innerPackInfoId; + private Queue _innerPackInfoPool; + public InnerPackInfo RentInnerPackInfo() + { + if (_innerPackInfoPool.Count == 0) + { + return new InnerPackInfo() + { + PackInfoId = ++_innerPackInfoId + }; + } + + if (!_innerPackInfoPool.TryDequeue(out var innerPackInfo)) + { + return new InnerPackInfo() + { + PackInfoId = ++_innerPackInfoId + }; + } + + innerPackInfo.PackInfoId = ++_innerPackInfoId; + return innerPackInfo; + } + + public void ReturnInnerPackInfo(InnerPackInfo innerPackInfo) + { + if (_innerPackInfoPool.Count > 256) + { + // 池子里最多缓存256个、其实这样设置有点多了、其实用不了256个。 + // 反而设置越大内存会占用越多。 + return; + } + + _innerPackInfoPool.Enqueue(innerPackInfo); + } +#endif + public override void Dispose() + { + NetworkType = NetworkType.None; + NetworkTarget = NetworkTarget.None; + NetworkProtocolType = NetworkProtocolType.None; + MemoryStreamBufferPool.Dispose(); + _outerPackInfoPool?.Clear(); +#if FANTASY_NET + _innerPackInfoPool?.Clear(); +#endif + base.Dispose(); + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Protocol/Interface/ANetworkServerChannel.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Protocol/Interface/ANetworkServerChannel.cs new file mode 100644 index 0000000..788a235 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Protocol/Interface/ANetworkServerChannel.cs @@ -0,0 +1,55 @@ +#if FANTASY_NET +using System.IO; +using System.Net; +using Fantasy.Serialize; + +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member + +namespace Fantasy.Network.Interface +{ + public abstract class ANetworkServerChannel : INetworkChannel + { + /// + /// 获取通道的唯一标识 ID。 + /// + public readonly uint Id; + /// + /// 获取通道的远程终端点。 + /// + public readonly EndPoint RemoteEndPoint; + /// + /// 获取或设置通道所属的场景。 + /// + public Scene Scene { get; protected set; } + /// + /// 获取或设置通道所属的会话。 + /// + public Session Session { get; protected set; } + /// + /// 获取通道是否已经被释放。 + /// + public bool IsDisposed { get; protected set; } + + protected ANetworkServerChannel(ANetwork network, uint id, EndPoint remoteEndPoint) + { + Id = id; + Scene = network.Scene; + RemoteEndPoint = remoteEndPoint; + Session = Session.Create(network.NetworkMessageScheduler, this, network.NetworkTarget); + } + + public virtual void Dispose() + { + IsDisposed = true; + + if (!Session.IsDisposed) + { + Session.Dispose(); + } + } + + public abstract void Send(uint rpcId, long routeId, MemoryStreamBuffer memoryStream, IMessage message); + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Protocol/Interface/INetworkChannel.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Protocol/Interface/INetworkChannel.cs new file mode 100644 index 0000000..52f341a --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Protocol/Interface/INetworkChannel.cs @@ -0,0 +1,14 @@ +using System; +using System.IO; +using Fantasy.Serialize; + +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member +namespace Fantasy.Network.Interface +{ + public interface INetworkChannel : IDisposable + { + public Session Session { get;} + public bool IsDisposed { get;} + public void Send(uint rpcId, long routeId, MemoryStreamBuffer memoryStream, IMessage message); + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Protocol/KCP/Base/Kcp.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Protocol/KCP/Base/Kcp.cs new file mode 100644 index 0000000..b425a66 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Protocol/KCP/Base/Kcp.cs @@ -0,0 +1,626 @@ +#if UNITY_2021_3_OR_NEWER || GODOT +using System; +using System.Threading; +#endif +using static KCP.IKCP; + +#pragma warning disable CS8601 +#pragma warning disable CS8602 +#pragma warning disable CS8625 + +// ReSharper disable IdentifierTypo +// ReSharper disable GrammarMistakeInComment +// ReSharper disable PossibleNullReferenceException +// ReSharper disable ConvertToAutoPropertyWithPrivateSetter + +namespace KCP +{ + /// + /// Kcp + /// + public sealed unsafe class Kcp : IDisposable + { + /// + /// Kcp + /// + private IKCPCB* _kcp; + + /// + /// Output function + /// + private KcpCallback _output; + + /// + /// Buffer + /// + private byte[] _buffer; + + /// + /// Disposed + /// + private int _disposed; + + /// + /// Structure + /// + /// Output + public Kcp(KcpCallback output) : this(0, output) + { + } + + /// + /// Structure + /// + /// ConversationId + /// Output + public Kcp(uint conv, KcpCallback output) + { + _kcp = ikcp_create(conv, ref _buffer); + _output = output; + } + + /// + /// Set + /// + public bool IsSet => _kcp != null; + + /// + /// Conversation id + /// + public uint ConversationId => _kcp->conv; + + /// + /// Maximum transmission unit + /// + public uint MaximumTransmissionUnit => _kcp->mtu; + + /// + /// Maximum segment size + /// + public uint MaximumSegmentSize => _kcp->mss; + + /// + /// Connection state + /// + public int State => _kcp->state; + + /// + /// The sequence number of the first unacknowledged packet + /// + public uint SendUna => _kcp->snd_una; + + /// + /// The sequence number for the next packet to be sent + /// + public uint SendNext => _kcp->snd_nxt; + + /// + /// The sequence number for the next packet expected to be received + /// + public uint ReceiveNext => _kcp->rcv_nxt; + + /// + /// Slow start threshold for congestion control + /// + public uint SlowStartThreshold => _kcp->ssthresh; + + /// + /// Round-trip time variance + /// + public int RxRttval => _kcp->rx_rttval; + + /// + /// Smoothed round-trip time + /// + public int RxSrtt => _kcp->rx_srtt; + + /// + /// Retransmission timeout + /// + public int RxRto => _kcp->rx_rto; + + /// + /// Minimum retransmission timeout + /// + public int RxMinrto => _kcp->rx_minrto; + + /// + /// Send window size + /// + public uint SendWindowSize => _kcp->snd_wnd; + + /// + /// Receive window size + /// + public uint ReceiveWindowSize => _kcp->rcv_wnd; + + /// + /// Remote window size + /// + public uint RemoteWindowSize => _kcp->rmt_wnd; + + /// + /// Congestion window size + /// + public uint CongestionWindowSize => _kcp->cwnd; + + /// + /// Probe variable for fast recovery + /// + public uint Probe => _kcp->probe; + + /// + /// Current timestamp + /// + public uint Current => _kcp->current; + + /// + /// Flush interval + /// + public uint Interval => _kcp->interval; + + /// + /// Timestamp for the next flush + /// + public uint TimestampFlush => _kcp->ts_flush; + + /// + /// Number of retransmissions + /// + public uint Transmissions => _kcp->xmit; + + /// + /// Number of packets in the receive buffer + /// + public uint ReceiveBufferCount => _kcp->nrcv_buf; + + /// + /// Number of packets in the receive queue + /// + public uint ReceiveQueueCount => _kcp->nrcv_que; + + /// + /// Number of packets wait to receive + /// + public uint WaitReceiveCount => _kcp->nrcv_buf + _kcp->nrcv_que; + + /// + /// Number of packets in the send buffer + /// + public uint SendBufferCount => _kcp->nsnd_buf; + + /// + /// Number of packets in the send queue + /// + public uint SendQueueCount => _kcp->nsnd_que; + + /// + /// Number of packets wait to send + /// + public uint WaitSendCount => _kcp->nsnd_buf + _kcp->nsnd_que; + + /// + /// Whether Nagle's algorithm is disabled + /// + public uint NoDelay => _kcp->nodelay; + + /// + /// Whether the KCP connection has been updated + /// + public uint Updated => _kcp->updated; + + /// + /// Timestamp for the next probe + /// + public uint TimestampProbe => _kcp->ts_probe; + + /// + /// Probe wait time + /// + public uint ProbeWait => _kcp->probe_wait; + + /// + /// Incremental increase + /// + public uint Increment => _kcp->incr; + + /// + /// Pointer to the acknowledge list + /// + public uint* AckList => _kcp->acklist; + + /// + /// Count of acknowledges + /// + public uint AckCount => _kcp->ackcount; + + /// + /// Number of acknowledge blocks + /// + public uint AckBlock => _kcp->ackblock; + + /// + /// Buffer + /// + public byte[] Buffer => _buffer; + + /// + /// Fast resend trigger count + /// + public int FastResend => _kcp->fastresend; + + /// + /// Fast resend limit + /// + public int FastResendLimit => _kcp->fastlimit; + + /// + /// Whether congestion control is disabled + /// + public int NoCongestionWindow => _kcp->nocwnd; + + /// + /// Whether stream mode is enabled + /// + public int StreamMode => _kcp->stream; + + /// + /// Output function pointer + /// + public KcpCallback Output => _output; + + /// + /// Dispose + /// + public void Dispose() + { + if (Interlocked.CompareExchange(ref _disposed, 1, 0) != 0) + return; + ikcp_release(_kcp); + _kcp = null; + _output = null; + _buffer = null; + GC.SuppressFinalize(this); + } + + /// + /// Set output + /// + /// Output + public void SetOutput(KcpCallback output) => _output = output; + + /// + /// Destructure + /// + ~Kcp() => Dispose(); + + /// + /// Send + /// + /// Buffer + /// Sent bytes + public int Send(byte[] buffer) + { + fixed (byte* src = &buffer[0]) + return ikcp_send(_kcp, src, buffer.Length); + } + + /// + /// Send + /// + /// Buffer + /// Length + /// Sent bytes + public int Send(byte[] buffer, int length) + { + fixed (byte* src = &buffer[0]) + return ikcp_send(_kcp, src, length); + } + + /// + /// Send + /// + /// Buffer + /// Offset + /// Length + /// Sent bytes + public int Send(byte[] buffer, int offset, int length) + { + fixed (byte* src = &buffer[offset]) + return ikcp_send(_kcp, src, length); + } + + /// + /// Send + /// + /// Buffer + /// Sent bytes + public int Send(ReadOnlySpan buffer) + { + fixed (byte* src = &buffer[0]) + return ikcp_send(_kcp, src, buffer.Length); + } + + /// + /// Send + /// + /// Buffer + /// Sent bytes + public int Send(ReadOnlyMemory buffer) + { + fixed (byte* src = &buffer.Span[0]) + return ikcp_send(_kcp, src, buffer.Length); + } + + /// + /// Send + /// + /// Buffer + /// Sent bytes + public int Send(ArraySegment buffer) + { + fixed (byte* src = &buffer.Array[buffer.Offset]) + return ikcp_send(_kcp, src, buffer.Count); + } + + /// + /// Send + /// + /// Buffer + /// Length + /// Sent bytes + public int Send(byte* buffer, int length) => ikcp_send(_kcp, buffer, length); + + /// + /// Send + /// + /// Buffer + /// Offset + /// Length + /// Sent bytes + public int Send(byte* buffer, int offset, int length) => ikcp_send(_kcp, buffer + offset, length); + + /// + /// Input + /// + /// Buffer + /// Input bytes + public int Input(byte[] buffer) + { + fixed (byte* src = &buffer[0]) + return ikcp_input(_kcp, src, buffer.Length); + } + + /// + /// Input + /// + /// Buffer + /// Length + /// Input bytes + public int Input(byte[] buffer, int length) + { + fixed (byte* src = &buffer[0]) + return ikcp_input(_kcp, src, length); + } + + /// + /// Input + /// + /// Buffer + /// Offset + /// Length + /// Input bytes + public int Input(byte[] buffer, int offset, int length) + { + fixed (byte* src = &buffer[offset]) + return ikcp_input(_kcp, src, length); + } + + /// + /// Input + /// + /// Buffer + /// Input bytes + public int Input(ReadOnlySpan buffer) + { + fixed (byte* src = &buffer[0]) + return ikcp_input(_kcp, src, buffer.Length); + } + + /// + /// Input + /// + /// Buffer + /// Input bytes + public int Input(ReadOnlyMemory buffer) + { + fixed (byte* src = &buffer.Span[0]) + return ikcp_input(_kcp, src, buffer.Length); + } + + /// + /// Input + /// + /// Buffer + /// Input bytes + public int Input(ArraySegment buffer) + { + fixed (byte* src = &buffer.Array[buffer.Offset]) + return ikcp_input(_kcp, src, buffer.Count); + } + + /// + /// Input + /// + /// Buffer + /// Length + /// Input bytes + public int Input(byte* buffer, int length) => ikcp_input(_kcp, buffer, length); + + /// + /// Input + /// + /// Buffer + /// Offset + /// Length + /// Input bytes + public int Input(byte* buffer, int offset, int length) => ikcp_input(_kcp, buffer + offset, length); + + /// + /// Peek size + /// + /// Peeked size + public int PeekSize() => ikcp_peeksize(_kcp); + + /// + /// Receive + /// + /// Buffer + /// Received bytes + public int Receive(byte[] buffer) + { + fixed (byte* dest = &buffer[0]) + return ikcp_recv(_kcp, dest, buffer.Length); + } + + /// + /// Receive + /// + /// Buffer + /// Length + /// Received bytes + public int Receive(byte[] buffer, int length) + { + fixed (byte* dest = &buffer[0]) + return ikcp_recv(_kcp, dest, length); + } + + /// + /// Receive + /// + /// Buffer + /// Offset + /// Length + /// Received bytes + public int Receive(byte[] buffer, int offset, int length) + { + fixed (byte* dest = &buffer[offset]) + return ikcp_recv(_kcp, dest, length); + } + + /// + /// Receive + /// + /// Buffer + /// Received bytes + public int Receive(Span buffer) + { + fixed (byte* dest = &buffer[0]) + return ikcp_recv(_kcp, dest, buffer.Length); + } + + /// + /// Receive + /// + /// Buffer + /// Received bytes + public int Receive(Memory buffer) + { + fixed (byte* dest = &buffer.Span[0]) + return ikcp_recv(_kcp, dest, buffer.Length); + } + + /// + /// Receive + /// + /// Buffer + /// Received bytes + public int Receive(ArraySegment buffer) + { + fixed (byte* dest = &buffer.Array[buffer.Offset]) + return ikcp_recv(_kcp, dest, buffer.Count); + } + + /// + /// Receive + /// + /// Buffer + /// Length + /// Received bytes + public int Receive(byte* buffer, int length) => ikcp_recv(_kcp, buffer, length); + + /// + /// Receive + /// + /// Buffer + /// Offset + /// Length + /// Received bytes + public int Receive(byte* buffer, int offset, int length) => ikcp_recv(_kcp, buffer + offset, length); + + /// + /// Update + /// + /// Timestamp + public void Update(uint current) => ikcp_update(_kcp, current, _output, _buffer); + + /// + /// Check + /// + /// Timestamp + /// Next flush timestamp + public uint Check(uint current) => ikcp_check(_kcp, current); + + /// + /// Flush + /// + public void Flush() => ikcp_flush(_kcp, _output, _buffer); + + /// + /// Set maximum transmission unit + /// + /// Maximum transmission unit + /// Set + public int SetMtu(int mtu) => ikcp_setmtu(_kcp, mtu, ref _buffer); + + /// + /// Set flush interval + /// + /// Flush interval + public void SetInterval(int interval) => ikcp_interval(_kcp, interval); + + /// + /// Set no delay + /// + /// Whether Nagle's algorithm is disabled + /// Flush interval + /// Fast resend trigger count + /// No congestion window + public void SetNoDelay(int nodelay, int interval, int resend, int nc) => ikcp_nodelay(_kcp, nodelay, interval, resend, nc); + + /// + /// Set window size + /// + /// Send window size + /// Receive window size + public void SetWindowSize(int sndwnd, int rcvwnd) => ikcp_wndsize(_kcp, sndwnd, rcvwnd); + + /// + /// Set fast resend limit + /// + /// Fast resend limit + public void SetFastResendLimit(int fastlimit) => ikcp_fastresendlimit(_kcp, fastlimit); + + /// + /// Set whether stream mode is enabled + /// + /// Whether stream mode is enabled + public void SetStreamMode(int stream) => ikcp_streammode(_kcp, stream); + + /// + /// Set minimum retransmission timeout + /// + /// Minimum retransmission timeout + public void SetMinrto(int minrto) => ikcp_minrto(_kcp, minrto); + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Protocol/KCP/Base/ikcpc.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Protocol/KCP/Base/ikcpc.cs new file mode 100644 index 0000000..2575805 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Protocol/KCP/Base/ikcpc.cs @@ -0,0 +1,1218 @@ +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using Fantasy; +using static KCP.IQUEUEHEAD; +using static KCP.KCPBASIC; + +#pragma warning disable CS8600 +#pragma warning disable CS8602 +#pragma warning disable CS8981 + +// ReSharper disable IdentifierTypo +// ReSharper disable InconsistentNaming +// ReSharper disable ConvertIfStatementToSwitchStatement + +namespace KCP +{ + internal static unsafe class IKCP + { + private static void memcpy(void* dest, void* src, int n) + { + Unsafe.CopyBlockUnaligned(dest, src, (uint)n); + } + + private static void memcpy(void* dest, void* src, uint n) + { + Unsafe.CopyBlockUnaligned(dest, src, n); + } + + private static void* malloc(nint size) => +#if !UNITY_2021_3_OR_NEWER || NET6_0_OR_GREATER + NativeMemory.Alloc((nuint)size); +#else + (void*)Marshal.AllocHGlobal(size); +#endif + + private static void* malloc(nuint size) => +#if !UNITY_2021_3_OR_NEWER || NET6_0_OR_GREATER + NativeMemory.Alloc(size); +#else + (void*)Marshal.AllocHGlobal((nint)size); +#endif + + private static void free(void* ptr) => +#if !UNITY_2021_3_OR_NEWER || NET6_0_OR_GREATER + NativeMemory.Free(ptr); +#else + Marshal.FreeHGlobal((nint)ptr); +#endif + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static byte* ikcp_encode8u(byte* p, byte c) + { + *p++ = c; + return p; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static byte* ikcp_decode8u(byte* p, byte* c) + { + *c = *p++; + return p; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static byte* ikcp_encode16u(byte* p, ushort w) + { + memcpy(p, &w, 2); + p += 2; + return p; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static byte* ikcp_decode16u(byte* p, ushort* w) + { + memcpy(w, p, 2); + p += 2; + return p; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static byte* ikcp_encode32u(byte* p, uint l) + { + memcpy(p, &l, 4); + p += 4; + return p; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static byte* ikcp_decode32u(byte* p, uint* l) + { + memcpy(l, p, 4); + p += 4; + return p; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static uint _imin_(uint a, uint b) => a <= b ? a : b; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static uint _imax_(uint a, uint b) => a >= b ? a : b; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static uint _ibound_(uint lower, uint middle, uint upper) => _imin_(_imax_(lower, middle), upper); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static int _iclamp_(int x, uint min, uint max) => x < min ? (int)min : x > max ? (int)max : x; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static uint _iceilpow2_(uint x) + { + x--; + x |= x >> 1; + x |= x >> 2; + x |= x >> 4; + x |= x >> 8; + x |= x >> 16; + x++; + return x; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static int _itimediff(uint later, uint earlier) => (int)(later - earlier); + + private static void* ikcp_malloc(nint size) => malloc(size); + + private static void* ikcp_malloc(nuint size) => malloc(size); + + private static void ikcp_free(void* ptr) => free(ptr); + + private static IKCPSEG* ikcp_segment_new(IKCPCB* kcp, int size) => (IKCPSEG*)ikcp_malloc(sizeof(IKCPSEG) + size); + + private static void ikcp_segment_delete(IKCPCB* kcp, IKCPSEG* seg) => ikcp_free(seg); + + private static void ikcp_output(KcpCallback output, byte[] data, int size) + { + if (size == 0) + return; + output(data, ref size); + } + + public static IKCPCB* ikcp_create(uint conv, ref byte[] buffer) + { + var kcp = (IKCPCB*)ikcp_malloc(sizeof(IKCPCB)); + kcp->conv = conv; + kcp->snd_una = 0; + kcp->snd_nxt = 0; + kcp->rcv_nxt = 0; + kcp->ts_probe = 0; + kcp->probe_wait = 0; + kcp->snd_wnd = WND_SND; + kcp->rcv_wnd = WND_RCV; + kcp->rmt_wnd = WND_RCV; + kcp->cwnd = 0; + kcp->incr = 0; + kcp->probe = 0; + kcp->mtu = MTU_DEF; + kcp->mss = kcp->mtu - OVERHEAD; + kcp->stream = 0; + buffer = new byte[REVERSED_HEAD + (kcp->mtu + OVERHEAD) * 3]; + iqueue_init(&kcp->snd_queue); + iqueue_init(&kcp->rcv_queue); + iqueue_init(&kcp->snd_buf); + iqueue_init(&kcp->rcv_buf); + kcp->nrcv_buf = 0; + kcp->nsnd_buf = 0; + kcp->nrcv_que = 0; + kcp->nsnd_que = 0; + kcp->state = 0; + kcp->acklist = null; + kcp->ackblock = 0; + kcp->ackcount = 0; + kcp->rx_srtt = 0; + kcp->rx_rttval = 0; + kcp->rx_rto = (int)RTO_DEF; + kcp->rx_minrto = (int)RTO_MIN; + kcp->current = 0; + kcp->interval = INTERVAL; + kcp->ts_flush = INTERVAL; + kcp->nodelay = 0; + kcp->updated = 0; + kcp->ssthresh = THRESH_INIT; + kcp->fastresend = 0; + kcp->fastlimit = (int)FASTACK_LIMIT; + kcp->nocwnd = 0; + kcp->xmit = 0; + return kcp; + } + + public static void ikcp_release(IKCPCB* kcp) + { + if (kcp != null) + { + IKCPSEG* seg; + while (!iqueue_is_empty(&kcp->snd_buf)) + { + seg = iqueue_entry(kcp->snd_buf.next); + iqueue_del(&seg->node); + ikcp_segment_delete(kcp, seg); + } + + while (!iqueue_is_empty(&kcp->rcv_buf)) + { + seg = iqueue_entry(kcp->rcv_buf.next); + iqueue_del(&seg->node); + ikcp_segment_delete(kcp, seg); + } + + while (!iqueue_is_empty(&kcp->snd_queue)) + { + seg = iqueue_entry(kcp->snd_queue.next); + iqueue_del(&seg->node); + ikcp_segment_delete(kcp, seg); + } + + while (!iqueue_is_empty(&kcp->rcv_queue)) + { + seg = iqueue_entry(kcp->rcv_queue.next); + iqueue_del(&seg->node); + ikcp_segment_delete(kcp, seg); + } + + if (kcp->acklist != null) + ikcp_free(kcp->acklist); + kcp->nrcv_buf = 0; + kcp->nsnd_buf = 0; + kcp->nrcv_que = 0; + kcp->nsnd_que = 0; + kcp->ackcount = 0; + kcp->acklist = null; + ikcp_free(kcp); + } + } + + public static int ikcp_recv(IKCPCB* kcp, byte* buffer, int len) + { + if (iqueue_is_empty(&kcp->rcv_queue)) + return -1; + var peeksize = ikcp_peeksize_internal(kcp); + if (peeksize < 0) + return -2; + int recover; + IQUEUEHEAD* p; + IKCPSEG* seg; + if (len < 0) + { + len = -len; + if (peeksize > len) + return -3; + recover = kcp->nrcv_que >= kcp->rcv_wnd ? 1 : 0; + p = kcp->rcv_queue.next; + for (len = 0; p != &kcp->rcv_queue;) + { + seg = iqueue_entry(p); + p = p->next; + if (buffer != null) + { + memcpy(buffer, seg->data, seg->len); + buffer += seg->len; + } + + len += (int)seg->len; + var fragment = (int)seg->frg; + if (fragment == 0) + break; + } + } + else + { + if (peeksize > len) + return -3; + recover = kcp->nrcv_que >= kcp->rcv_wnd ? 1 : 0; + p = kcp->rcv_queue.next; + for (len = 0; p != &kcp->rcv_queue;) + { + seg = iqueue_entry(p); + p = p->next; + if (buffer != null) + { + memcpy(buffer, seg->data, seg->len); + buffer += seg->len; + } + + len += (int)seg->len; + var fragment = (int)seg->frg; + iqueue_del(&seg->node); + ikcp_segment_delete(kcp, seg); + kcp->nrcv_que--; + if (fragment == 0) + break; + } + } + + while (!iqueue_is_empty(&kcp->rcv_buf)) + { + seg = iqueue_entry(kcp->rcv_buf.next); + if (seg->sn == kcp->rcv_nxt && kcp->nrcv_que < kcp->rcv_wnd) + { + iqueue_del(&seg->node); + kcp->nrcv_buf--; + iqueue_add_tail(&seg->node, &kcp->rcv_queue); + kcp->nrcv_que++; + kcp->rcv_nxt++; + } + else + { + break; + } + } + + if (kcp->nrcv_que < kcp->rcv_wnd && recover != 0) + kcp->probe |= ASK_TELL; + return len; + } + + public static int ikcp_peeksize(IKCPCB* kcp) => iqueue_is_empty(&kcp->rcv_queue) ? -1 : ikcp_peeksize_internal(kcp); + + private static int ikcp_peeksize_internal(IKCPCB* kcp) + { + var seg = iqueue_entry(kcp->rcv_queue.next); + if (seg->frg == 0) + return (int)seg->len; + if (kcp->nrcv_que < seg->frg + 1) + return -1; + IQUEUEHEAD* p; + var length = 0; + for (p = kcp->rcv_queue.next; p != &kcp->rcv_queue; p = p->next) + { + seg = iqueue_entry(p); + length += (int)seg->len; + if (seg->frg == 0) + break; + } + + return length; + } + + public static int ikcp_send(IKCPCB* kcp, byte* buffer, int len) + { + if (len < 0) + return -1; + IKCPSEG* seg; + var sent = 0; + if (kcp->stream != 0) + { + if (!iqueue_is_empty(&kcp->snd_queue)) + { + var old = iqueue_entry(kcp->snd_queue.prev); + if (old->len < kcp->mss) + { + var capacity = (int)kcp->mss - (int)old->len; + var extend = len < capacity ? len : capacity; + seg = ikcp_segment_new(kcp, (int)old->len + extend); + iqueue_add_tail(&seg->node, &kcp->snd_queue); + memcpy(seg->data, old->data, old->len); + if (buffer != null) + { + memcpy(seg->data + old->len, buffer, extend); + buffer += extend; + } + + seg->len = old->len + (uint)extend; + seg->frg = 0; + len -= extend; + iqueue_del_init(&old->node); + ikcp_segment_delete(kcp, old); + sent = extend; + } + } + + if (len <= 0) + return sent; + int count; + if (len <= (int)kcp->mss) + { + count = 1; + } + else + { + count = (int)((len + kcp->mss - 1) / kcp->mss); + if (count >= (int)kcp->rcv_wnd) + return sent > 0 ? sent : -2; + if (count == 0) + count = 1; + } + + int i; + for (i = 0; i < count; ++i) + { + var size = len > (int)kcp->mss ? (int)kcp->mss : len; + seg = ikcp_segment_new(kcp, size); + if (buffer != null && len > 0) + memcpy(seg->data, buffer, size); + seg->len = (uint)size; + seg->frg = 0; + iqueue_init(&seg->node); + iqueue_add_tail(&seg->node, &kcp->snd_queue); + kcp->nsnd_que++; + if (buffer != null) + buffer += size; + len -= size; + sent += size; + } + } + else + { + int count; + if (len <= (int)kcp->mss) + { + count = 1; + } + else + { + count = (int)((len + kcp->mss - 1) / kcp->mss); + if (count > FRG_LIMIT || count >= (int)kcp->rcv_wnd) + return -2; + if (count == 0) + count = 1; + } + + int i; + for (i = 0; i < count; ++i) + { + var size = len > (int)kcp->mss ? (int)kcp->mss : len; + seg = ikcp_segment_new(kcp, size); + if (buffer != null && len > 0) + memcpy(seg->data, buffer, size); + seg->len = (uint)size; + seg->frg = (uint)(count - i - 1); + iqueue_init(&seg->node); + iqueue_add_tail(&seg->node, &kcp->snd_queue); + kcp->nsnd_que++; + if (buffer != null) + buffer += size; + len -= size; + sent += size; + } + } + + return sent; + } + + private static void ikcp_update_ack(IKCPCB* kcp, int rtt) + { + if (kcp->rx_srtt == 0) + { + kcp->rx_srtt = rtt; + kcp->rx_rttval = rtt / 2; + } + else + { + var delta = rtt - kcp->rx_srtt; + if (delta < 0) + delta = -delta; + kcp->rx_rttval = (3 * kcp->rx_rttval + delta) / 4; + kcp->rx_srtt = (7 * kcp->rx_srtt + rtt) / 8; + if (kcp->rx_srtt < 1) + kcp->rx_srtt = 1; + } + + var rto = (int)(kcp->rx_srtt + _imax_(kcp->interval, (uint)(4 * kcp->rx_rttval))); + kcp->rx_rto = (int)_ibound_((uint)kcp->rx_minrto, (uint)rto, RTO_MAX); + } + + private static void ikcp_shrink_buf(IKCPCB* kcp) + { + var p = kcp->snd_buf.next; + if (p != &kcp->snd_buf) + { + var seg = iqueue_entry(p); + kcp->snd_una = seg->sn; + } + else + { + kcp->snd_una = kcp->snd_nxt; + } + } + + private static void ikcp_parse_ack(IKCPCB* kcp, uint sn) + { + if (_itimediff(sn, kcp->snd_una) < 0 || _itimediff(sn, kcp->snd_nxt) >= 0) + return; + IQUEUEHEAD* p, next; + for (p = kcp->snd_buf.next; p != &kcp->snd_buf; p = next) + { + var seg = iqueue_entry(p); + next = p->next; + if (sn == seg->sn) + { + iqueue_del(p); + ikcp_segment_delete(kcp, seg); + kcp->nsnd_buf--; + break; + } + + if (_itimediff(sn, seg->sn) < 0) + break; + } + } + + private static void ikcp_parse_una(IKCPCB* kcp, uint una) + { + IQUEUEHEAD* p, next; + for (p = kcp->snd_buf.next; p != &kcp->snd_buf; p = next) + { + var seg = iqueue_entry(p); + next = p->next; + if (_itimediff(una, seg->sn) > 0) + { + iqueue_del(p); + ikcp_segment_delete(kcp, seg); + kcp->nsnd_buf--; + } + else + { + break; + } + } + } + + private static void ikcp_parse_fastack(IKCPCB* kcp, uint sn, uint ts) + { + if (_itimediff(sn, kcp->snd_una) < 0 || _itimediff(sn, kcp->snd_nxt) >= 0) + return; + IQUEUEHEAD* p, next; + for (p = kcp->snd_buf.next; p != &kcp->snd_buf; p = next) + { + var seg = iqueue_entry(p); + next = p->next; + if (_itimediff(sn, seg->sn) < 0) + break; + if (sn != seg->sn) + { +#if KCP_FASTACK_CONSERVE + seg->fastack++; +#else + if (_itimediff(ts, seg->ts) >= 0) + seg->fastack++; +#endif + } + } + } + + private static int ikcp_ack_push(IKCPCB* kcp, uint sn, uint ts) + { + var newsize = kcp->ackcount + 1; + if (newsize > kcp->ackblock) + { + var newblock = newsize <= 8 ? 8 : _iceilpow2_(newsize); + var acklist = (uint*)ikcp_malloc(newblock << 3); + if (kcp->acklist != null) + { + uint x; + for (x = 0; x < kcp->ackcount; ++x) + { + acklist[x * 2] = kcp->acklist[x * 2]; + acklist[x * 2 + 1] = kcp->acklist[x * 2 + 1]; + } + + ikcp_free(kcp->acklist); + } + + kcp->acklist = acklist; + kcp->ackblock = newblock; + } + + var ptr = &kcp->acklist[kcp->ackcount * 2]; + ptr[0] = sn; + ptr[1] = ts; + kcp->ackcount++; + return 0; + } + + private static void ikcp_ack_get(IKCPCB* kcp, int p, uint* sn, uint* ts) + { + if (sn != null) + sn[0] = kcp->acklist[p * 2]; + if (ts != null) + ts[0] = kcp->acklist[p * 2 + 1]; + } + + private static void ikcp_parse_data(IKCPCB* kcp, IKCPSEG* newseg) + { + var sn = newseg->sn; + if (_itimediff(sn, kcp->rcv_nxt + kcp->rcv_wnd) >= 0 || _itimediff(sn, kcp->rcv_nxt) < 0) + { + ikcp_segment_delete(kcp, newseg); + return; + } + + IQUEUEHEAD* p, prev; + var repeat = 0; + for (p = kcp->rcv_buf.prev; p != &kcp->rcv_buf; p = prev) + { + var seg = iqueue_entry(p); + prev = p->prev; + if (seg->sn == sn) + { + repeat = 1; + break; + } + + if (_itimediff(sn, seg->sn) > 0) + break; + } + + if (repeat == 0) + { + iqueue_init(&newseg->node); + iqueue_add(&newseg->node, p); + kcp->nrcv_buf++; + } + else + { + ikcp_segment_delete(kcp, newseg); + } + + while (!iqueue_is_empty(&kcp->rcv_buf)) + { + var seg = iqueue_entry(kcp->rcv_buf.next); + if (seg->sn == kcp->rcv_nxt && kcp->nrcv_que < kcp->rcv_wnd) + { + iqueue_del(&seg->node); + kcp->nrcv_buf--; + iqueue_add_tail(&seg->node, &kcp->rcv_queue); + kcp->nrcv_que++; + kcp->rcv_nxt++; + } + else + { + break; + } + } + } + + public static int ikcp_input(IKCPCB* kcp, byte* data, int size) + { + if (data == null || size < (int)OVERHEAD) + return -1; + var prev_una = kcp->snd_una; + uint maxack = 0, latest_ts = 0; + var flag = 0; + while (true) + { + uint ts, sn, len, una, conv; + ushort wnd; + byte cmd, frg; + if (size < (int)OVERHEAD) + break; + data = ikcp_decode32u(data, &conv); + if (conv != kcp->conv) + return -1; + data = ikcp_decode8u(data, &cmd); + data = ikcp_decode8u(data, &frg); + data = ikcp_decode16u(data, &wnd); + data = ikcp_decode32u(data, &ts); + data = ikcp_decode32u(data, &sn); + data = ikcp_decode32u(data, &una); + data = ikcp_decode32u(data, &len); + size -= (int)OVERHEAD; + if (size < len || (int)len < 0) + return -2; + if (cmd != CMD_PUSH && cmd != CMD_ACK && cmd != CMD_WASK && cmd != CMD_WINS) + return -3; + kcp->rmt_wnd = wnd; + ikcp_parse_una(kcp, una); + ikcp_shrink_buf(kcp); + if (cmd == CMD_ACK) + { + if (_itimediff(kcp->current, ts) >= 0) + ikcp_update_ack(kcp, _itimediff(kcp->current, ts)); + ikcp_parse_ack(kcp, sn); + ikcp_shrink_buf(kcp); + if (flag == 0) + { + flag = 1; + maxack = sn; + latest_ts = ts; + } + else + { + if (_itimediff(sn, maxack) > 0) + { +#if KCP_FASTACK_CONSERVE + maxack = sn; + latest_ts = ts; +#else + if (_itimediff(ts, latest_ts) > 0) + { + maxack = sn; + latest_ts = ts; + } +#endif + } + } + } + else if (cmd == CMD_PUSH) + { + if (_itimediff(sn, kcp->rcv_nxt + kcp->rcv_wnd) < 0) + { + if (ikcp_ack_push(kcp, sn, ts) != 0) + return -4; + if (_itimediff(sn, kcp->rcv_nxt) >= 0) + { + var seg = ikcp_segment_new(kcp, (int)len); + seg->conv = conv; + seg->cmd = cmd; + seg->frg = frg; + seg->wnd = wnd; + seg->ts = ts; + seg->sn = sn; + seg->una = una; + seg->len = len; + if (len > 0) + memcpy(seg->data, data, len); + ikcp_parse_data(kcp, seg); + } + } + } + else if (cmd == CMD_WASK) + { + kcp->probe |= ASK_TELL; + } + else if (cmd != CMD_WINS) + { + return -3; + } + + data += len; + size -= (int)len; + } + + if (flag != 0) + ikcp_parse_fastack(kcp, maxack, latest_ts); + if (_itimediff(kcp->snd_una, prev_una) > 0) + { + if (kcp->cwnd < kcp->rmt_wnd) + { + var mss = kcp->mss; + if (kcp->cwnd < kcp->ssthresh) + { + kcp->cwnd++; + kcp->incr += mss; + } + else + { + if (kcp->incr < mss) + kcp->incr = mss; + kcp->incr += mss * mss / kcp->incr + mss / 16; + if ((kcp->cwnd + 1) * mss <= kcp->incr) + kcp->cwnd = (kcp->incr + mss - 1) / (mss > 0 ? mss : 1); + } + + if (kcp->cwnd > kcp->rmt_wnd) + { + kcp->cwnd = kcp->rmt_wnd; + kcp->incr = kcp->rmt_wnd * mss; + } + } + } + + return 0; + } + + private static byte* ikcp_encode_seg(byte* ptr, IKCPSEG* seg) + { + ptr = ikcp_encode32u(ptr, seg->conv); + ptr = ikcp_encode8u(ptr, (byte)seg->cmd); + ptr = ikcp_encode8u(ptr, (byte)seg->frg); + ptr = ikcp_encode16u(ptr, (ushort)seg->wnd); + ptr = ikcp_encode32u(ptr, seg->ts); + ptr = ikcp_encode32u(ptr, seg->sn); + ptr = ikcp_encode32u(ptr, seg->una); + ptr = ikcp_encode32u(ptr, seg->len); + return ptr; + } + + private static int ikcp_wnd_unused(IKCPCB* kcp) => kcp->nrcv_que < kcp->rcv_wnd ? (int)(kcp->rcv_wnd - kcp->nrcv_que) : 0; + + public static void ikcp_flush(IKCPCB* kcp, KcpCallback output, byte[] bytes) + { + if (kcp->updated == 0) + return; + ikcp_flush_internal(kcp, output, bytes); + } + + private static void ikcp_flush_internal(IKCPCB* kcp, KcpCallback output, byte[] bytes) + { + var current = kcp->current; + fixed (byte* buffer = &bytes[REVERSED_HEAD]) + { + var ptr = buffer; + int size, i; + IQUEUEHEAD* p; + var change = 0; + var lost = 0; + IKCPSEG seg; + seg.conv = kcp->conv; + seg.cmd = CMD_ACK; + seg.frg = 0; + seg.wnd = (uint)ikcp_wnd_unused(kcp); + seg.una = kcp->rcv_nxt; + seg.len = 0; + seg.sn = 0; + seg.ts = 0; + var count = (int)kcp->ackcount; + for (i = 0; i < count; ++i) + { + size = (int)(ptr - buffer); + if (size + (int)OVERHEAD > (int)kcp->mtu) + { + ikcp_output(output, bytes, size); + ptr = buffer; + } + + ikcp_ack_get(kcp, i, &seg.sn, &seg.ts); + ptr = ikcp_encode_seg(ptr, &seg); + } + + kcp->ackcount = 0; + if (kcp->rmt_wnd == 0) + { + if (kcp->probe_wait == 0) + { + kcp->probe_wait = PROBE_INIT; + kcp->ts_probe = kcp->current + kcp->probe_wait; + } + else + { + if (_itimediff(kcp->current, kcp->ts_probe) >= 0) + { + if (kcp->probe_wait < PROBE_INIT) + kcp->probe_wait = PROBE_INIT; + kcp->probe_wait += kcp->probe_wait / 2; + if (kcp->probe_wait > PROBE_LIMIT) + kcp->probe_wait = PROBE_LIMIT; + kcp->ts_probe = kcp->current + kcp->probe_wait; + kcp->probe |= ASK_SEND; + } + } + } + else + { + kcp->ts_probe = 0; + kcp->probe_wait = 0; + } + + if ((kcp->probe != 0) & (ASK_SEND != 0)) + { + seg.cmd = CMD_WASK; + size = (int)(ptr - buffer); + if (size + (int)OVERHEAD > (int)kcp->mtu) + { + ikcp_output(output, bytes, size); + ptr = buffer; + } + + ptr = ikcp_encode_seg(ptr, &seg); + } + + if ((kcp->probe != 0) & (ASK_TELL != 0)) + { + seg.cmd = CMD_WINS; + size = (int)(ptr - buffer); + if (size + (int)OVERHEAD > (int)kcp->mtu) + { + ikcp_output(output, bytes, size); + ptr = buffer; + } + + ptr = ikcp_encode_seg(ptr, &seg); + } + + kcp->probe = 0; + var cwnd = _imin_(kcp->snd_wnd, kcp->rmt_wnd); + if (kcp->nocwnd == 0) + cwnd = _imin_(kcp->cwnd, cwnd); + while (_itimediff(kcp->snd_nxt, kcp->snd_una + cwnd) < 0) + { + if (iqueue_is_empty(&kcp->snd_queue)) + break; + var newseg = iqueue_entry(kcp->snd_queue.next); + iqueue_del(&newseg->node); + iqueue_add_tail(&newseg->node, &kcp->snd_buf); + kcp->nsnd_que--; + kcp->nsnd_buf++; + newseg->conv = kcp->conv; + newseg->cmd = CMD_PUSH; + newseg->wnd = seg.wnd; + newseg->ts = current; + newseg->sn = kcp->snd_nxt++; + newseg->una = kcp->rcv_nxt; + newseg->resendts = current; + newseg->rto = (uint)kcp->rx_rto; + newseg->fastack = 0; + newseg->xmit = 0; + } + + var resent = kcp->fastresend > 0 ? (uint)kcp->fastresend : 4294967295; + if (kcp->nodelay == 0) + { + var rtomin = (uint)(kcp->rx_rto >> 3); + for (p = kcp->snd_buf.next; p != &kcp->snd_buf; p = p->next) + { + var segment = iqueue_entry(p); + var needsend = 0; + if (segment->xmit == 0) + { + needsend = 1; + segment->xmit++; + segment->rto = (uint)kcp->rx_rto; + segment->resendts = current + segment->rto + rtomin; + } + else if (_itimediff(current, segment->resendts) >= 0) + { + needsend = 1; + segment->xmit++; + kcp->xmit++; + segment->rto += _imax_(segment->rto, (uint)kcp->rx_rto); + segment->resendts = current + segment->rto; + lost = 1; + } + else if (segment->fastack >= resent) + { + if ((int)segment->xmit <= kcp->fastlimit || kcp->fastlimit == 0) + { + needsend = 1; + segment->xmit++; + segment->fastack = 0; + segment->resendts = current + segment->rto; + change++; + } + } + + if (needsend != 0) + { + segment->ts = current; + segment->wnd = seg.wnd; + segment->una = kcp->rcv_nxt; + size = (int)(ptr - buffer); + var need = (int)(OVERHEAD + segment->len); + if (size + need > (int)kcp->mtu) + { + ikcp_output(output, bytes, size); + ptr = buffer; + } + + ptr = ikcp_encode_seg(ptr, segment); + if (segment->len > 0) + { + memcpy(ptr, segment->data, segment->len); + ptr += segment->len; + } + + if (segment->xmit >= DEADLINK) + kcp->state = -1; + } + } + } + else if (kcp->nodelay == 1) + { + for (p = kcp->snd_buf.next; p != &kcp->snd_buf; p = p->next) + { + var segment = iqueue_entry(p); + var needsend = 0; + if (segment->xmit == 0) + { + needsend = 1; + segment->xmit++; + segment->rto = (uint)kcp->rx_rto; + segment->resendts = current + segment->rto; + } + else if (_itimediff(current, segment->resendts) >= 0) + { + needsend = 1; + segment->xmit++; + kcp->xmit++; + var step = (int)segment->rto; + segment->rto += (uint)(step / 2); + segment->resendts = current + segment->rto; + lost = 1; + } + else if (segment->fastack >= resent) + { + if ((int)segment->xmit <= kcp->fastlimit || kcp->fastlimit == 0) + { + needsend = 1; + segment->xmit++; + segment->fastack = 0; + segment->resendts = current + segment->rto; + change++; + } + } + + if (needsend != 0) + { + segment->ts = current; + segment->wnd = seg.wnd; + segment->una = kcp->rcv_nxt; + size = (int)(ptr - buffer); + var need = (int)(OVERHEAD + segment->len); + if (size + need > (int)kcp->mtu) + { + ikcp_output(output, bytes, size); + ptr = buffer; + } + + ptr = ikcp_encode_seg(ptr, segment); + if (segment->len > 0) + { + memcpy(ptr, segment->data, segment->len); + ptr += segment->len; + } + + if (segment->xmit >= DEADLINK) + kcp->state = -1; + } + } + } + else + { + for (p = kcp->snd_buf.next; p != &kcp->snd_buf; p = p->next) + { + var segment = iqueue_entry(p); + var needsend = 0; + if (segment->xmit == 0) + { + needsend = 1; + segment->xmit++; + segment->rto = (uint)kcp->rx_rto; + segment->resendts = current + segment->rto; + } + else if (_itimediff(current, segment->resendts) >= 0) + { + needsend = 1; + segment->xmit++; + kcp->xmit++; + var step = (int)segment->rto; + segment->rto += (uint)(step / 2); + segment->resendts = current + segment->rto; + lost = 1; + } + else if (segment->fastack >= resent) + { + if ((int)segment->xmit <= kcp->fastlimit || kcp->fastlimit == 0) + { + needsend = 1; + segment->xmit++; + segment->fastack = 0; + segment->resendts = current + segment->rto; + change++; + } + } + + if (needsend != 0) + { + segment->ts = current; + segment->wnd = seg.wnd; + segment->una = kcp->rcv_nxt; + size = (int)(ptr - buffer); + var need = (int)(OVERHEAD + segment->len); + if (size + need > (int)kcp->mtu) + { + ikcp_output(output, bytes, size); + ptr = buffer; + } + + ptr = ikcp_encode_seg(ptr, segment); + if (segment->len > 0) + { + memcpy(ptr, segment->data, segment->len); + ptr += segment->len; + } + + if (segment->xmit >= DEADLINK) + kcp->state = -1; + } + } + } + + size = (int)(ptr - buffer); + if (size > 0) + ikcp_output(output, bytes, size); + if (change != 0) + { + var inflight = kcp->snd_nxt - kcp->snd_una; + kcp->ssthresh = inflight / 2; + if (kcp->ssthresh < THRESH_MIN) + kcp->ssthresh = THRESH_MIN; + kcp->cwnd = kcp->ssthresh + resent; + kcp->incr = kcp->cwnd * kcp->mss; + } + + if (lost != 0) + { + kcp->ssthresh = cwnd / 2; + if (kcp->ssthresh < THRESH_MIN) + kcp->ssthresh = THRESH_MIN; + kcp->cwnd = 1; + kcp->incr = kcp->mss; + } + + if (kcp->cwnd < 1) + { + kcp->cwnd = 1; + kcp->incr = kcp->mss; + } + } + } + + public static void ikcp_update(IKCPCB* kcp, uint current, KcpCallback output, byte[] bytes) + { + kcp->current = current; + if (kcp->updated == 0) + { + kcp->updated = 1; + kcp->ts_flush = kcp->current; + } + + var slap = _itimediff(kcp->current, kcp->ts_flush); + if (slap >= 10000 || slap < -10000) + { + kcp->ts_flush = kcp->current; + slap = 0; + } + + if (slap >= 0) + { + kcp->ts_flush += kcp->interval; + if (_itimediff(kcp->current, kcp->ts_flush) >= 0) + kcp->ts_flush = kcp->current + kcp->interval; + ikcp_flush_internal(kcp, output, bytes); + } + } + + public static uint ikcp_check(IKCPCB* kcp, uint current) + { + if (kcp->updated == 0) + return current; + var ts_flush = kcp->ts_flush; + if (_itimediff(current, ts_flush) >= 10000 || _itimediff(current, ts_flush) < -10000) + ts_flush = current; + if (_itimediff(current, ts_flush) >= 0) + return current; + var tm_packet = 2147483647; + var tm_flush = _itimediff(ts_flush, current); + IQUEUEHEAD* p; + for (p = kcp->snd_buf.next; p != &kcp->snd_buf; p = p->next) + { + var seg = iqueue_entry(p); + var diff = _itimediff(seg->resendts, current); + if (diff <= 0) + return current; + if (diff < tm_packet) + tm_packet = diff; + } + + var minimal = (uint)(tm_packet < tm_flush ? tm_packet : tm_flush); + if (minimal >= kcp->interval) + minimal = kcp->interval; + return current + minimal; + } + + public static int ikcp_setmtu(IKCPCB* kcp, int mtu, ref byte[] buffer) + { + if (kcp->mtu == (uint)mtu) + return 0; + if (mtu < (int)OVERHEAD) + return -1; + buffer = new byte[REVERSED_HEAD + (mtu + OVERHEAD) * 3]; + kcp->mtu = (uint)mtu; + kcp->mss = kcp->mtu - OVERHEAD; + return 0; + } + + public static void ikcp_interval(IKCPCB* kcp, int interval) + { + interval = _iclamp_(interval, INTERVAL_MIN, INTERVAL_LIMIT); + kcp->interval = (uint)interval; + } + + public static void ikcp_nodelay(IKCPCB* kcp, int nodelay, int interval, int resend, int nc) + { + nodelay = _iclamp_(nodelay, NODELAY_MIN, NODELAY_LIMIT); + kcp->nodelay = (uint)nodelay; + if (nodelay != 0) + kcp->rx_minrto = (int)RTO_NDL; + else + kcp->rx_minrto = (int)RTO_MIN; + interval = _iclamp_(interval, INTERVAL_MIN, INTERVAL_LIMIT); + kcp->interval = (uint)interval; + resend = _iclamp_(resend, 0, 4294967295); + kcp->fastresend = resend; + kcp->nocwnd = nc == 1 ? 1 : 0; + } + + public static void ikcp_wndsize(IKCPCB* kcp, int sndwnd, int rcvwnd) + { + sndwnd = _iclamp_(sndwnd, WND_SND, 2147483647); + rcvwnd = _iclamp_(rcvwnd, WND_RCV, 2147483647); + kcp->snd_wnd = (uint)sndwnd; + kcp->rcv_wnd = (uint)rcvwnd; + } + + public static void ikcp_fastresendlimit(IKCPCB* kcp, int fastlimit) + { + fastlimit = _iclamp_(fastlimit, FASTACK_MIN, FASTACK_LIMIT); + kcp->fastlimit = fastlimit; + } + + public static void ikcp_streammode(IKCPCB* kcp, int stream) => kcp->stream = stream == 1 ? 1 : 0; + + public static void ikcp_minrto(IKCPCB* kcp, int minrto) + { + minrto = _iclamp_(minrto, INTERVAL_MIN, RTO_MAX); + kcp->rx_minrto = minrto; + } + } +} diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Protocol/KCP/Base/ikcph.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Protocol/KCP/Base/ikcph.cs new file mode 100644 index 0000000..ebd5cc6 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Protocol/KCP/Base/ikcph.cs @@ -0,0 +1,159 @@ +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +#pragma warning disable CS1591 +#pragma warning disable CS8981 + +// ReSharper disable IdentifierTypo +// ReSharper disable InconsistentNaming + +namespace KCP +{ + public delegate void KcpCallback(byte[] buffer, ref int length); + + internal unsafe struct IQUEUEHEAD + { + public IQUEUEHEAD* next; + public IQUEUEHEAD* prev; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void iqueue_init(IQUEUEHEAD* ptr) + { + ptr->next = ptr; + ptr->prev = ptr; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static IKCPSEG* iqueue_entry(IQUEUEHEAD* ptr) => (IKCPSEG*)(byte*)(IKCPSEG*)ptr; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool iqueue_is_empty(IQUEUEHEAD* entry) => entry == entry->next; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void iqueue_del(IQUEUEHEAD* entry) + { + entry->next->prev = entry->prev; + entry->prev->next = entry->next; + entry->next = null; + entry->prev = null; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void iqueue_del_init(IQUEUEHEAD* entry) + { + iqueue_del(entry); + iqueue_init(entry); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void iqueue_add(IQUEUEHEAD* node, IQUEUEHEAD* head) + { + node->prev = head; + node->next = head->next; + head->next->prev = node; + head->next = node; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void iqueue_add_tail(IQUEUEHEAD* node, IQUEUEHEAD* head) + { + node->prev = head->prev; + node->next = head; + head->prev->next = node; + head->prev = node; + } + } + + [StructLayout(LayoutKind.Sequential)] + internal unsafe struct IKCPSEG + { + public IQUEUEHEAD node; + public uint conv; + public uint cmd; + public uint frg; + public uint wnd; + public uint ts; + public uint sn; + public uint una; + public uint len; + public uint resendts; + public uint rto; + public uint fastack; + public uint xmit; + public fixed byte data[1]; + } + + [StructLayout(LayoutKind.Sequential)] + internal unsafe struct IKCPCB + { + public uint conv, mtu, mss; + public int state; + public uint snd_una, snd_nxt, rcv_nxt; + public uint ssthresh; + public int rx_rttval, rx_srtt, rx_rto, rx_minrto; + public uint snd_wnd, rcv_wnd, rmt_wnd, cwnd, probe; + public uint current, interval, ts_flush, xmit; + public uint nrcv_buf, nsnd_buf; + public uint nrcv_que, nsnd_que; + public uint nodelay, updated; + public uint ts_probe, probe_wait; + public uint incr; + public IQUEUEHEAD snd_queue; + public IQUEUEHEAD rcv_queue; + public IQUEUEHEAD snd_buf; + public IQUEUEHEAD rcv_buf; + public uint* acklist; + public uint ackcount; + public uint ackblock; + public int fastresend; + public int fastlimit; + public int nocwnd, stream; + } + + public static class KCPBASIC + { + public const uint RTO_NDL = 30; + public const uint RTO_MIN = 100; + public const uint RTO_DEF = 200; + public const uint RTO_MAX = 60000; + public const uint CMD_PUSH = 81; + public const uint CMD_ACK = 82; + public const uint CMD_WASK = 83; + public const uint CMD_WINS = 84; + public const uint ASK_SEND = 1; + public const uint ASK_TELL = 2; + public const uint WND_SND = 32; + public const uint WND_RCV = 128; + public const uint MTU_DEF = 1400; + public const uint ACK_FAST = 3; + public const uint INTERVAL = 100; + public const uint INTERVAL_MIN = 1; + public const uint INTERVAL_LIMIT = 5000; + public const uint OVERHEAD = 24; + public const uint DEADLINK = 20; + public const uint THRESH_INIT = 2; + public const uint THRESH_MIN = 2; + public const uint PROBE_INIT = 7000; + public const uint PROBE_LIMIT = 120000; + public const uint FRG_LIMIT = 255; + public const uint NODELAY_MIN = 0; + public const uint NODELAY_LIMIT = 2; + public const uint FASTACK_MIN = 0; + public const uint FASTACK_LIMIT = 5; + public const uint OUTPUT = 1; + public const uint INPUT = 2; + public const uint SEND = 4; + public const uint RECV = 8; + public const uint IN_DATA = 16; + public const uint IN_ACK = 32; + public const uint IN_PROBE = 64; + public const uint IN_WINS = 128; + public const uint OUT_DATA = 256; + public const uint OUT_ACK = 512; + public const uint OUT_PROBE = 1024; + public const uint OUT_WINS = 2048; + + // TODO: remove it if not needed + public const uint REVERSED_HEAD = 5; + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Protocol/KCP/Client/KCPClientNetwork.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Protocol/KCP/Client/KCPClientNetwork.cs new file mode 100644 index 0000000..8881cfb --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Protocol/KCP/Client/KCPClientNetwork.cs @@ -0,0 +1,687 @@ +#if !FANTASY_WEBGL +using System; +using System.Buffers; +using System.Collections.Generic; +using System.IO; +using System.IO.Pipelines; +using System.Net; +using System.Net.Sockets; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Security.Cryptography; +using System.Threading; +using Fantasy.Async; +using Fantasy.Entitas.Interface; +using Fantasy.Helper; +using Fantasy.Network.Interface; +using Fantasy.PacketParser; +using Fantasy.Serialize; +using KCP; +// ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract +// ReSharper disable PossibleNullReferenceException +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. + +#pragma warning disable CS8622 // Nullability of reference types in type of parameter doesn't match the target delegate (possibly because of nullability attributes). + +#pragma warning disable CS8602 // Dereference of a possibly null reference. +namespace Fantasy.Network.KCP +{ + public sealed class KCPClientNetworkUpdateSystem : UpdateSystem + { + protected override void Update(KCPClientNetwork self) + { + self.CheckUpdate(); + } + } + public sealed class KCPClientNetwork : AClientNetwork + { + private Kcp _kcp; + private Socket _socket; + private int _maxSndWnd; + private long _startTime; + private bool _isConnected; + private bool _isDisconnect; + private uint _updateMinTime; + private bool _isInnerDispose; + private long _connectTimeoutId; + private bool _allowWraparound = true; + private IPEndPoint _remoteAddress; + private BufferPacketParser _packetParser; + private readonly Pipe _pipe = new Pipe(); + private readonly byte[] _sendBuff = new byte[5]; + private readonly byte[] _receiveBuffer = new byte[Packet.PacketBodyMaxLength + 20]; + private readonly List _updateTimeOutTime = new List(); + private readonly SortedSet _updateTimer = new SortedSet(); + private readonly SocketAsyncEventArgs _connectEventArgs = new SocketAsyncEventArgs(); + private readonly Queue _messageCache = new Queue(); + private readonly CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource(); +#if FANTASY_UNITY + private readonly EndPoint _ipEndPoint = new IPEndPoint(IPAddress.Any, 0); +#endif + private event Action OnConnectFail; + private event Action OnConnectComplete; + private event Action OnConnectDisconnect; + public uint ChannelId { get; private set; } + private uint TimeNow => (uint) (TimeHelper.Now - _startTime); + + public void Initialize(NetworkTarget networkTarget) + { + base.Initialize(NetworkType.Client, NetworkProtocolType.KCP, networkTarget); + _packetParser = PacketParserFactory.CreateClientBufferPacket(this); + } + + public override void Dispose() + { + if (IsDisposed || _isInnerDispose) + { + return; + } + + _isInnerDispose = true; + + if (!_isDisconnect) + { + SendDisconnect(); + } + + base.Dispose(); + ClearConnectTimeout(); + + if (!_cancellationTokenSource.IsCancellationRequested) + { + try + { + _cancellationTokenSource.Cancel(); + } + catch (OperationCanceledException) + { + // 通常情况下,此处的异常可以忽略 + } + } + + OnConnectDisconnect?.Invoke(); + _kcp.Dispose(); + + if (_socket.Connected) + { + _socket.Close(); + } + + _packetParser.Dispose(); + ChannelId = 0; + _isConnected = false; + _messageCache.Clear(); + } + + #region Connect + + public override Session Connect(string remoteAddress, Action onConnectComplete, Action onConnectFail, Action onConnectDisconnect, bool isHttps, int connectTimeout = 5000) + { + if (IsInit) + { + throw new NotSupportedException($"KCPClientNetwork Has already been initialized. If you want to call Connect again, please re instantiate it."); + } + + IsInit = true; + _startTime = TimeHelper.Now; + ChannelId = CreateChannelId(); + _remoteAddress = NetworkHelper.GetIPEndPoint(remoteAddress); + OnConnectFail = onConnectFail; + OnConnectComplete = onConnectComplete; + OnConnectDisconnect = onConnectDisconnect; + _connectEventArgs.Completed += OnConnectSocketCompleted; + _connectTimeoutId = Scene.TimerComponent.Net.OnceTimer(connectTimeout, () => + { + OnConnectFail?.Invoke(); + Dispose(); + }); + _connectEventArgs.RemoteEndPoint = _remoteAddress; + _socket = new Socket(_remoteAddress.AddressFamily, SocketType.Dgram, ProtocolType.Udp); + _socket.Blocking = false; + _socket.SetSocketBufferToOsLimit(); + _socket.SetSioUdpConnReset(); + _socket.Bind(new IPEndPoint(IPAddress.Any, 0)); + _kcp = KCPFactory.Create(NetworkTarget, ChannelId, KcpSpanCallback, out var kcpSettings); + _maxSndWnd = kcpSettings.MaxSendWindowSize; + + if (!_socket.ConnectAsync(_connectEventArgs)) + { + try + { + OnReceiveSocketComplete(); + } + catch (Exception e) + { + Log.Error(e); + OnConnectFail?.Invoke(); + } + } + + Session = Session.Create(this, _remoteAddress); + return Session; + } + + private void OnConnectSocketCompleted(object sender, SocketAsyncEventArgs asyncEventArgs) + { + if (_cancellationTokenSource.IsCancellationRequested) + { + return; + } + + if (asyncEventArgs.LastOperation == SocketAsyncOperation.Connect) + { + if (asyncEventArgs.SocketError == SocketError.Success) + { + Scene.ThreadSynchronizationContext.Post(OnReceiveSocketComplete); + } + else + { + Scene.ThreadSynchronizationContext.Post(() => + { + OnConnectFail?.Invoke(); + Dispose(); + }); + } + } + } + + private void OnReceiveSocketComplete() + { + SendRequestConnection(); + ReadPipeDataAsync().Coroutine(); + ReceiveSocketAsync().Coroutine(); + } + + #endregion + + #region ReceiveSocket + + private async FTask ReceiveSocketAsync() + { + while (!_cancellationTokenSource.IsCancellationRequested) + { + try + { + var memory = _pipe.Writer.GetMemory(8192); +#if FANTASY_UNITY + MemoryMarshal.TryGetArray(memory, out ArraySegment arraySegment); + var result = await _socket.ReceiveFromAsync(arraySegment, SocketFlags.None, _ipEndPoint); + _pipe.Writer.Advance(result.ReceivedBytes); + await _pipe.Writer.FlushAsync(); +#else + var result = await _socket.ReceiveAsync(memory, SocketFlags.None, _cancellationTokenSource.Token); + _pipe.Writer.Advance(result); + await _pipe.Writer.FlushAsync(); +#endif + } + catch (SocketException) + { + Dispose(); + break; + } + catch (OperationCanceledException) + { + break; + } + catch (ObjectDisposedException) + { + Dispose(); + break; + } + catch (Exception ex) + { + Log.Error($"Unexpected exception: {ex.Message}"); + } + } + + await _pipe.Writer.CompleteAsync(); + } + + #endregion + + #region ReceivePipeData + + private async FTask ReadPipeDataAsync() + { + var pipeReader = _pipe.Reader; + while (!_cancellationTokenSource.IsCancellationRequested) + { + ReadResult result = default; + + try + { + result = await pipeReader.ReadAsync(_cancellationTokenSource.Token); + } + catch (OperationCanceledException) + { + // 出现这个异常表示取消了_cancellationTokenSource。一般Channel断开会取消。 + break; + } + + var buffer = result.Buffer; + var consumed = buffer.Start; + var examined = buffer.End; + + while (TryReadMessage(ref buffer, out var header, out var channelId, out var message)) + { + ReceiveData(ref header, ref channelId, ref message); + consumed = buffer.Start; + } + + if (result.IsCompleted) + { + break; + } + + pipeReader.AdvanceTo(consumed, examined); + } + } + + private unsafe bool TryReadMessage(ref ReadOnlySequence buffer, out KcpHeader header, out uint channelId, out ReadOnlyMemory message) + { + if (buffer.Length < 5) + { + channelId = 0; + message = default; + header = KcpHeader.None; + if (buffer.Length > 0) + { + buffer = buffer.Slice(buffer.Length); + } + return false; + } + + var readOnlyMemory = buffer.First; + + if (MemoryMarshal.TryGetArray(readOnlyMemory, out var arraySegment)) + { + fixed (byte* bytePointer = &arraySegment.Array[arraySegment.Offset]) + { + header = (KcpHeader)bytePointer[0]; + channelId = Unsafe.ReadUnaligned(ref bytePointer[1]); + } + } + else + { + // 如果无法获取数组段,回退到安全代码来执行。这种情况几乎不会发生、为了保险还是写一下了。 + var firstSpan = readOnlyMemory.Span; + header = (KcpHeader)firstSpan[0]; + channelId = MemoryMarshal.Read(firstSpan.Slice(1, 4)); + + } + + message = readOnlyMemory.Slice(5); + buffer = buffer.Slice(readOnlyMemory.Length); + return true; + } + + private void ReceiveData(ref KcpHeader header, ref uint channelId, ref ReadOnlyMemory buffer) + { + switch (header) + { + // 发送握手给服务器 + case KcpHeader.RepeatChannelId: + { + // 到这里是客户端的channelId再服务器上已经存在、需要重新生成一个再次尝试连接 + ChannelId = CreateChannelId(); + SendRequestConnection(); + break; + } + // 收到服务器发送会来的确认握手 + case KcpHeader.WaitConfirmConnection: + { + if (channelId != ChannelId) + { + break; + } + + ClearConnectTimeout(); + SendConfirmConnection(); + OnConnectComplete?.Invoke(); + _isConnected = true; + while (_messageCache.TryDequeue(out var memoryStream)) + { + SendMemoryStream(memoryStream); + } + break; + } + // 收到服务器发送的消息 + case KcpHeader.ReceiveData: + { + if (buffer.Length == 5) + { + Log.Warning($"KCP Server KcpHeader.Data buffer.Length == 5"); + break; + } + + if (channelId != ChannelId) + { + break; + } + + Input(buffer); + break; + } + // 接收到服务器的断开连接消息 + case KcpHeader.Disconnect: + { + if (channelId != ChannelId) + { + break; + } + + _isDisconnect = true; + Dispose(); + break; + } + } + } + + private void Input(ReadOnlyMemory buffer) + { + _kcp.Input(buffer); + AddToUpdate(0); + + while (!_cancellationTokenSource.IsCancellationRequested) + { + try + { + var peekSize = _kcp.PeekSize(); + + if (peekSize < 0) + { + return; + } + + var receiveCount = _kcp.Receive(_receiveBuffer, peekSize); + + if (receiveCount != peekSize) + { + return; + } + + if (!_packetParser.UnPack(_receiveBuffer, ref receiveCount, out var packInfo)) + { + continue; + } + + Session.Receive(packInfo); + } + catch (ScanException e) + { + Log.Debug($"RemoteAddress:{_remoteAddress} \n{e}"); + Dispose(); + } + catch (Exception e) + { + Log.Error(e); + } + } + } + + #endregion + + #region Update + + public void CheckUpdate() + { + var nowTime = TimeNow; + _allowWraparound = nowTime < _updateMinTime; + + if (IsTimeGreaterThan(nowTime, _updateMinTime) && _updateTimer.Count > 0) + { + foreach (var timeId in _updateTimer) + { + if (IsTimeGreaterThan(timeId, nowTime)) + { + _updateMinTime = timeId; + break; + } + + _updateTimeOutTime.Add(timeId); + } + + foreach (var timeId in _updateTimeOutTime) + { + _updateTimer.Remove(timeId); + KcpUpdate(); + } + + _updateTimeOutTime.Clear(); + } + + _allowWraparound = true; + } + + private void AddToUpdate(uint tillTime) + { + if (tillTime == 0) + { + KcpUpdate(); + return; + } + + if (IsTimeGreaterThan(_updateMinTime, tillTime) || _updateMinTime == 0) + { + _updateMinTime = tillTime; + } + + _updateTimer.Add(tillTime); + } + + private void KcpUpdate() + { + var nowTime = TimeNow; + + try + { + _kcp.Update(nowTime); + } + catch (Exception e) + { + Log.Error(e); + } + + AddToUpdate(_kcp.Check(nowTime)); + } + + private const uint HalfMaxUint = uint.MaxValue / 2; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private bool IsTimeGreaterThan(uint timeId, uint nowTime) + { + if (!_allowWraparound) + { + return timeId > nowTime; + } + var diff = timeId - nowTime; + // 如果 diff 的值在 [0, HalfMaxUint] 范围内,说明 timeId 是在 nowTime 之后或相等。 + // 如果 diff 的值在 (HalfMaxUint, uint.MaxValue] 范围内,说明 timeId 是在 nowTime 之前(时间回绕的情况)。 + return diff < HalfMaxUint || diff == HalfMaxUint; + } + + #endregion + + #region Send + + private const byte KcpHeaderDisconnect = (byte)KcpHeader.Disconnect; + private const byte KcpHeaderReceiveData = (byte)KcpHeader.ReceiveData; + private const byte KcpHeaderRequestConnection = (byte)KcpHeader.RequestConnection; + private const byte KcpHeaderConfirmConnection = (byte)KcpHeader.ConfirmConnection; + + public override void Send(uint rpcId, long routeId, MemoryStreamBuffer memoryStream, IMessage message) + { + if (_cancellationTokenSource.IsCancellationRequested) + { + return; + } + + var buffer = _packetParser.Pack(ref rpcId, ref routeId, memoryStream, message); + + if (!_isConnected) + { + _messageCache.Enqueue(buffer); + return; + } + + SendMemoryStream(buffer); + } + + private void SendMemoryStream(MemoryStreamBuffer memoryStream) + { + if (_kcp.WaitSendCount > _maxSndWnd) + { + // 检查等待发送的消息,如果超出两倍窗口大小,KCP作者给的建议是要断开连接 + Log.Warning($"ERR_KcpWaitSendSizeTooLarge {_kcp.WaitSendCount} > {_maxSndWnd}"); + Dispose(); + return; + } + + try + { + _kcp.Send(memoryStream.GetBuffer(), 0, (int)memoryStream.Position); + AddToUpdate(0); + } + finally + { + if (memoryStream.MemoryStreamBufferSource == MemoryStreamBufferSource.Pack) + { + MemoryStreamBufferPool.ReturnMemoryStream(memoryStream); + } + } + } + + private unsafe void SendRequestConnection() + { + try + { + fixed (byte* p = _sendBuff) + { + p[0] = KcpHeaderRequestConnection; + *(uint*)(p + 1) = ChannelId; + } + + SendAsync(_sendBuff, 0, 5); + } + catch (Exception e) + { + Log.Error(e); + } + } + + private unsafe void SendConfirmConnection() + { + try + { + fixed (byte* p = _sendBuff) + { + p[0] = KcpHeaderConfirmConnection; + *(uint*)(p + 1) = ChannelId; + } + + SendAsync(_sendBuff, 0, 5); + } + catch (Exception e) + { + Log.Error(e); + } + } + + private unsafe void SendDisconnect() + { + try + { + fixed (byte* p = _sendBuff) + { + p[0] = KcpHeaderDisconnect; + *(uint*)(p + 1) = ChannelId; + } + + SendAsync(_sendBuff, 0, 5); + } + catch (Exception e) + { + Log.Error(e); + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void SendAsync(byte[] buffer, int offset, int count) + { + try + { + _socket.Send(new ArraySegment(buffer, offset, count), SocketFlags.None); + } + catch (ArgumentException ex) + { + Log.Error($"ArgumentException: {ex.Message}"); // 处理参数错误 + } + catch (SocketException) + { + //Log.Error($"SocketException: {ex.Message}"); // 处理网络错误 + Dispose(); + } + catch (ObjectDisposedException ex) + { + Log.Error($"ObjectDisposedException: {ex.Message}"); // 处理套接字已关闭的情况 + Dispose(); + } + catch (InvalidOperationException ex) + { + Log.Error($"InvalidOperationException: {ex.Message}"); // 处理无效操作 + } + catch (Exception ex) + { + Log.Error($"Exception: {ex.Message}"); // 捕获其他异常 + } + } + + private unsafe void KcpSpanCallback(byte[] buffer, ref int count) + { + if (IsDisposed) + { + return; + } + + if (count == 0) + { + throw new Exception("KcpOutput count 0"); + } + + fixed (byte* p = buffer) + { + p[0] = KcpHeaderReceiveData; + *(uint*)(p + 1) = ChannelId; + } + + SendAsync(buffer, 0, count + 5); + } + + #endregion + + public override void RemoveChannel(uint channelId) + { + Dispose(); + } + + private void ClearConnectTimeout() + { + if (_connectTimeoutId == 0) + { + return; + } + + Scene?.TimerComponent?.Net.Remove(ref _connectTimeoutId); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static unsafe uint CreateChannelId() + { + uint value; + RandomNumberGenerator.Fill(MemoryMarshal.CreateSpan(ref *(byte*)&value, 4)); + return 0xC0000000 | (value & int.MaxValue); + } + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Protocol/KCP/KCPSettings.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Protocol/KCP/KCPSettings.cs new file mode 100644 index 0000000..7e0d926 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Protocol/KCP/KCPSettings.cs @@ -0,0 +1,89 @@ +#if !FANTASY_WEBGL +using System; +using KCP; + +#pragma warning disable CS1591 +namespace Fantasy.Network.KCP +{ + public class KCPSettings + { + public int Mtu { get; private set; } + public int SendWindowSize { get; private set; } + public int ReceiveWindowSize { get; private set; } + public int MaxSendWindowSize { get; private set; } + + public static KCPSettings Create(NetworkTarget networkTarget) + { + var settings = new KCPSettings(); + + switch (networkTarget) + { + case NetworkTarget.Outer: + { + // 外网设置470的原因: + // 1、mtu设置过大有可能路由器过滤掉 + // 2、降低 mtu 到 470,同样数据虽然会发更多的包,但是小包在路由层优先级更高 + settings.Mtu = 470; +#if FANTASY_NET + settings.SendWindowSize = 8192; + settings.ReceiveWindowSize = 8192; + settings.MaxSendWindowSize = 8192 * 8192 * 7; +#endif +#if FANTASY_UNITY || FANTASY_CONSOLE + settings.SendWindowSize = 512; + settings.ReceiveWindowSize = 512; + settings.MaxSendWindowSize = 512 * 512 * 7; +#endif + + break; + } +#if FANTASY_NET + case NetworkTarget.Inner: + { + // 内网设置1400的原因 + // 1、一般都是同一台服务器来运行多个进程来处理 + // 2、内网每个进程跟其他进程只有一个通道进行发送、所以发送的数量会比较大 + // 3、如果不把窗口设置大点、会出现消息滞后。 + // 4、因为内网发送的可不只是外网转发数据、还有可能是其他进程的通讯 + settings.Mtu = 1200; + settings.SendWindowSize = 8192; + settings.ReceiveWindowSize = 8192; + settings.MaxSendWindowSize = 8192 * 8192 * 7; + break; + } +#endif + default: + { + throw new NotSupportedException($"KCPServerNetwork NotSupported NetworkType:{networkTarget}"); + } + } + + return settings; + } + } + + public static class KCPFactory + { + public static Kcp Create(NetworkTarget networkTarget, uint conv, KcpCallback output, out KCPSettings kcpSettings) + { + var kcp = new Kcp(conv, output); + kcpSettings = KCPSettings.Create(networkTarget); + kcp.SetNoDelay(1, 5, 2, 1); + kcp.SetWindowSize(kcpSettings.SendWindowSize, kcpSettings.ReceiveWindowSize); + kcp.SetMtu(kcpSettings.Mtu); + kcp.SetMinrto(30); + return kcp; + } + + public static Kcp Create(KCPSettings kcpSettings, uint conv, KcpCallback output) + { + var kcp = new Kcp(conv, output); + kcp.SetNoDelay(1, 5, 2, 1); + kcp.SetWindowSize(kcpSettings.SendWindowSize, kcpSettings.ReceiveWindowSize); + kcp.SetMtu(kcpSettings.Mtu); + kcp.SetMinrto(30); + return kcp; + } + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Protocol/KCP/KcpHeader.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Protocol/KCP/KcpHeader.cs new file mode 100644 index 0000000..28ddace --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Protocol/KCP/KcpHeader.cs @@ -0,0 +1,14 @@ +namespace Fantasy.Network.KCP +#pragma warning disable CS1591 +{ + public enum KcpHeader : byte + { + None = 0x00, + RequestConnection = 0x01, + WaitConfirmConnection = 0x02, + ConfirmConnection = 0x03, + RepeatChannelId = 0x04, + ReceiveData = 0x06, + Disconnect = 0x07 + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Protocol/KCP/Server/KCPServerNetwork.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Protocol/KCP/Server/KCPServerNetwork.cs new file mode 100644 index 0000000..54b550d --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Protocol/KCP/Server/KCPServerNetwork.cs @@ -0,0 +1,619 @@ +#if FANTASY_NET +using System.Buffers; +using System.IO.Pipelines; +using System.Net; +using System.Net.Sockets; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using Fantasy.Async; +using Fantasy.DataStructure.Collection; +using Fantasy.Entitas.Interface; +using Fantasy.Helper; +using Fantasy.Network.Interface; +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member + +// ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract +#pragma warning disable CS8604 // Possible null reference argument. +#pragma warning disable CS8600 // Converting null literal or possible null value to non-nullable type. +#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. +#pragma warning disable CS8602 // Dereference of a possibly null reference. + +#pragma warning disable CS8622 // Nullability of reference types in type of parameter doesn't match the target delegate (possibly because of nullability attributes). + +namespace Fantasy.Network.KCP +{ + public sealed class KCPServerNetworkUpdateSystem : UpdateSystem + { + protected override void Update(KCPServerNetwork self) + { + self.Update(); + } + } + + public struct PendingConnection + { + public readonly uint ChannelId; + public readonly uint TimeOutId; + public readonly IPEndPoint RemoteEndPoint; + + public PendingConnection(uint channelId, IPEndPoint remoteEndPoint, uint time) + { + ChannelId = channelId; + RemoteEndPoint = remoteEndPoint; + TimeOutId = time + 10 * 1000; // 设置10秒超时,如果10秒内没有确认连接则删除。 + } + } + + public sealed class KCPServerNetwork : ANetwork + { + private Socket _socket; + private long _startTime; + private uint _updateMinTime; + private uint _pendingMinTime; + private bool _allowWraparound = true; + private readonly Pipe _pipe = new Pipe(); + private readonly byte[] _sendBuff = new byte[5]; + private readonly List _pendingTimeOutTime = new List(); + private readonly HashSet _updateChannels = new HashSet(); + private readonly List _updateTimeOutTime = new List(); + private readonly Queue _endPoint = new Queue(); + private readonly CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource(); + private readonly SortedOneToManyList _updateTimer = new SortedOneToManyList(); + + private readonly Dictionary _pendingConnection = new Dictionary(); + private readonly SortedOneToManyList _pendingConnectionTimeOut = new SortedOneToManyList(); + private readonly Dictionary _connectionChannel = new Dictionary(); + + public KCPSettings Settings { get; private set; } + + private uint TimeNow => (uint)(TimeHelper.Now - _startTime); + + public void Initialize(NetworkTarget networkTarget, IPEndPoint address) + { + _startTime = TimeHelper.Now; + Settings = KCPSettings.Create(networkTarget); + base.Initialize(NetworkType.Server, NetworkProtocolType.KCP, networkTarget); + _socket = new Socket(address.AddressFamily, SocketType.Dgram, ProtocolType.Udp); + _socket.Blocking = false; + _socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, false); + if (address.AddressFamily == AddressFamily.InterNetworkV6) + { + _socket.SetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.IPv6Only, false); + } + + _socket.Blocking = false; + _socket.Bind(address); + _socket.SetSocketBufferToOsLimit(); + _socket.SetSioUdpConnReset(); + ReadPipeDataAsync().Coroutine(); + ReceiveSocketAsync().Coroutine(); + Log.Info($"SceneConfigId = {Scene.SceneConfigId} networkTarget = {networkTarget.ToString()} KCPServer Listen {address}"); + } + + public override void Dispose() + { + if (IsDisposed) + { + return; + } + + if (!_cancellationTokenSource.IsCancellationRequested) + { + try + { + _cancellationTokenSource.Cancel(); + } + catch (OperationCanceledException) + { + // 通常情况下,此处的异常可以忽略 + } + } + + foreach (var (_, channel) in _connectionChannel.ToArray()) + { + channel.Dispose(); + } + + _connectionChannel.Clear(); + _pendingConnection.Clear(); + + if (_socket != null) + { + _socket.Dispose(); + _socket = null; + } + + base.Dispose(); + } + + #region ReceiveSocket + + private async FTask ReceiveSocketAsync() + { + EndPoint remoteEndPoint = new IPEndPoint(IPAddress.Any, 0); + + while (!_cancellationTokenSource.IsCancellationRequested) + { + try + { + var memory = _pipe.Writer.GetMemory(8192); + var socketReceiveFromResult = await _socket.ReceiveFromAsync(memory, SocketFlags.None, remoteEndPoint, _cancellationTokenSource.Token); + var receivedBytes = socketReceiveFromResult.ReceivedBytes; + + if (receivedBytes == 5) + { + switch ((KcpHeader)memory.Span[0]) + { + case KcpHeader.RequestConnection: + case KcpHeader.ConfirmConnection: + { + _endPoint.Enqueue(socketReceiveFromResult.RemoteEndPoint.Clone()); + break; + } + } + } + + _pipe.Writer.Advance(receivedBytes); + await _pipe.Writer.FlushAsync(); + } + catch (SocketException ex) + { + Log.Error($"Socket exception: {ex.Message}"); + Dispose(); + break; + } + catch (OperationCanceledException) + { + break; + } + catch (ObjectDisposedException) + { + Dispose(); + break; + } + catch (Exception ex) + { + Log.Error($"Unexpected exception: {ex.Message}"); + } + } + + await _pipe.Writer.CompleteAsync(); + } + + #endregion + + #region ReceivePipeData + + private async FTask ReadPipeDataAsync() + { + var pipeReader = _pipe.Reader; + while (!_cancellationTokenSource.IsCancellationRequested) + { + ReadResult result = default; + + try + { + result = await pipeReader.ReadAsync(_cancellationTokenSource.Token); + } + catch (OperationCanceledException) + { + // 出现这个异常表示取消了_cancellationTokenSource。一般Channel断开会取消。 + break; + } + + var buffer = result.Buffer; + var consumed = buffer.Start; + var examined = buffer.End; + + while (TryReadMessage(ref buffer, out var header, out var channelId, out var message)) + { + ReceiveData(ref header, ref channelId, ref message); + consumed = buffer.Start; + } + + if (result.IsCompleted) + { + break; + } + + pipeReader.AdvanceTo(consumed, examined); + } + + await pipeReader.CompleteAsync(); + } + + private unsafe bool TryReadMessage(ref ReadOnlySequence buffer, out KcpHeader header, out uint channelId, out ReadOnlyMemory message) + { + if (buffer.Length < 5) + { + channelId = 0; + message = default; + header = KcpHeader.None; + if (buffer.Length > 0) + { + buffer = buffer.Slice(buffer.Length); + } + return false; + } + + var readOnlyMemory = buffer.First; + + if (MemoryMarshal.TryGetArray(readOnlyMemory, out var arraySegment)) + { + fixed (byte* bytePointer = &arraySegment.Array[arraySegment.Offset]) + { + header = (KcpHeader)bytePointer[0]; + channelId = Unsafe.ReadUnaligned(ref bytePointer[1]); + } + } + else + { + // 如果无法获取数组段,回退到安全代码来执行。这种情况几乎不会发生、为了保险还是写一下了。 + var firstSpan = readOnlyMemory.Span; + header = (KcpHeader)firstSpan[0]; + channelId = MemoryMarshal.Read(firstSpan.Slice(1, 4)); + } + + message = readOnlyMemory.Slice(5); + buffer = buffer.Slice(readOnlyMemory.Length); + return true; + } + + private void ReceiveData(ref KcpHeader header, ref uint channelId, ref ReadOnlyMemory buffer) + { + switch (header) + { + // 客户端请求建立KCP连接 + case KcpHeader.RequestConnection: + { + _endPoint.TryDequeue(out var ipEndPoint); + + if (_pendingConnection.TryGetValue(channelId, out var pendingConnection)) + { + if (!ipEndPoint.IPEndPointEquals(pendingConnection.RemoteEndPoint)) + { + // 重复通道ID,向客户端发送重复通道ID消息 + SendRepeatChannelId(ref channelId, ipEndPoint); + } + + break; + } + + if (_connectionChannel.ContainsKey(channelId)) + { + // 已存在的通道ID,向客户端发送重复通道ID消息 + SendRepeatChannelId(ref channelId, ipEndPoint); + break; + } + + AddPendingConnection(ref channelId, ipEndPoint); + break; + } + // 客户端确认建立KCP连接 + case KcpHeader.ConfirmConnection: + { + _endPoint.TryDequeue(out var ipEndPoint); + if (!ConfirmPendingConnection(ref channelId, ipEndPoint)) + { + break; + } + + AddConnection(ref channelId, ipEndPoint.Clone()); + break; + } + // 接收KCP的数据 + case KcpHeader.ReceiveData: + { + if (buffer.Length == 5) + { + Log.Warning($"KCP Server KcpHeader.Data buffer.Length == 5"); + break; + } + + if (_connectionChannel.TryGetValue(channelId, out var channel)) + { + channel.Input(buffer); + } + + break; + } + // 断开KCP连接 + case KcpHeader.Disconnect: + { + // 断开不需要清楚PendingConnection让ClearPendingConnection自动清楚就可以了,并且不一定有Pending。 + RemoveChannel(channelId); + break; + } + } + } + + #endregion + + #region Update + + public void Update() + { + var timeNow = TimeNow; + _allowWraparound = timeNow < _updateMinTime; + CheckUpdateTimerOut(ref timeNow); + UpdateChannel(ref timeNow); + PendingTimerOut(ref timeNow); + _allowWraparound = true; + } + + private void CheckUpdateTimerOut(ref uint nowTime) + { + if (_updateTimer.Count == 0) + { + return; + } + + if (IsTimeGreaterThan(_updateMinTime, nowTime)) + { + return; + } + + _updateTimeOutTime.Clear(); + + foreach (var kv in _updateTimer) + { + var timeId = kv.Key; + + if (IsTimeGreaterThan(timeId, nowTime)) + { + _updateMinTime = timeId; + break; + } + + _updateTimeOutTime.Add(timeId); + } + + foreach (var timeId in _updateTimeOutTime) + { + foreach (var channelId in _updateTimer[timeId]) + { + _updateChannels.Add(channelId); + } + + _updateTimer.RemoveKey(timeId); + } + } + + private void UpdateChannel(ref uint timeNow) + { + foreach (var channelId in _updateChannels) + { + if (!_connectionChannel.TryGetValue(channelId, out var channel)) + { + continue; + } + + if (channel.IsDisposed) + { + _connectionChannel.Remove(channelId); + continue; + } + + channel.Kcp.Update(timeNow); + AddUpdateChannel(channelId, channel.Kcp.Check(timeNow)); + } + + _updateChannels.Clear(); + } + + private void PendingTimerOut(ref uint timeNow) + { + if (_pendingConnectionTimeOut.Count == 0) + { + return; + } + + if (IsTimeGreaterThan(_pendingMinTime, timeNow)) + { + return; + } + + _pendingTimeOutTime.Clear(); + + foreach (var kv in _pendingConnectionTimeOut) + { + var timeId = kv.Key; + + if (IsTimeGreaterThan(timeId, timeNow)) + { + _pendingMinTime = timeId; + break; + } + + _pendingTimeOutTime.Add(timeId); + } + + foreach (var timeId in _pendingTimeOutTime) + { + foreach (var channelId in _pendingConnectionTimeOut[timeId]) + { + _pendingConnection.Remove(channelId); + } + + _pendingConnectionTimeOut.RemoveKey(timeId); + } + } + + public void AddUpdateChannel(uint channelId, uint tillTime) + { + if (tillTime == 0) + { + _updateChannels.Add(channelId); + return; + } + + if (IsTimeGreaterThan(_updateMinTime, tillTime)) + { + _updateMinTime = tillTime; + } + + _updateTimer.Add(tillTime, channelId); + } + + private const uint HalfMaxUint = uint.MaxValue / 2; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private bool IsTimeGreaterThan(uint timeId, uint nowTime) + { + if (!_allowWraparound) + { + return timeId > nowTime; + } + + var diff = timeId - nowTime; + // 如果 diff 的值在 [0, HalfMaxUint] 范围内,说明 timeId 是在 nowTime 之后或相等。 + // 如果 diff 的值在 (HalfMaxUint, uint.MaxValue] 范围内,说明 timeId 是在 nowTime 之前(时间回绕的情况)。 + return diff < HalfMaxUint || diff == HalfMaxUint; + } + + #endregion + + #region Pending + + private void AddPendingConnection(ref uint channelId, IPEndPoint ipEndPoint) + { + var now = TimeNow; + var pendingConnection = new PendingConnection(channelId, ipEndPoint, now); + + if (IsTimeGreaterThan(_pendingMinTime, pendingConnection.TimeOutId) || _pendingMinTime == 0) + { + _pendingMinTime = pendingConnection.TimeOutId; + } + + _pendingConnection.Add(channelId, pendingConnection); + _pendingConnectionTimeOut.Add(pendingConnection.TimeOutId, channelId); + SendWaitConfirmConnection(ref channelId, ipEndPoint); + } + + private bool ConfirmPendingConnection(ref uint channelId, EndPoint ipEndPoint) + { + if (!_pendingConnection.TryGetValue(channelId, out var pendingConnection)) + { + return false; + } + + if (!ipEndPoint.IPEndPointEquals(pendingConnection.RemoteEndPoint)) + { + Log.Error($"KCPSocket syn address diff: {channelId} {pendingConnection.RemoteEndPoint} {ipEndPoint}"); + return false; + } + + _pendingConnection.Remove(channelId); + _pendingConnectionTimeOut.RemoveValue(pendingConnection.TimeOutId, pendingConnection.ChannelId); +#if FANTASY_DEVELOP + Log.Debug($"KCPSocket _pendingConnection:{_pendingConnection.Count} _pendingConnectionTimer:{_pendingConnectionTimeOut.Count}"); +#endif + return true; + } + + #endregion + + #region Connection + + private void AddConnection(ref uint channelId, IPEndPoint ipEndPoint) + { + var eventArgs = new KCPServerNetworkChannel(this, channelId, ipEndPoint); + _connectionChannel.Add(channelId, eventArgs); +#if FANTASY_DEVELOP + Log.Debug($"AddConnection _connectionChannel:{_connectionChannel.Count()}"); +#endif + } + + public override void RemoveChannel(uint channelId) + { + if (!_connectionChannel.Remove(channelId, out var channel)) + { + return; + } + + if (!channel.IsDisposed) + { + SendDisconnect(ref channelId, channel.RemoteEndPoint); + channel.Dispose(); + } +#if FANTASY_DEVELOP + Log.Debug($"RemoveChannel _connectionChannel:{_connectionChannel.Count()}"); +#endif + } + + #endregion + + #region Send + + private const byte KcpHeaderDisconnect = (byte)KcpHeader.Disconnect; + private const byte KcpHeaderRepeatChannelId = (byte)KcpHeader.RepeatChannelId; + private const byte KcpHeaderWaitConfirmConnection = (byte)KcpHeader.WaitConfirmConnection; + + private unsafe void SendDisconnect(ref uint channelId, EndPoint clientEndPoint) + { + fixed (byte* p = _sendBuff) + { + p[0] = KcpHeaderDisconnect; + *(uint*)(p + 1) = channelId; + } + + SendAsync(_sendBuff, 0, 5, clientEndPoint); + } + + private unsafe void SendRepeatChannelId(ref uint channelId, EndPoint clientEndPoint) + { + fixed (byte* p = _sendBuff) + { + p[0] = KcpHeaderRepeatChannelId; + *(uint*)(p + 1) = channelId; + } + + SendAsync(_sendBuff, 0, 5, clientEndPoint); + } + + private unsafe void SendWaitConfirmConnection(ref uint channelId, EndPoint clientEndPoint) + { + fixed (byte* p = _sendBuff) + { + p[0] = KcpHeaderWaitConfirmConnection; + *(uint*)(p + 1) = channelId; + } + + SendAsync(_sendBuff, 0, 5, clientEndPoint); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void SendAsync(byte[] buffer, int offset, int count, EndPoint endPoint) + { + try + { + _socket.SendTo(new ArraySegment(buffer, offset, count), SocketFlags.None, endPoint); + } + catch (ArgumentException ex) + { + Log.Error($"ArgumentException: {ex.Message}"); // 处理参数错误 + } + catch (SocketException) + { + //Log.Error($"SocketException: {ex.Message}"); // 处理网络错误 + } + catch (ObjectDisposedException) + { + // 处理套接字已关闭的情况 + } + catch (InvalidOperationException ex) + { + Log.Error($"InvalidOperationException: {ex.Message}"); // 处理无效操作 + } + catch (Exception ex) + { + Log.Error($"Exception: {ex.Message}"); // 捕获其他异常 + } + } + + #endregion + } +} + +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Protocol/KCP/Server/KCPServerNetworkChannel.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Protocol/KCP/Server/KCPServerNetworkChannel.cs new file mode 100644 index 0000000..3d5be09 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Protocol/KCP/Server/KCPServerNetworkChannel.cs @@ -0,0 +1,155 @@ +#if FANTASY_NET +using System.Net; +using System.Net.Sockets; +using System.Runtime.CompilerServices; +using Fantasy.Helper; +using Fantasy.Network.Interface; +using Fantasy.PacketParser; +using Fantasy.Serialize; +using KCP; +// ReSharper disable ParameterHidesMember +#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. + +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member + +namespace Fantasy.Network.KCP +{ + /// + /// KCP 服务器网络通道,用于处理服务器与客户端之间的数据通信。 + /// + public class KCPServerNetworkChannel : ANetworkServerChannel + { + private bool _isInnerDispose; + private readonly int _maxSndWnd; + private KCPServerNetwork _kcpServerNetwork; + private readonly BufferPacketParser _packetParser; + private readonly byte[] _receiveBuffer = new byte[Packet.PacketBodyMaxLength + 20]; + public Kcp Kcp { get; private set; } + public uint ChannelId { get; private set; } + + public KCPServerNetworkChannel(KCPServerNetwork network, uint channelId, IPEndPoint ipEndPoint) : base(network, channelId, ipEndPoint) + { + _kcpServerNetwork = network; + ChannelId = channelId; + _maxSndWnd = network.Settings.MaxSendWindowSize; + Kcp = KCPFactory.Create(network.Settings, ChannelId, KcpSpanCallback); + _packetParser = PacketParserFactory.CreateServerBufferPacket(network); + } + + public override void Dispose() + { + if (IsDisposed || _isInnerDispose) + { + return; + } + + _isInnerDispose = true; + _kcpServerNetwork.RemoveChannel(Id); + base.Dispose(); + IsDisposed = true; + Kcp.Dispose(); + Kcp = null; + ChannelId = 0; + _kcpServerNetwork = null; + } + + public void Input(ReadOnlyMemory buffer) + { + Kcp.Input(buffer); + _kcpServerNetwork.AddUpdateChannel(ChannelId, 0); + + while (!IsDisposed) + { + try + { + var peekSize = Kcp.PeekSize(); + + if (peekSize < 0) + { + return; + } + + var receiveCount = Kcp.Receive(_receiveBuffer, peekSize); + + if (receiveCount != peekSize) + { + return; + } + + if (!_packetParser.UnPack(_receiveBuffer, ref receiveCount, out var packInfo)) + { + continue; + } + + Session.Receive(packInfo); + } + catch (ScanException e) + { + Log.Debug($"RemoteAddress:{RemoteEndPoint} \n{e}"); + Dispose(); + } + catch (Exception e) + { + Log.Error(e); + } + } + } + + public override void Send(uint rpcId, long routeId, MemoryStreamBuffer memoryStream, IMessage message) + { + if (IsDisposed) + { + return; + } + + if (Kcp.WaitSendCount > _maxSndWnd) + { + // 检查等待发送的消息,如果超出两倍窗口大小,KCP作者给的建议是要断开连接 + Log.Warning($"ERR_KcpWaitSendSizeTooLarge {Kcp.WaitSendCount} > {_maxSndWnd}"); + Dispose(); + return; + } + + var buffer = _packetParser.Pack(ref rpcId, ref routeId, memoryStream, message); + Kcp.Send(buffer.GetBuffer(), 0, (int)buffer.Position); + + if (buffer.MemoryStreamBufferSource == MemoryStreamBufferSource.Pack) + { + _kcpServerNetwork.MemoryStreamBufferPool.ReturnMemoryStream(buffer); + } + + _kcpServerNetwork.AddUpdateChannel(ChannelId, 0); + } + + private const byte KcpHeaderReceiveData = (byte)KcpHeader.ReceiveData; + + private unsafe void KcpSpanCallback(byte[] buffer, ref int count) + { + if (IsDisposed) + { + return; + } + + try + { + if (count == 0) + { + throw new Exception("KcpOutput count 0"); + } + + fixed (byte* p = buffer) + { + p[0] = KcpHeaderReceiveData; + *(uint*)(p + 1) = ChannelId; + } + + _kcpServerNetwork.SendAsync(buffer, 0, count + 5, RemoteEndPoint); + } + catch (Exception e) + { + Log.Error(e); + } + } + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Protocol/NetworkProtocolFactory.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Protocol/NetworkProtocolFactory.cs new file mode 100644 index 0000000..c7b6ecc --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Protocol/NetworkProtocolFactory.cs @@ -0,0 +1,95 @@ +using System; +using System.Net; +using Fantasy.Entitas; +using Fantasy.Helper; +using Fantasy.Network.Interface; +#if !FANTASY_WEBGL +using Fantasy.Network.TCP; +using Fantasy.Network.KCP; +#endif +#if FANTASY_NET +using Fantasy.Network.HTTP; +#endif +using Fantasy.Network.WebSocket; + +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member + +namespace Fantasy.Network +{ + internal static class NetworkProtocolFactory + { +#if FANTASY_NET + public static ANetwork CreateServer(Scene scene, NetworkProtocolType protocolType, NetworkTarget networkTarget, string bindIp, int port) + { + switch (protocolType) + { + case NetworkProtocolType.TCP: + { + var network = Entity.Create(scene, false, false); + var address = NetworkHelper.ToIPEndPoint(bindIp, port); + network.Initialize(networkTarget, address); + return network; + } + case NetworkProtocolType.KCP: + { + var network = Entity.Create(scene, false, true); + var address = NetworkHelper.ToIPEndPoint(bindIp, port); + network.Initialize(networkTarget, address); + return network; + } + case NetworkProtocolType.WebSocket: + { + var network = Entity.Create(scene, false, true); + network.Initialize(networkTarget, bindIp, port); + return network; + } + case NetworkProtocolType.HTTP: + { + var network = Entity.Create(scene, false, true); + network.Initialize(networkTarget, bindIp, port); + return network; + } + default: + { + throw new NotSupportedException($"Unsupported NetworkProtocolType:{protocolType}"); + } + } + } +#endif + public static AClientNetwork CreateClient(Scene scene, NetworkProtocolType protocolType, NetworkTarget networkTarget) + { +#if !FANTASY_WEBGL + switch (protocolType) + { + case NetworkProtocolType.TCP: + { + var network = Entity.Create(scene, false, false); + network.Initialize(networkTarget); + return network; + } + case NetworkProtocolType.KCP: + { + var network = Entity.Create(scene, false, true); + network.Initialize(networkTarget); + return network; + } + case NetworkProtocolType.WebSocket: + { + var network = Entity.Create(scene, false, true); + network.Initialize(networkTarget); + return network; + } + default: + { + throw new NotSupportedException($"Unsupported NetworkProtocolType:{protocolType}"); + } + } +#else + // Webgl平台只能用这个协议。 + var network = Entity.Create(scene, false, true); + network.Initialize(networkTarget); + return network; +#endif + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Protocol/NetworkProtocolType.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Protocol/NetworkProtocolType.cs new file mode 100644 index 0000000..55a04c9 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Protocol/NetworkProtocolType.cs @@ -0,0 +1,69 @@ +namespace Fantasy.Network +{ + /// + /// 网络服务器类型 + /// + public enum NetworkType + { + /// + /// 默认 + /// + None = 0, + /// + /// 客户端网络 + /// + Client = 1, +#if FANTASY_NET + /// + /// 服务器网络 + /// + Server = 2 +#endif + } + /// + /// 网络服务的目标 + /// + public enum NetworkTarget + { + /// + /// 默认 + /// + None = 0, + /// + /// 对外 + /// + Outer = 1, +#if FANTASY_NET + /// + /// 对内 + /// + Inner = 2 +#endif + } + /// + /// 支持的网络协议 + /// + public enum NetworkProtocolType + { + /// + /// 默认 + /// + None = 0, + /// + /// KCP + /// + KCP = 1, + /// + /// TCP + /// + TCP = 2, + /// + /// WebSocket + /// + WebSocket = 3, + /// + /// HTTP + /// + HTTP = 4, + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Protocol/NetworkThreadComponent.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Protocol/NetworkThreadComponent.cs new file mode 100644 index 0000000..c0c166b --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Protocol/NetworkThreadComponent.cs @@ -0,0 +1,100 @@ +#if !FANTASY_WEBGL +using System; +using System.Collections.Generic; +using System.Threading; +using Fantasy.Entitas; +// ReSharper disable ForCanBeConvertedToForeach +#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. + +namespace Fantasy.Network +{ + internal interface INetworkThreadUpdate + { + void Update(); + } + + /// + /// 网络线程组件 + /// + internal sealed class NetworkThreadComponent : Entity + { + private Thread _netWorkThread; + internal ThreadSynchronizationContext SynchronizationContext { get; private set; } + private readonly List _updates = new List(); + + internal NetworkThreadComponent Initialize() + { + SynchronizationContext = new ThreadSynchronizationContext(); + _netWorkThread = new Thread(Update) + { + IsBackground = true + }; + _netWorkThread.Start(); + return this; + } + + public override void Dispose() + { + if (IsDisposed) + { + return; + } + + SynchronizationContext.Post(() => + { + _updates.Clear(); + _netWorkThread.Join(); + _netWorkThread = null; + SynchronizationContext = null; + }); + + base.Dispose(); + } + + private void Update() + { + // 将同步上下文设置为网络线程的上下文,以确保操作在正确的线程上下文中执行。 + System.Threading.SynchronizationContext.SetSynchronizationContext(SynchronizationContext); + // 循环执行 + while (!IsDisposed) + { + for (var i = 0; i < _updates.Count; i++) + { + try + { + _updates[i].Update(); + } + catch (Exception e) + { + Log.Error(e); + } + } + SynchronizationContext.Update(); + Thread.Sleep(1); + } + } + + internal void AddNetworkThreadUpdate(INetworkThreadUpdate update) + { + SynchronizationContext.Post(() => + { + if (_updates.Contains(update)) + { + Log.Warning($"{update.GetType().FullName} Network thread update is already running"); + return; + } + _updates.Add(update); + }); + } + + internal void RemoveNetworkThreadUpdate(INetworkThreadUpdate update) + { + SynchronizationContext.Post(() => + { + _updates.Remove(update); + }); + } + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Protocol/TCP/Client/TCPClientNetwork.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Protocol/TCP/Client/TCPClientNetwork.cs new file mode 100644 index 0000000..1caafd7 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Protocol/TCP/Client/TCPClientNetwork.cs @@ -0,0 +1,403 @@ +#if !FANTASY_WEBGL +using System; +using System.Buffers; +using System.Collections.Generic; +using System.IO; +using System.IO.Pipelines; +using System.Net; +using System.Net.Sockets; +using System.Runtime.InteropServices; +using System.Threading; +using Fantasy.Async; +using Fantasy.Helper; +using Fantasy.Network.Interface; +using Fantasy.PacketParser; +using Fantasy.Serialize; +// ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract +#pragma warning disable CS8602 // Dereference of a possibly null reference. +#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member + +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. +#pragma warning disable CS8604 // Possible null reference argument. +#pragma warning disable CS8600 // Converting null literal or possible null value to non-nullable type. +#pragma warning disable CS8622 // Nullability of reference types in type of parameter doesn't match the target delegate (possibly because of nullability attributes). + +namespace Fantasy.Network.TCP +{ + public sealed class TCPClientNetwork : AClientNetwork + { + private bool _isSending; + private bool _isInnerDispose; + private long _connectTimeoutId; + private Socket _socket; + private IPEndPoint _remoteEndPoint; + private SocketAsyncEventArgs _sendArgs; + private ReadOnlyMemoryPacketParser _packetParser; + private readonly Pipe _pipe = new Pipe(); + private readonly Queue _sendBuffers = new Queue(); + private readonly CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource(); + + private Action _onConnectFail; + private Action _onConnectComplete; + private Action _onConnectDisconnect; + + public uint ChannelId { get; private set; } + + public void Initialize(NetworkTarget networkTarget) + { + base.Initialize(NetworkType.Client, NetworkProtocolType.TCP, networkTarget); + } + + public override void Dispose() + { + if (IsDisposed || _isInnerDispose) + { + return; + } + + _isSending = false; + _isInnerDispose = true; + base.Dispose(); + ClearConnectTimeout(); + + if (!_cancellationTokenSource.IsCancellationRequested) + { + try + { + _cancellationTokenSource.Cancel(); + } + catch (OperationCanceledException) + { + // 通常情况下,此处的异常可以忽略 + } + } + + _onConnectDisconnect?.Invoke(); + + if (_socket.Connected) + { + _socket.Close(); + _socket = null; + } + + _sendBuffers.Clear(); + _packetParser?.Dispose(); + ChannelId = 0; + _sendArgs = null; + } + + /// + /// 连接到远程服务器。 + /// + /// 远程服务器的终端点。 + /// 连接成功时的回调。 + /// 连接失败时的回调。 + /// 连接断开时的回调。 + /// + /// 连接超时时间,单位:毫秒。 + /// 连接的会话。 + public override Session Connect(string remoteAddress, Action onConnectComplete, Action onConnectFail, Action onConnectDisconnect, bool isHttps, int connectTimeout = 5000) + { + // 如果已经初始化过一次,抛出异常,要求重新实例化 + + if (IsInit) + { + throw new NotSupportedException("TCPClientNetwork Has already been initialized. If you want to call Connect again, please re instantiate it."); + } + + IsInit = true; + _isSending = false; + _onConnectFail = onConnectFail; + _onConnectComplete = onConnectComplete; + _onConnectDisconnect = onConnectDisconnect; + // 设置连接超时定时器 + _connectTimeoutId = Scene.TimerComponent.Net.OnceTimer(connectTimeout, () => + { + _onConnectFail?.Invoke(); + Dispose(); + }); + _packetParser = PacketParserFactory.CreateClientReadOnlyMemoryPacket(this); + _remoteEndPoint = NetworkHelper.GetIPEndPoint(remoteAddress); + _socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); + _socket.NoDelay = true; + _socket.SetSocketBufferToOsLimit(); + _sendArgs = new SocketAsyncEventArgs(); + _sendArgs.Completed += OnSendCompleted; + var outArgs = new SocketAsyncEventArgs + { + RemoteEndPoint = _remoteEndPoint + }; + outArgs.Completed += OnConnectSocketCompleted; + + if (!_socket.ConnectAsync(outArgs)) + { + OnReceiveSocketComplete(); + } + + Session = Session.Create(this, _remoteEndPoint); + return Session; + } + + private void OnConnectSocketCompleted(object sender, SocketAsyncEventArgs asyncEventArgs) + { + if (_cancellationTokenSource.IsCancellationRequested) + { + return; + } + + if (asyncEventArgs.LastOperation == SocketAsyncOperation.Connect) + { + if (asyncEventArgs.SocketError == SocketError.Success) + { + Scene.ThreadSynchronizationContext.Post(OnReceiveSocketComplete); + } + else + { + Scene.ThreadSynchronizationContext.Post(() => + { + _onConnectFail?.Invoke(); + Dispose(); + }); + } + } + } + + private void OnReceiveSocketComplete() + { + ClearConnectTimeout(); + _onConnectComplete?.Invoke(); + ReadPipeDataAsync().Coroutine(); + ReceiveSocketAsync().Coroutine(); + } + + #region ReceiveSocket + + private async FTask ReceiveSocketAsync() + { + while (!_cancellationTokenSource.IsCancellationRequested) + { + try + { + var memory = _pipe.Writer.GetMemory(8192); +#if UNITY_2021 + // Unity2021.3.14f有个恶心的问题,使用ReceiveAsync会导致memory不能正确写入 + // 所有只能使用ReceiveFromAsync来接收消息,但ReceiveFromAsync只有一个接受ArraySegment的接口。 + MemoryMarshal.TryGetArray(memory, out ArraySegment arraySegment); + var result = await _socket.ReceiveFromAsync(arraySegment, SocketFlags.None, _remoteEndPoint); + _pipe.Writer.Advance(result.ReceivedBytes); +#else + var count = await _socket.ReceiveAsync(memory, SocketFlags.None, _cancellationTokenSource.Token); + _pipe.Writer.Advance(count); +#endif + await _pipe.Writer.FlushAsync(); + } + catch (SocketException) + { + Dispose(); + break; + } + catch (OperationCanceledException) + { + break; + } + catch (ObjectDisposedException) + { + Dispose(); + break; + } + catch (Exception ex) + { + Log.Error($"Unexpected exception: {ex.Message}"); + } + } + + await _pipe.Writer.CompleteAsync(); + } + + #endregion + + #region ReceivePipeData + + private async FTask ReadPipeDataAsync() + { + var pipeReader = _pipe.Reader; + while (!_cancellationTokenSource.IsCancellationRequested) + { + ReadResult result = default; + + try + { + result = await pipeReader.ReadAsync(_cancellationTokenSource.Token); + } + catch (OperationCanceledException) + { + // 出现这个异常表示取消了_cancellationTokenSource。一般Channel断开会取消。 + break; + } + + var buffer = result.Buffer; + var consumed = buffer.Start; + var examined = buffer.End; + + while (TryReadMessage(ref buffer, out var message)) + { + ReceiveData(ref message); + consumed = buffer.Start; + } + + if (result.IsCompleted) + { + break; + } + + pipeReader.AdvanceTo(consumed, examined); + } + + await pipeReader.CompleteAsync(); + } + + private bool TryReadMessage(ref ReadOnlySequence buffer, out ReadOnlyMemory message) + { + if (buffer.Length == 0) + { + message = default; + return false; + } + + message = buffer.First; + + if (message.Length == 0) + { + message = default; + return false; + } + + buffer = buffer.Slice(message.Length); + return true; + } + + private void ReceiveData(ref ReadOnlyMemory buffer) + { + try + { + while (_packetParser.UnPack(ref buffer, out var packInfo)) + { + if (_cancellationTokenSource.IsCancellationRequested) + { + return; + } + Session.Receive(packInfo); + } + } + catch (ScanException e) + { + Log.Warning(e.Message); + Dispose(); + } + catch (Exception e) + { + Log.Error(e); + Dispose(); + } + } + + #endregion + + #region Send + + public override void Send(uint rpcId, long routeId, MemoryStreamBuffer memoryStream, IMessage message) + { + _sendBuffers.Enqueue(_packetParser.Pack(ref rpcId, ref routeId, memoryStream, message)); + + if (!_isSending) + { + Send(); + } + } + + private void Send() + { + if (_isSending || IsDisposed) + { + return; + } + + _isSending = true; + + while (_sendBuffers.Count > 0) + { + var memoryStreamBuffer = _sendBuffers.Dequeue(); + _sendArgs.UserToken = memoryStreamBuffer; + _sendArgs.SetBuffer(new ArraySegment(memoryStreamBuffer.GetBuffer(), 0, (int)memoryStreamBuffer.Position)); + + try + { + if (_socket.SendAsync(_sendArgs)) + { + break; + } + + ReturnMemoryStream(memoryStreamBuffer); + } + catch + { + _isSending = false; + return; + } + } + + _isSending = false; + } + + private void ReturnMemoryStream(MemoryStreamBuffer memoryStream) + { + if (memoryStream.MemoryStreamBufferSource == MemoryStreamBufferSource.Pack) + { + MemoryStreamBufferPool.ReturnMemoryStream(memoryStream); + } + } + + private void OnSendCompleted(object sender, SocketAsyncEventArgs asyncEventArgs) + { + if (asyncEventArgs.SocketError != SocketError.Success || asyncEventArgs.BytesTransferred == 0) + { + _isSending = false; + return; + } + + var memoryStreamBuffer = (MemoryStreamBuffer)asyncEventArgs.UserToken; + Scene.ThreadSynchronizationContext.Post(() => + { + ReturnMemoryStream(memoryStreamBuffer); + + if (_sendBuffers.Count > 0) + { + Send(); + } + else + { + _isSending = false; + } + }); + } + + #endregion + + public override void RemoveChannel(uint channelId) + { + Dispose(); + } + + private void ClearConnectTimeout() + { + if (_connectTimeoutId == 0) + { + return; + } + + Scene.TimerComponent.Net.Remove(ref _connectTimeoutId); + } + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Protocol/TCP/Server/TCPServerNetwork.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Protocol/TCP/Server/TCPServerNetwork.cs new file mode 100644 index 0000000..3f3d531 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Protocol/TCP/Server/TCPServerNetwork.cs @@ -0,0 +1,151 @@ +#if FANTASY_NET +using System.Net; +using System.Net.Sockets; +using Fantasy.Helper; +using Fantasy.Network.Interface; +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member + +// ReSharper disable GCSuppressFinalizeForTypeWithoutDestructor +#pragma warning disable CS8622 // Nullability of reference types in type of parameter doesn't match the target delegate (possibly because of nullability attributes). +#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. + +namespace Fantasy.Network.TCP +{ + public sealed class TCPServerNetwork : ANetwork + { + private Random _random; + private Socket _socket; + private SocketAsyncEventArgs _acceptAsync; + private readonly Dictionary _connectionChannel = new Dictionary(); + + public void Initialize(NetworkTarget networkTarget, IPEndPoint address) + { + base.Initialize(NetworkType.Server, NetworkProtocolType.TCP, networkTarget); + _random = new Random(); + _acceptAsync = new SocketAsyncEventArgs(); + _socket = new Socket(address.AddressFamily, SocketType.Stream, ProtocolType.Tcp); + _socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, false); + + if (address.AddressFamily == AddressFamily.InterNetworkV6) + { + _socket.SetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.IPv6Only, false); + } + + _socket.Bind(address); + _socket.Listen(int.MaxValue); + _socket.SetSocketBufferToOsLimit(); + Log.Info($"SceneConfigId = {Scene.SceneConfigId} networkTarget = {networkTarget.ToString()} TCPServer Listen {address}"); + _acceptAsync.Completed += OnCompleted; + AcceptAsync(); + } + + public override void Dispose() + { + if (IsDisposed) + { + return; + } + + foreach (var networkChannel in _connectionChannel.Values.ToArray()) + { + networkChannel.Dispose(); + } + + _connectionChannel.Clear(); + _random = null; + _socket.Dispose(); + _socket = null; + _acceptAsync.Dispose(); + _acceptAsync = null; + GC.SuppressFinalize(this); + base.Dispose(); + } + + private void AcceptAsync() + { + _acceptAsync.AcceptSocket = null; + + if (_socket.AcceptAsync(_acceptAsync)) + { + return; + } + + OnAcceptComplete(_acceptAsync); + } + + private void OnAcceptComplete(SocketAsyncEventArgs asyncEventArgs) + { + if (asyncEventArgs.AcceptSocket == null) + { + return; + } + + if (asyncEventArgs.SocketError != SocketError.Success) + { + Log.Error($"Socket Accept Error: {_acceptAsync.SocketError}"); + return; + } + + try + { + uint channelId; + do + { + channelId = 0xC0000000 | (uint)_random.Next(); + } while (_connectionChannel.ContainsKey(channelId)); + + _connectionChannel.Add(channelId, new TCPServerNetworkChannel(this, asyncEventArgs.AcceptSocket, channelId)); + } + catch (Exception e) + { + Log.Error(e); + } + finally + { + AcceptAsync(); + } + } + + public override void RemoveChannel(uint channelId) + { + if (IsDisposed || !_connectionChannel.Remove(channelId, out var channel)) + { + return; + } + + if (channel.IsDisposed) + { + return; + } + + channel.Dispose(); + } + + #region 网络线程(由Socket底层产生的线程) + + private void OnCompleted(object sender, SocketAsyncEventArgs asyncEventArgs) + { + switch (asyncEventArgs.LastOperation) + { + case SocketAsyncOperation.Accept: + { + Scene.ThreadSynchronizationContext.Post(() => + { + OnAcceptComplete(asyncEventArgs); + }); + break; + } + default: + { + throw new Exception($"Socket Accept Error: {asyncEventArgs.LastOperation}"); + } + } + } + + #endregion + } +} +#endif + + diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Protocol/TCP/Server/TCPServerNetworkChannel.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Protocol/TCP/Server/TCPServerNetworkChannel.cs new file mode 100644 index 0000000..122a54f --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Protocol/TCP/Server/TCPServerNetworkChannel.cs @@ -0,0 +1,295 @@ +#if FANTASY_NET +using System.Buffers; +using System.IO.Pipelines; +using System.Net.Sockets; +using Fantasy.Async; +using Fantasy.Network.Interface; +using Fantasy.PacketParser; +using Fantasy.Serialize; +// ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract +#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member + +#pragma warning disable CS8600 // Converting null literal or possible null value to non-nullable type. +#pragma warning disable CS8602 // Dereference of a possibly null reference. + +#pragma warning disable CS8604 // Possible null reference argument. +#pragma warning disable CS8622 // Nullability of reference types in type of parameter doesn't match the target delegate (possibly because of nullability attributes). + +namespace Fantasy.Network.TCP +{ + public sealed class TCPServerNetworkChannel : ANetworkServerChannel + { + private bool _isSending; + private bool _isInnerDispose; + private readonly Socket _socket; + private readonly ANetwork _network; + private readonly Pipe _pipe = new Pipe(); + private readonly SocketAsyncEventArgs _sendArgs; + private readonly ReadOnlyMemoryPacketParser _packetParser; + private readonly Queue _sendBuffers = new Queue(); + private readonly CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource(); + + public TCPServerNetworkChannel(ANetwork network, Socket socket, uint id) : base(network, id, socket.RemoteEndPoint) + { + _socket = socket; + _network = network; + _socket.NoDelay = true; + _sendArgs = new SocketAsyncEventArgs(); + _sendArgs.Completed += OnSendCompletedHandler; + _packetParser = PacketParserFactory.CreateServerReadOnlyMemoryPacket(network); + ReadPipeDataAsync().Coroutine(); + ReceiveSocketAsync().Coroutine(); + } + + public override void Dispose() + { + if (IsDisposed || _isInnerDispose) + { + return; + } + + _isInnerDispose = true; + _network.RemoveChannel(Id); + + if (!_cancellationTokenSource.IsCancellationRequested) + { + try + { + _cancellationTokenSource.Cancel(); + } + catch (OperationCanceledException) + { + // 通常情况下,此处的异常可以忽略 + } + } + + base.Dispose(); + + if (_socket != null) + { + _socket.Shutdown(SocketShutdown.Both); + _socket.Close(); + } + + _sendBuffers.Clear(); + _packetParser.Dispose(); + _isSending = false; + } + + #region ReceiveSocket + + private async FTask ReceiveSocketAsync() + { + while (!_cancellationTokenSource.IsCancellationRequested) + { + try + { + var memory = _pipe.Writer.GetMemory(8192); + var count = await _socket.ReceiveAsync(memory, SocketFlags.None, _cancellationTokenSource.Token); + + if (count == 0) + { + Dispose(); + return; + } + + _pipe.Writer.Advance(count); + await _pipe.Writer.FlushAsync(); + } + catch (SocketException) + { + Dispose(); + break; + } + catch (OperationCanceledException) + { + break; + } + catch (ObjectDisposedException) + { + Dispose(); + break; + } + catch (Exception ex) + { + Log.Error($"Unexpected exception: {ex.Message}"); + } + } + + await _pipe.Writer.CompleteAsync(); + } + + #endregion + + #region ReceivePipeData + + private async FTask ReadPipeDataAsync() + { + var pipeReader = _pipe.Reader; + while (!_cancellationTokenSource.IsCancellationRequested) + { + ReadResult result = default; + + try + { + result = await pipeReader.ReadAsync(_cancellationTokenSource.Token); + } + catch (OperationCanceledException) + { + // 出现这个异常表示取消了_cancellationTokenSource。一般Channel断开会取消。 + break; + } + + var buffer = result.Buffer; + var consumed = buffer.Start; + var examined = buffer.End; + + while (TryReadMessage(ref buffer, out var message)) + { + ReceiveData(ref message); + consumed = buffer.Start; + } + + if (result.IsCompleted) + { + break; + } + + pipeReader.AdvanceTo(consumed, examined); + } + + await pipeReader.CompleteAsync(); + } + + private bool TryReadMessage(ref ReadOnlySequence buffer, out ReadOnlyMemory message) + { + if (buffer.Length == 0) + { + message = default; + return false; + } + + message = buffer.First; + + if (message.Length == 0) + { + message = default; + return false; + } + + buffer = buffer.Slice(message.Length); + return true; + } + + private void ReceiveData(ref ReadOnlyMemory buffer) + { + try + { + while (_packetParser.UnPack(ref buffer, out var packInfo)) + { + if (_cancellationTokenSource.IsCancellationRequested) + { + return; + } + + Session.Receive(packInfo); + } + } + catch (ScanException e) + { + Log.Warning($"RemoteAddress:{RemoteEndPoint} \n{e}"); + Dispose(); + } + catch (Exception e) + { + Log.Error($"RemoteAddress:{RemoteEndPoint} \n{e}"); + Dispose(); + } + } + + #endregion + + #region Send + + public override void Send(uint rpcId, long routeId, MemoryStreamBuffer memoryStream, IMessage message) + { + _sendBuffers.Enqueue(_packetParser.Pack(ref rpcId, ref routeId, memoryStream, message)); + + if (!_isSending) + { + Send(); + } + } + + private void Send() + { + if (_isSending || IsDisposed) + { + return; + } + + _isSending = true; + + while (_sendBuffers.Count > 0) + { + var memoryStreamBuffer = _sendBuffers.Dequeue(); + _sendArgs.UserToken = memoryStreamBuffer; + _sendArgs.SetBuffer(new ArraySegment(memoryStreamBuffer.GetBuffer(), 0, (int)memoryStreamBuffer.Position)); + + try + { + if (_socket.SendAsync(_sendArgs)) + { + break; + } + + ReturnMemoryStream(memoryStreamBuffer); + } + catch + { + _isSending = false; + return; + } + } + + _isSending = false; + } + + private void ReturnMemoryStream(MemoryStreamBuffer memoryStream) + { + if (memoryStream.MemoryStreamBufferSource == MemoryStreamBufferSource.Pack) + { + _network.MemoryStreamBufferPool.ReturnMemoryStream(memoryStream); + } + } + + private void OnSendCompletedHandler(object sender, SocketAsyncEventArgs asyncEventArgs) + { + if (asyncEventArgs.SocketError != SocketError.Success || asyncEventArgs.BytesTransferred == 0) + { + _isSending = false; + return; + } + + var memoryStreamBuffer = (MemoryStreamBuffer)asyncEventArgs.UserToken; + + Scene.ThreadSynchronizationContext.Post(() => + { + ReturnMemoryStream(memoryStreamBuffer); + + if (_sendBuffers.Count > 0) + { + Send(); + } + else + { + _isSending = false; + } + }); + } + + #endregion + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Protocol/WebSocket/Client/WebSocketClientNetwork.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Protocol/WebSocket/Client/WebSocketClientNetwork.cs new file mode 100644 index 0000000..ac041e0 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Protocol/WebSocket/Client/WebSocketClientNetwork.cs @@ -0,0 +1,334 @@ +#if FANTASY_NET || FANTASY_CONSOLE +using System.Buffers; +using System.IO.Pipelines; +using System.Net.WebSockets; +using Fantasy.Async; +using Fantasy.Helper; +using Fantasy.Network.Interface; +using Fantasy.PacketParser; +using Fantasy.Serialize; +// ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member +#pragma warning disable CS8603 // Possible null reference return. +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. +#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. +namespace Fantasy.Network.WebSocket +{ + public sealed class WebSocketClientNetwork : AClientNetwork + { + private bool _isSending; + private bool _isInnerDispose; + private long _connectTimeoutId; + private ClientWebSocket _clientWebSocket; + private ReadOnlyMemoryPacketParser _packetParser; + private readonly Pipe _pipe = new Pipe(); + private readonly Queue _sendBuffers = new Queue(); + private readonly CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource(); + + private Action _onConnectFail; + private Action _onConnectComplete; + private Action _onConnectDisconnect; + + public void Initialize(NetworkTarget networkTarget) + { + base.Initialize(NetworkType.Client, NetworkProtocolType.WebSocket, networkTarget); + _packetParser = PacketParserFactory.CreateClientReadOnlyMemoryPacket(this); + } + + public override void Dispose() + { + if (IsDisposed || _isInnerDispose) + { + return; + } + + _isInnerDispose = true; + if (!_cancellationTokenSource.IsCancellationRequested) + { + try + { + _cancellationTokenSource.Cancel(); + } + catch (OperationCanceledException) + { + // 通常情况下,此处的异常可以忽略 + } + } + + base.Dispose(); + ClearConnectTimeout(); + WebSocketClientDisposeAsync().Coroutine(); + _onConnectDisconnect?.Invoke(); + _packetParser.Dispose(); + _packetParser = null; + _isSending = false; + } + + private async FTask WebSocketClientDisposeAsync() + { + if (_clientWebSocket == null) + { + return; + } + + await _clientWebSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "Closing", CancellationToken.None); + _clientWebSocket.Dispose(); + _clientWebSocket = null; + } + + public override Session Connect(string remoteAddress, Action onConnectComplete, Action onConnectFail, Action onConnectDisconnect, bool isHttps, int connectTimeout = 5000) + { + if (IsInit) + { + throw new NotSupportedException( + $"WebSocketClientNetwork Id:{Id} Has already been initialized. If you want to call Connect again, please re instantiate it."); + } + + IsInit = true; + _onConnectFail = onConnectFail; + _onConnectComplete = onConnectComplete; + _onConnectDisconnect = onConnectDisconnect; + // 设置连接超时定时器 + _connectTimeoutId = Scene.TimerComponent.Net.OnceTimer(connectTimeout, () => + { + _onConnectFail?.Invoke(); + Dispose(); + }); + + _clientWebSocket = new ClientWebSocket(); + var webSocketAddress = WebSocketHelper.GetWebSocketAddress(remoteAddress, isHttps); + + try + { + _clientWebSocket.ConnectAsync(new Uri(webSocketAddress), _cancellationTokenSource.Token).Wait(); + + if (_cancellationTokenSource.IsCancellationRequested) + { + return null; + } + } + catch (WebSocketException wse) + { + Log.Error($"WebSocket error: {wse.Message}"); + Dispose(); + return null; + } + catch (Exception e) + { + Log.Error($"An error occurred: {e.Message}"); + Dispose(); + return null; + } + + ClearConnectTimeout(); + ReadPipeDataAsync().Coroutine(); + ReceiveSocketAsync().Coroutine(); + _onConnectComplete?.Invoke(); + Session = Session.Create(this, null); + return Session; + } + + #region ReceiveSocket + + private async FTask ReceiveSocketAsync() + { + while (!_cancellationTokenSource.IsCancellationRequested) + { + try + { + var memory = _pipe.Writer.GetMemory(8192); + // 这里接收的数据不一定是一个完整的包。如果大于8192就会分成多个包。 + var receiveResult = await _clientWebSocket.ReceiveAsync(memory, _cancellationTokenSource.Token); + + if (receiveResult.MessageType == WebSocketMessageType.Close) + { + break; + } + + var count = receiveResult.Count; + + if (count > 0) + { + await PipeWriterFlushAsync(count); + } + } + catch (OperationCanceledException) + { + break; + } + catch (ObjectDisposedException) + { + Dispose(); + break; + } + // 这个先暂时注释掉,因为有些时候会出现WebSocketException + // 因为会出现这个挥手的错误,下个版本处理一下。 + // The remote party closed the WebSocket connection without completing the close handshake. + // catch (WebSocketException wse) + // { + // Log.Error($"WebSocket error: {wse.Message}"); + // Dispose(); + // break; + // } + catch (Exception e) + { + Log.Error(e); + } + } + + await _pipe.Writer.CompleteAsync(); + } + + private async FTask PipeWriterFlushAsync(int count) + { + _pipe.Writer.Advance(count); + await _pipe.Writer.FlushAsync(); + } + + #endregion + + #region ReceivePipeData + + private async FTask ReadPipeDataAsync() + { + var pipeReader = _pipe.Reader; + while (!_cancellationTokenSource.IsCancellationRequested) + { + ReadResult result = default; + + try + { + result = await pipeReader.ReadAsync(_cancellationTokenSource.Token); + } + catch (OperationCanceledException) + { + // 出现这个异常表示取消了_cancellationTokenSource。一般Channel断开会取消。 + break; + } + + var buffer = result.Buffer; + var consumed = buffer.Start; + var examined = buffer.End; + + while (TryReadMessage(ref buffer, out var message)) + { + ReceiveData(ref message); + consumed = buffer.Start; + } + + if (result.IsCompleted) + { + break; + } + + pipeReader.AdvanceTo(consumed, examined); + } + + await pipeReader.CompleteAsync(); + } + + private bool TryReadMessage(ref ReadOnlySequence buffer, out ReadOnlyMemory message) + { + if (buffer.Length == 0) + { + message = default; + return false; + } + + message = buffer.First; + + if (message.Length == 0) + { + message = default; + return false; + } + + buffer = buffer.Slice(message.Length); + return true; + } + + private void ReceiveData(ref ReadOnlyMemory buffer) + { + try + { + while (_packetParser.UnPack(ref buffer, out var packInfo)) + { + if (_cancellationTokenSource.IsCancellationRequested) + { + return; + } + + Session.Receive(packInfo); + } + } + catch (ScanException e) + { + Log.Warning(e.Message); + Dispose(); + } + catch (Exception e) + { + Log.Error(e); + Dispose(); + } + } + + #endregion + + #region Send + + public override void Send(uint rpcId, long routeId, MemoryStreamBuffer memoryStream, IMessage message) + { + _sendBuffers.Enqueue(_packetParser.Pack(ref rpcId, ref routeId, memoryStream, message)); + + if (!_isSending) + { + Send().Coroutine(); + } + } + + private async FTask Send() + { + if (_isSending || IsDisposed) + { + return; + } + + _isSending = true; + + while (_isSending) + { + if (!_sendBuffers.TryDequeue(out var memoryStream)) + { + _isSending = false; + return; + } + + await _clientWebSocket.SendAsync(new ArraySegment(memoryStream.GetBuffer(), 0, (int)memoryStream.Position), WebSocketMessageType.Binary, true, _cancellationTokenSource.Token); + + if (memoryStream.MemoryStreamBufferSource == MemoryStreamBufferSource.Pack) + { + MemoryStreamBufferPool.ReturnMemoryStream(memoryStream); + } + } + } + + #endregion + + public override void RemoveChannel(uint channelId) + { + Dispose(); + } + + private void ClearConnectTimeout() + { + if (_connectTimeoutId == 0) + { + return; + } + + Scene.TimerComponent.Net.Remove(ref _connectTimeoutId); + } + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Protocol/WebSocket/Client/WebSocketClientNetworkWebgl.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Protocol/WebSocket/Client/WebSocketClientNetworkWebgl.cs new file mode 100644 index 0000000..39373f1 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Protocol/WebSocket/Client/WebSocketClientNetworkWebgl.cs @@ -0,0 +1,180 @@ +#if !FANTASY_NET && !FANTASY_CONSOLE +using System; +using System.Collections.Generic; +using System.IO; +using Fantasy.Helper; +using Fantasy.Network.Interface; +using Fantasy.PacketParser; +using Fantasy.Serialize; +using UnityWebSocket; + +namespace Fantasy.Network.WebSocket +{ + // 因为webgl的限制、注定这个要是在游戏主线程里。所以这个库不会再其他线程执行的。 + // WebGL:在WebGL环境下运行 + // 另外不是运行在WebGL环境下,也没必要使用WebSocket协议了。完全可以使用TCP或KCP运行。同样也不会有那个队列产生的GC。 + public class WebSocketClientNetwork : AClientNetwork + { + private UnityWebSocket.WebSocket _webSocket; + private bool _isInnerDispose; + private bool _isConnected; + private long _connectTimeoutId; + private BufferPacketParser _packetParser; + private readonly Queue _messageCache = new Queue(); + + private Action _onConnectFail; + private Action _onConnectComplete; + private Action _onConnectDisconnect; + + public void Initialize(NetworkTarget networkTarget) + { + base.Initialize(NetworkType.Client, NetworkProtocolType.WebSocket, networkTarget); + _packetParser = PacketParserFactory.CreateClient(this); + } + + public override void Dispose() + { + if (IsDisposed || _isInnerDispose) + { + return; + } + + _isInnerDispose = true; + base.Dispose(); + + if (_webSocket != null && _webSocket.ReadyState != WebSocketState.Closed) + { + _onConnectDisconnect?.Invoke(); + _webSocket.CloseAsync(); + } + + _packetParser.Dispose(); + ClearConnectTimeout(); + _messageCache.Clear(); + } + + public override Session Connect(string remoteAddress, Action onConnectComplete, Action onConnectFail, Action onConnectDisconnect, bool isHttps, int connectTimeout = 5000) + { + // 如果已经初始化过一次,抛出异常,要求重新实例化 + + if (IsInit) + { + throw new NotSupportedException($"WebSocketClientNetwork Id:{Id} Has already been initialized. If you want to call Connect again, please re instantiate it."); + } + + IsInit = true; + _onConnectFail = onConnectFail; + _onConnectComplete = onConnectComplete; + _onConnectDisconnect = onConnectDisconnect; + _connectTimeoutId = Scene.TimerComponent.Net.OnceTimer(connectTimeout, () => + { + _onConnectFail?.Invoke(); + Dispose(); + }); + var webSocketAddress = WebSocketHelper.GetWebSocketAddress(remoteAddress, isHttps); + _webSocket = new UnityWebSocket.WebSocket(webSocketAddress); + _webSocket.OnOpen += OnNetworkConnectComplete; + _webSocket.OnMessage += OnReceiveComplete; + _webSocket.OnClose += (sender, args) => + { + _onConnectDisconnect?.Invoke(); + Dispose(); + }; + _webSocket.ConnectAsync(); + Session = Session.Create(this, null); + return Session; + } + + private void OnNetworkConnectComplete(object sender, OpenEventArgs e) + { + if (IsDisposed) + { + return; + } + + _isConnected = true; + ClearConnectTimeout(); + _onConnectComplete?.Invoke(); + + while (_messageCache.TryDequeue(out var memoryStream)) + { + Send(memoryStream); + } + } + + #region Receive + + private void OnReceiveComplete(object sender, MessageEventArgs e) + { + try + { + // WebSocket 协议已经在协议层面处理了消息的边界问题,因此不需要额外的粘包处理逻辑。 + // 所以如果解包的时候出现任何错误只能是恶意攻击造成的。 + var rawDataLength = e.RawData.Length; + _packetParser.UnPack(e.RawData, ref rawDataLength, out var packInfo); + Session.Receive(packInfo); + } + catch (ScanException ex) + { + Log.Warning($"{ex}"); + Dispose(); + } + catch (Exception ex) + { + Log.Error($"{ex}"); + Dispose(); + } + } + + #endregion + + #region Send + + public override void Send(uint rpcId, long routeId, MemoryStreamBuffer memoryStream, IMessage message) + { + if (IsDisposed) + { + return; + } + + var buffer = _packetParser.Pack(ref rpcId, ref routeId, memoryStream, message); + + if (!_isConnected) + { + _messageCache.Enqueue(buffer); + return; + } + + Send(buffer); + } + + private void Send(MemoryStreamBuffer memoryStream) + { + _webSocket.SendAsync(memoryStream.GetBuffer(), 0, (int)memoryStream.Position); +#if !UNITY_EDITOR && UNITY_WEBGL + if (memoryStream.MemoryStreamBufferSource == MemoryStreamBufferSource.Pack) + { + MemoryStreamBufferPool.ReturnMemoryStream(memoryStream); + } +#endif + } + + #endregion + + public override void RemoveChannel(uint channelId) + { + Dispose(); + } + + private void ClearConnectTimeout() + { + if (_connectTimeoutId == 0) + { + return; + } + + Scene?.TimerComponent?.Net?.Remove(ref _connectTimeoutId); + } + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Protocol/WebSocket/Server/WebSocketServerNetwork.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Protocol/WebSocket/Server/WebSocketServerNetwork.cs new file mode 100644 index 0000000..09feb2b --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Protocol/WebSocket/Server/WebSocketServerNetwork.cs @@ -0,0 +1,112 @@ +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member +#if FANTASY_NET +using System.Net; +using System.Security.Cryptography.X509Certificates; +using Fantasy.Async; +using Fantasy.Network.Interface; + +// ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract +// ReSharper disable PossibleMultipleEnumeration +#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. +namespace Fantasy.Network.WebSocket; + +public class WebSocketServerNetwork : ANetwork +{ + private Random _random; + private HttpListener _httpListener; + private readonly Dictionary _connectionChannel = new Dictionary(); + + public void Initialize(NetworkTarget networkTarget, string bindIp, int port) + { + base.Initialize(NetworkType.Server, NetworkProtocolType.WebSocket, networkTarget); + + try + { + _random = new Random(); + _httpListener = new HttpListener(); + StartAcceptAsync(bindIp, port).Coroutine(); + } + catch (HttpListenerException e) + { + if (e.ErrorCode == 5) + { + throw new Exception($"CMD管理员中输入: netsh http add urlacl url=http://*:8080/ user=Everyone", e); + } + + Log.Error(e); + } + catch (Exception e) + { + Log.Error(e); + } + } + + public override void Dispose() + { + if (IsDisposed) + { + return; + } + + if (_httpListener != null) + { + _httpListener.Close(); + _httpListener = null; + } + + foreach (var channel in _connectionChannel.Values.ToArray()) + { + channel.Dispose(); + } + + _connectionChannel.Clear(); + base.Dispose(); + } + + private async FTask StartAcceptAsync(string bindIp, int port) + { + var listenUrl = ""; + var certificatePath = Path.Combine(AppContext.BaseDirectory, $"certificate{bindIp}{port}"); + listenUrl = Directory.Exists(certificatePath) ? $"https://{bindIp}:{port}/" : $"http://{bindIp}:{port}/"; + _httpListener.Prefixes.Add(listenUrl); + _httpListener.Start(); + Log.Info($"SceneConfigId = {Scene.SceneConfigId} WebSocketServer Listen {listenUrl}"); + while (!IsDisposed) + { + try + { + var httpListenerContext = await _httpListener.GetContextAsync(); + var webSocketContext = await httpListenerContext.AcceptWebSocketAsync(null); + var channelId = 0xC0000000 | (uint) _random.Next(); + + while (_connectionChannel.ContainsKey(channelId)) + { + channelId = 0xC0000000 | (uint) _random.Next(); + } + + _connectionChannel.Add(channelId, new WebSocketServerNetworkChannel(this, channelId, webSocketContext, httpListenerContext.Request.RemoteEndPoint)); + } + catch (Exception e) + { + Log.Error(e); + } + } + } + + public override void RemoveChannel(uint channelId) + { + if (IsDisposed || !_connectionChannel.Remove(channelId, out var channel)) + { + return; + } + + if (channel.IsDisposed) + { + return; + } + + channel.Dispose(); + } +} +#endif diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Protocol/WebSocket/Server/WebSocketServerNetworkChannel.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Protocol/WebSocket/Server/WebSocketServerNetworkChannel.cs new file mode 100644 index 0000000..7e8c70c --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Protocol/WebSocket/Server/WebSocketServerNetworkChannel.cs @@ -0,0 +1,253 @@ +#if FANTASY_NET +using System.Buffers; +using System.IO.Pipelines; +using System.Net; +using System.Net.Sockets; +using System.Net.WebSockets; +using Fantasy.Async; +using Fantasy.Network.Interface; +using Fantasy.PacketParser; +using Fantasy.Serialize; +#pragma warning disable CS8602 // Dereference of a possibly null reference. +#pragma warning disable CS8600 // Converting null literal or possible null value to non-nullable type. +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member + +namespace Fantasy.Network.WebSocket; + +public sealed class WebSocketServerNetworkChannel : ANetworkServerChannel +{ + private bool _isSending; + private bool _isInnerDispose; + private readonly Pipe _pipe = new Pipe(); + private readonly System.Net.WebSockets.WebSocket _webSocket; + private readonly WebSocketServerNetwork _network; + private readonly ReadOnlyMemoryPacketParser _packetParser; + private readonly Queue _sendBuffers = new Queue(); + private readonly CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource(); + + public WebSocketServerNetworkChannel(ANetwork network, uint id, HttpListenerWebSocketContext httpListenerWebSocketContext, IPEndPoint remoteEndPoint) : base(network, id, remoteEndPoint) + { + _network = (WebSocketServerNetwork)network; + _webSocket = httpListenerWebSocketContext.WebSocket; + _packetParser = PacketParserFactory.CreateServerReadOnlyMemoryPacket(network); + ReadPipeDataAsync().Coroutine(); + ReceiveSocketAsync().Coroutine(); + } + + public override void Dispose() + { + if (IsDisposed || _isInnerDispose) + { + return; + } + + _isInnerDispose = true; + if (!_cancellationTokenSource.IsCancellationRequested) + { + try + { + _cancellationTokenSource.Cancel(); + } + catch (OperationCanceledException) + { + // 通常情况下,此处的异常可以忽略 + } + } + _sendBuffers.Clear(); + _network.RemoveChannel(Id); + base.Dispose(); + if (_webSocket.State == WebSocketState.Open || _webSocket.State == WebSocketState.CloseReceived) + { + _webSocket.CloseOutputAsync(WebSocketCloseStatus.NormalClosure, "Normal Closure", + _cancellationTokenSource.Token).GetAwaiter().GetResult(); + } + _webSocket.Dispose(); + _isSending = false; + } + + #region ReceiveSocket + + private async FTask ReceiveSocketAsync() + { + while (!_cancellationTokenSource.IsCancellationRequested) + { + try + { + var memory = _pipe.Writer.GetMemory(8192); + // 这里接收的数据不一定是一个完整的包。如果大于8192就会分成多个包。 + var receiveResult = await _webSocket.ReceiveAsync(memory, _cancellationTokenSource.Token); + + if (receiveResult.MessageType == WebSocketMessageType.Close) + { + Dispose(); + break; + } + + var count = receiveResult.Count; + + if (count > 0) + { + await PipeWriterFlushAsync(count); + } + } + catch (OperationCanceledException) + { + break; + } + catch (ObjectDisposedException) + { + Dispose(); + break; + } + catch (WebSocketException) + { + // Log.Error($"WebSocket error: {wse.Message}"); + Dispose(); + break; + } + catch (Exception e) + { + Log.Error(e); + } + } + + await _pipe.Writer.CompleteAsync(); + } + + private async FTask PipeWriterFlushAsync(int count) + { + _pipe.Writer.Advance(count); + await _pipe.Writer.FlushAsync(); + } + + #endregion + + #region ReceivePipeData + + private async FTask ReadPipeDataAsync() + { + var pipeReader = _pipe.Reader; + while (!_cancellationTokenSource.IsCancellationRequested) + { + ReadResult result = default; + + try + { + result = await pipeReader.ReadAsync(_cancellationTokenSource.Token); + } + catch (OperationCanceledException) + { + // 出现这个异常表示取消了_cancellationTokenSource。一般Channel断开会取消。 + break; + } + + var buffer = result.Buffer; + var consumed = buffer.Start; + var examined = buffer.End; + + while (TryReadMessage(ref buffer, out var message)) + { + ReceiveData(ref message); + consumed = buffer.Start; + } + + if (result.IsCompleted) + { + break; + } + + pipeReader.AdvanceTo(consumed, examined); + } + + await pipeReader.CompleteAsync(); + } + + private bool TryReadMessage(ref ReadOnlySequence buffer, out ReadOnlyMemory message) + { + if (buffer.Length == 0) + { + message = default; + return false; + } + + message = buffer.First; + + if (message.Length == 0) + { + message = default; + return false; + } + + buffer = buffer.Slice(message.Length); + return true; + } + + private void ReceiveData(ref ReadOnlyMemory buffer) + { + try + { + while (_packetParser.UnPack(ref buffer, out var packInfo)) + { + if (_cancellationTokenSource.IsCancellationRequested) + { + return; + } + + Session.Receive(packInfo); + } + } + catch (ScanException e) + { + Log.Warning($"RemoteAddress:{RemoteEndPoint} \n{e}"); + Dispose(); + } + catch (Exception e) + { + Log.Error($"RemoteAddress:{RemoteEndPoint} \n{e}"); + Dispose(); + } + } + + #endregion + + #region Send + + public override void Send(uint rpcId, long routeId, MemoryStreamBuffer memoryStream, IMessage message) + { + _sendBuffers.Enqueue(_packetParser.Pack(ref rpcId, ref routeId, memoryStream, message)); + + if (!_isSending) + { + Send().Coroutine(); + } + } + + private async FTask Send() + { + if (_isSending || IsDisposed) + { + return; + } + + _isSending = true; + + while (_isSending) + { + if (!_sendBuffers.TryDequeue(out var memoryStream)) + { + _isSending = false; + return; + } + + await _webSocket.SendAsync(new ArraySegment(memoryStream.GetBuffer(), 0, (int)memoryStream.Position), WebSocketMessageType.Binary, true, _cancellationTokenSource.Token); + + if (memoryStream.MemoryStreamBufferSource == MemoryStreamBufferSource.Pack) + { + _network.MemoryStreamBufferPool.ReturnMemoryStream(memoryStream); + } + } + } + + #endregion +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Route/RouteComponent.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Route/RouteComponent.cs new file mode 100644 index 0000000..ba00add --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Route/RouteComponent.cs @@ -0,0 +1,65 @@ +using Fantasy.Entitas; + +#if FANTASY_NET +namespace Fantasy.Network; + +/// +/// 自定义Route组件、如果要自定义Route协议必须使用这个组件 +/// +public sealed class RouteComponent : Entity +{ + /// + /// 存储路由类型和路由ID的映射关系。 + /// + public readonly Dictionary RouteAddress = new Dictionary(); + + /// + /// 添加路由类型和路由ID的映射关系。 + /// + /// 路由类型。 + /// 路由ID。 + public void AddAddress(long routeType, long routeId) + { + RouteAddress.Add(routeType, routeId); + } + + /// + /// 移除指定路由类型的映射关系。 + /// + /// 路由类型。 + public void RemoveAddress(long routeType) + { + RouteAddress.Remove(routeType); + } + + /// + /// 获取指定路由类型的路由ID。 + /// + /// 路由类型。 + /// 路由ID。 + public long GetRouteId(long routeType) + { + return RouteAddress.GetValueOrDefault(routeType, 0); + } + + /// + /// 尝试获取指定路由类型的路由ID。 + /// + /// 路由类型。 + /// 输出的路由ID。 + /// 如果获取成功返回true,否则返回false。 + public bool TryGetRouteId(long routeType, out long routeId) + { + return RouteAddress.TryGetValue(routeType, out routeId); + } + + /// + /// 释放组件资源,清空映射关系。 + /// + public override void Dispose() + { + RouteAddress.Clear(); + base.Dispose(); + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Session/Component/ConsoleSessionHeartbeatComponent.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Session/Component/ConsoleSessionHeartbeatComponent.cs new file mode 100644 index 0000000..dc4677e --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Session/Component/ConsoleSessionHeartbeatComponent.cs @@ -0,0 +1,156 @@ +// ReSharper disable MemberCanBePrivate.Global + +#if FANTASY_CONSOLE + +using System; +using Fantasy.Async; +using Fantasy.Entitas; +using Fantasy.Entitas.Interface; +using Fantasy.Helper; +using Fantasy.InnerMessage; +using Fantasy.Timer; +#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. + +namespace Fantasy.Network +{ + public class SessionHeartbeatComponentAwakeSystem : AwakeSystem + { + protected override void Awake(SessionHeartbeatComponent self) + { + self.TimerComponent = self.Scene.TimerComponent; + } + } + + /// + /// 负责管理会话心跳的组件。 + /// + public class SessionHeartbeatComponent : Entity + { + public int TimeOut; + public long TimerId; + public long LastTime; + public long SelfRunTimeId; + public long TimeOutTimerId; + public long SessionRunTimeId; + public TimerComponent TimerComponent; + public EntityReference Session; + private readonly PingRequest _pingRequest = new PingRequest(); + + public int Ping { get; private set; } + + public override void Dispose() + { + if (IsDisposed) + { + return; + } + + Stop(); + Ping = 0; + Session = null; + TimeOut = 0; + SelfRunTimeId = 0; + base.Dispose(); + } + + /// + /// 使用指定的间隔启动心跳功能。 + /// + /// 以毫秒为单位的心跳请求发送间隔。 + /// 设置与服务器的通信超时时间,如果超过这个时间限制,将自动断开会话(Session)。 + /// 用于检测与服务器连接超时频率。 + public void Start(int interval, int timeOut = 2000, int timeOutInterval = 3000) + { + TimeOut = timeOut + interval; + Session = (Session)Parent; + SelfRunTimeId = RuntimeId; + LastTime = TimeHelper.Now; + + if (TimerComponent == null) + { + Log.Error("请在Unity的菜单执行Fantasy->Generate link.xml再重新打包"); + return; + } + + TimerId = TimerComponent.Net.RepeatedTimer(interval, () => RepeatedSend().Coroutine()); + TimeOutTimerId = TimerComponent.Net.RepeatedTimer(timeOutInterval, CheckTimeOut); + } + + private void CheckTimeOut() + { + if (TimeHelper.Now - LastTime < TimeOut) + { + return; + } + + Session entityReference = Session; + + if (entityReference == null) + { + return; + } + + entityReference.Dispose(); + } + + /// + /// 停止心跳功能。 + /// + public void Stop() + { + if (TimerId != 0) + { + TimerComponent?.Net.Remove(ref TimerId); + } + + if (TimeOutTimerId != 0) + { + TimerComponent?.Net.Remove(ref TimeOutTimerId); + } + } + + /// + /// 异步发送心跳请求并处理响应。 + /// + /// 表示进行中操作的异步任务。 + private async FTask RepeatedSend() + { + if (SelfRunTimeId != RuntimeId) + { + Stop(); + return; + } + + Session session = Session; + + if (session == null) + { + Dispose(); + return; + } + + try + { + var requestTime = TimeHelper.Now; + + var pingResponse = (PingResponse)await session.Call(_pingRequest); + + if (pingResponse.ErrorCode != 0) + { + return; + } + + var responseTime = TimeHelper.Now; + LastTime = responseTime; + Ping = (int)(responseTime - requestTime) / 2; + TimeHelper.TimeDiff = pingResponse.Now + Ping - responseTime; + } + catch (Exception) + { + Dispose(); + } + } + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Session/Component/SessionIdleCheckerComponent.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Session/Component/SessionIdleCheckerComponent.cs new file mode 100644 index 0000000..1edc1cf --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Session/Component/SessionIdleCheckerComponent.cs @@ -0,0 +1,104 @@ +using Fantasy.Entitas; +using Fantasy.Entitas.Interface; +using Fantasy.Helper; +using Fantasy.Timer; + +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. +#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member +#if FANTASY_NET +namespace Fantasy.Network; + +public class SessionIdleCheckerComponentAwakeSystem : AwakeSystem +{ + protected override void Awake(SessionIdleCheckerComponent self) + { + self.TimerComponent = self.Scene.TimerComponent; + } +} + +/// +/// 负责检查会话空闲超时的组件。 +/// +public class SessionIdleCheckerComponent : Entity +{ + /// + /// 空闲超时时间(毫秒) + /// + private long _timeOut; + /// + /// 检查计时器的 ID + /// + private long _timerId; + /// + /// 用于确保组件完整性的自身运行时 ID + /// + private long _selfRuntimeId; + /// + /// 对会话对象的引用 + /// + private Session _session; + public TimerComponent TimerComponent; + + /// + /// 重写 Dispose 方法以释放资源。 + /// + public override void Dispose() + { + Stop(); // 停止检查计时器 + _timeOut = 0; // 重置空闲超时时间 + _selfRuntimeId = 0; // 重置自身运行时 ID + _session = null; // 清除会话引用 + base.Dispose(); + } + + /// + /// 使用指定的间隔和空闲超时时间启动空闲检查功能。 + /// + /// 以毫秒为单位的检查间隔。 + /// 以毫秒为单位的空闲超时时间。 + public void Start(int interval, int timeOut) + { + _timeOut = timeOut; + _session = (Session)Parent; + _selfRuntimeId = RuntimeId; + // 安排重复计时器,在指定的间隔内执行 Check 方法 + _timerId = TimerComponent.Net.RepeatedTimer(interval, Check); + } + + /// + /// 停止空闲检查功能。 + /// + public void Stop() + { + if (_timerId == 0) + { + return; + } + + TimerComponent.Net.Remove(ref _timerId); + } + + /// + /// 执行空闲检查操作。 + /// + private void Check() + { + if (_selfRuntimeId != RuntimeId || IsDisposed || _session == null) + { + Stop(); + return; + } + + var timeNow = TimeHelper.Now; + + if (timeNow - _session.LastReceiveTime < _timeOut) + { + return; + } + + Log.Warning($"session timeout id:{Id} timeNow:{timeNow} _session.LastReceiveTime:{_session.LastReceiveTime} _timeOut:{_timeOut}"); + _session.Dispose(); + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Session/Component/UnitySessionHeartbeatComponent.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Session/Component/UnitySessionHeartbeatComponent.cs new file mode 100644 index 0000000..83c7cbf --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Session/Component/UnitySessionHeartbeatComponent.cs @@ -0,0 +1,156 @@ +// ReSharper disable MemberCanBePrivate.Global + +using System; +using Fantasy.Async; +using Fantasy.Entitas; +using Fantasy.Entitas.Interface; +using Fantasy.Helper; +using Fantasy.InnerMessage; +using Fantasy.Timer; + +#if FANTASY_UNITY + +namespace Fantasy.Network +{ + public class SessionHeartbeatComponentAwakeSystem : AwakeSystem + { + protected override void Awake(SessionHeartbeatComponent self) + { + self.TimerComponent = self.Scene.TimerComponent; + } + } + + /// + /// 负责管理会话心跳的组件。 + /// + public class SessionHeartbeatComponent : Entity + { + public int TimeOut; + public long TimerId; + public long LastTime; + public long SelfRunTimeId; + public long TimeOutTimerId; + public TimerComponent TimerComponent; + public EntityReference Session; + private readonly PingRequest _pingRequest = new PingRequest(); + + public int Ping { get; private set; } + + public override void Dispose() + { + if (IsDisposed) + { + return; + } + + Stop(); + Ping = 0; + Session = null; + TimeOut = 0; + LastTime = 0; + SelfRunTimeId = 0; + base.Dispose(); + } + + /// + /// 使用指定的间隔启动心跳功能。 + /// + /// 以毫秒为单位的心跳请求发送间隔。 + /// 设置与服务器的通信超时时间,如果超过这个时间限制,将自动断开会话(Session)。 + /// 用于检测与服务器连接超时频率。 + public void Start(int interval, int timeOut = 5000, int timeOutInterval = 3000) + { + TimeOut = timeOut + interval; + Session = (Session)Parent; + SelfRunTimeId = RuntimeId; + LastTime = TimeHelper.Now; + + if (TimerComponent == null) + { + Log.Error("请在Unity的菜单执行Fantasy->Generate link.xml再重新打包"); + return; + } + + TimerId = TimerComponent.Unity.RepeatedTimer(interval, () => + { + RepeatedSend().Coroutine(); + }); + TimeOutTimerId = TimerComponent.Unity.RepeatedTimer(timeOutInterval, CheckTimeOut); + } + + private void CheckTimeOut() + { + if (TimeHelper.Now - LastTime < TimeOut) + { + return; + } + + Session entityReference = Session; + + if (entityReference == null) + { + return; + } + + entityReference.Dispose(); + } + + /// + /// 停止心跳功能。 + /// + public void Stop() + { + if (TimerId != 0) + { + TimerComponent?.Unity.Remove(ref TimerId); + } + + if (TimeOutTimerId != 0) + { + TimerComponent?.Unity.Remove(ref TimeOutTimerId); + } + } + + /// + /// 异步发送心跳请求并处理响应。 + /// + /// 表示进行中操作的异步任务。 + private async FTask RepeatedSend() + { + if (SelfRunTimeId != RuntimeId) + { + Stop(); + return; + } + + Session session = Session; + + if (session == null) + { + Dispose(); + return; + } + + try + { + var requestTime = TimeHelper.Now; + var pingResponse = (PingResponse)await session.Call(_pingRequest); + + if (pingResponse.ErrorCode != 0) + { + return; + } + + var responseTime = TimeHelper.Now; + LastTime = responseTime; + Ping = (int)(responseTime - requestTime) / 2; + TimeHelper.TimeDiff = pingResponse.Now + Ping - responseTime; + } + catch (Exception) + { + Dispose(); + } + } + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Session/ProcessSession/ProcessScheduler.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Session/ProcessSession/ProcessScheduler.cs new file mode 100644 index 0000000..345eb5b --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Session/ProcessSession/ProcessScheduler.cs @@ -0,0 +1,260 @@ +#if FANTASY_NET +// ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract +using Fantasy.IdFactory; +using Fantasy.Network; +using Fantasy.Network.Interface; +using Fantasy.PacketParser.Interface; +using Fantasy.Platform.Net; + +namespace Fantasy.Scheduler; + +internal static class ProcessScheduler +{ + public static void Scheduler(this ProcessSession session, Type messageType, uint rpcId, long routeId, APackInfo packInfo) + { + switch (packInfo.OpCodeIdStruct.Protocol) + { + case OpCodeType.InnerResponse: + case OpCodeType.InnerRouteResponse: + case OpCodeType.InnerAddressableResponse: + case OpCodeType.OuterAddressableResponse: + case OpCodeType.OuterCustomRouteResponse: + { + using (packInfo) + { + var sessionScene = session.Scene; + var message = packInfo.Deserialize(messageType); + sessionScene.ThreadSynchronizationContext.Post(() => + { + // 因为有可能是其他Scene线程下发送过来的、所以必须放到当前Scene进程下运行。 + sessionScene.NetworkMessagingComponent.ResponseHandler(rpcId, (IResponse)message); + }); + } + + return; + } + case OpCodeType.InnerRouteMessage: + { + using (packInfo) + { + var sceneId = IdFactoryHelper.RuntimeIdTool.GetSceneId(ref routeId); + + if (!Process.TryGetScene(sceneId, out var scene)) + { + throw new Exception($"not found scene routeId:{routeId}"); + } + + var message = packInfo.Deserialize(messageType); + + scene.ThreadSynchronizationContext.Post(() => + { + var entity = scene.GetEntity(routeId); + var sceneMessageDispatcherComponent = scene.MessageDispatcherComponent; + + if (entity == null || entity.IsDisposed) + { + return; + } + + sceneMessageDispatcherComponent.RouteMessageHandler(session, messageType, entity, message, rpcId).Coroutine(); + }); + } + + return; + } + case OpCodeType.InnerRouteRequest: + { + using (packInfo) + { + var sceneId = IdFactoryHelper.RuntimeIdTool.GetSceneId(ref routeId); + + if (!Process.TryGetScene(sceneId, out var scene)) + { + throw new Exception($"not found scene routeId:{routeId}"); + } + + var message = packInfo.Deserialize(messageType); + + scene.ThreadSynchronizationContext.Post(() => + { + var entity = scene.GetEntity(routeId); + var sceneMessageDispatcherComponent = scene.MessageDispatcherComponent; + + if (entity == null || entity.IsDisposed) + { + sceneMessageDispatcherComponent.FailRouteResponse(session, messageType, InnerErrorCode.ErrNotFoundRoute, rpcId); + return; + } + + sceneMessageDispatcherComponent.RouteMessageHandler(session, messageType, entity, message, rpcId).Coroutine(); + }); + } + + return; + } + case OpCodeType.OuterAddressableMessage: + case OpCodeType.OuterCustomRouteMessage: + case OpCodeType.OuterAddressableRequest: + case OpCodeType.OuterCustomRouteRequest: + { + using (packInfo) + { + var sceneId = IdFactoryHelper.RuntimeIdTool.GetSceneId(ref routeId); + + if (!Process.TryGetScene(sceneId, out var scene)) + { + throw new NotSupportedException($"not found scene routeId = {routeId}"); + } + + var message = packInfo.Deserialize(messageType); + + scene.ThreadSynchronizationContext.Post(() => + { + var entity = scene.GetEntity(routeId); + + if (entity == null || entity.IsDisposed) + { + scene.MessageDispatcherComponent.FailRouteResponse(session, messageType, InnerErrorCode.ErrNotFoundRoute, rpcId); + return; + } + + scene.MessageDispatcherComponent.RouteMessageHandler(session, messageType, entity, message, rpcId).Coroutine(); + }); + } + return; + } + default: + { + var packInfoProtocolCode = packInfo.ProtocolCode; + packInfo.Dispose(); + throw new NotSupportedException($"SessionInnerScheduler Received unsupported message protocolCode:{packInfoProtocolCode} messageType:{messageType}"); + } + } + } + + public static void Scheduler(this ProcessSession session, Type messageType, uint rpcId, long routeId, uint protocolCode, object message) + { + OpCodeIdStruct opCodeIdStruct = protocolCode; + + switch (opCodeIdStruct.Protocol) + { + case OpCodeType.InnerResponse: + case OpCodeType.InnerRouteResponse: + case OpCodeType.InnerAddressableResponse: + case OpCodeType.OuterAddressableResponse: + case OpCodeType.OuterCustomRouteResponse: + { + var sessionScene = session.Scene; + sessionScene.ThreadSynchronizationContext.Post(() => + { + var iResponse = (IResponse)session.Deserialize(messageType, message, ref opCodeIdStruct); + // 因为有可能是其他Scene线程下发送过来的、所以必须放到当前Scene进程下运行。 + sessionScene.NetworkMessagingComponent.ResponseHandler(rpcId, iResponse); + }); + + return; + } + case OpCodeType.InnerAddressableMessage: + case OpCodeType.InnerRouteMessage: + { + var sceneId = IdFactoryHelper.RuntimeIdTool.GetSceneId(ref routeId); + + if (!Process.TryGetScene(sceneId, out var scene)) + { + throw new Exception($"not found scene routeId:{routeId}"); + } + + var messageObject = session.Deserialize(messageType, message, ref opCodeIdStruct); + + scene.ThreadSynchronizationContext.Post(() => + { + var entity = scene.GetEntity(routeId); + var sceneMessageDispatcherComponent = scene.MessageDispatcherComponent; + + if (entity == null || entity.IsDisposed) + { + return; + } + + sceneMessageDispatcherComponent.RouteMessageHandler(session, messageType, entity, messageObject, rpcId).Coroutine(); + }); + + return; + } + case OpCodeType.InnerAddressableRequest: + case OpCodeType.InnerRouteRequest: + { + var sceneId = IdFactoryHelper.RuntimeIdTool.GetSceneId(ref routeId); + + if (!Process.TryGetScene(sceneId, out var scene)) + { + throw new Exception($"not found scene routeId:{routeId}"); + } + + var messageObject = session.Deserialize(messageType, message, ref opCodeIdStruct); + + scene.ThreadSynchronizationContext.Post(() => + { + var entity = scene.GetEntity(routeId); + var sceneMessageDispatcherComponent = scene.MessageDispatcherComponent; + + if (entity == null || entity.IsDisposed) + { + sceneMessageDispatcherComponent.FailRouteResponse(session, message.GetType(), InnerErrorCode.ErrNotFoundRoute, rpcId); + return; + } + + sceneMessageDispatcherComponent.RouteMessageHandler(session, messageType, entity, messageObject, rpcId).Coroutine(); + }); + + return; + } + case OpCodeType.OuterAddressableMessage: + case OpCodeType.OuterCustomRouteMessage: + { + var sceneId = IdFactoryHelper.RuntimeIdTool.GetSceneId(ref routeId); + + if (!Process.TryGetScene(sceneId, out var scene)) + { + Log.Error($"not found scene routeId:{routeId}"); + return; + } + + var messageObject = session.Deserialize(messageType, message, ref opCodeIdStruct); + + scene.ThreadSynchronizationContext.Post(() => + { + var entity = scene.GetEntity(routeId); + + switch (entity) + { + case null: + { + // 执行到这里是说明Session已经断开了 + // 因为这里是其他服务器Send到外网的数据、所以不需要给发送端返回就可以 + return; + } + case Session gateSession: + { + // 这里如果是Session只可能是Gate的Session、如果是的话、肯定是转发Address消息 + gateSession.Send((IMessage)messageObject, rpcId); + return; + } + default: + { + scene.MessageDispatcherComponent.RouteMessageHandler(session, messageType, entity, messageObject, rpcId).Coroutine(); + return; + } + } + }); + + return; + } + default: + { + throw new NotSupportedException($"SessionInnerScheduler Received unsupported message protocolCode:{protocolCode} messageType:{messageType}"); + } + } + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Session/ProcessSession/ProcessSession.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Session/ProcessSession/ProcessSession.cs new file mode 100644 index 0000000..f576673 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Session/ProcessSession/ProcessSession.cs @@ -0,0 +1,125 @@ +using Fantasy.Async; +using Fantasy.Network.Interface; +using Fantasy.PacketParser; +using Fantasy.PacketParser.Interface; +using Fantasy.Pool; +using Fantasy.Scheduler; +using Fantasy.Serialize; +#pragma warning disable CS8604 // Possible null reference argument. +#pragma warning disable CS8603 // Possible null reference return. + +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member +#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. +#if FANTASY_NET +namespace Fantasy.Network; + +/// +/// 网络服务器内部会话。 +/// +public sealed class ProcessSession : Session +{ + private readonly MemoryStreamBufferPool _memoryStreamBufferPool = new MemoryStreamBufferPool(); + private readonly Dictionary> _createInstances = new Dictionary>(); + + /// + /// 发送消息到服务器内部。 + /// + /// 要发送的消息。 + /// RPC 标识符。 + /// 路由标识符。 + public override void Send(IMessage message, uint rpcId = 0, long routeId = 0) + { + if (IsDisposed) + { + return; + } + + this.Scheduler(message.GetType(), rpcId, routeId, message.OpCode(), message); + } + + /// + /// 发送路由消息到服务器内部。 + /// + /// 要发送的路由消息。 + /// RPC 标识符。 + /// 路由标识符。 + public override void Send(IRouteMessage routeMessage, uint rpcId = 0, long routeId = 0) + { + if (IsDisposed) + { + return; + } + + this.Scheduler(routeMessage.GetType(), rpcId, routeId, routeMessage.OpCode(), routeMessage); + } + + public override void Send(uint rpcId, long routeId, Type messageType, APackInfo packInfo) + { + if (IsDisposed) + { + return; + } + + this.Scheduler(messageType, rpcId, routeId, packInfo); + } + + public override void Send(ProcessPackInfo packInfo, uint rpcId = 0, long routeId = 0) + { + this.Scheduler(packInfo.MessageType, rpcId, routeId, packInfo); + } + + public override void Send(MemoryStreamBuffer memoryStream, uint rpcId = 0, long routeId = 0) + { + throw new Exception("The use of this method is not supported"); + } + + public override FTask Call(IRouteRequest request, long routeId = 0) + { + throw new Exception("The use of this method is not supported"); + } + + public override FTask Call(IRequest request, long routeId = 0) + { + throw new Exception("The use of this method is not supported"); + } + + public object Deserialize(Type messageType, object message, ref OpCodeIdStruct opCodeIdStruct) + { + var memoryStream = _memoryStreamBufferPool.RentMemoryStream(MemoryStreamBufferSource.None); + + try + { + if (SerializerManager.TryGetSerializer(opCodeIdStruct.OpCodeProtocolType, out var serializer)) + { + serializer.Serialize(messageType, message, memoryStream); + + if (memoryStream.Position == 0) + { + if (_createInstances.TryGetValue(messageType, out var createInstance)) + { + return createInstance(); + } + + createInstance = CreateInstance.CreateObject(messageType); + _createInstances.Add(messageType, createInstance); + return createInstance(); + } + + memoryStream.SetLength(memoryStream.Position); + memoryStream.Seek(0, SeekOrigin.Begin); + return serializer.Deserialize(messageType, memoryStream); + } + } + catch (Exception e) + { + Log.Error($"ProcessSession.Deserialize {e}"); + } + finally + { + _memoryStreamBufferPool.ReturnMemoryStream(memoryStream); + } + + throw new Exception($"type:{messageType} Does not support processing protocol"); + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Session/ProcessSession/ProcessSessionInfo.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Session/ProcessSession/ProcessSessionInfo.cs new file mode 100644 index 0000000..6e3a534 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Session/ProcessSession/ProcessSessionInfo.cs @@ -0,0 +1,17 @@ +using Fantasy.Network.Interface; + +#if FANTASY_NET +namespace Fantasy.Network; + +internal sealed class ProcessSessionInfo(Session session, AClientNetwork aClientNetwork) : IDisposable +{ + public readonly Session Session = session; + public readonly AClientNetwork AClientNetwork = aClientNetwork; + + public void Dispose() + { + Session.Dispose(); + AClientNetwork?.Dispose(); + } +} +#endif diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Session/Session.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Session/Session.cs new file mode 100644 index 0000000..9fc7868 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Network/Session/Session.cs @@ -0,0 +1,262 @@ +// ReSharper disable RedundantUsingDirective +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Net; +using Fantasy.Async; +using Fantasy.Entitas; +using Fantasy.Entitas.Interface; +using Fantasy.Helper; +using Fantasy.Network.Interface; +using Fantasy.PacketParser; +using Fantasy.PacketParser.Interface; +using Fantasy.Scheduler; +using Fantasy.Serialize; +#if FANTASY_NET +using Fantasy.Platform.Net; +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member +#endif +// ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract +#pragma warning disable CS8600 // Converting null literal or possible null value to non-nullable type. +#pragma warning disable CS8602 // Dereference of a possibly null reference. +#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. +#pragma warning disable CS8603 +#pragma warning disable CS8601 +#pragma warning disable CS8618 + +namespace Fantasy.Network +{ + /// + /// 网络会话的基类,用于管理网络通信。 + /// + public class Session : Entity, ISupportedMultiEntity + { + private uint _rpcId; + internal long LastReceiveTime; + /// + /// 关联的网络连接通道 + /// + public INetworkChannel Channel { get; private set; } + /// + /// 当前Session的终结点信息 + /// + public IPEndPoint RemoteEndPoint { get; private set; } + private ANetworkMessageScheduler NetworkMessageScheduler { get; set;} + public readonly Dictionary> RequestCallback = new(); + /// + /// Session的Dispose委托 + /// + public event Action OnDispose; +#if FANTASY_NET + internal static Session Create(ANetworkMessageScheduler networkMessageScheduler, ANetworkServerChannel channel, NetworkTarget networkTarget) + { + var session = Entity.Create(channel.Scene, false, true); + session.Channel = channel; + session.NetworkMessageScheduler = networkMessageScheduler; + session.RemoteEndPoint = channel.RemoteEndPoint as IPEndPoint; + session.OnDispose = channel.Dispose; + session.LastReceiveTime = TimeHelper.Now; + // 在外部网络目标下,添加会话空闲检查组件 + if (networkTarget == NetworkTarget.Outer) + { + var interval = ProcessDefine.SessionIdleCheckerInterval; + var timeOut = ProcessDefine.SessionIdleCheckerTimeout; + session.AddComponent().Start(interval, timeOut); + } + return session; + } +#endif + internal static Session Create(AClientNetwork network, IPEndPoint remoteEndPoint) + { + // 创建会话实例 + var session = Entity.Create(network.Scene, false, true); + session.Channel = network; + session.RemoteEndPoint = remoteEndPoint; + session.OnDispose = network.Dispose; + session.NetworkMessageScheduler = network.NetworkMessageScheduler; + session.LastReceiveTime = TimeHelper.Now; + return session; + } +#if FANTASY_NET + internal static ProcessSession CreateInnerSession(Scene scene) + { + var session = Entity.Create(scene, false, false); + session.NetworkMessageScheduler = new InnerMessageScheduler(scene); + return session; + } + + /// + /// 发送一个消息,框架内部使用建议不要用这个方法。 + /// + /// 如果是RPC消息需要传递一个RPCId + /// routeId + /// 消息的类型 + /// packInfo消息包 + public virtual void Send(uint rpcId, long routeId, Type messageType, APackInfo packInfo) + { + if (IsDisposed) + { + return; + } + + Channel.Send(rpcId, routeId, packInfo.MemoryStream, null); + } + + /// + /// 发送一个消息,框架内部使用建议不要用这个方法。 + /// + /// 一个ProcessPackInfo消息包 + /// 如果是RPC消息需要传递一个RPCId + /// routeId + public virtual void Send(ProcessPackInfo packInfo, uint rpcId = 0, long routeId = 0) + { + if (IsDisposed) + { + return; + } + + using (packInfo) + { + Channel.Send(rpcId, routeId, packInfo.MemoryStream, null); + } + } + + /// + /// 发送一个消息 + /// + /// 需要发送的MemoryStreamBuffer + /// 如果是RPC消息需要传递一个RPCId + /// routeId + public virtual void Send(MemoryStreamBuffer memoryStream, uint rpcId = 0, long routeId = 0) + { + if (IsDisposed) + { + return; + } + + Channel.Send(rpcId, routeId, memoryStream, null); + } +#endif + /// + /// 销毁一个Session,当执行了这个方法会自动断开网络的连接。 + /// + public override void Dispose() + { + if (IsDisposed) + { + return; + } + + _rpcId = 0; + LastReceiveTime = 0; + Channel = null; + RemoteEndPoint = null; + NetworkMessageScheduler = null; + base.Dispose(); + + // 终止所有等待中的请求回调 + foreach (var requestCallback in RequestCallback.Values.ToArray()) + { + requestCallback.SetException(new Exception($"session is dispose: {Id}")); + } + + RequestCallback.Clear(); + OnDispose?.Invoke(); + } + + /// + /// 发送一个消息 + /// + /// 消息的实例 + /// 如果是RPC消息需要传递一个RPCId + /// routeId + public virtual void Send(IMessage message, uint rpcId = 0, long routeId = 0) + { + if (IsDisposed) + { + return; + } + + Channel.Send(rpcId, routeId, null, message); + } + + /// + /// 发送一个消息 + /// + /// 消息的实例,不同的是这个是发送Route消息使用的 + /// 如果是RPC消息需要传递一个RPCId + /// routeId + public virtual void Send(IRouteMessage routeMessage, uint rpcId = 0, long routeId = 0) + { + if (IsDisposed) + { + return; + } + + Channel.Send(rpcId, routeId, null, routeMessage); + } + + /// + /// 发送一个RPC消息 + /// + /// 请求Route消息的实例 + /// routeId + /// + public virtual FTask Call(IRouteRequest request, long routeId = 0) + { + if (IsDisposed) + { + return null; + } + + var requestCallback = FTask.Create(); + var rpcId = ++_rpcId; + RequestCallback.Add(rpcId, requestCallback); + Send(request, rpcId, routeId); + return requestCallback; + } + + /// + /// 发送一个RPC消息 + /// + /// 请求消息的实例 + /// routeId + /// + public virtual FTask Call(IRequest request, long routeId = 0) + { + if (IsDisposed) + { + return null; + } + + var requestCallback = FTask.Create(); + var rpcId = ++_rpcId; + RequestCallback.Add(rpcId, requestCallback); + Send(request, rpcId, routeId); + return requestCallback; + } + + internal void Receive(APackInfo packInfo) + { + if (IsDisposed) + { + return; + } + + LastReceiveTime = TimeHelper.Now; + + try + { + NetworkMessageScheduler.Scheduler(this, packInfo).Coroutine(); + } + catch (Exception e) + { + // 如果解析失败,只有一种可能,那就是有人恶意发包。 + // 所以这里强制关闭了当前连接。不让对方一直发包。 + Dispose(); + Log.Error(e); + } + } + } +} diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Platform/Console/Entry.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Platform/Console/Entry.cs new file mode 100644 index 0000000..e45d060 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Platform/Console/Entry.cs @@ -0,0 +1,101 @@ +#if FANTASY_CONSOLE +using Fantasy.Assembly; +using Fantasy.Async; +using Fantasy.Serialize; +#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. +#pragma warning disable CS8603 // Possible null reference return. +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. +namespace Fantasy.Platform.Console +{ + public struct OnFantasyInit + { + public Scene Scene; + } + + /// + /// 一般的控制台启动入口,可以适用大部分客户端环境 + /// + public sealed class Entry + { + private static bool _isInit; + private static Thread _updateThread; + public static Scene Scene { get; private set; } + + /// + /// 初始化框架 + /// + /// + public static async FTask Initialize(params System.Reflection.Assembly[] assemblies) + { + if (_isInit) + { + Log.Error("Fantasy has already been initialized and does not need to be initialized again!"); + return; + } + + // 初始化程序集管理系统 + await AssemblySystem.InnerInitialize(assemblies); + // 初始化序列化 + SerializerManager.Initialize(); + _isInit = true; + Log.Debug("Fantasy Initialize Complete!"); + } + + /// + /// 启动框架。 + /// 如果您的平台有每帧更新逻辑的方法,请不要调用这个方法。 + /// 如果没有实现每帧执行方法平台需要调用这个方法,目的是开启一个新的线程来每帧执行Update。 + /// 注意因为开启了一个新的线程来处理更新逻辑,所以要注意多线程的问题。 + /// + public static void StartUpdate() + { + _updateThread = new Thread(() => + { + while (_isInit) + { + ThreadScheduler.Update(); + Thread.Sleep(1); + } + }) + { + IsBackground = true + }; + _updateThread.Start(); + } + + /// + /// 在Entry中创建一个Scene,如果Scene已经被创建过,将先销毁Scene再创建。 + /// + /// + /// + public static async FTask CreateScene(string sceneRuntimeType = SceneRuntimeType.MainThread) + { + Scene?.Dispose(); + Scene = await Scene.Create(sceneRuntimeType); + await Scene.EventComponent.PublishAsync(new OnFantasyInit() + { + Scene = Scene + }); + return Scene; + } + + /// + /// 如果有的话一定要在每帧执行这个方法 + /// + public void Update() + { + ThreadScheduler.Update(); + } + + public static void Dispose() + { + AssemblySystem.Dispose(); + SerializerManager.Dispose(); + Scene?.Dispose(); + Scene = null; + _isInit = false; + } + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Platform/Console/ThreadSynchronizationContext.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Platform/Console/ThreadSynchronizationContext.cs new file mode 100644 index 0000000..29fd54a --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Platform/Console/ThreadSynchronizationContext.cs @@ -0,0 +1,38 @@ +#if FANTASY_CONSOLE +#pragma warning disable CS8601 // Possible null reference assignment. +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. +#pragma warning disable CS8765 // Nullability of type of parameter doesn't match overridden member (possibly because of nullability attributes). +namespace Fantasy +{ + public sealed class ThreadSynchronizationContext : SynchronizationContext + { + private Action _actionHandler; + private readonly Queue _queue = new(); + + public void Update() + { + while (_queue.TryDequeue(out _actionHandler)) + { + try + { + _actionHandler(); + } + catch (Exception e) + { + Log.Error(e); + } + } + } + + public override void Post(SendOrPostCallback callback, object state) + { + Post(() => callback(state)); + } + + public void Post(Action action) + { + _queue.Enqueue(action); + } + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Platform/Net/ConfigTable/MachineConfig.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Platform/Net/ConfigTable/MachineConfig.cs new file mode 100644 index 0000000..e09b00e --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Platform/Net/ConfigTable/MachineConfig.cs @@ -0,0 +1,88 @@ +#if FANTASY_NET +// ReSharper disable InconsistentNaming +using System.Collections.Concurrent; +using System.Runtime.Serialization; +using Fantasy.Helper; +using Newtonsoft.Json; +#pragma warning disable CS8601 // Possible null reference assignment. +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. +namespace Fantasy.Platform.Net +{ + /// + /// 用于记录服务器物理信息 + /// + public sealed class MachineConfigData + { + /// + /// 存放所有MachineConfigInfo信息 + /// + public List List; + [JsonIgnore] + [IgnoreDataMember] + private readonly ConcurrentDictionary _configs = new ConcurrentDictionary(); + /// + /// 获得MachineConfig的实例 + /// + public static MachineConfigData Instance { get; private set; } + /// + /// 初始化MachineConfig + /// + /// + public static void Initialize(string machineConfigJson) + { + Instance = machineConfigJson.Deserialize(); + foreach (var config in Instance.List) + { + Instance._configs.TryAdd(config.Id, config); + } + } + /// + /// 根据Id获取MachineConfig + /// + /// + /// + /// + public MachineConfig Get(uint id) + { + if (_configs.TryGetValue(id, out var machineConfigInfo)) + { + return machineConfigInfo; + } + + throw new FileNotFoundException($"MachineConfig not find {id} Id"); + } + /// + /// 根据Id获取MachineConfig + /// + /// + /// + /// + public bool TryGet(uint id, out MachineConfig config) + { + return _configs.TryGetValue(id, out config); + } + } + /// + /// 表示一个物理服务器的信息 + /// + public sealed class MachineConfig + { + /// + /// Id + /// + public uint Id { get; set; } + /// + /// 外网IP + /// + public string OuterIP { get; set; } + /// + /// 外网绑定IP + /// + public string OuterBindIP { get; set; } + /// + /// 内网绑定IP + /// + public string InnerBindIP { get; set; } + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Platform/Net/ConfigTable/ProcessConfig.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Platform/Net/ConfigTable/ProcessConfig.cs new file mode 100644 index 0000000..4a400b0 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Platform/Net/ConfigTable/ProcessConfig.cs @@ -0,0 +1,100 @@ +#if FANTASY_NET +using System.Collections.Concurrent; +using System.Runtime.Serialization; +using Fantasy.Helper; +using Newtonsoft.Json; +// ReSharper disable CollectionNeverUpdated.Global +#pragma warning disable CS8601 // Possible null reference assignment. +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. + +namespace Fantasy.Platform.Net +{ + /// + /// 用于管理进程信息 + /// + public sealed class ProcessConfigData + { + /// + /// 存放所有ProcessConfig信息 + /// + public List List; + [JsonIgnore] + [IgnoreDataMember] + private readonly ConcurrentDictionary _configs = new ConcurrentDictionary(); + /// + /// 获得ProcessConfigData的实例 + /// + public static ProcessConfigData Instance { get; private set; } + /// + /// 初始化MachineConfig + /// + /// + public static void Initialize(string processConfigJson) + { + Instance = processConfigJson.Deserialize(); + foreach (var config in Instance.List) + { + Instance._configs.TryAdd(config.Id, config); + } + } + /// + /// 根据Id获取ProcessConfig + /// + /// + /// + /// + public ProcessConfig Get(uint id) + { + if (_configs.TryGetValue(id, out var processConfigInfo)) + { + return processConfigInfo; + } + + throw new FileNotFoundException($"MachineConfig not find {id} Id"); + } + /// + /// 根据Id获取ProcessConfig + /// + /// + /// + /// + public bool TryGet(uint id, out ProcessConfig config) + { + return _configs.TryGetValue(id, out config); + } + /// + /// 按照startupGroup寻找属于startupGroup组的ProcessConfig + /// + /// startupGroup + /// + public IEnumerable ForEachByStartupGroup(uint startupGroup) + { + foreach (var processConfig in List) + { + if (processConfig.StartupGroup == startupGroup) + { + yield return processConfig; + } + } + } + } + /// + /// 表示一个进程配置信息 + /// + public sealed class ProcessConfig + { + /// + /// 进程Id + /// + public uint Id { get; set; } + /// + /// 机器ID + /// + public uint MachineId { get; set; } + /// + /// 启动组 + /// + public uint StartupGroup { get; set; } + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Platform/Net/ConfigTable/SceneConfig.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Platform/Net/ConfigTable/SceneConfig.cs new file mode 100644 index 0000000..9eff1aa --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Platform/Net/ConfigTable/SceneConfig.cs @@ -0,0 +1,196 @@ +#if FANTASY_NET +using System.Collections.Concurrent; +using System.Runtime.Serialization; +using Fantasy.DataStructure.Collection; +using Fantasy.DataStructure.Dictionary; +using Fantasy.Helper; +using Fantasy.IdFactory; +using Newtonsoft.Json; +#pragma warning disable CS8603 // Possible null reference return. +#pragma warning disable CS8601 // Possible null reference assignment. + +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. +namespace Fantasy.Platform.Net +{ + /// + /// 存放所有SceneConfigInfo信息 + /// + public sealed class SceneConfigData + { + /// + /// 存放所有SceneConfig信息 + /// + public List List; + [JsonIgnore] + [IgnoreDataMember] + private readonly ConcurrentDictionary _configs = new ConcurrentDictionary(); + [JsonIgnore] + [IgnoreDataMember] + private readonly OneToManyList _sceneConfigBySceneType = new OneToManyList(); + [JsonIgnore] + [IgnoreDataMember] + private readonly OneToManyList _sceneConfigByProcess = new OneToManyList(); + [JsonIgnore] [IgnoreDataMember] + private readonly Dictionary>> _worldSceneTypes = new Dictionary>>(); + /// + /// 获得SceneConfigData的实例 + /// + public static SceneConfigData Instance { get; private set; } + /// + /// 初始化SceneConfig + /// + /// + public static void Initialize(string sceneConfigJson) + { + Instance = sceneConfigJson.Deserialize(); + foreach (var config in Instance.List) + { + config.Initialize(); + Instance._configs.TryAdd(config.Id, config); + Instance._sceneConfigByProcess.Add(config.ProcessConfigId, config); + Instance._sceneConfigBySceneType.Add(config.SceneType, config); + + var configWorldConfigId = (int)config.WorldConfigId; + + if (!Instance._worldSceneTypes.TryGetValue(configWorldConfigId, out var sceneConfigDic)) + { + sceneConfigDic = new Dictionary>(); + Instance._worldSceneTypes.Add(configWorldConfigId, sceneConfigDic); + } + + if (!sceneConfigDic.TryGetValue(config.SceneType, out var sceneConfigList)) + { + sceneConfigList = new List(); + sceneConfigDic.Add(config.SceneType, sceneConfigList); + } + + sceneConfigList.Add(config); + } + } + + /// + /// 根据Id获取SceneConfig + /// + /// + /// + /// + public SceneConfig Get(uint id) + { + if (_configs.TryGetValue(id, out var sceneConfigInfo)) + { + return sceneConfigInfo; + } + + throw new FileNotFoundException($"WorldConfig not find {id} Id"); + } + + /// + /// 根据Id获取SceneConfig + /// + /// + /// + /// + public bool TryGet(uint id, out SceneConfig config) + { + return _configs.TryGetValue(id, out config); + } + + /// + /// 获得SceneConfig + /// + /// + /// + public List GetByProcess(uint serverConfigId) + { + return _sceneConfigByProcess.TryGetValue(serverConfigId, out var list) ? list : new List(); + } + + /// + /// 获得SceneConfig + /// + /// + /// + public List GetSceneBySceneType(int sceneType) + { + return !_sceneConfigBySceneType.TryGetValue(sceneType, out var list) ? new List() : list; + } + + /// + /// 获得SceneConfig + /// + /// + /// + /// + public List GetSceneBySceneType(int world, int sceneType) + { + if (!_worldSceneTypes.TryGetValue(world, out var sceneConfigDic)) + { + return new List(); + } + + if (!sceneConfigDic.TryGetValue(sceneType, out var list)) + { + return new List(); + } + + return list; + } + } + + /// + /// 表示一个Scene配置信息 + /// + public sealed class SceneConfig + { + /// + /// ID + /// + public uint Id { get; set; } + /// + /// 进程Id + /// + public uint ProcessConfigId { get; set; } + /// + /// 世界Id + /// + public uint WorldConfigId { get; set; } + /// + /// Scene运行类型 + /// + public string SceneRuntimeType { get; set; } + /// + /// Scene类型 + /// + public string SceneTypeString { get; set; } + /// + /// 协议类型 + /// + public string NetworkProtocol { get; set; } + /// + /// 外网端口 + /// + public int OuterPort { get; set; } + /// + /// 内网端口 + /// + public int InnerPort { get; set; } + /// + /// Scene类型 + /// + public int SceneType { get; set; } + /// + /// RouteId + /// + [JsonIgnore] + [IgnoreDataMember] + public long RouteId { get; private set; } + /// + /// 初始化方法 + /// + public void Initialize() + { + RouteId = IdFactoryHelper.RuntimeId(0, Id, (byte)WorldConfigId, 0); + } + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Platform/Net/ConfigTable/WorldConfig.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Platform/Net/ConfigTable/WorldConfig.cs new file mode 100644 index 0000000..9b0ede5 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Platform/Net/ConfigTable/WorldConfig.cs @@ -0,0 +1,93 @@ +#if FANTASY_NET +using System.Collections.Concurrent; +using System.Runtime.Serialization; +using Fantasy.Helper; +using Newtonsoft.Json; +#pragma warning disable CS8601 // Possible null reference assignment. + +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. +namespace Fantasy.Platform.Net +{ + /// + /// 存放所有WorldConfigInfo信息 + /// + public sealed class WorldConfigData + { + /// + /// 存放所有WorldConfigInfo信息 + /// + public List List; + [JsonIgnore] + [IgnoreDataMember] + private readonly ConcurrentDictionary _configs = new ConcurrentDictionary(); + /// + /// 获得WorldConfig的实例 + /// + public static WorldConfigData Instance { get; private set; } + /// + /// 初始化WorldConfig + /// + /// + public static void Initialize(string worldConfigJson) + { + Instance = worldConfigJson.Deserialize(); + foreach (var config in Instance.List) + { + Instance._configs.TryAdd(config.Id, config); + } + } + /// + /// 根据Id获取WorldConfig + /// + /// + /// + /// + public WorldConfig Get(uint id) + { + if (_configs.TryGetValue(id, out var worldConfigInfo)) + { + return worldConfigInfo; + } + + throw new FileNotFoundException($"WorldConfig not find {id} Id"); + } + /// + /// 根据Id获取WorldConfig + /// + /// + /// + /// + public bool TryGet(uint id, out WorldConfig config) + { + return _configs.TryGetValue(id, out config); + } + } + + /// + /// 表示一个世界配置信息 + /// + public sealed class WorldConfig + { + /// + /// Id + /// + public uint Id { get; set; } + /// + /// 名称 + /// + public string WorldName { get; set; } + /// + /// 数据库连接字符串 + /// + public string DbConnection { get; set; } + /// + /// 数据库名称 + /// + public string DbName { get; set; } + /// + /// 数据库类型 + /// + public string DbType { get; set; } + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Platform/Net/Entry.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Platform/Net/Entry.cs new file mode 100644 index 0000000..313ad0b --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Platform/Net/Entry.cs @@ -0,0 +1,121 @@ +#if FANTASY_NET +using CommandLine; +using Fantasy.Assembly; +using Fantasy.Async; +using Fantasy.Helper; +using Fantasy.IdFactory; +using Fantasy.Network; +using Fantasy.Serialize; +// ReSharper disable FunctionNeverReturns + +namespace Fantasy.Platform.Net; + +/// +/// Fantasy.Net 应用程序入口 +/// +/// 当命令行格式异常时抛出。 +/// 不支持的 ProcessType 类型异常。 +public static class Entry +{ + /// + /// 框架初始化 + /// + /// 注册的Assembly + public static async FTask Initialize(params System.Reflection.Assembly[] assemblies) + { + // 解析命令行参数 + Parser.Default.ParseArguments(Environment.GetCommandLineArgs()) + .WithNotParsed(error => throw new Exception("Command line format error!")) + .WithParsed(option => + { + ProcessDefine.Options = option; + ProcessDefine.InnerNetwork = Enum.Parse(option.InnerNetwork); + }); + // 初始化Log系统 + Log.Initialize(); + // 检查启动参数,后期可能有机器人等不同的启动参数 + switch (ProcessDefine.Options.ProcessType) + { + case "Game": + { + break; + } + default: + { + throw new NotSupportedException($"ProcessType is {ProcessDefine.Options.ProcessType} Unrecognized!"); + } + } + // 初始化程序集管理系统 + await AssemblySystem.InnerInitialize(assemblies); + // 初始化序列化 + SerializerManager.Initialize(); + // 精度处理(只针对Windows下有作用、其他系统没有这个问题、一般也不会用Windows来做服务器的) + WinPeriod.Initialize(); + } + + /// + /// 启动Fantasy.Net + /// + public static async FTask Start() + { + // 启动Process + StartProcess().Coroutine(); + await FTask.CompletedTask; + while (true) + { + ThreadScheduler.Update(); + Thread.Sleep(1); + } + } + + /// + /// 初始化并且启动框架 + /// + /// + public static async FTask Start(params System.Reflection.Assembly[] assemblies) + { + await Initialize(assemblies); + await Start(); + } + + private static async FTask StartProcess() + { + if (ProcessDefine.Options.StartupGroup != 0) + { + foreach (var processConfig in ProcessConfigData.Instance.ForEachByStartupGroup((uint)ProcessDefine.Options.StartupGroup)) + { + await Process.Create(processConfig.Id); + } + + return; + } + + switch (ProcessDefine.Options.Mode) + { + case "Develop": + { + foreach (var processConfig in ProcessConfigData.Instance.List) + { + await Process.Create(processConfig.Id); + } + + return; + } + case "Release": + { + await Process.Create(ProcessDefine.Options.ProcessId); + return; + } + } + } + + /// + /// 关闭 Fantasy + /// + public static void Close() + { + AssemblySystem.Dispose(); + SerializerManager.Dispose(); + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Platform/Net/Process.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Platform/Net/Process.cs new file mode 100644 index 0000000..361ca74 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Platform/Net/Process.cs @@ -0,0 +1,150 @@ +#if FANTASY_NET +using System.Collections.Concurrent; +using Fantasy.Async; +using Fantasy.IdFactory; + +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. +#pragma warning disable CS8601 // Possible null reference assignment. +namespace Fantasy.Platform.Net; + +/// +/// 一个进程的实例 +/// +public sealed class Process : IDisposable +{ + /// + /// 当前进程的Id + /// + public readonly uint Id; + /// + /// 进程关联的MachineId + /// + public readonly uint MachineId; + private readonly ConcurrentDictionary _processScenes = new ConcurrentDictionary(); + private static readonly ConcurrentDictionary Scenes = new ConcurrentDictionary(); + private Process() {} + private Process(uint id, uint machineId) + { + Id = id; + MachineId = machineId; + } + + internal bool IsProcess(ref long routeId) + { + var sceneId = IdFactoryHelper.RuntimeIdTool.GetSceneId(ref routeId); + return _processScenes.ContainsKey(sceneId); + } + + internal bool IsProcess(ref uint sceneId) + { + return _processScenes.ContainsKey(sceneId); + } + + internal void AddSceneToProcess(Scene scene) + { + _processScenes.TryAdd(scene.SceneConfigId, scene); + } + + internal void RemoveSceneToProcess(Scene scene, bool isDispose) + { + _processScenes.Remove(scene.SceneConfigId, out _); + + if (isDispose) + { + scene.Dispose(); + } + } + + internal bool TryGetSceneToProcess(long routeId, out Scene scene) + { + var sceneId = IdFactoryHelper.RuntimeIdTool.GetSceneId(ref routeId); + return _processScenes.TryGetValue(sceneId, out scene); + } + + internal bool TryGetSceneToProcess(uint sceneId, out Scene scene) + { + return _processScenes.TryGetValue(sceneId, out scene); + } + /// + /// 销毁方法 + /// + public void Dispose() + { + if (_processScenes.IsEmpty) + { + return; + } + + var sceneQueue = new Queue(); + + foreach (var (_, scene) in _processScenes) + { + sceneQueue.Enqueue(scene); + } + + while (sceneQueue.TryDequeue(out var removeScene)) + { + removeScene.Dispose(); + } + + _processScenes.Clear(); + } + + internal static async FTask Create(uint processConfigId) + { + if (!ProcessConfigData.Instance.TryGet(processConfigId, out var processConfig)) + { + Log.Error($"not found processConfig by Id:{processConfigId}"); + return null; + } + + if (!MachineConfigData.Instance.TryGet(processConfig.MachineId, out var machineConfig)) + { + Log.Error($"not found machineConfig by Id:{processConfig.MachineId}"); + return null; + } + + var process = new Process(processConfigId, processConfig.MachineId); + var sceneConfigs = SceneConfigData.Instance.GetByProcess(processConfigId); + + foreach (var sceneConfig in sceneConfigs) + { + await Scene.Create(process, machineConfig, sceneConfig); + } + + Log.Info($"Process:{processConfigId} Startup Complete SceneCount:{sceneConfigs.Count}"); + return process; + } + + internal bool IsInAppliaction(ref uint sceneId) + { + return _processScenes.ContainsKey(sceneId); + } + + internal static void AddScene(Scene scene) + { + Scenes.TryAdd(scene.SceneConfigId, scene); + } + + internal static void RemoveScene(Scene scene, bool isDispose) + { + Scenes.Remove(scene.SceneConfigId, out _); + + if (isDispose) + { + scene.Dispose(); + } + } + + internal static bool TryGetScene(long routeId, out Scene scene) + { + var sceneId = IdFactoryHelper.RuntimeIdTool.GetSceneId(ref routeId); + return Scenes.TryGetValue(sceneId, out scene); + } + + internal static bool TryGetScene(uint sceneId, out Scene scene) + { + return Scenes.TryGetValue(sceneId, out scene); + } +} +#endif diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Platform/Net/ProcessDefine.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Platform/Net/ProcessDefine.cs new file mode 100644 index 0000000..2bcc4e0 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Platform/Net/ProcessDefine.cs @@ -0,0 +1,99 @@ +#if FANTASY_NET +using CommandLine; +using Fantasy.Network; + +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. +namespace Fantasy.Platform.Net; + +/// +/// Process运行模式 +/// +public enum ProcessMode +{ + /// + /// 默认 + /// + None =0, + /// + /// 开发模式 + /// + Develop = 1, + /// + /// 发布模式 + /// + Release = 2 +} + +internal sealed class CommandLineOptions +{ + /// + /// 用于启动指定的进程,该进程的 ID 与 ProcessConfig 的 ID 相关联。此参数只能传递单个 ID,不支持传递多个 ID。 + /// + [Option("pid", Required = false, Default = (uint)0, HelpText = "Enter an ProcessIdId such as 1")] + public uint ProcessId { get; set; } + /// + /// Process类型,获取或设置应用程序的类型。 + /// Game - 游戏服务器Process + /// Robot - 机器人(暂未支持该功能) + /// + [Option('a', "ProcessType", Required = false, Default = "Game", HelpText = "Game")] + public string ProcessType { get; set; } + /// + /// 服务器运行模式,获取或设置服务器的运行模式。 + /// Develop - 开发模式(启动Process配置表中的所有Process) + /// Release - 发布模式(根据ProcessId启动Process) + /// + [Option('m', "Mode", Required = true, Default = "Release", HelpText = "Develop:启动Process配置表中的所有Process,\nRelease:根据ProcessId启动Process")] + public string Mode { get; set; } + /// + /// 服务器内部网络协议 + /// TCP - 服务器内部之间通讯使用TCP协议 + /// KCP - 服务器内部之间通讯使用KCP协议 + /// WebSocket - 服务器内部之间通讯使用WebSocket协议(不推荐、TCP或KCP) + /// + [Option('n', "InnerNetwork", Required = false, Default = "TCP", HelpText = "TCP、KCP、WebSocket")] + public string InnerNetwork { get; set; } + /// + /// 会话空闲检查超时时间。 + /// + [Option('t', "SessionIdleCheckerTimeout", Required = false, Default = 8000, HelpText = "Session idle check timeout")] + public int SessionIdleCheckerTimeout { get; set; } + /// + /// 会话空闲检查间隔。 + /// + [Option('i', "SessionIdleCheckerInterval", Required = false, Default = 5000, HelpText = "Session idle check interval")] + public int SessionIdleCheckerInterval { get; set; } + /// + /// 启动组。 + /// + [Option('g', "StartupGroup", Required = false, Default = 0, HelpText = "Used to start a group of Process")] + public int StartupGroup { get; set; } +} + +/// +/// AppDefine +/// +internal static class ProcessDefine +{ + /// + /// 命令行选项 + /// + public static CommandLineOptions Options; + /// + /// App程序Id + /// + public static uint ProcessId => Options.ProcessId; + /// + /// 会话空闲检查超时时间。 + /// + public static int SessionIdleCheckerTimeout => Options.SessionIdleCheckerTimeout; + /// + /// 会话空闲检查间隔。 + /// + public static int SessionIdleCheckerInterval => Options.SessionIdleCheckerInterval; + /// + /// 内部网络通讯协议类型 + /// + public static NetworkProtocolType InnerNetwork; +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Platform/Net/ThreadSynchronizationContext.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Platform/Net/ThreadSynchronizationContext.cs new file mode 100644 index 0000000..bb2948a --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Platform/Net/ThreadSynchronizationContext.cs @@ -0,0 +1,52 @@ +#if FANTASY_NET +using System.Collections.Concurrent; +#pragma warning disable CS8765 +#pragma warning disable CS8601 +#pragma warning disable CS8618 + +namespace Fantasy; + +/// +/// 线程的同步上下文 +/// +public sealed class ThreadSynchronizationContext : SynchronizationContext +{ + private readonly ConcurrentQueue _queue = new(); + /// + /// 执行当前上下文投递过的逻辑 + /// + public void Update() + { + while (_queue.TryDequeue(out var actionHandler)) + { + try + { + actionHandler(); + } + catch (Exception e) + { + Log.Error(e); + } + } + } + + /// + /// 投递一个逻辑到当前上下文 + /// + /// + /// + public override void Post(SendOrPostCallback callback, object state) + { + Post(() => callback(state)); + } + + /// + /// 投递一个逻辑到当前上下文 + /// + /// + public void Post(Action action) + { + _queue.Enqueue(action); + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Platform/Unity/AppDefine.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Platform/Unity/AppDefine.cs new file mode 100644 index 0000000..d9d85ae --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Platform/Unity/AppDefine.cs @@ -0,0 +1,19 @@ +#if FANTASY_UNITY +namespace Fantasy.Platform.Unity +{ + public static class AppDefine + { + public static string RemoteUpdatePath; + public static bool EditorModel = true; + public const string VersionName = "version.bytes"; + public const string VersionMD5Name = "version.md5"; + public const string AssetBundleManifestName = "Fantasy"; + public static bool IsEditor => UnityEngine.Application.isEditor && EditorModel; + public static string AssetBundleSaveDirectory => "Assets/AssetBundles"; + public static string LocalAssetBundlePath => UnityEngine.Application.streamingAssetsPath; + public static string RemoteAssetBundlePath => UnityEngine.Application.persistentDataPath; + public static string PersistentDataVersion => $"{UnityEngine.Application.persistentDataPath}/{VersionName}"; + public static string StreamingAssetsVersion => $"{UnityEngine.Application.streamingAssetsPath}/{VersionName}"; + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Platform/Unity/Attributes/BsonDefaultValueAttribute.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Platform/Unity/Attributes/BsonDefaultValueAttribute.cs new file mode 100644 index 0000000..49914ec --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Platform/Unity/Attributes/BsonDefaultValueAttribute.cs @@ -0,0 +1,11 @@ +#if FANTASY_UNITY +using System; +namespace MongoDB.Bson.Serialization.Attributes +{ + [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)] + public class BsonDefaultValueAttribute : Attribute + { + public BsonDefaultValueAttribute(object defaultValue) { } + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Platform/Unity/Attributes/BsonElementAttribute.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Platform/Unity/Attributes/BsonElementAttribute.cs new file mode 100644 index 0000000..3892727 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Platform/Unity/Attributes/BsonElementAttribute.cs @@ -0,0 +1,13 @@ +#if FANTASY_UNITY +using System; +namespace MongoDB.Bson.Serialization.Attributes +{ + [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)] + public class BsonElementAttribute : Attribute + { + public BsonElementAttribute() { } + + public BsonElementAttribute(string elementName) { } + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Platform/Unity/Attributes/BsonIdAttribute.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Platform/Unity/Attributes/BsonIdAttribute.cs new file mode 100644 index 0000000..48274d0 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Platform/Unity/Attributes/BsonIdAttribute.cs @@ -0,0 +1,11 @@ +#if FANTASY_UNITY +using System; +namespace MongoDB.Bson.Serialization.Attributes +{ + [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)] + public class BsonIdAttribute : Attribute + { + + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Platform/Unity/Attributes/BsonIgnoreAttribute.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Platform/Unity/Attributes/BsonIgnoreAttribute.cs new file mode 100644 index 0000000..23e55c8 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Platform/Unity/Attributes/BsonIgnoreAttribute.cs @@ -0,0 +1,11 @@ +#if FANTASY_UNITY +using System; +namespace MongoDB.Bson.Serialization.Attributes +{ + [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)] + public class BsonIgnoreAttribute : Attribute + { + + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Platform/Unity/Attributes/BsonIgnoreIfDefaultAttribute.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Platform/Unity/Attributes/BsonIgnoreIfDefaultAttribute.cs new file mode 100644 index 0000000..82dddde --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Platform/Unity/Attributes/BsonIgnoreIfDefaultAttribute.cs @@ -0,0 +1,13 @@ +#if FANTASY_UNITY +using System; +namespace MongoDB.Bson.Serialization.Attributes +{ + [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)] + public class BsonIgnoreIfDefaultAttribute : Attribute + { + public BsonIgnoreIfDefaultAttribute() { } + + public BsonIgnoreIfDefaultAttribute(bool value) { } + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Platform/Unity/Attributes/BsonIgnoreIfNullAttribute.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Platform/Unity/Attributes/BsonIgnoreIfNullAttribute.cs new file mode 100644 index 0000000..f330a8b --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Platform/Unity/Attributes/BsonIgnoreIfNullAttribute.cs @@ -0,0 +1,11 @@ +#if FANTASY_UNITY +using System; +namespace MongoDB.Bson.Serialization.Attributes +{ + [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)] + public class BsonIgnoreIfNullAttribute : Attribute + { + + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Platform/Unity/Entry.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Platform/Unity/Entry.cs new file mode 100644 index 0000000..fd05f75 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Platform/Unity/Entry.cs @@ -0,0 +1,101 @@ +#if FANTASY_UNITY +using System.Linq; +using Fantasy.Assembly; +using Fantasy.Async; +using Fantasy.Serialize; +using UnityEngine; + +#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. +#pragma warning disable CS8603 // Possible null reference return. +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. + +namespace Fantasy.Platform.Unity +{ + public sealed class FantasyObject : MonoBehaviour + { + public static GameObject FantasyObjectGameObject { get; private set; } + // 这个方法将在游戏启动时自动调用 + [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)] + static void OnRuntimeMethodLoad() + { + FantasyObjectGameObject = new GameObject("Fantasy.Net"); + DontDestroyOnLoad(FantasyObjectGameObject); + } + private void OnApplicationQuit() + { + Destroy(FantasyObjectGameObject); + } + } + + public struct OnSceneCreate + { + public Scene Scene; + public object Arg; + } + + public class Entry : MonoBehaviour + { + private static bool _isInit; + public static Scene Scene { get; private set; } + + /// + /// 初始化框架 + /// + /// + public static async FTask Initialize(params System.Reflection.Assembly[] assemblies) + { + if (_isInit) + { + Log.Error("Fantasy has already been initialized and does not need to be initialized again!"); + return; + } + Log.Register(new UnityLog()); + await AssemblySystem.InnerInitialize(assemblies); + // 初始化序列化 + SerializerManager.Initialize(); +#if FANTASY_WEBGL + ThreadSynchronizationContext.Initialize(); +#endif + _isInit = true; + FantasyObject.FantasyObjectGameObject.AddComponent(); + Log.Debug("Fantasy Initialize Complete!"); + } + + /// + /// 在Entry中创建一个Scene,如果Scene已经被创建过,将先销毁Scene再创建。 + /// + /// + /// + /// + public static async FTask CreateScene(object arg = null, string sceneRuntimeType = SceneRuntimeType.MainThread) + { + Scene?.Dispose(); + Scene = await Scene.Create(sceneRuntimeType); + await Scene.EventComponent.PublishAsync(new OnSceneCreate() + { + Arg = arg, + Scene = Scene + }); + return Scene; + } + + private void Update() + { + ThreadScheduler.Update(); + } + + private void OnDestroy() + { + AssemblySystem.Dispose(); + SerializerManager.Dispose(); + if (Scene != null) + { + Scene?.Dispose(); + Scene = null; + } + _isInit = false; + } + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Platform/Unity/Temp.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Platform/Unity/Temp.cs new file mode 100644 index 0000000..399488f --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Platform/Unity/Temp.cs @@ -0,0 +1,108 @@ +// using System.Reflection; +// using Fantasy.Assembly; +// using Fantasy.Async; +// // using UnityEngine; +// #pragma warning disable CS0649 // Field is never assigned to, and will always have its default value +// #pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. +// #pragma warning disable CS8603 // Possible null reference return. +// #pragma warning disable CS1591 // Missing XML comment for publicly visible type or member +// #pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. +// +// namespace Fantasy.Platform.Unity +// { +// public class MonoBehaviour +// { +// +// } +// +// public class GameObject +// { +// public GameObject(string name) +// { +// +// } +// } +// +// internal enum RuntimeInitializeLoadType +// { +// BeforeSceneLoad = 1, +// } +// +// internal class RuntimeInitializeOnLoadMethodAttribute : Attribute +// { +// public RuntimeInitializeLoadType RuntimeInitializeLoadType; +// +// public RuntimeInitializeOnLoadMethodAttribute(RuntimeInitializeLoadType loadType) +// { +// +// } +// } +// +// public sealed class FantasyObject : MonoBehaviour +// { +// public static GameObject FantasyObjectGameObject { get; private set; } +// // 这个方法将在游戏启动时自动调用 +// [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)] +// static void OnRuntimeMethodLoad() +// { +// FantasyObjectGameObject = new GameObject("Fantasy.Net"); +// // DontDestroyOnLoad(FantasyObjectGameObject); +// } +// private void OnApplicationQuit() +// { +// // Destroy(FantasyObjectGameObject); +// } +// } +// +// public struct OnFantasyInit +// { +// public Scene Scene; +// } +// +// public class Entry : MonoBehaviour +// { +// private static bool _isInit; +// public static Scene Scene { get; private set; } +// /// +// /// 初始化框架 +// /// +// public static async FTask Initialize(params System.Reflection.Assembly[] assemblies) +// { +// Scene?.Dispose(); +// // 初始化程序集管理系统 +// AssemblySystem.Initialize(assemblies); +// if (!_isInit) +// { +// #if FANTASY_WEBGL +// ThreadSynchronizationContext.Initialize(); +// #endif +// _isInit = true; +// // FantasyObject.FantasyObjectGameObject.AddComponent(); +// } +// // Scene = await Scene.Create(SceneRuntimeType.MainThread); +// // await Scene.EventComponent.PublishAsync(new OnFantasyInit() +// // { +// // Scene = Scene +// // }); +// // return Scene; +// await FTask.CompletedTask; +// return null; +// } +// +// private void Update() +// { +// ThreadScheduler.Update(); +// } +// +// private void OnDestroy() +// { +// AssemblySystem.Dispose(); +// if (Scene != null) +// { +// Scene?.Dispose(); +// Scene = null; +// } +// _isInit = false; +// } +// } +// } diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Platform/Unity/ThreadSynchronizationContext.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Platform/Unity/ThreadSynchronizationContext.cs new file mode 100644 index 0000000..44b165a --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Platform/Unity/ThreadSynchronizationContext.cs @@ -0,0 +1,104 @@ +#if FANTASY_UNITY && !FANTASY_WEBGL +#pragma warning disable CS8765 +#pragma warning disable CS8601 +#pragma warning disable CS8618 +using System; +using System.Collections.Concurrent; +using System.Threading; + +namespace Fantasy +{ + public sealed class ThreadSynchronizationContext : SynchronizationContext + { + private Action _actionHandler; + private readonly ConcurrentQueue _queue = new(); + + public void Update() + { + while (_queue.TryDequeue(out _actionHandler)) + { + try + { + _actionHandler(); + } + catch (Exception e) + { + Log.Error(e); + } + } + } + + public override void Post(SendOrPostCallback callback, object state) + { + Post(() => callback(state)); + } + + public void Post(Action action) + { + _queue.Enqueue(action); + } + } +} +#endif +#if FANTASY_UNITY && FANTASY_WEBGL +using System; +using System.Collections.Generic; +using System.Threading; +using Fantasy; +using UnityEngine; +using Object = UnityEngine.Object; + +public class WebGLSynchronizationContextUpdater : MonoBehaviour +{ + private ThreadSynchronizationContext _context; + + public void Initialize(ThreadSynchronizationContext context) + { + _context = context; + } + + void Update() + { + _context.Update(); + } +} +public sealed class ThreadSynchronizationContext : SynchronizationContext +{ + private Action _actionHandler; + private readonly Queue _queue = new(); + + public static void Initialize() + { + var context = new ThreadSynchronizationContext(); + SetSynchronizationContext(context); + var go = new GameObject("WebGLSynchronizationContextUpdater"); + go.AddComponent().Initialize(context); + Object.DontDestroyOnLoad(go); + } + + public void Update() + { + while (_queue.TryDequeue(out _actionHandler)) + { + try + { + _actionHandler(); + } + catch (Exception e) + { + Log.Error(e); + } + } + } + + public override void Post(SendOrPostCallback callback, object state) + { + Post(() => callback(state)); + } + + public void Post(Action action) + { + _queue.Enqueue(action); + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Pool/Concurrent/MultiThreadPool.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Pool/Concurrent/MultiThreadPool.cs new file mode 100644 index 0000000..4c946d1 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Pool/Concurrent/MultiThreadPool.cs @@ -0,0 +1,37 @@ +#if !FANTASY_WEBGL +using System; +using System.Collections.Concurrent; +using System.Runtime.CompilerServices; +#pragma warning disable CS8603 // Possible null reference return. + +namespace Fantasy.Pool +{ + /// + /// 线程安全的静态通用对象池。 + /// + internal static class MultiThreadPool + { + private static readonly ConcurrentDictionary ObjectPools = new ConcurrentDictionary(); + + public static T Rent() where T : IPool, new() + { + return ObjectPools.GetOrAdd(typeof(T), t => new MultiThreadPoolQueue(2000, () => new T())).Rent(); + } + + public static IPool Rent(Type type) + { + return ObjectPools.GetOrAdd(type, t => new MultiThreadPoolQueue(2000, CreateInstance.CreateIPool(type))).Rent(); + } + + public static void Return(T obj) where T : IPool, new() + { + if (!obj.IsPool()) + { + return; + } + + ObjectPools.GetOrAdd(typeof(T), t => new MultiThreadPoolQueue(2000, () => new T())).Return(obj); + } + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Pool/Concurrent/MultiThreadPoolQueue.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Pool/Concurrent/MultiThreadPoolQueue.cs new file mode 100644 index 0000000..df15a1c --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Pool/Concurrent/MultiThreadPoolQueue.cs @@ -0,0 +1,76 @@ +#if !FANTASY_WEBGL +using System; +using System.Collections.Concurrent; +using System.Threading; +// ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract +#pragma warning disable CS8601 // Possible null reference assignment. +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. +#pragma warning disable CS8603 // Possible null reference return. + +namespace Fantasy.Pool +{ + /// + /// 线程安全的对象池。 + /// + internal class MultiThreadPoolQueue + { + private int _poolCount; + private readonly int _maxCapacity; + private readonly Func _createInstance; + private readonly ConcurrentQueue _poolQueue = new ConcurrentQueue(); + private MultiThreadPoolQueue() { } + + public MultiThreadPoolQueue(int maxCapacity, Func createInstance) + { + _maxCapacity = maxCapacity; + _createInstance = createInstance; + } + + public T Rent() where T : IPool, new() + { + if (!_poolQueue.TryDequeue(out var t)) + { + var pool = new T(); + pool.SetIsPool(true); + return pool; + } + + t.SetIsPool(true); + Interlocked.Decrement(ref _poolCount); + return (T)t; + } + + public IPool Rent() + { + if (!_poolQueue.TryDequeue(out var t)) + { + var instance = _createInstance(); + instance.SetIsPool(true); + return instance; + } + + t.SetIsPool(true); + Interlocked.Decrement(ref _poolCount); + return t; + } + + public void Return(IPool obj) + { + if (!obj.IsPool()) + { + return; + } + + obj.SetIsPool(false); + + if (Interlocked.Increment(ref _poolCount) <= _maxCapacity) + { + _poolQueue.Enqueue(obj); + return; + } + + Interlocked.Decrement(ref _poolCount); + } + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Pool/Interface/IPool.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Pool/Interface/IPool.cs new file mode 100644 index 0000000..1775f28 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Pool/Interface/IPool.cs @@ -0,0 +1,18 @@ +namespace Fantasy.Pool +{ + /// + /// 实现了这个接口代表支持对象池 + /// + public interface IPool + { + /// + /// 是否从池里创建的 + /// + bool IsPool(); + /// + /// 设置是否从池里创建的 + /// + /// + void SetIsPool(bool isPool); + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Pool/Normal/Pool.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Pool/Normal/Pool.cs new file mode 100644 index 0000000..88006e1 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Pool/Normal/Pool.cs @@ -0,0 +1,77 @@ +using System; +using System.Collections.Generic; +// ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract +// ReSharper disable CheckNamespace + +namespace Fantasy.Pool +{ + /// + /// 静态的对象池系统,不支持多线程。 + /// + /// + public static class Pool where T : IPool, new() + { + private static readonly Queue PoolQueue = new Queue(); + /// + /// 池子里可用的数量 + /// + public static int Count => PoolQueue.Count; + + /// + /// 租借 + /// + /// + public static T Rent() + { + return PoolQueue.Count == 0 ? new T() : PoolQueue.Dequeue(); + } + + /// + /// 租借 + /// + /// 如果池子里没有,会先执行这个委托。 + /// + public static T Rent(Func generator) + { + return PoolQueue.Count == 0 ? generator() : PoolQueue.Dequeue(); + } + + /// + /// 返还 + /// + /// + public static void Return(T t) + { + if (t == null) + { + return; + } + + PoolQueue.Enqueue(t); + } + + /// + /// 返还 + /// + /// 返还的东西 + /// 返还后执行的委托 + public static void Return(T t, Action reset) + { + if (t == null) + { + return; + } + + reset(t); + PoolQueue.Enqueue(t); + } + + /// + /// 清空池子 + /// + public static void Clear() + { + PoolQueue.Clear(); + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Pool/Normal/PoolCore.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Pool/Normal/PoolCore.cs new file mode 100644 index 0000000..94144f1 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Pool/Normal/PoolCore.cs @@ -0,0 +1,203 @@ +using System; +using System.Collections.Generic; +using System.Runtime.CompilerServices; +using Fantasy.DataStructure.Collection; + +// ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract +#pragma warning disable CS8600 // Converting null literal or possible null value to non-nullable type. +#pragma warning disable CS8603 // Possible null reference return. + +namespace Fantasy.Pool +{ + /// + /// 对象池抽象接口,用于创建和管理可重复使用的对象实例。 + /// + public abstract class PoolCore : IDisposable + { + private int _poolCount; + private readonly int _maxCapacity; + /// + /// 池子里可用的数量 + /// + public int Count => _poolQueue.Count; + private readonly OneToManyQueue _poolQueue = new OneToManyQueue(); + private readonly Dictionary> _typeCheckCache = new Dictionary>(); + + /// + /// 构造函数 + /// + /// 初始的容量 + protected PoolCore(int maxCapacity) + { + _maxCapacity = maxCapacity; + } + + /// + /// 租借 + /// + /// + /// + public T Rent() where T : IPool, new() + { + if (!_poolQueue.TryDequeue(typeof(T), out var queue)) + { + queue = new T(); + } + + queue.SetIsPool(true); + _poolCount--; + return (T)queue; + } + + /// + /// 租借 + /// + /// 租借的类型 + /// + /// + public IPool Rent(Type type) + { + if (!_poolQueue.TryDequeue(type, out var queue)) + { + if (!_typeCheckCache.TryGetValue(type, out var createInstance)) + { + if (!typeof(IPool).IsAssignableFrom(type)) + { + throw new NotSupportedException($"{this.GetType().FullName} Type:{type.FullName} must inherit from IPool"); + } + else + { + createInstance = CreateInstance.CreateIPool(type); + _typeCheckCache[type] = createInstance; + } + } + + var instance = createInstance(); + instance.SetIsPool(true); + return instance; + } + + queue.SetIsPool(true); + _poolCount--; + return queue; + } + + /// + /// 返还 + /// + /// + /// + public void Return(Type type, IPool obj) + { + if (obj == null) + { + return; + } + + if (!obj.IsPool()) + { + return; + } + + if (_poolCount >= _maxCapacity) + { + return; + } + + _poolCount++; + obj.SetIsPool(false); + _poolQueue.Enqueue(type, obj); + } + + /// + /// 销毁方法 + /// + public virtual void Dispose() + { + _poolCount = 0; + _poolQueue.Clear(); + _typeCheckCache.Clear(); + } + } + + /// + /// 泛型对象池核心类,用于创建和管理可重复使用的对象实例。 + /// + /// 要池化的对象类型 + public abstract class PoolCore where T : IPool, new() + { + private int _poolCount; + private readonly int _maxCapacity; + private readonly Queue _poolQueue = new Queue(); + /// + /// 池子里可用的数量 + /// + public int Count => _poolQueue.Count; + + /// + /// 构造函数 + /// + /// 初始的容量 + protected PoolCore(int maxCapacity) + { + _maxCapacity = maxCapacity; + } + + /// + /// 租借 + /// + /// + public virtual T Rent() + { + T dequeue; + + if (_poolQueue.Count == 0) + { + dequeue = new T(); + } + else + { + _poolCount--; + dequeue = _poolQueue.Dequeue(); + } + + dequeue.SetIsPool(true); + return dequeue; + } + + /// + /// 返还 + /// + /// + public virtual void Return(T item) + { + if (item == null) + { + return; + } + + if (!item.IsPool()) + { + return; + } + + if (_poolCount >= _maxCapacity) + { + return; + } + + _poolCount++; + item.SetIsPool(false); + _poolQueue.Enqueue(item); + } + + /// + /// 销毁方法 + /// + public virtual void Dispose() + { + _poolCount = 0; + _poolQueue.Clear(); + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Pool/Normal/PoolWithDisposable.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Pool/Normal/PoolWithDisposable.cs new file mode 100644 index 0000000..3f97f1c --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Pool/Normal/PoolWithDisposable.cs @@ -0,0 +1,140 @@ +using System; +using System.Collections.Generic; +// ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract + +namespace Fantasy.Pool +{ + /// + /// 静态通用对象池,用于存储实现了 IDisposable 接口的对象。 + /// + /// 要存储在对象池中的对象类型,必须实现 IDisposable 接口。 + public abstract class PoolWithDisposable : IDisposable where T : IPool, IDisposable, new() + { + private int _poolCount; + private readonly int _maxCapacity; + private readonly Queue _poolQueue = new Queue(); + /// + /// 池子里可用的数量 + /// + public int Count => _poolQueue.Count; + + /// + /// 构造函数 + /// + /// 初始的容量 + protected PoolWithDisposable(int maxCapacity) + { + _maxCapacity = maxCapacity; + } + + /// + /// 租借 + /// + /// + public T Rent() + { + T dequeue; + if (_poolQueue.Count == 0) + { + dequeue = new T(); + } + else + { + _poolCount--; + dequeue = _poolQueue.Dequeue(); + } + + dequeue.SetIsPool(true); + return dequeue; + } + + /// + /// 租借 + /// + /// + /// + public T Rent(Func generator) + { + T dequeue; + + if (_poolQueue.Count == 0) + { + dequeue = generator(); + } + else + { + _poolCount--; + dequeue = _poolQueue.Dequeue(); + } + + dequeue.SetIsPool(true); + return dequeue; + } + + /// + /// 返还 + /// + /// + public void Return(T t) + { + if (t == null) + { + return; + } + + if (!t.IsPool()) + { + return; + } + + if (_poolCount >= _maxCapacity) + { + return; + } + + _poolCount++; + t.SetIsPool(true); + _poolQueue.Enqueue(t); + t.Dispose(); + } + + /// + /// 返还 + /// + /// + /// + public void Return(T t, Action reset) + { + if (t == null) + { + return; + } + + if (!t.IsPool()) + { + reset(t); + return; + } + + if (_poolCount >= _maxCapacity) + { + return; + } + + reset(t); + _poolCount++; + t.SetIsPool(false); + _poolQueue.Enqueue(t); + t.Dispose(); + } + + /// + /// 销毁方法 + /// + public virtual void Dispose() + { + _poolCount = 0; + _poolQueue.Clear(); + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Pool/PoolHelper.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Pool/PoolHelper.cs new file mode 100644 index 0000000..d9214fd --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Pool/PoolHelper.cs @@ -0,0 +1,79 @@ +using System; +using System.Reflection.Emit; +using Fantasy.Serialize; + +#pragma warning disable CS8604 // Possible null reference argument. + +namespace Fantasy.Pool +{ + internal static class CreateInstance where T : IPool + { + public static Func Create { get; } + + static CreateInstance() + { + var type = typeof(T); + var dynamicMethod = new DynamicMethod($"CreateInstance_{type.Name}", type, Type.EmptyTypes, true); + var il = dynamicMethod.GetILGenerator(); + il.Emit(OpCodes.Newobj, type.GetConstructor(Type.EmptyTypes)); + il.Emit(OpCodes.Ret); + Create = (Func) dynamicMethod.CreateDelegate(typeof(Func)); + } + } + + internal static class CreateInstance + { + public static Func CreateIPool(Type type) + { + var dynamicMethod = new DynamicMethod($"CreateInstance_{type.Name}", type, Type.EmptyTypes, true); + var il = dynamicMethod.GetILGenerator(); + il.Emit(OpCodes.Newobj, type.GetConstructor(Type.EmptyTypes)); + il.Emit(OpCodes.Ret); + return (Func)dynamicMethod.CreateDelegate(typeof(Func)); + } + + public static Func CreateObject(Type type) + { + var dynamicMethod = new DynamicMethod($"CreateInstance_{type.Name}", type, Type.EmptyTypes, true); + var il = dynamicMethod.GetILGenerator(); + il.Emit(OpCodes.Newobj, type.GetConstructor(Type.EmptyTypes)); + il.Emit(OpCodes.Ret); + return (Func)dynamicMethod.CreateDelegate(typeof(Func)); + } + + public static Func CreateMessage(Type type) + { + var dynamicMethod = new DynamicMethod($"CreateInstance_{type.Name}", type, Type.EmptyTypes, true); + var il = dynamicMethod.GetILGenerator(); + il.Emit(OpCodes.Newobj, type.GetConstructor(Type.EmptyTypes)); + il.Emit(OpCodes.Ret); + return (Func)dynamicMethod.CreateDelegate(typeof(Func)); + } + } + + // public static class CreateInstance + // { + // public static Func Create(Type type) + // { + // var dynamicMethod = new DynamicMethod($"CreateInstance_{type.Name}", type, Type.EmptyTypes, true); + // var il = dynamicMethod.GetILGenerator(); + // il.Emit(OpCodes.Newobj, type.GetConstructor(Type.EmptyTypes)); + // il.Emit(OpCodes.Ret); + // return (Func)dynamicMethod.CreateDelegate(typeof(Func)); + // } + // } + + // /// + // /// 利用泛型的特性来减少反射的使用。 + // /// + // /// + // public static class PoolChecker where T : new() + // { + // public static bool IsPool { get; } + // + // static PoolChecker() + // { + // IsPool = typeof(IPool).IsAssignableFrom(typeof(T)); + // } + // } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Scene/ISceneUpdate.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Scene/ISceneUpdate.cs new file mode 100644 index 0000000..f736edf --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Scene/ISceneUpdate.cs @@ -0,0 +1,15 @@ +namespace Fantasy +{ + internal interface ISceneUpdate + { + void Update(); + } + + internal sealed class EmptySceneUpdate : ISceneUpdate + { + public void Update() + { + + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Scene/OnCreateSceneEvent.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Scene/OnCreateSceneEvent.cs new file mode 100644 index 0000000..d192300 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Scene/OnCreateSceneEvent.cs @@ -0,0 +1,22 @@ +namespace Fantasy +{ + /// + /// 当Scene创建完成后发送的事件参数 + /// + public struct OnCreateScene + { + /// + /// 获取与事件关联的场景实体。 + /// + public readonly Scene Scene; + /// + /// 初始化一个新的 OnCreateScene 实例。 + /// + /// + public OnCreateScene(Scene scene) + { + Scene = scene; + } + } + +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Scene/Scene.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Scene/Scene.cs new file mode 100644 index 0000000..f0a08b7 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Scene/Scene.cs @@ -0,0 +1,543 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Fantasy.Async; +using Fantasy.Entitas; +using Fantasy.Event; +using Fantasy.IdFactory; +using Fantasy.Network; +using Fantasy.Network.Interface; +using Fantasy.Pool; +using Fantasy.Scheduler; +using Fantasy.Timer; +#if FANTASY_NET +using Fantasy.DataBase; +using Fantasy.Platform.Net; +using Fantasy.SingleCollection; +using System.Runtime.CompilerServices; +using Fantasy.Network.Route; +// ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract +#endif +#pragma warning disable CS8601 // Possible null reference assignment. +#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. +#pragma warning disable CS8603 // Possible null reference return. +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. +#pragma warning disable CS8602 // Dereference of a possibly null reference. +#pragma warning disable CS8600 // Converting null literal or possible null value to non-nullable type. +namespace Fantasy +{ + /// + /// 表示一个场景实体,用于创建与管理特定的游戏场景信息。 + /// + public partial class Scene : Entity + { + #region Members + /// + /// 当前Scene的父Scene,一般是用于实现子Scene的嵌套。 + /// 这个后期新版本会把Scene和SubScene分开,这里先暂时这样处理。 + /// + public Scene RootScene { get; internal set; } +#if FANTASY_NET + /// + /// Scene类型,对应SceneConfig的SceneType + /// + public int SceneType { get; private set; } + /// + /// 所属的世界 + /// + public World World { get; private set; } + /// + /// 所在的Process + /// + public Process Process { get; private set; } + /// + /// SceneConfig的Id + /// + public uint SceneConfigId { get; private set; } + internal ANetwork InnerNetwork { get; private set; } + internal ANetwork OuterNetwork { get; private set; } + internal SceneConfig SceneConfig => SceneConfigData.Instance.Get(SceneConfigId); + private readonly Dictionary _processSessionInfos = new Dictionary(); +#endif + /// + /// 当前Scene的上下文 + /// + public ThreadSynchronizationContext ThreadSynchronizationContext { get; internal set; } + /// + /// 当前Scene的下创建的Entity + /// + private readonly Dictionary _entities = new Dictionary(); + internal readonly Dictionary> TypeInstance = new Dictionary>(); + #endregion + + #region IdFactory + + /// + /// Entity实体Id的生成器 + /// + public IEntityIdFactory EntityIdFactory { get; private set; } + /// + /// Entity实体RuntimeId的生成器 + /// + public IRuntimeIdFactory RuntimeIdFactory { get; private set; } + + #endregion + + #region Pool + + internal EntityPool EntityPool; + internal EntityListPool EntityListPool; + internal EntitySortedDictionaryPool EntitySortedDictionaryPool; + + #endregion + + #region Component + + /// + /// Scene下的任务调度器系统组件 + /// + public TimerComponent TimerComponent { get; internal set; } + /// + /// Scene下的事件系统组件 + /// + public EventComponent EventComponent { get; internal set; } + /// + /// Scene下的ESC系统组件 + /// + public EntityComponent EntityComponent { get; internal set; } + /// + /// Scene下的网络消息对象池组件 + /// + public MessagePoolComponent MessagePoolComponent { get; internal set; } + /// + /// Scene下的协程锁组件 + /// + public CoroutineLockComponent CoroutineLockComponent { get; internal set; } + /// + /// Scene下的网络消息派发组件 + /// + internal MessageDispatcherComponent MessageDispatcherComponent { get; set; } +#if FANTASY_NET + /// + /// Scene下的Entity分表组件 + /// + public SingleCollectionComponent SingleCollectionComponent { get; internal set; } + /// + /// Scene下的内网消息发送组件 + /// + public NetworkMessagingComponent NetworkMessagingComponent { get; internal set; } +#endif + #endregion + + #region Initialize + + private async FTask Initialize() + { + EntityPool = new EntityPool(); + EntityListPool = new EntityListPool(); + EntitySortedDictionaryPool = new EntitySortedDictionaryPool(); + SceneUpdate = EntityComponent = await Create(this, false, false).Initialize(); + MessagePoolComponent = AddComponent(false); + EventComponent = await AddComponent(false).Initialize(); + TimerComponent = AddComponent(false).Initialize(); + CoroutineLockComponent = AddComponent(false).Initialize(); + MessageDispatcherComponent = await AddComponent(false).Initialize(); +#if FANTASY_NET + NetworkMessagingComponent = AddComponent(false); + SingleCollectionComponent = await AddComponent(false).Initialize(); +#endif + } + /// + /// Scene销毁方法,执行了该方法会把当前Scene下的所有实体都销毁掉。 + /// + public override void Dispose() + { + if (IsDisposed) + { + return; + } +#if FANTASY_NET + foreach (var (_, innerSession) in _processSessionInfos) + { + innerSession.Dispose(); + } + _processSessionInfos.Clear(); +#endif +#if FANTASY_UNITY + Session = null; + _unityWorldId--; + _unitySceneId--; + UnityNetwork?.Dispose(); +#endif + TypeInstance.Clear(); + EventComponent.Dispose(); + MessagePoolComponent.Dispose(); + EntityPool.Dispose(); + EntityListPool.Dispose(); + EntitySortedDictionaryPool.Dispose(); +#if FANTASY_NET + if (World != null) + { + if (RootScene == null) + { + World.Dispose(); + } + else + { + RootScene.RemoveEntity(RuntimeId); + RootScene = null; + } + + World = null; + } +#else + if (RootScene != null) + { + RootScene.RemoveEntity(RuntimeId); + RootScene = null; + } +#endif + base.Dispose(); + } + + #endregion + + internal ISceneUpdate SceneUpdate { get; set; } + + internal void Update() + { + try + { + SceneUpdate.Update(); + } + catch (Exception e) + { + Log.Error(e); + } + } + + #region Create + +#if FANTASY_UNITY || FANTASY_CONSOLE + private static uint _unitySceneId = 0; + private static byte _unityWorldId = 0; + public Session Session { get; private set; } + private AClientNetwork UnityNetwork { get; set; } + /// + /// 创建一个Unity的Scene,注意:该方法只能在主线程下使用。 + /// + /// 选择Scene的运行方式 + /// + /// + public static async FTask Create(string sceneRuntimeType = SceneRuntimeType.MainThread) + { + var world = ++_unityWorldId; + + if (world > byte.MaxValue - 1) + { + throw new Exception($"World ID ({world}) exceeds the maximum allowed value of 255."); + } + + var sceneId = (uint)(++_unitySceneId + world * 1000); + + if (sceneId > 255255) + { + throw new Exception($"Scene ID ({sceneId}) exceeds the maximum allowed value of 255255."); + } + + var scene = new Scene(); + scene.Scene = scene; + scene.Parent = scene; + scene.Type = typeof(Scene); + scene.EntityIdFactory = IdFactoryHelper.EntityIdFactory(sceneId, world); + scene.RuntimeIdFactory = IdFactoryHelper.RuntimeIdFactory(0, sceneId, world); + scene.Id = IdFactoryHelper.EntityId(0, sceneId, world, 0); + scene.RuntimeId = IdFactoryHelper.RuntimeId(0, sceneId, world, 0); + scene.AddEntity(scene); + await SetScheduler(scene, sceneRuntimeType); + scene.ThreadSynchronizationContext.Post(() => + { + scene.EventComponent.PublishAsync(new OnCreateScene(scene)).Coroutine(); + }); + return scene; + } + public Session Connect(string remoteAddress, NetworkProtocolType networkProtocolType, Action onConnectComplete, Action onConnectFail, Action onConnectDisconnect, bool isHttps, int connectTimeout = 5000) + { + UnityNetwork?.Dispose(); + UnityNetwork = NetworkProtocolFactory.CreateClient(this, networkProtocolType, NetworkTarget.Outer); + Session = UnityNetwork.Connect(remoteAddress, onConnectComplete, onConnectFail, onConnectDisconnect, isHttps, connectTimeout); + return Session; + } +#endif +#if FANTASY_NET + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static Scene Create(Process process, byte worldId, uint sceneConfigId) + { + var scene = new Scene(); + scene.Scene = scene; + scene.Parent = scene; + scene.Type = typeof(Scene); + scene.Process = process; + scene.EntityIdFactory = IdFactoryHelper.EntityIdFactory(sceneConfigId, worldId); + scene.RuntimeIdFactory = IdFactoryHelper.RuntimeIdFactory(0,sceneConfigId, worldId); + scene.Id = IdFactoryHelper.EntityId(0, sceneConfigId, worldId, 0); + scene.RuntimeId = IdFactoryHelper.RuntimeId(0, sceneConfigId, worldId, 0); + scene.AddEntity(scene); + return scene; + } + /// + /// 创建一个新的Scene + /// + /// 所属的Process + /// 对应的MachineConfig配置文件 + /// 对应的SceneConfig配置文件 + /// 创建成功后会返回创建的Scene的实例 + public static async FTask Create(Process process, MachineConfig machineConfig, SceneConfig sceneConfig) + { + var scene = Create(process, (byte)sceneConfig.WorldConfigId, sceneConfig.Id); + scene.SceneType = sceneConfig.SceneType; + scene.SceneConfigId = sceneConfig.Id; + await SetScheduler(scene, sceneConfig.SceneRuntimeType); + + if (sceneConfig.WorldConfigId != 0) + { + scene.World = World.Create(scene, (byte)sceneConfig.WorldConfigId); + } + + if (sceneConfig.InnerPort != 0) + { + // 创建内网网络服务器 + scene.InnerNetwork = NetworkProtocolFactory.CreateServer(scene, ProcessDefine.InnerNetwork, NetworkTarget.Inner, machineConfig.InnerBindIP, sceneConfig.InnerPort); + } + + if (sceneConfig.OuterPort != 0) + { + // 创建外网网络服务 + var networkProtocolType = Enum.Parse(sceneConfig.NetworkProtocol); + scene.OuterNetwork = NetworkProtocolFactory.CreateServer(scene, networkProtocolType, NetworkTarget.Outer, machineConfig.OuterBindIP, sceneConfig.OuterPort); + } + Process.AddScene(scene); + process.AddSceneToProcess(scene); + scene.ThreadSynchronizationContext.Post(() => + { + if (sceneConfig.SceneTypeString == "Addressable") + { + // 如果是AddressableScene,自动添加上AddressableManageComponent。 + scene.AddComponent(); + } + + scene.EventComponent.PublishAsync(new OnCreateScene(scene)).Coroutine(); + }); + return scene; + } + /// + /// 在Scene下面创建一个子Scene,一般用于副本,或者一些特殊的场景。 + /// + /// 主Scene的实例 + /// SceneType,可以在SceneType里找到,例如:SceneType.Addressable + /// 子Scene创建成功后执行的委托,可以传递null + /// + public static SubScene CreateSubScene(Scene parentScene, int sceneType, Action onSubSceneComplete = null) + { + var scene = new SubScene(); + scene.Scene = scene; + scene.Parent = scene; + scene.RootScene = parentScene; + scene.Type = typeof(SubScene); + scene.SceneType = sceneType; + scene.World = parentScene.World; + scene.Process = parentScene.Process; + scene.EntityIdFactory = parentScene.EntityIdFactory; + scene.RuntimeIdFactory = parentScene.RuntimeIdFactory; + scene.Id = scene.EntityIdFactory.Create; + scene.RuntimeId = scene.RuntimeIdFactory.Create; + scene.AddEntity(scene); + scene.Initialize(parentScene); + scene.ThreadSynchronizationContext.Post(() => OnEvent().Coroutine()); + return scene; + async FTask OnEvent() + { + await scene.EventComponent.PublishAsync(new OnCreateScene(scene)); + onSubSceneComplete?.Invoke(scene, parentScene); + } + } +#endif + private static async FTask SetScheduler(Scene scene, string sceneRuntimeType) + { + switch (sceneRuntimeType) + { + case "MainThread": + { + scene.ThreadSynchronizationContext = ThreadScheduler.MainScheduler.ThreadSynchronizationContext; + scene.SceneUpdate = new EmptySceneUpdate(); + ThreadScheduler.AddMainScheduler(scene); + await scene.Initialize(); + break; + } + case "MultiThread": + { +#if !FANTASY_WEBGL + scene.ThreadSynchronizationContext = new ThreadSynchronizationContext(); +#endif + scene.SceneUpdate = new EmptySceneUpdate(); + ThreadScheduler.AddToMultiThreadScheduler(scene); + await scene.Initialize(); + break; + } + case "ThreadPool": + { +#if !FANTASY_WEBGL + scene.ThreadSynchronizationContext = new ThreadSynchronizationContext(); +#endif + scene.SceneUpdate = new EmptySceneUpdate(); + ThreadScheduler.AddToThreadPoolScheduler(scene); + await scene.Initialize(); + break; + } + } + } + #endregion + + #region Entities + + /// + /// 添加一个实体到当前Scene下 + /// + /// 实体实例 + public virtual void AddEntity(Entity entity) + { + _entities.Add(entity.RuntimeId, entity); + } + + /// + /// 根据RunTimeId查询一个实体 + /// + /// 实体的RunTimeId + /// 返回的实体 + public virtual Entity GetEntity(long runTimeId) + { + return _entities.TryGetValue(runTimeId, out var entity) ? entity : null; + } + + /// + /// 根据RunTimeId查询一个实体 + /// + /// 实体的RunTimeId + /// 实体实例 + /// 返回一个bool值来提示是否查找到这个实体 + public virtual bool TryGetEntity(long runTimeId, out Entity entity) + { + return _entities.TryGetValue(runTimeId, out entity); + } + + /// + /// 根据RunTimeId查询一个实体 + /// + /// 实体的RunTimeId + /// 要查询实体的泛型类型 + /// 返回的实体 + public virtual T GetEntity(long runTimeId) where T : Entity + { + return _entities.TryGetValue(runTimeId, out var entity) ? (T)entity : null; + } + + /// + /// 根据RunTimeId查询一个实体 + /// + /// 实体的RunTimeId + /// 实体实例 + /// 要查询实体的泛型类型 + /// 返回一个bool值来提示是否查找到这个实体 + public virtual bool TryGetEntity(long runTimeId, out T entity) where T : Entity + { + if (_entities.TryGetValue(runTimeId, out var getEntity)) + { + entity = (T)getEntity; + return true; + } + + entity = null; + return false; + } + + /// + /// 删除一个实体,仅是删除不会指定实体的销毁方法 + /// + /// 实体的RunTimeId + /// 返回一个bool值来提示是否删除了这个实体 + public virtual bool RemoveEntity(long runTimeId) + { + return _entities.Remove(runTimeId); + } + + /// + /// 删除一个实体,仅是删除不会指定实体的销毁方法 + /// + /// 实体实例 + /// 返回一个bool值来提示是否删除了这个实体 + public virtual bool RemoveEntity(Entity entity) + { + return _entities.Remove(entity.RuntimeId); + } + + #endregion + + #region InnerSession + +#if FANTASY_NET + /// + /// 根据runTimeId获得Session + /// + /// + /// + /// + public virtual Session GetSession(long runTimeId) + { + var sceneId = IdFactoryHelper.RuntimeIdTool.GetSceneId(ref runTimeId); + + if (_processSessionInfos.TryGetValue(sceneId, out var processSessionInfo)) + { + if (!processSessionInfo.Session.IsDisposed) + { + return processSessionInfo.Session; + } + + _processSessionInfos.Remove(sceneId); + } + + if (Process.IsInAppliaction(ref sceneId)) + { + // 如果在同一个Process下,不需要通过Socket发送了,直接通过Process下转发。 + var processSession = Session.CreateInnerSession(Scene); + _processSessionInfos.Add(sceneId, new ProcessSessionInfo(processSession, null)); + return processSession; + } + + if (!SceneConfigData.Instance.TryGet(sceneId, out var sceneConfig)) + { + throw new Exception($"The scene with sceneId {sceneId} was not found in the configuration file"); + } + + if (!ProcessConfigData.Instance.TryGet(sceneConfig.ProcessConfigId, out var processConfig)) + { + throw new Exception($"The process with processId {sceneConfig.ProcessConfigId} was not found in the configuration file"); + } + + if (!MachineConfigData.Instance.TryGet(processConfig.MachineId, out var machineConfig)) + { + throw new Exception($"The machine with machineId {processConfig.MachineId} was not found in the configuration file"); + } + + var remoteAddress = $"{machineConfig.InnerBindIP}:{sceneConfig.InnerPort}"; + var client = NetworkProtocolFactory.CreateClient(Scene, ProcessDefine.InnerNetwork, NetworkTarget.Inner); + var session = client.Connect(remoteAddress, null, () => + { + Log.Error($"Unable to connect to the target server sourceServerId:{Scene.Process.Id} targetServerId:{sceneConfig.ProcessConfigId}"); + }, null, false); + _processSessionInfos.Add(sceneId, new ProcessSessionInfo(session, client)); + return session; + } +#endif + #endregion + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Scene/SceneRuntimeType.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Scene/SceneRuntimeType.cs new file mode 100644 index 0000000..f22e11a --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Scene/SceneRuntimeType.cs @@ -0,0 +1,21 @@ +namespace Fantasy +{ + /// + /// Scene的运行类型 + /// + public class SceneRuntimeType + { + /// + /// Scene在主线程中运行. + /// + public const string MainThread = "MainThread"; + /// + /// Scene在一个独立的线程中运行. + /// + public const string MultiThread = "MultiThread"; + /// + /// Scene在一个根据当前CPU核心数创建的线程池中运行. + /// + public const string ThreadPool = "ThreadPool"; + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Scene/Scheduler/ISceneScheduler.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Scene/Scheduler/ISceneScheduler.cs new file mode 100644 index 0000000..c04cc30 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Scene/Scheduler/ISceneScheduler.cs @@ -0,0 +1,11 @@ +using System; + +namespace Fantasy +{ + internal interface ISceneScheduler : IDisposable + { + void Add(Scene scene); + void Remove(Scene scene); + void Update(); + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Scene/Scheduler/MainScheduler.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Scene/Scheduler/MainScheduler.cs new file mode 100644 index 0000000..692def0 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Scene/Scheduler/MainScheduler.cs @@ -0,0 +1,83 @@ +using System.Collections.Generic; +#if FANTASY_UNITY || FANTASY_NET || !FANTASY_WEBGL +using System.Threading; +#endif +#if FANTASY_NET +using Fantasy.Platform.Net; +#endif +namespace Fantasy +{ + internal sealed class MainScheduler : ISceneScheduler + { + private readonly Queue _queue = new Queue(); + public readonly ThreadSynchronizationContext ThreadSynchronizationContext; + + public MainScheduler() + { + ThreadSynchronizationContext = new ThreadSynchronizationContext(); +#if !FANTASY_WEBGL + SynchronizationContext.SetSynchronizationContext(ThreadSynchronizationContext); +#endif + } + public void Dispose() + { + _queue.Clear(); + } + + public void Add(Scene scene) + { + ThreadSynchronizationContext.Post(() => + { + if (scene.IsDisposed) + { + return; + } + + _queue.Enqueue(scene); + }); + } + + public void Remove(Scene scene) + { + ThreadSynchronizationContext.Post(() => + { + if (scene.IsDisposed) + { + return; + } + + var initialCount = _queue.Count; + for (var i = 0; i < initialCount; i++) + { + var currentScene = _queue.Dequeue(); + if (currentScene != scene) + { + _queue.Enqueue(currentScene); + } + } + }); + } + + public void Update() + { + ThreadSynchronizationContext.Update(); + var initialCount = _queue.Count; + + while (initialCount-- > 0) + { + if(!_queue.TryDequeue(out var scene)) + { + continue; + } + + if (scene.IsDisposed) + { + continue; + } + + scene.Update(); + _queue.Enqueue(scene); + } + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Scene/Scheduler/MultiThreadScheduler.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Scene/Scheduler/MultiThreadScheduler.cs new file mode 100644 index 0000000..28f2d42 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Scene/Scheduler/MultiThreadScheduler.cs @@ -0,0 +1,103 @@ +#if !FANTASY_WEBGL || !FANTASY_SINGLETHREAD +using System; +using System.Collections.Concurrent; +using System.Threading; +namespace Fantasy +{ + internal struct MultiThreadStruct : IDisposable + { + public readonly Thread Thread; + public readonly CancellationTokenSource Cts; + + public MultiThreadStruct(Thread thread, CancellationTokenSource cts) + { + Thread = thread; + Cts = cts; + } + + public void Dispose() + { + Cts.Cancel(); + if (Thread.IsAlive) + { + Thread.Join(); + } + Cts.Dispose(); + } + } + + internal sealed class MultiThreadScheduler : ISceneScheduler + { + private bool _isDisposed; + private readonly ConcurrentDictionary _threads = new ConcurrentDictionary(); + public int ThreadCount => _threads.Count; + + public void Dispose() + { + if (_isDisposed) + { + return; + } + + _isDisposed = true; + + foreach (var (_, multiThreadStruct) in _threads.ToArray()) + { + multiThreadStruct.Dispose(); + } + + _threads.Clear(); + } + + public void Add(Scene scene) + { + var cts = new CancellationTokenSource(); + var thread = new Thread(() => Loop(scene, cts.Token)); + _threads.TryAdd(scene.RuntimeId, new MultiThreadStruct(thread, cts)); + thread.Start(); + } + + public void Remove(Scene scene) + { + if (_threads.TryRemove(scene.RuntimeId, out var multiThreadStruct)) + { + multiThreadStruct.Dispose(); + } + } + + public void Update() + { + throw new NotImplementedException(); + } + + private void Loop(Scene scene, CancellationToken cancellationToken) + { + var sceneThreadSynchronizationContext = scene.ThreadSynchronizationContext; + SynchronizationContext.SetSynchronizationContext(sceneThreadSynchronizationContext); + + while (!cancellationToken.IsCancellationRequested) + { + try + { + if (scene.IsDisposed) + { + Remove(scene); + return; + } + + sceneThreadSynchronizationContext.Update(); + scene.Update(); + } + catch (Exception e) + { + Log.Error($"Error in MultiThreadScheduler loop: {e.Message}"); + } + finally + { + Thread.Sleep(1); + } + } + } + } +} +#endif diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Scene/Scheduler/ThreadPoolScheduler.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Scene/Scheduler/ThreadPoolScheduler.cs new file mode 100644 index 0000000..9f5a44c --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Scene/Scheduler/ThreadPoolScheduler.cs @@ -0,0 +1,140 @@ +#if !FANTASY_WEBGL || !FANTASY_SINGLETHREAD +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Threading; +// ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract +#pragma warning disable CS8604 // Possible null reference argument. +namespace Fantasy +{ + internal sealed class ThreadPoolScheduler : ISceneScheduler + { + private bool _isDisposed; + private readonly List _threads; + private readonly ConcurrentBag _queue = new ConcurrentBag(); + private readonly CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource(); + + public ThreadPoolScheduler() + { + // 最大线程数、避免线程过多发生的资源抢占问题。 + // 但如果使用了MultiThreadScheduler,那么这里的线程数就算是设置了也有可能导致线程过多的问题。 + // 线程过多看每个线程的抢占情况,如果抢占资源占用不是很大也没什么大问题。如果过大的情况,就会有性能问题。 + // 所以根据情况来使用不同的调度器。 + var maxThreadCount = Environment.ProcessorCount; + _threads = new List(maxThreadCount); + + for (var i = 0; i < maxThreadCount; ++i) + { + Thread thread = new(() => Loop(_cancellationTokenSource.Token)) + { + IsBackground = true + }; + _threads.Add(thread); + thread.Start(); + } + } + + public void Dispose() + { + if (_isDisposed) + { + return; + } + + _isDisposed = true; + _cancellationTokenSource.Cancel(); + + foreach (var thread in _threads) + { + if (thread.IsAlive) + { + thread.Join(); + } + } + + _cancellationTokenSource.Dispose(); + _threads.Clear(); + } + + public void Add(Scene scene) + { + if (_isDisposed) + { + return; + } + + _queue.Add(scene); + } + + public void Remove(Scene scene) + { + if (_isDisposed) + { + return; + } + + var newQueue = new Queue(); + + while (!_queue.IsEmpty) + { + if (_queue.TryTake(out var currentScene)) + { + if (currentScene != scene) + { + newQueue.Enqueue(currentScene); + } + } + } + + while (newQueue.TryDequeue(out var newScene)) + { + _queue.Add(newScene); + } + } + + public void Update() + { + throw new NotImplementedException(); + } + + private void Loop(CancellationToken cancellationToken) + { + while (!cancellationToken.IsCancellationRequested) + { + if (_queue.TryTake(out var scene)) + { + if (scene == null || scene.IsDisposed) + { + continue; + } + + var sceneThreadSynchronizationContext = scene.ThreadSynchronizationContext; + SynchronizationContext.SetSynchronizationContext(sceneThreadSynchronizationContext); + + try + { + sceneThreadSynchronizationContext.Update(); + scene.Update(); + } + catch (Exception e) + { + Log.Error($"Error in ThreadPoolScheduler scene: {e.Message}"); + } + finally + { + SynchronizationContext.SetSynchronizationContext(null); + } + + _queue.Add(scene); + Thread.Sleep(1); + } + else + { + // 当队列为空的时候、避免无效循环消耗CPU。 + Thread.Sleep(10); + } + } + } + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Scene/Scheduler/ThreadScheduler.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Scene/Scheduler/ThreadScheduler.cs new file mode 100644 index 0000000..5bd0dea --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Scene/Scheduler/ThreadScheduler.cs @@ -0,0 +1,66 @@ +// ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. +namespace Fantasy +{ + /// + /// 线程调度器 + /// + internal static class ThreadScheduler + { + /// + /// 主线程调度器 + /// + public static MainScheduler MainScheduler { get; private set; } + /// + /// 多线程调度器,根据当前CPU核心数量创建的固定线程。 + /// + public static ISceneScheduler MultiThreadScheduler { get; private set; } + /// + /// 线程池调度器 + /// + public static ISceneScheduler ThreadPoolScheduler { get; private set; } + + static ThreadScheduler() + { + MainScheduler = new MainScheduler(); + } + + internal static void Update() + { + MainScheduler.Update(); + } + + internal static void AddMainScheduler(Scene scene) + { + MainScheduler.Add(scene); + } + + internal static void AddToMultiThreadScheduler(Scene scene) + { + if (MultiThreadScheduler == null) + { +#if FANTASY_SINGLETHREAD || FANTASY_WEBGL + MultiThreadScheduler = MainScheduler; +#else + MultiThreadScheduler = new MultiThreadScheduler(); +#endif + } + + MultiThreadScheduler.Add(scene); + } + + internal static void AddToThreadPoolScheduler(Scene scene) + { + if (ThreadPoolScheduler == null) + { +#if FANTASY_SINGLETHREAD || FANTASY_WEBGL + ThreadPoolScheduler = MainScheduler; +#else + ThreadPoolScheduler = new ThreadPoolScheduler(); +#endif + } + + ThreadPoolScheduler.Add(scene); + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Scene/SubScene.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Scene/SubScene.cs new file mode 100644 index 0000000..5e8296e --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Scene/SubScene.cs @@ -0,0 +1,123 @@ +using System.Runtime.Serialization; +using Fantasy.Entitas; +using Newtonsoft.Json; +using Fantasy.Network; +using MongoDB.Bson.Serialization.Attributes; +using ProtoBuf; + +#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring as nullable. + +namespace Fantasy +{ + /// + /// 代表一个Scene下的子Scene + /// + public sealed partial class SubScene : Scene + { + internal void Initialize(Scene rootScene) + { + EntityPool = rootScene.EntityPool; + EntityListPool = rootScene.EntityListPool; + EntitySortedDictionaryPool = rootScene.EntitySortedDictionaryPool; + SceneUpdate = rootScene.SceneUpdate; + TimerComponent = rootScene.TimerComponent; + EventComponent = rootScene.EventComponent; + EntityComponent = rootScene.EntityComponent; + MessagePoolComponent = rootScene.MessagePoolComponent; + CoroutineLockComponent = rootScene.CoroutineLockComponent; + MessageDispatcherComponent = rootScene.MessageDispatcherComponent; + #if FANTASY_NET + NetworkMessagingComponent = rootScene.NetworkMessagingComponent; + SingleCollectionComponent = rootScene.SingleCollectionComponent; + #endif + ThreadSynchronizationContext = rootScene.ThreadSynchronizationContext; + } + + /// + /// 添加一个实体到当前Scene下 + /// + /// 实体实例 + public override void AddEntity(Entity entity) + { + RootScene.AddEntity(entity); + } + + /// + /// 根据RunTimeId查询一个实体 + /// + /// 实体的RunTimeId + /// 返回的实体 + public override Entity GetEntity(long runTimeId) + { + return RootScene.GetEntity(runTimeId); + } + + /// + /// 根据RunTimeId查询一个实体 + /// + /// 实体的RunTimeId + /// 实体实例 + /// 返回一个bool值来提示是否查找到这个实体 + public override bool TryGetEntity(long runTimeId, out Entity entity) + { + return RootScene.TryGetEntity(runTimeId, out entity); + } + + /// + /// 根据RunTimeId查询一个实体 + /// + /// 实体的RunTimeId + /// 要查询实体的泛型类型 + /// 返回的实体 + public override T GetEntity(long runTimeId) + { + return RootScene.GetEntity(runTimeId); + } + + /// + /// 根据RunTimeId查询一个实体 + /// + /// 实体的RunTimeId + /// 实体实例 + /// 要查询实体的泛型类型 + /// 返回一个bool值来提示是否查找到这个实体 + public override bool TryGetEntity(long runTimeId, out T entity) + { + return RootScene.TryGetEntity(runTimeId, out entity); + } + + /// + /// 删除一个实体,仅是删除不会指定实体的销毁方法 + /// + /// 实体的RunTimeId + /// 返回一个bool值来提示是否删除了这个实体 + public override bool RemoveEntity(long runTimeId) + { + return RootScene.RemoveEntity(runTimeId); + } + + /// + /// 删除一个实体,仅是删除不会指定实体的销毁方法 + /// + /// 实体实例 + /// 返回一个bool值来提示是否删除了这个实体 + public override bool RemoveEntity(Entity entity) + { + return RootScene.RemoveEntity(entity); + } + +#if FANTASY_NET + /// + /// 根据runTimeId获得Session + /// + /// + /// + /// + public override Session GetSession(long runTimeId) + { + return RootScene.GetSession(runTimeId); + } + #endif + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Serialize/BsonPack/BsonPackHelperNet.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Serialize/BsonPack/BsonPackHelperNet.cs new file mode 100644 index 0000000..bb5293b --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Serialize/BsonPack/BsonPackHelperNet.cs @@ -0,0 +1,311 @@ +#if FANTASY_NET +using System.Buffers; +using System.Collections; +using System.ComponentModel; +using System.Reflection; +using Fantasy.Assembly; +using Fantasy.Entitas; +using MongoDB.Bson; +using MongoDB.Bson.IO; +using MongoDB.Bson.Serialization; +using MongoDB.Bson.Serialization.Conventions; +using MongoDB.Bson.Serialization.Serializers; +#pragma warning disable CS8603 // Possible null reference return. +#pragma warning disable CS8600 // Converting null literal or possible null value to non-nullable type. +#pragma warning disable CS8602 // Dereference of a possibly null reference. + +namespace Fantasy.Serialize +{ + /// + /// BSON帮助方法 + /// + public class BsonPackHelper : ISerialize + { + /// + /// 序列化器的名字 + /// + public string SerializeName { get; } = "Bson"; + + /// + /// 构造函数 + /// + public BsonPackHelper() + { + // 清除掉注册过的LookupClassMap。 + + var classMapRegistryField = typeof(BsonClassMap).GetField("__classMaps", BindingFlags.Static | BindingFlags.NonPublic); + + if (classMapRegistryField != null) + { + ((Dictionary)classMapRegistryField.GetValue(null)).Clear(); + } + + // 清除掉注册过的ConventionRegistry。 + + var registryField = typeof(ConventionRegistry).GetField("_lookup", BindingFlags.Static | BindingFlags.NonPublic); + + if (registryField != null) + { + var registry = registryField.GetValue(null); + var dictionaryField = registry.GetType().GetField("_conventions", BindingFlags.Instance | BindingFlags.NonPublic); + if (dictionaryField != null) + { + ((IDictionary)dictionaryField.GetValue(registry)).Clear(); + } + } + + // 初始化ConventionRegistry、注册IgnoreExtraElements。 + + ConventionRegistry.Register("IgnoreExtraElements", new ConventionPack { new IgnoreExtraElementsConvention(true) }, type => true); + + // 注册一个自定义的序列化器。 + + // BsonSerializer.TryRegisterSerializer(typeof(float2), new StructBsonSerialize()); + // BsonSerializer.TryRegisterSerializer(typeof(float3), new StructBsonSerialize()); + // BsonSerializer.TryRegisterSerializer(typeof(float4), new StructBsonSerialize()); + // BsonSerializer.TryRegisterSerializer(typeof(quaternion), new StructBsonSerialize()); + BsonSerializer.RegisterSerializer(new ObjectSerializer(x => true)); + + // 注册LookupClassMap。 + + foreach (var type in AssemblySystem.ForEach()) + { + if (type.IsInterface || type.IsAbstract || type.IsGenericType || !typeof(Entity).IsAssignableFrom(type)) + { + continue; + } + + BsonClassMap.LookupClassMap(type); + } + } + + /// + /// 反序列化 + /// + /// + /// + /// + public T Deserialize(byte[] bytes) + { + var @object = BsonSerializer.Deserialize(bytes); + if (@object is ASerialize aSerialize) + { + aSerialize.AfterDeserialization(); + } + return @object; + } + + /// + /// 反序列化 + /// + /// + /// + /// + public T Deserialize(MemoryStreamBuffer buffer) + { + var @object = BsonSerializer.Deserialize(buffer); + if (@object is ASerialize aSerialize) + { + aSerialize.AfterDeserialization(); + } + return @object; + } + + /// + /// 反序列化 + /// + /// + /// + /// + public object Deserialize(Type type, byte[] bytes) + { + var @object = BsonSerializer.Deserialize(bytes, type); + if (@object is ASerialize aSerialize) + { + aSerialize.AfterDeserialization(); + } + return @object; + } + + /// + /// 反序列化 + /// + /// + /// + /// + public object Deserialize(Type type, MemoryStreamBuffer buffer) + { + var @object = BsonSerializer.Deserialize(buffer, type); + if (@object is ASerialize aSerialize) + { + aSerialize.AfterDeserialization(); + } + return @object; + } + + /// + /// 反序列化 + /// + /// + /// + /// + /// + /// + public unsafe T Deserialize(byte[] bytes, int index, int count) + { + T @object; + + fixed (byte* ptr = &bytes[index]) + { + using var stream = new UnmanagedMemoryStream(ptr, count); + @object = BsonSerializer.Deserialize(stream); + } + + if (@object is ASerialize aSerialize) + { + aSerialize.AfterDeserialization(); + } + + return @object; + } + + /// + /// 反序列化 + /// + /// + /// + /// + /// + /// + public unsafe object Deserialize(Type type, byte[] bytes, int index, int count) + { + object @object; + + fixed (byte* ptr = &bytes[index]) + { + using var stream = new UnmanagedMemoryStream(ptr, count); + @object = BsonSerializer.Deserialize(stream, type); + } + + if (@object is ASerialize aSerialize) + { + aSerialize.AfterDeserialization(); + } + + return @object; + } + + /// + /// 序列化 + /// + /// + /// + /// + public void Serialize(T @object, IBufferWriter buffer) + { + if (@object is ASerialize aSerialize) + { + aSerialize.BeginInit(); + } + + using IBsonWriter bsonWriter = + new BsonBinaryWriter((MemoryStream)buffer, BsonBinaryWriterSettings.Defaults); + BsonSerializer.Serialize(bsonWriter, @object); + } + + /// + /// 序列化 + /// + /// + /// + public void Serialize(object @object, IBufferWriter buffer) + { + if (@object is ASerialize aSerialize) + { + aSerialize.BeginInit(); + } + + using IBsonWriter bsonWriter = + new BsonBinaryWriter((MemoryStream)buffer, BsonBinaryWriterSettings.Defaults); + BsonSerializer.Serialize(bsonWriter, @object.GetType(), @object); + } + + /// + /// 序列化 + /// + /// + /// + /// + public void Serialize(Type type, object @object, IBufferWriter buffer) + { + if (@object is ASerialize aSerialize) + { + aSerialize.BeginInit(); + } + + using IBsonWriter bsonWriter = + new BsonBinaryWriter((MemoryStream)buffer, BsonBinaryWriterSettings.Defaults); + BsonSerializer.Serialize(bsonWriter, type, @object); + } + + /// + /// 序列化并返回的长度 + /// + /// + /// + /// + /// + public int SerializeAndReturnLength(Type type, object @object, MemoryStreamBuffer buffer) + { + if (@object is ASerialize aSerialize) + { + aSerialize.BeginInit(); + } + + using IBsonWriter bsonWriter = new BsonBinaryWriter(buffer, BsonBinaryWriterSettings.Defaults); + BsonSerializer.Serialize(bsonWriter, type, @object); + return (int)buffer.Length; + } + + /// + /// 序列化 + /// + /// + /// + public static byte[] Serialize(object @object) + { + if (@object is ASerialize aSerialize) + { + aSerialize.BeginInit(); + } + return @object.ToBson(@object.GetType()); + } + + /// + /// 序列化 + /// + /// + /// + /// + public static byte[] Serialize(T @object) + { + if (@object is ASerialize aSerialize) + { + aSerialize.BeginInit(); + } + return @object.ToBson(); + } + + /// + /// 克隆 + /// + /// + /// + /// + public T Clone(T t) + { + return Deserialize(Serialize(t)); + } + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Serialize/BsonPack/BsonPackHelperUnity.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Serialize/BsonPack/BsonPackHelperUnity.cs new file mode 100644 index 0000000..df44fcb --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Serialize/BsonPack/BsonPackHelperUnity.cs @@ -0,0 +1,60 @@ +#if FANTASY_UNITY +using System; +using System.Buffers; +namespace Fantasy.Serialize +{ + public class BsonPackHelper : ISerialize + { + public string SerializeName { get; } = "Bson"; + public T Deserialize(byte[] bytes) + { + throw new NotImplementedException(); + } + + public T Deserialize(MemoryStreamBuffer buffer) + { + throw new NotImplementedException(); + } + + public object Deserialize(Type type, byte[] bytes) + { + throw new NotImplementedException(); + } + + public object Deserialize(Type type, MemoryStreamBuffer buffer) + { + throw new NotImplementedException(); + } + + public T Deserialize(byte[] bytes, int index, int count) + { + throw new NotImplementedException(); + } + + public object Deserialize(Type type, byte[] bytes, int index, int count) + { + throw new NotImplementedException(); + } + + public void Serialize(T @object, IBufferWriter buffer) + { + throw new NotImplementedException(); + } + + public void Serialize(object @object, IBufferWriter buffer) + { + throw new NotImplementedException(); + } + + public void Serialize(Type type, object @object, IBufferWriter buffer) + { + throw new NotImplementedException(); + } + + public T Clone(T t) + { + throw new NotImplementedException(); + } + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Serialize/BsonPack/StructBsonSerialize.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Serialize/BsonPack/StructBsonSerialize.cs new file mode 100644 index 0000000..15d8663 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Serialize/BsonPack/StructBsonSerialize.cs @@ -0,0 +1,65 @@ +#if FANTASY_NET +using System.Reflection; +using MongoDB.Bson; +using MongoDB.Bson.IO; +using MongoDB.Bson.Serialization; +using MongoDB.Bson.Serialization.Serializers; + +namespace Fantasy.Serialize; + +/// +/// 提供对结构体类型进行 BSON 序列化和反序列化的辅助类。 +/// +/// 要序列化和反序列化的结构体类型。 +public class StructBsonSerialize : StructSerializerBase where TValue : struct +{ + /// + /// 将结构体对象序列化为 BSON 数据。 + /// + /// 序列化上下文。 + /// 序列化参数。 + /// 要序列化的结构体对象。 + public override void Serialize(BsonSerializationContext context, BsonSerializationArgs args, TValue value) + { + var nominalType = args.NominalType; + var bsonWriter = context.Writer; + bsonWriter.WriteStartDocument(); + var fields = nominalType.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); + foreach (var field in fields) + { + bsonWriter.WriteName(field.Name); + BsonSerializer.Serialize(bsonWriter, field.FieldType, field.GetValue(value)); + } + bsonWriter.WriteEndDocument(); + } + + /// + /// 将 BSON 数据反序列化为结构体对象。 + /// + /// 反序列化上下文。 + /// 反序列化参数。 + /// 反序列化得到的结构体对象。 + public override TValue Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args) + { + //boxing is required for SetValue to work + object obj = new TValue(); + var actualType = args.NominalType; + var bsonReader = context.Reader; + bsonReader.ReadStartDocument(); + while (bsonReader.ReadBsonType() != BsonType.EndOfDocument) + { + var name = bsonReader.ReadName(Utf8NameDecoder.Instance); + + var field = actualType.GetField(name, + BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); + if (field != null) + { + var value = BsonSerializer.Deserialize(bsonReader, field.FieldType); + field.SetValue(obj, value); + } + } + bsonReader.ReadEndDocument(); + return (TValue) obj; + } +} +#endif diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Serialize/BsonPack/SupportInitializeChecker.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Serialize/BsonPack/SupportInitializeChecker.cs new file mode 100644 index 0000000..82c6829 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Serialize/BsonPack/SupportInitializeChecker.cs @@ -0,0 +1,17 @@ +#if FANTASY_NET +using System.ComponentModel; +using Fantasy.Entitas; + +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member +namespace Fantasy.Serialize; + +public static class SupportInitializeChecker where T : Entity +{ + public static bool IsSupported { get; } + + static SupportInitializeChecker() + { + IsSupported = typeof(ISupportInitialize).IsAssignableFrom(typeof(T)); + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Serialize/Interface/ASerialize.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Serialize/Interface/ASerialize.cs new file mode 100644 index 0000000..7487b86 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Serialize/Interface/ASerialize.cs @@ -0,0 +1,60 @@ +using System; +using System.ComponentModel; +using System.Runtime.Serialization; +using Fantasy.Pool; +#if FANTASY_NET || FANTASY_UNITY || FANTASY_CONSOLE +using MongoDB.Bson.Serialization.Attributes; +#endif +using Newtonsoft.Json; +using ProtoBuf; +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member +#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. + +namespace Fantasy.Serialize +{ + public abstract class ASerialize : ISupportInitialize, IDisposable + { + public virtual void Dispose() { } + public virtual void BeginInit() { } + public virtual void EndInit() { } + public virtual void AfterDeserialization() => EndInit(); + } + + public abstract class AMessage : ASerialize, IPool + { +#if FANTASY_NET || FANTASY_UNITY || FANTASY_CONSOLE + [BsonIgnore] + [JsonIgnore] + [IgnoreDataMember] + [ProtoIgnore] + private Scene _scene; + protected Scene GetScene() + { + return _scene; + } + + public void SetScene(Scene scene) + { + _scene = scene; + } +#endif +#if FANTASY_NET + [BsonIgnore] +#endif + [JsonIgnore] + [IgnoreDataMember] + [ProtoIgnore] + private bool _isPool; + + public bool IsPool() + { + return _isPool; + } + + public void SetIsPool(bool isPool) + { + _isPool = isPool; + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Serialize/Interface/ISerialize.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Serialize/Interface/ISerialize.cs new file mode 100644 index 0000000..a3a9159 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Serialize/Interface/ISerialize.cs @@ -0,0 +1,87 @@ +using System; +using System.Buffers; + +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member +namespace Fantasy.Serialize +{ + public interface ISerialize + { + /// + /// 序列化器的名字,用于在协议里指定用什么协议序列化使用 + /// + string SerializeName { get; } + /// + /// 反序列化 + /// + /// + /// + /// + T Deserialize(byte[] bytes); + /// + /// 反序列化 + /// + /// + /// + /// + T Deserialize(MemoryStreamBuffer buffer); + /// + /// 反序列化 + /// + /// + /// + /// + object Deserialize(Type type, byte[] bytes); + /// + /// 反序列化 + /// + /// + /// + /// + object Deserialize(Type type, MemoryStreamBuffer buffer); + /// + /// 反序列化 + /// + /// + /// + /// + /// + /// + T Deserialize(byte[] bytes, int index, int count); + /// + /// 反序列化 + /// + /// + /// + /// + /// + /// + object Deserialize(Type type, byte[] bytes, int index, int count); + /// + /// 序列化 + /// + /// + /// + /// + void Serialize(T @object, IBufferWriter buffer); + /// + /// 序列化 + /// + /// + /// + void Serialize(object @object, IBufferWriter buffer); + /// + /// 序列化 + /// + /// + /// + /// + void Serialize(Type type, object @object, IBufferWriter buffer); + /// + /// 克隆 + /// + /// + /// + /// + T Clone(T t); + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Serialize/MemoryStreamBuffer.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Serialize/MemoryStreamBuffer.cs new file mode 100644 index 0000000..d3176f1 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Serialize/MemoryStreamBuffer.cs @@ -0,0 +1,71 @@ +using System; +using System.Buffers; +using System.IO; +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member + +namespace Fantasy.Serialize +{ + public enum MemoryStreamBufferSource + { + None = 0, + Pack = 1, + UnPack = 2, + } + + public sealed class MemoryStreamBuffer : MemoryStream, IBufferWriter + { + public MemoryStreamBufferSource MemoryStreamBufferSource; + public MemoryStreamBuffer() { } + + public MemoryStreamBuffer(MemoryStreamBufferSource memoryStreamBufferSource, int capacity) : base(capacity) + { + MemoryStreamBufferSource = memoryStreamBufferSource; + } + public MemoryStreamBuffer(byte[] buffer): base(buffer) { } + + public void Advance(int count) + { + if (count < 0) + { + throw new ArgumentOutOfRangeException(nameof(count), count, "The value of 'count' cannot be negative."); + } + + var newLength = Position + count; + if (newLength > Length) + { + SetLength(newLength); + } + Position = newLength; + } + + public Memory GetMemory(int sizeHint = 0) + { + if (sizeHint < 0) + { + throw new ArgumentOutOfRangeException(nameof(sizeHint), sizeHint, "The value of 'count' cannot be negative."); + } + + if (Length - Position <= sizeHint) + { + SetLength(Position + sizeHint); + } + + return new Memory(GetBuffer(), (int)Position, (int)(Length - Position)); + } + + public Span GetSpan(int sizeHint = 0) + { + if (sizeHint < 0) + { + throw new ArgumentOutOfRangeException(nameof(sizeHint), sizeHint, "The value of 'count' cannot be negative."); + } + + if (Length - Position <= sizeHint) + { + SetLength(Position + sizeHint); + } + + return new Span(GetBuffer(), (int)Position, (int)(Length - Position)); + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Serialize/ProtoBufPackHelper/IProto.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Serialize/ProtoBufPackHelper/IProto.cs new file mode 100644 index 0000000..2267dd2 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Serialize/ProtoBufPackHelper/IProto.cs @@ -0,0 +1,9 @@ +namespace Fantasy.Serialize +{ + /// + /// 代表是一个ProtoBuf协议 + /// + public interface IProto + { + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Serialize/ProtoBufPackHelper/ProtoBufPackHelperNet.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Serialize/ProtoBufPackHelper/ProtoBufPackHelperNet.cs new file mode 100644 index 0000000..cda6b7b --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Serialize/ProtoBufPackHelper/ProtoBufPackHelperNet.cs @@ -0,0 +1,225 @@ +using System.Buffers; +using Fantasy.Assembly; +using ProtoBuf.Meta; + +#if FANTASY_NET || FANTASY_EXPORTER +namespace Fantasy.Serialize +{ + /// + /// ProtoBufP帮助类,Net平台使用 + /// + public sealed class ProtoBufPackHelper : ISerialize + { + /// + /// 序列化器的名字 + /// + public string SerializeName { get; } = "ProtoBuf"; + + /// + /// 构造函数 + /// + public ProtoBufPackHelper () + { +#if FANTASY_NET + RuntimeTypeModel.Default.AutoAddMissingTypes = true; + RuntimeTypeModel.Default.AllowParseableTypes = true; + RuntimeTypeModel.Default.AutoAddMissingTypes = true; + RuntimeTypeModel.Default.AutoCompile = true; + RuntimeTypeModel.Default.UseImplicitZeroDefaults = true; + RuntimeTypeModel.Default.InferTagFromNameDefault = true; + + foreach (var type in AssemblySystem.ForEach(typeof(IProto))) + { + RuntimeTypeModel.Default.Add(type, true); + } + + RuntimeTypeModel.Default.CompileInPlace(); +#endif + } + + /// + /// 使用ProtoBuf反序列化数据到实例 + /// + /// + /// + /// + public T Deserialize(byte[] bytes) + { + var memory = new ReadOnlyMemory(bytes); + var @object = RuntimeTypeModel.Default.Deserialize(memory); + if (@object is ASerialize aSerialize) + { + aSerialize.AfterDeserialization(); + } + return @object; + } + /// + /// 使用ProtoBuf反序列化数据到实例 + /// + /// + /// + /// + public T Deserialize(MemoryStreamBuffer buffer) + { + var @object = RuntimeTypeModel.Default.Deserialize(buffer); + if (@object is ASerialize aSerialize) + { + aSerialize.AfterDeserialization(); + } + + return @object; + } + /// + /// 使用ProtoBuf反序列化数据到实例 + /// + /// + /// + /// + public object Deserialize(Type type, byte[] bytes) + { + var memory = new ReadOnlyMemory(bytes); + var @object = RuntimeTypeModel.Default.Deserialize(type, memory); + if (@object is ASerialize aSerialize) + { + aSerialize.AfterDeserialization(); + } + + return @object; + } + /// + /// 使用ProtoBuf反序列化数据到实例 + /// + /// + /// + /// + public object Deserialize(Type type, MemoryStreamBuffer buffer) + { + var @object = RuntimeTypeModel.Default.Deserialize(type, buffer); + if (@object is ASerialize aSerialize) + { + aSerialize.AfterDeserialization(); + } + + return @object; + } + /// + /// 使用ProtoBuf反序列化数据到实例 + /// + /// + /// + /// + /// + /// + public T Deserialize(byte[] bytes, int index, int count) + { + var memory = new ReadOnlyMemory(bytes, index, count); + var @object = RuntimeTypeModel.Default.Deserialize(memory); + if (@object is ASerialize aSerialize) + { + aSerialize.AfterDeserialization(); + } + + return @object; + } + /// + /// 使用ProtoBuf反序列化数据到实例 + /// + /// + /// + /// + /// + /// + public object Deserialize(Type type, byte[] bytes, int index, int count) + { + var memory = new ReadOnlyMemory(bytes, index, count); + var @object = RuntimeTypeModel.Default.Deserialize(type, memory); + if (@object is ASerialize aSerialize) + { + aSerialize.AfterDeserialization(); + } + + return @object; + } + /// + /// 使用ProtoBuf序列化某一个实例到IBufferWriter中 + /// + /// + /// + /// + public void Serialize(T @object, IBufferWriter buffer) + { + if (@object is ASerialize aSerialize) + { + aSerialize.BeginInit(); + } + + RuntimeTypeModel.Default.Serialize(buffer, @object); + } + /// + /// 使用ProtoBuf序列化某一个实例到IBufferWriter中 + /// + /// + /// + public void Serialize(object @object, IBufferWriter buffer) + { + if (@object is ASerialize aSerialize) + { + aSerialize.BeginInit(); + } + + RuntimeTypeModel.Default.Serialize(buffer, @object); + } + /// + /// 使用ProtoBuf序列化某一个实例到IBufferWriter中 + /// + /// + /// + /// + public void Serialize(Type type, object @object, IBufferWriter buffer) + { + if (@object is ASerialize aSerialize) + { + aSerialize.BeginInit(); + } + + RuntimeTypeModel.Default.Serialize(buffer, @object); + } + internal byte[] Serialize(object @object) + { + if (@object is ASerialize aSerialize) + { + aSerialize.BeginInit(); + } + + using (var buffer = new MemoryStream()) + { + RuntimeTypeModel.Default.Serialize(buffer, @object); + return buffer.ToArray(); + } + } + private byte[] Serialize(T @object) + { + if (@object is ASerialize aSerialize) + { + aSerialize.BeginInit(); + } + + using (var buffer = new MemoryStream()) + { + RuntimeTypeModel.Default.Serialize(buffer, @object); + return buffer.ToArray(); + } + } + /// + /// 克隆 + /// + /// + /// + /// + public T Clone(T t) + { + return Deserialize(Serialize(t)); + } + } +} +#endif diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Serialize/ProtoBufPackHelper/ProtoBufPackHelperUnity.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Serialize/ProtoBufPackHelper/ProtoBufPackHelperUnity.cs new file mode 100644 index 0000000..6df5903 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Serialize/ProtoBufPackHelper/ProtoBufPackHelperUnity.cs @@ -0,0 +1,202 @@ +#if FANTASY_UNITY || FANTASY_CONSOLE +using System; +using System.Buffers; +using System.IO; +using Fantasy.Assembly; +using ProtoBuf; +using ProtoBuf.Meta; + +namespace Fantasy.Serialize +{ + /// + /// ProtoBufP帮助类,Unity平台使用 + /// + public sealed class ProtoBufPackHelper : ISerialize + { + /// + /// 序列化器的名字 + /// + public string SerializeName { get; } = "ProtoBuf"; + + /// + /// 使用ProtoBuf反序列化数据到实例 + /// + /// + /// + /// + public unsafe T Deserialize(byte[] bytes) + { + fixed (byte* ptr = bytes) + { + using var stream = new UnmanagedMemoryStream(ptr, bytes.Length); + var @object = ProtoBuf.Serializer.Deserialize(stream); + if (@object is ASerialize aSerialize) + { + aSerialize.AfterDeserialization(); + } + return @object; + } + } + /// + /// 使用ProtoBuf反序列化数据到实例 + /// + /// + /// + /// + public T Deserialize(MemoryStreamBuffer buffer) + { + var @object = ProtoBuf.Serializer.Deserialize(buffer); + if (@object is ASerialize aSerialize) + { + aSerialize.AfterDeserialization(); + } + return @object; + } + /// + /// 使用ProtoBuf反序列化数据到实例 + /// + /// + /// + /// + public unsafe object Deserialize(Type type, byte[] bytes) + { + fixed (byte* ptr = bytes) + { + using var stream = new UnmanagedMemoryStream(ptr, bytes.Length); + var @object = ProtoBuf.Serializer.Deserialize(type, stream); + if (@object is ASerialize aSerialize) + { + aSerialize.AfterDeserialization(); + } + + return @object; + } + } + /// + /// 使用ProtoBuf反序列化数据到实例 + /// + /// + /// + /// + public object Deserialize(Type type, MemoryStreamBuffer buffer) + { + var @object = ProtoBuf.Serializer.Deserialize(type, buffer); + if (@object is ASerialize aSerialize) + { + aSerialize.AfterDeserialization(); + } + + return @object; + } + /// + /// 使用ProtoBuf反序列化数据到实例 + /// + /// + /// + /// + /// + /// + public unsafe T Deserialize(byte[] bytes, int index, int count) + { + fixed (byte* ptr = &bytes[index]) + { + using var stream = new UnmanagedMemoryStream(ptr, count); + var @object = ProtoBuf.Serializer.Deserialize(stream); + if (@object is ASerialize aSerialize) + { + aSerialize.AfterDeserialization(); + } + return @object; + } + } + /// + /// 使用ProtoBuf反序列化数据到实例 + /// + /// + /// + /// + /// + /// + public unsafe object Deserialize(Type type, byte[] bytes, int index, int count) + { + fixed (byte* ptr = &bytes[index]) + { + using var stream = new UnmanagedMemoryStream(ptr, count); + var @object = ProtoBuf.Serializer.Deserialize(type, stream); + if (@object is ASerialize aSerialize) + { + aSerialize.AfterDeserialization(); + } + return @object; + } + } + /// + /// 使用ProtoBuf序列化某一个实例到IBufferWriter中 + /// + /// + /// + /// + public void Serialize(T @object, IBufferWriter buffer) + { + if (@object is ASerialize aSerialize) + { + aSerialize.BeginInit(); + } + + RuntimeTypeModel.Default.Serialize((MemoryStream)buffer, @object); + } + /// + /// 使用ProtoBuf序列化某一个实例到IBufferWriter中 + /// + /// + /// + public void Serialize(object @object, IBufferWriter buffer) + { + if (@object is ASerialize aSerialize) + { + aSerialize.BeginInit(); + } + + RuntimeTypeModel.Default.Serialize((MemoryStream)buffer, @object); + } + /// + /// 使用ProtoBuf序列化某一个实例到IBufferWriter中 + /// + /// + /// + /// + public void Serialize(Type type, object @object, IBufferWriter buffer) + { + if (@object is ASerialize aSerialize) + { + aSerialize.BeginInit(); + } + + RuntimeTypeModel.Default.Serialize((MemoryStream)buffer, @object); + } + private byte[] Serialize(T @object) + { + if (@object is ASerialize aSerialize) + { + aSerialize.BeginInit(); + } + + using (var buffer = new MemoryStream()) + { + RuntimeTypeModel.Default.Serialize(buffer, @object); + return buffer.ToArray(); + } + } + /// + /// 克隆 + /// + /// + /// + /// + public T Clone(T t) + { + return Deserialize(Serialize(t)); + } + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Serialize/SerializerManager.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Serialize/SerializerManager.cs new file mode 100644 index 0000000..dc49bf0 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Runtime/Core/Serialize/SerializerManager.cs @@ -0,0 +1,153 @@ +using System; +using System.Collections.Generic; +using Fantasy.Assembly; +using Fantasy.Helper; +#if !FANTASY_EXPORTER +using Fantasy.Network; +#endif +using ProtoBuf; +#pragma warning disable CS8604 // Possible null reference argument. +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. +#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. +#pragma warning disable CS8602 // Dereference of a possibly null reference. +#pragma warning disable CS8600 // Converting null literal or possible null value to non-nullable type. + +namespace Fantasy.Serialize +{ + /// + /// 框架内置的序列化器类型 + /// + public static class FantasySerializerType + { + /// + /// ProtoBuf在SerializerManager的数组下标 + /// + public const int ProtoBuf = 0; + /// + /// Bson在SerializerManager的数组下标 + /// + public const int Bson = 1; + } + + /// + /// 管理序列化静态方法,主要是优化网络协议时使用。 + /// + public static class SerializerManager + { + private static ISerialize[] _serializers; + private static bool _isInitialized = false; + +#if FANTASY_NET || FANTASY_UNITY + /// + /// 初始化方法 + /// + public static void Initialize() + { + if (_isInitialized) + { + return; + } + + try + { + var sort = new SortedList(); + + foreach (var serializerType in AssemblySystem.ForEach(typeof(ISerialize))) + { + var serializer = (ISerialize)Activator.CreateInstance(serializerType); + var computeHash64 = HashCodeHelper.ComputeHash64(serializer.SerializeName); + sort.Add(computeHash64, serializer); + } + + var index = 1; + _serializers = new ISerialize[sort.Count]; + + foreach (var (_, serialize) in sort) + { + var serializerIndex = 0; + + switch (serialize) + { + case ProtoBufPackHelper: + { + serializerIndex = FantasySerializerType.ProtoBuf; + break; + } + case BsonPackHelper: + { + serializerIndex = FantasySerializerType.Bson; + break; + } + default: + { + serializerIndex = ++index; + break; + } + } + + _serializers[serializerIndex] = serialize; + } + + _isInitialized = true; + Log.Info($"初始化序列化器成功,数量为:{_serializers.Length}"); + } + catch (Exception e) + { + Log.Error(e); + Dispose(); + } + } +#else + /// + /// 初始化方法 + /// + public static void Initialize() + { + if (_isInitialized) + { + return; + } + + _serializers = new ISerialize[1]; + _serializers[0] = new ProtoBufPackHelper(); + } +#endif + + /// + /// 销毁方法 + /// + public static void Dispose() + { + _isInitialized = false; + Array.Clear(_serializers, 0, _serializers.Length); + } + + /// + /// 根据协议类型获取序列化器 + /// + /// + /// + public static ISerialize GetSerializer(uint opCodeProtocolType) + { + return _serializers[opCodeProtocolType]; + } + + /// + /// 获得一个序列化器 + /// + /// + /// + /// + public static bool TryGetSerializer(uint opCodeProtocolType, out ISerialize serializer) + { + if (opCodeProtocolType < _serializers.Length) + { + serializer = _serializers[opCodeProtocolType]; + return true; + } + + serializer = default; + return false; + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/icon.png b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/icon.png new file mode 100644 index 0000000..8ae7488 Binary files /dev/null and b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Net/Fantasy.Net/icon.png differ diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.Config/Config/Excel/Custom.txt b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.Config/Config/Excel/Custom.txt new file mode 100644 index 0000000..fd90a9b --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.Config/Config/Excel/Custom.txt @@ -0,0 +1 @@ +// 自定义导出配置文件,用于配置自定义导出自定义程序的路径 diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.Config/Config/Excel/Server/MachineConfig.xlsx b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.Config/Config/Excel/Server/MachineConfig.xlsx new file mode 100644 index 0000000..999e939 Binary files /dev/null and b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.Config/Config/Excel/Server/MachineConfig.xlsx differ diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.Config/Config/Excel/Server/ProcessConfig.xlsx b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.Config/Config/Excel/Server/ProcessConfig.xlsx new file mode 100644 index 0000000..001235a Binary files /dev/null and b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.Config/Config/Excel/Server/ProcessConfig.xlsx differ diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.Config/Config/Excel/Server/SceneConfig.xlsx b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.Config/Config/Excel/Server/SceneConfig.xlsx new file mode 100644 index 0000000..a4ca05e Binary files /dev/null and b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.Config/Config/Excel/Server/SceneConfig.xlsx differ diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.Config/Config/Excel/Server/WorldConfig.xlsx b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.Config/Config/Excel/Server/WorldConfig.xlsx new file mode 100644 index 0000000..8194c9a Binary files /dev/null and b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.Config/Config/Excel/Server/WorldConfig.xlsx differ diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.Config/Config/Excel/Version.txt b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.Config/Config/Excel/Version.txt new file mode 100644 index 0000000..1877ad8 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.Config/Config/Excel/Version.txt @@ -0,0 +1 @@ +{"WorksheetNames":["MachineConfig","ProcessConfig","WorldConfig","SceneConfig","SceneTypeConfig"],"Tables":{"MachineConfig":1725984682557,"SceneConfig":1726083372000,"WorldConfig":1724007858627,"ProcessConfig":1725195494442}} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.Config/Config/Json/Server/MachineConfigData.Json b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.Config/Config/Json/Server/MachineConfigData.Json new file mode 100644 index 0000000..f56f98e --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.Config/Config/Json/Server/MachineConfigData.Json @@ -0,0 +1,3 @@ +{"List":[ +{"Id":1,"OuterIP":"127.0.0.1","OuterBindIP":"127.0.0.1","InnerBindIP":"127.0.0.1"} +]} diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.Config/Config/Json/Server/ProcessConfigData.Json b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.Config/Config/Json/Server/ProcessConfigData.Json new file mode 100644 index 0000000..a05a13c --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.Config/Config/Json/Server/ProcessConfigData.Json @@ -0,0 +1,3 @@ +{"List":[ +{"Id":1,"MachineId":1,"StartupGroup":0} +]} diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.Config/Config/Json/Server/SceneConfigData.Json b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.Config/Config/Json/Server/SceneConfigData.Json new file mode 100644 index 0000000..44996e7 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.Config/Config/Json/Server/SceneConfigData.Json @@ -0,0 +1,6 @@ +{"List":[ +{"Id":1001,"ProcessConfigId":1,"WorldConfigId":1,"SceneRuntimeType":"MultiThread","SceneTypeString":"Addressable","NetworkProtocol":null,"OuterPort":0,"InnerPort":11001,"SceneType":2}, +{"Id":1002,"ProcessConfigId":1,"WorldConfigId":1,"SceneRuntimeType":"MultiThread","SceneTypeString":"Gate","NetworkProtocol":"KCP","OuterPort":20000,"InnerPort":11002,"SceneType":3}, +{"Id":1003,"ProcessConfigId":1,"WorldConfigId":1,"SceneRuntimeType":"MultiThread","SceneTypeString":"Map","NetworkProtocol":null,"OuterPort":0,"InnerPort":11003,"SceneType":4}, +{"Id":1004,"ProcessConfigId":1,"WorldConfigId":1,"SceneRuntimeType":"MultiThread","SceneTypeString":"Chat","NetworkProtocol":null,"OuterPort":0,"InnerPort":11004,"SceneType":8} +]} diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.Config/Config/Json/Server/WorldConfigData.Json b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.Config/Config/Json/Server/WorldConfigData.Json new file mode 100644 index 0000000..60dd090 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.Config/Config/Json/Server/WorldConfigData.Json @@ -0,0 +1,3 @@ +{"List":[ +{"Id":1,"WorldName":"测试服","DbConnection":null,"DbName":"fantasy_main","DbType":"MongoDB"} +]} diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.Config/Config/NetworkProtocol/Inner/InnerMessage.proto b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.Config/Config/NetworkProtocol/Inner/InnerMessage.proto new file mode 100644 index 0000000..a8b51b8 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.Config/Config/NetworkProtocol/Inner/InnerMessage.proto @@ -0,0 +1,27 @@ +syntax = "proto3"; +package Sining.Message; +message G2A_TestRequest // IRouteRequest,G2A_TestResponse +{ + +} +message G2A_TestResponse // IRouteResponse +{ + +} +message G2M_RequestAddressableId // IRouteRequest,M2G_ResponseAddressableId +{ + +} +message M2G_ResponseAddressableId // IRouteResponse +{ + int64 AddressableId = 1; // Map服务器返回的AddressableId +} +/// 通知Chat服务器创建一个RouteId +message G2Chat_CreateRouteRequest // IRouteRequest,Chat2G_CreateRouteResponse +{ + int64 GateRouteId = 1; +} +message Chat2G_CreateRouteResponse // IRouteResponse +{ + int64 ChatRouteId = 1; +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.Config/Config/NetworkProtocol/OpCode.Cache b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.Config/Config/NetworkProtocol/OpCode.Cache new file mode 100644 index 0000000..9e26dfe --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.Config/Config/NetworkProtocol/OpCode.Cache @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.Config/Config/NetworkProtocol/Outer/OuterMessage.proto b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.Config/Config/NetworkProtocol/Outer/OuterMessage.proto new file mode 100644 index 0000000..b036a74 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.Config/Config/NetworkProtocol/Outer/OuterMessage.proto @@ -0,0 +1,64 @@ +syntax = "proto3"; +package Fantasy.Network.Message; +// 协议分为: +// ProtoBuf:可以在Outer和Inner文件里使用。 +// MemoryPack:可以在Outer和Inner文件里使用。 +// Bson:仅支持在Inner文件里使用。 +// 使用方式: +// 在message协议上方添加// Protocol+空格+协议名字 +// 例如:// Protocol ProtoBuf 或 // Protocol MemoryPack +message C2G_TestMessage // IMessage +{ + string Tag = 1; +} +message C2G_TestRequest // IRequest,G2C_TestResponse +{ + string Tag = 1; +} +message G2C_TestResponse // IResponse +{ + string Tag = 1; +} +message C2G_CreateAddressableRequest // IRequest,G2C_CreateAddressableResponse +{ + +} +message G2C_CreateAddressableResponse // IResponse +{ + +} +message C2M_TestMessage // IAddressableRouteMessage +{ + string Tag = 1; +} +message C2M_TestRequest // IAddressableRouteRequest,M2C_TestResponse +{ + string Tag = 1; +} +message M2C_TestResponse // IAddressableRouteResponse +{ + string Tag = 1; +} +/// 通知Gate服务器创建一个Chat的Route连接 +message C2G_CreateChatRouteRequest // IRequest,G2C_CreateChatRouteResponse +{ + +} +message G2C_CreateChatRouteResponse // IResponse +{ + +} +/// 发送一个Route消息给Chat +message C2Chat_TestMessage // ICustomRouteMessage,ChatRoute +{ + string Tag = 1; +} +/// 发送一个RPCRoute消息给Chat +message C2Chat_TestMessageRequest // ICustomRouteRequest,Chat2C_TestMessageResponse,ChatRoute +{ + string Tag = 1; +} +message Chat2C_TestMessageResponse // ICustomRouteResponse +{ + string Tag = 1; +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.Config/Config/NetworkProtocol/RouteType.Config b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.Config/Config/NetworkProtocol/RouteType.Config new file mode 100644 index 0000000..66082cf --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.Config/Config/NetworkProtocol/RouteType.Config @@ -0,0 +1,3 @@ +// Route协议定义(需要定义1000以上、因为1000以内的框架预留) +GateRoute = 1001 // Gate +ChatRoute = 1002 // Chat \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.Config/Fantasy-Net.Config.targets b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.Config/Fantasy-Net.Config.targets new file mode 100644 index 0000000..19464f8 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.Config/Fantasy-Net.Config.targets @@ -0,0 +1,25 @@ + + + + + + + + + + + + $(MSBuildProjectDirectory)\Tools\Exporter\ConfigTable\%(RecursiveDir)%(Filename)%(Extension) + + + + + + + + + + diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.Config/Fantasy.Config.csproj b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.Config/Fantasy.Config.csproj new file mode 100644 index 0000000..d20709d --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.Config/Fantasy.Config.csproj @@ -0,0 +1,36 @@ + + + + Fantasy-Net.Config + 2024.1.4 + Fantasy-Net.Config + qq362946 + qq362946 + ../../nupkg + false + + Fantasy is a high-performance network development framework based on .NET, supporting mainstream protocols. It is designed for development teams or individuals needing a quick start, scalability, and a distributed, cross-platform solution at the commercial level. Fantasy aims to provide easy-to-use tools while ensuring high system performance and scalability. + Copyright 2026 qq362946 + README.md + https://www.code-fantasy.com/ + https://github.com/qq362946/Fantasy + git + Net, c#, Server, Game, GameServer, Fantasy , Network + icon.png + net8.0 + enable + enable + Fantasy-Net.Config + + + + + + + + + + + + + diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.Config/README.md b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.Config/README.md new file mode 100644 index 0000000..697ec05 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.Config/README.md @@ -0,0 +1,16 @@ +# Fantasy-Net.Config +在Config文件夹中,存放着Fantasy所需的各种配置文件。这些文件涵盖了多个方面。每个配置文件都有其特定的格式和功能,通过精心设计的这些配置文件,开发团队能够快速调整框架参数,以实现更好的游戏体验,从而提升Fantasy的整体质量。 +## Excel文件夹 +里面存放了Fantasy.Net所需的四个Excel配置文件。用户可以利用Fantasy-Net.Exporter工具,依据这四个Excel文件生成相应的JSON文件,以供框架使用。这一过程不仅简化了数据处理,还确保了不同组件之间的无缝对接,使得工作流程更加高效。请确保在导出之前,Excel文件的格式和内容符合要求,以避免产生错误。 +## Json文件夹 +在该目录中存放了Fantasy.Net所需的四个JSON配置文件。用户可以根据这四个文件的模板进行添加或修改配置,以满足具体需求。每个项目的功能说明在相应的Excel文件中有详细描述,方便用户理解和使用这些配置文件。我们建议用户仔细阅读Excel文件中的说明,以确保配置的正确性和有效性。 +## NetworkProtocol文件夹 +存放框架所需定义网络协议的模版和文件夹 +### Inner文件夹 +定义服务器之间的网络协议 +### Outer文件夹 +定义客户端和服务器之间的网络协议 +### RouteType.Config +定义自定义Route协议的配置文件 +## 交流与讨论: +__讨论QQ群 : Fantasy服务器开发交流群 569888673 __ \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.Config/icon.png b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.Config/icon.png new file mode 100644 index 0000000..8ae7488 Binary files /dev/null and b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.Config/icon.png differ diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.ConfigTable/Net/ConfigTableHelper.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.ConfigTable/Net/ConfigTableHelper.cs new file mode 100644 index 0000000..242bd3c --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.ConfigTable/Net/ConfigTableHelper.cs @@ -0,0 +1,94 @@ +using System; +using System.Collections.Generic; +using System.IO; +using Fantasy.Platform.Net; +using Fantasy.Serialize; +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. + +// ReSharper disable SuspiciousTypeConversion.Global + +namespace Fantasy.ConfigTable +{ + /// + /// 配置表帮助类 + /// + public static class ConfigTableHelper + { + private static string _configTableBinaryDirectory; + private static readonly object Lock = new object(); + // 配置表数据缓存字典 + private static readonly Dictionary ConfigDic = new (); + /// + /// 初始化ConfigTableHelper + /// + /// + public static void Initialize(string configTableBinaryDirectory) + { + _configTableBinaryDirectory = configTableBinaryDirectory; + } + /// + /// 加载配置表数据 + /// + /// 配置表类型 + /// 配置表数据 + public static T Load() where T : ASerialize + { + lock (Lock) + { + try + { + var dataConfig = typeof(T).Name; + + if (ConfigDic.TryGetValue(dataConfig, out var aProto)) + { + return (T)aProto; + } + + var configFile = GetConfigPath(dataConfig); + var bytes = File.ReadAllBytes(configFile); + // Log.Debug($"dataConfig:{dataConfig} {bytes.Length}"); + var data = SerializerManager.GetSerializer(FantasySerializerType.ProtoBuf).Deserialize(bytes); + ConfigDic[dataConfig] = data; + return data; + } + catch (Exception ex) + { + throw new Exception($"ConfigTableManage:{typeof(T).Name} 数据表加载之后反序列化时出错:{ex}"); + } + } + } + + /// + /// 获取配置表文件路径 + /// + /// 配置表名称 + /// 配置表文件路径 + private static string GetConfigPath(string name) + { + var configFile = Path.Combine(_configTableBinaryDirectory, $"{name}.bytes"); + + if (File.Exists(configFile)) + { + return configFile; + } + + throw new FileNotFoundException($"{name}.byte not found: {configFile}"); + } + + /// + /// 重新加载配置表数据 + /// + public static void ReLoadConfigTable() + { + lock (Lock) + { + foreach (var (_, aProto) in ConfigDic) + { + ((IDisposable) aProto).Dispose(); + } + + ConfigDic.Clear(); + } + } + } +} diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.ConfigTable/Net/Dictionary/IntDictionaryConfig.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.ConfigTable/Net/Dictionary/IntDictionaryConfig.cs new file mode 100644 index 0000000..a9b13b3 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.ConfigTable/Net/Dictionary/IntDictionaryConfig.cs @@ -0,0 +1,33 @@ +using System.Collections.Generic; +using ProtoBuf; +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member + +// ReSharper disable CheckNamespace +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. + +namespace Fantasy.ConfigTable +{ + [ProtoContract] + public partial class IntDictionaryConfig + { + [ProtoMember(1)] + public Dictionary Dic; + public int this[int key] => GetValue(key); + public bool TryGetValue(int key, out int value) + { + value = default; + + if (!Dic.ContainsKey(key)) + { + return false; + } + + value = Dic[key]; + return true; + } + private int GetValue(int key) + { + return Dic.TryGetValue(key, out var value) ? value : 0; + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.ConfigTable/Net/Dictionary/StringDictionaryConfig.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.ConfigTable/Net/Dictionary/StringDictionaryConfig.cs new file mode 100644 index 0000000..708ccd7 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.ConfigTable/Net/Dictionary/StringDictionaryConfig.cs @@ -0,0 +1,35 @@ +using System.Collections.Generic; +using ProtoBuf; +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member + +// ReSharper disable CheckNamespace +// ReSharper disable CollectionNeverUpdated.Global +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. +#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. +#pragma warning disable CS8603 // Possible null reference return. +namespace Fantasy.ConfigTable +{ + [ProtoContract] + public sealed partial class StringDictionaryConfig + { + [ProtoMember(1)] + public Dictionary Dic; + public string this[int key] => GetValue(key); + public bool TryGetValue(int key, out string value) + { + value = default; + + if (!Dic.ContainsKey(key)) + { + return false; + } + + value = Dic[key]; + return true; + } + private string GetValue(int key) + { + return Dic.TryGetValue(key, out var value) ? value : null; + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.ConfigTable/Net/Fantasy.ConfigTable.csproj b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.ConfigTable/Net/Fantasy.ConfigTable.csproj new file mode 100644 index 0000000..44bab51 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.ConfigTable/Net/Fantasy.ConfigTable.csproj @@ -0,0 +1,33 @@ + + + + Fantasy-Net.ConfigTable + 2024.2.0 + Fantasy-Net.ConfigTable + qq362946 + qq362946 + ../../../nupkg + false + + Fantasy is a high-performance network development framework based on .NET, supporting mainstream protocols. It is designed for development teams or individuals needing a quick start, scalability, and a distributed, cross-platform solution at the commercial level. Fantasy aims to provide easy-to-use tools while ensuring high system performance and scalability. + Copyright 2026 qq362946 + https://www.code-fantasy.com/ + https://github.com/qq362946/Fantasy + git + Net, c#, Server, Game, GameServer, Fantasy , Network + icon.png + net8.0 + enable + enable + Fantasy-Net.ConfigTable + + + + + + + + + + + diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.ConfigTable/Net/Interface/IConfigTable.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.ConfigTable/Net/Interface/IConfigTable.cs new file mode 100644 index 0000000..0992677 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.ConfigTable/Net/Interface/IConfigTable.cs @@ -0,0 +1,7 @@ +namespace Fantasy.ConfigTable +{ + /// + /// 表示是一个配置文件 + /// + public interface IConfigTable { } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.ConfigTable/Net/icon.png b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.ConfigTable/Net/icon.png new file mode 100644 index 0000000..8ae7488 Binary files /dev/null and b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.ConfigTable/Net/icon.png differ diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.ConfigTable/README.md b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.ConfigTable/README.md new file mode 100644 index 0000000..aa00019 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.ConfigTable/README.md @@ -0,0 +1,74 @@ +# Fantasy.ConfigTable + +Fantasy配置表扩展包,配合Tools里面的配置导出工具使用,注意该包依赖Fantasy包。 + +- Unity : 需要先安装Fantasy.Unity +- Net : 需要先安装Fantasy.Net +## Unity + +在Unity中使用Package Manager,点击左上角➕选择add package from disk,选择package.json安装。 + +Unity端采用assetbundle方式加载配置文件,需要把配置文件放到一个包中,例如config的ab包。 + +可以在导出工具中设置导出到前端二进制文件的路径,设置到这个config包中。 + +用代码使用一个IConfigTableAssetBundle接口 + +```csharp +public sealed class AsserBundleManager : IConfigTableAssetBundle + { + public string Combine(string assetBundleDirectoryPath, string dataConfig) + { + // 该方法用于拼装ab包的路径,因为不同的ab包资源管理工具路径都不一样 + // 所以这里提供该方法自定义路径 + return Path.Combine(assetBundleDirectoryPath, $"{dataConfig}.bytes"); + } + + public byte[] LoadConfigTable(string assetBundlePath) + { + // 这里是加载包里的二进制文件的逻辑。 + // 正常的情况下需要分编辑器和打包环境下。 + // 这里只做了编辑器下拿取ab包里的某个配置文件的逻辑。 + // 正常情况下要把非编辑器环境的逻辑也要写好。 + if (File.Exists(assetBundlePath)) + { + return AssetDatabase.LoadAssetAtPath(assetBundlePath).bytes; + } + UnityEngine.Debug.LogError($"assetBundlePath:{assetBundlePath} not exist"); + return null; + } + } +``` + +上述工作完成够,可以在项目入口点执行初始化代码 + +```csharp +// 第一个参数是指定ab包的路径,但不包含配置名字,因为配置文件会在上面的AsserBundleManager里Combine方法拼接出的路径 +// 同样这里因为是编辑环境下,所以我输入的是一个路径。 +// 但如果打包后这个路径其实并不能使用,要把这个路径改成ab包发布都得正常路径。 +ConfigTableHelper.Initialize("Assets/Bundles/Config/", new AsserBundleManager()); +``` + +## Net + +```csharp +// 设置配置表的路径 +// 导出工具会把配置表的二进制数据导出到一个目录中。 +// 服务器启动的时候需要传入这个目录的路径。 +// 我这里使用了相对路径,大家可以根据自己的环境更改目录 +ConfigTableHelper.Initialize("../../../Config/Binary"); +``` + +## 使用 + +初始化完成后,就可以在项目中使用配置文件了 + +```csharp +// 例如我配置了一个表名为UnitConfig,那在导出在代码中使用只需要再这个表名后面加上Data +// 然后在使用下面的Instance就可以访问表里的数据了 + +// 获得表里的所有数据 +var instanceList = UnitConfigData.Instance.List; +// 根据表的主键Id来获得数据,这里的1就是表对应的Id +var unitConfig = UnitConfigData.Instance.Get(1); +``` \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.ConfigTable/Unity/Fantasy.ConfigTable.asmdef b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.ConfigTable/Unity/Fantasy.ConfigTable.asmdef new file mode 100644 index 0000000..7869fee --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.ConfigTable/Unity/Fantasy.ConfigTable.asmdef @@ -0,0 +1,16 @@ +{ + "name": "Fantasy.ConfigTable", + "rootNamespace": "", + "references": [ + "GUID:0b7224b83ba514121aa026f3857f820a" + ], + "includePlatforms": [], + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": false, + "precompiledReferences": [], + "autoReferenced": true, + "defineConstraints": [], + "versionDefines": [], + "noEngineReferences": false +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.ConfigTable/Unity/Fantasy.ConfigTable.asmdef.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.ConfigTable/Unity/Fantasy.ConfigTable.asmdef.meta new file mode 100644 index 0000000..5caa0e4 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.ConfigTable/Unity/Fantasy.ConfigTable.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: c4d36c5a80dc44c6e822eba8db9ed704 +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.ConfigTable/Unity/Runtime.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.ConfigTable/Unity/Runtime.meta new file mode 100644 index 0000000..489b45f --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.ConfigTable/Unity/Runtime.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: cfbf88374cb6b49f2947ab95a9bc08ba +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.ConfigTable/Unity/Runtime/ConfigTableHelper.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.ConfigTable/Unity/Runtime/ConfigTableHelper.cs new file mode 100644 index 0000000..bbeace3 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.ConfigTable/Unity/Runtime/ConfigTableHelper.cs @@ -0,0 +1,78 @@ +using System; +using System.Collections.Generic; +using Fantasy.Serialize; +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. + +// ReSharper disable SuspiciousTypeConversion.Global + +namespace Fantasy.ConfigTable +{ + /// + /// 配置表帮助类 + /// + public static class ConfigTableHelper + { + private static string _assetBundleDirectoryPath; + private static IConfigTableAssetBundle _configTableAssetBundle; + private static readonly object Lock = new object(); + // 配置表数据缓存字典 + private static readonly Dictionary ConfigDic = new (); + + /// + /// 初始化ConfigTableHelper + /// + /// + /// + public static void Initialize(string assetBundleDirectoryPath, IConfigTableAssetBundle configTableAssetBundle) + { + _assetBundleDirectoryPath = assetBundleDirectoryPath; + _configTableAssetBundle = configTableAssetBundle; + } + /// + /// 加载配置表数据 + /// + /// 配置表类型 + /// 配置表数据 + public static T Load() where T : ASerialize + { + lock (Lock) + { + try + { + var dataConfig = typeof(T).Name; + + if (ConfigDic.TryGetValue(dataConfig, out var aProto)) + { + return (T)aProto; + } + + var dataConfigPath = _configTableAssetBundle.Combine(_assetBundleDirectoryPath, dataConfig); + var bytes = _configTableAssetBundle.LoadConfigTable(dataConfigPath); + var data = SerializerManager.GetSerializer(FantasySerializerType.ProtoBuf).Deserialize(bytes); + ConfigDic[dataConfig] = data; + return data; + } + catch (Exception ex) + { + throw new Exception($"ConfigTableManage:{typeof(T).Name} 数据表加载之后反序列化时出错:{ex}"); + } + } + } + + /// + /// 重新加载配置表数据 + /// + public static void ReLoadConfigTable() + { + lock (Lock) + { + foreach (var (_, aProto) in ConfigDic) + { + ((IDisposable) aProto).Dispose(); + } + + ConfigDic.Clear(); + } + } + } +} diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.ConfigTable/Unity/Runtime/ConfigTableHelper.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.ConfigTable/Unity/Runtime/ConfigTableHelper.cs.meta new file mode 100644 index 0000000..132e91c --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.ConfigTable/Unity/Runtime/ConfigTableHelper.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2e3ca7a021b1c445a9f58c1e4645fe17 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.ConfigTable/Unity/Runtime/Dictionary.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.ConfigTable/Unity/Runtime/Dictionary.meta new file mode 100644 index 0000000..abc7cb3 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.ConfigTable/Unity/Runtime/Dictionary.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 6e10a07ad20ee4d7298ee808a3ea8b73 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.ConfigTable/Unity/Runtime/Dictionary/IntDictionaryConfig.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.ConfigTable/Unity/Runtime/Dictionary/IntDictionaryConfig.cs new file mode 100644 index 0000000..a9b13b3 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.ConfigTable/Unity/Runtime/Dictionary/IntDictionaryConfig.cs @@ -0,0 +1,33 @@ +using System.Collections.Generic; +using ProtoBuf; +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member + +// ReSharper disable CheckNamespace +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. + +namespace Fantasy.ConfigTable +{ + [ProtoContract] + public partial class IntDictionaryConfig + { + [ProtoMember(1)] + public Dictionary Dic; + public int this[int key] => GetValue(key); + public bool TryGetValue(int key, out int value) + { + value = default; + + if (!Dic.ContainsKey(key)) + { + return false; + } + + value = Dic[key]; + return true; + } + private int GetValue(int key) + { + return Dic.TryGetValue(key, out var value) ? value : 0; + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.ConfigTable/Unity/Runtime/Dictionary/IntDictionaryConfig.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.ConfigTable/Unity/Runtime/Dictionary/IntDictionaryConfig.cs.meta new file mode 100644 index 0000000..692433f --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.ConfigTable/Unity/Runtime/Dictionary/IntDictionaryConfig.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 294753d61a7ac401f9f1b75e43d7536e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.ConfigTable/Unity/Runtime/Dictionary/StringDictionaryConfig.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.ConfigTable/Unity/Runtime/Dictionary/StringDictionaryConfig.cs new file mode 100644 index 0000000..708ccd7 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.ConfigTable/Unity/Runtime/Dictionary/StringDictionaryConfig.cs @@ -0,0 +1,35 @@ +using System.Collections.Generic; +using ProtoBuf; +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member + +// ReSharper disable CheckNamespace +// ReSharper disable CollectionNeverUpdated.Global +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. +#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. +#pragma warning disable CS8603 // Possible null reference return. +namespace Fantasy.ConfigTable +{ + [ProtoContract] + public sealed partial class StringDictionaryConfig + { + [ProtoMember(1)] + public Dictionary Dic; + public string this[int key] => GetValue(key); + public bool TryGetValue(int key, out string value) + { + value = default; + + if (!Dic.ContainsKey(key)) + { + return false; + } + + value = Dic[key]; + return true; + } + private string GetValue(int key) + { + return Dic.TryGetValue(key, out var value) ? value : null; + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.ConfigTable/Unity/Runtime/Dictionary/StringDictionaryConfig.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.ConfigTable/Unity/Runtime/Dictionary/StringDictionaryConfig.cs.meta new file mode 100644 index 0000000..7c61f54 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.ConfigTable/Unity/Runtime/Dictionary/StringDictionaryConfig.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 295679520921148c685abac87ba609fd +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.ConfigTable/Unity/Runtime/Interface.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.ConfigTable/Unity/Runtime/Interface.meta new file mode 100644 index 0000000..92fa071 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.ConfigTable/Unity/Runtime/Interface.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e229cd1e867af419193a32fefaf271df +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.ConfigTable/Unity/Runtime/Interface/IConfigTable.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.ConfigTable/Unity/Runtime/Interface/IConfigTable.cs new file mode 100644 index 0000000..0992677 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.ConfigTable/Unity/Runtime/Interface/IConfigTable.cs @@ -0,0 +1,7 @@ +namespace Fantasy.ConfigTable +{ + /// + /// 表示是一个配置文件 + /// + public interface IConfigTable { } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.ConfigTable/Unity/Runtime/Interface/IConfigTable.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.ConfigTable/Unity/Runtime/Interface/IConfigTable.cs.meta new file mode 100644 index 0000000..4138cee --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.ConfigTable/Unity/Runtime/Interface/IConfigTable.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ba91b698a7df846c185a3d9e384f71b6 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.ConfigTable/Unity/Runtime/Interface/IConfigTableAssetBundle.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.ConfigTable/Unity/Runtime/Interface/IConfigTableAssetBundle.cs new file mode 100644 index 0000000..0e17a06 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.ConfigTable/Unity/Runtime/Interface/IConfigTableAssetBundle.cs @@ -0,0 +1,16 @@ +namespace Fantasy.ConfigTable +{ + public interface IConfigTableAssetBundle + { + /// + /// 不同的资源管理器有各自独特的包加载方式。 + /// 为了满足不同的需求,我们提供了这个接口,允许用户自定义拼装包路径。 + /// 通过这个接口,用户可以根据自己的特定格式和要求,灵活地加载包,从而提高资源管理的灵活性和效率。 + /// + /// + /// + /// + public string Combine(string assetBundleDirectoryPath, string dataConfig); + public byte[] LoadConfigTable(string assetBundlePath); + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.ConfigTable/Unity/Runtime/Interface/IConfigTableAssetBundle.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.ConfigTable/Unity/Runtime/Interface/IConfigTableAssetBundle.cs.meta new file mode 100644 index 0000000..65579ac --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.ConfigTable/Unity/Runtime/Interface/IConfigTableAssetBundle.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: a819f57dfada43d9955a9b402772cf6d +timeCreated: 1728549292 \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.ConfigTable/Unity/package.json b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.ConfigTable/Unity/package.json new file mode 100644 index 0000000..a07c9b7 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.ConfigTable/Unity/package.json @@ -0,0 +1,23 @@ +{ + "name": "com.fantasy.configtable", + "version": "2024.2.24", + "displayName": "Fantasy.ConfigTable", + "description": "Fantasy is a cross platform distributed server framework.", + "category": "Network Framework", + "documentationUrl": "https://www.code-fantasy.com/", + "changelogUrl": "https://www.code-fantasy.com/", + "licensesUrl": "https://www.code-fantasy.com/", + "keywords": [ + "Fantasy", + "Framework", + "hotfix", + "Server", + "Network" + ], + "author": { + "name": "Fantasy", + "email": "362946@qq.com", + "url": "https://www.code-fantasy.com/" + }, + "dependencies": {} +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.ConfigTable/Unity/package.json.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.ConfigTable/Unity/package.json.meta new file mode 100644 index 0000000..fb85612 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.ConfigTable/Unity/package.json.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: db12b302eec284d61984b0798590173a +PackageManifestImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.MemoryPack/Net/MemoryPack/MemoryPackHelper.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.MemoryPack/Net/MemoryPack/MemoryPackHelper.cs new file mode 100644 index 0000000..e60da3e --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.MemoryPack/Net/MemoryPack/MemoryPackHelper.cs @@ -0,0 +1,212 @@ +using System; +using System.Buffers; +using MemoryPack; + +namespace Fantasy.Serialize +{ + /// + /// MemoryPack帮助类 + /// + public sealed class MemoryPackHelper : ISerialize + { + /// + /// 序列化器的名字 + /// + public string SerializeName { get; } = "MemoryPack"; + + /// + /// 反序列化 + /// + /// + /// + /// + public T Deserialize(byte[] bytes) + { + var @object = MemoryPackSerializer.Deserialize(bytes); + if (@object is ASerialize aSerialize) + { + aSerialize.AfterDeserialization(); + } + + return @object; + } + + /// + /// 反序列化 + /// + /// + /// + /// + public T Deserialize(MemoryStreamBuffer buffer) + { + var @object = MemoryPackSerializer.Deserialize(buffer.GetSpan()); + if (@object is ASerialize aSerialize) + { + aSerialize.AfterDeserialization(); + } + + return @object; + } + + /// + /// 反序列化 + /// + /// + /// + /// + public object Deserialize(Type type, byte[] bytes) + { + var @object = MemoryPackSerializer.Deserialize(type,bytes); + if (@object is ASerialize aSerialize) + { + aSerialize.AfterDeserialization(); + } + + return @object; + } + + /// + /// 反序列化 + /// + /// + /// + /// + public object Deserialize(Type type, MemoryStreamBuffer buffer) + { + var @object = MemoryPackSerializer.Deserialize(type, buffer.GetSpan()); + if (@object is ASerialize aSerialize) + { + aSerialize.AfterDeserialization(); + } + + return @object; + } + + /// + /// 反序列化 + /// + /// + /// + /// + /// + /// + public T Deserialize(byte[] bytes, int index, int count) + { + var @object = MemoryPackSerializer.Deserialize(new ReadOnlySpan(bytes, index, count)); + if (@object is ASerialize aSerialize) + { + aSerialize.AfterDeserialization(); + } + + return @object; + } + + /// + /// 反序列化 + /// + /// + /// + /// + /// + /// + public object Deserialize(Type type, byte[] bytes, int index, int count) + { + var @object = MemoryPackSerializer.Deserialize(type, new ReadOnlySpan(bytes, index, count)); + if (@object is ASerialize aSerialize) + { + aSerialize.AfterDeserialization(); + } + + return @object; + } + + /// + /// 序列化 + /// + /// + /// + /// + public void Serialize(T @object, IBufferWriter buffer) + { + if (@object is ASerialize aSerialize) + { + aSerialize.BeginInit(); + } + + MemoryPackSerializer.Serialize>(buffer, @object); + } + + /// + /// 序列化 + /// + /// + /// + public void Serialize(object @object, IBufferWriter buffer) + { + if (@object is ASerialize aSerialize) + { + aSerialize.BeginInit(); + } + + MemoryPackSerializer.Serialize(@object.GetType(), buffer, @object); + } + + /// + /// 序列化 + /// + /// + /// + /// + public void Serialize(Type type, object @object, IBufferWriter buffer) + { + if (@object is ASerialize aSerialize) + { + aSerialize.BeginInit(); + } + + MemoryPackSerializer.Serialize(type, buffer, @object); + } + + /// + /// 序列化 + /// + /// + /// + public byte[] Serialize(object @object) + { + if (@object is ASerialize aSerialize) + { + aSerialize.BeginInit(); + } + + return MemoryPackSerializer.Serialize(@object.GetType(), @object); + } + + /// + /// 序列化 + /// + /// + /// + /// + public byte[] Serialize(T @object) + { + if (@object is ASerialize aSerialize) + { + aSerialize.BeginInit(); + } + + return MemoryPackSerializer.Serialize(@object); + } + + /// + /// 克隆 + /// + /// + /// + /// + public T Clone(T t) + { + return Deserialize(Serialize(t)); + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.MemoryPack/README.md b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.MemoryPack/README.md new file mode 100644 index 0000000..fe5b775 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.MemoryPack/README.md @@ -0,0 +1,25 @@ +# Fantasy.MemoryPack 扩展包 +## Unity +Unity使用,只需要再Unity文件夹里,导入Fantays.MemoryPack.unitypackage到Unity里即可。 +## Net + * 在你的项目里用Nuget或dotnet add package MemoryPack安装MemoryPack的库。 + * 再Net文件夹里把MemoryPack文件夹拷贝的项目中。 +## Tools +编辑改导表工具ExporterSettings.json文件,在文件Serializes里增加MemoryPack协议的说明. +```json +"Serializes": { + "Value": [ + { + "KeyIndex": 0, + "NameSpace" : "MemoryPack", + "SerializeName": "MemoryPack", + "Attribute": "\t[MemoryPackable]", + "Ignore": "\t\t[MemoryPackIgnore]", + "Member": "MemoryPackOrder" + } + ], + "Comment": "自定义序列化器" + } +``` +## 使用注意 +无论是Unity或Net下,导入所在的项目,必须要把当前程序集装载到框架中才可以。 diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.MemoryPack/Unity/Fantays.MemoryPack.unitypackage b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.MemoryPack/Unity/Fantays.MemoryPack.unitypackage new file mode 100644 index 0000000..eea504b Binary files /dev/null and b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.MemoryPack/Unity/Fantays.MemoryPack.unitypackage differ diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.NLog/Fantasy-Net.NLog.targets b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.NLog/Fantasy-Net.NLog.targets new file mode 100644 index 0000000..9a3ba44 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.NLog/Fantasy-Net.NLog.targets @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + Always + + + + Always + + + + diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.NLog/Fantasy.NLog.csproj b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.NLog/Fantasy.NLog.csproj new file mode 100644 index 0000000..6b3e743 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.NLog/Fantasy.NLog.csproj @@ -0,0 +1,37 @@ + + + + Fantasy-Net.NLog + 2024.1.20 + Fantasy-Net.NLog + qq362946 + qq362946 + ../../nupkg + false + + Fantasy is a high-performance network development framework based on .NET, supporting mainstream protocols. It is designed for development teams or individuals needing a quick start, scalability, and a distributed, cross-platform solution at the commercial level. Fantasy aims to provide easy-to-use tools while ensuring high system performance and scalability. + Copyright 2026 qq362946 + https://www.code-fantasy.com/ + https://github.com/qq362946/Fantasy + git + Net, c#, Server, Game, GameServer, Fantasy , Network + icon.png + net8.0 + enable + enable + Fantasy-Net.NLog + + + + + + + + + + + + + + + diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.NLog/NLog.config b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.NLog/NLog.config new file mode 100644 index 0000000..4df5ea1 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.NLog/NLog.config @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.NLog/NLog.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.NLog/NLog.cs new file mode 100644 index 0000000..efe9672 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.NLog/NLog.cs @@ -0,0 +1,167 @@ +using Fantasy.Platform.Net; +using NLog; + +namespace Fantasy +{ + /// + /// 使用 NLog 实现的日志记录器。 + /// + public class NLog : ILog + { + private readonly Logger _logger; // NLog 日志记录器实例 + + /// + /// 初始化 NLog 实例。 + /// + /// 日志记录器的名称。 + public NLog(string name) + { + // 获取指定名称的 NLog 日志记录器 + _logger = LogManager.GetLogger(name); + } + + /// + /// 初始化方法 + /// + /// + public void Initialize(ProcessMode processMode) + { + // 非Benchmark模式、根据不同的运行模式来选择日志的方式 + switch (processMode) + { + case ProcessMode.Develop: + { + LogManager.Configuration.RemoveRuleByName("ServerDebug"); + LogManager.Configuration.RemoveRuleByName("ServerTrace"); + LogManager.Configuration.RemoveRuleByName("ServerInfo"); + LogManager.Configuration.RemoveRuleByName("ServerWarn"); + LogManager.Configuration.RemoveRuleByName("ServerError"); + break; + } + case ProcessMode.Release: + { + LogManager.Configuration.RemoveRuleByName("ConsoleTrace"); + LogManager.Configuration.RemoveRuleByName("ConsoleDebug"); + LogManager.Configuration.RemoveRuleByName("ConsoleInfo"); + LogManager.Configuration.RemoveRuleByName("ConsoleWarn"); + LogManager.Configuration.RemoveRuleByName("ConsoleError"); + break; + } + } + } + + /// + /// 记录跟踪级别的日志消息。 + /// + /// 日志消息。 + public void Trace(string message) + { + _logger.Trace(message); + } + + /// + /// 记录警告级别的日志消息。 + /// + /// 日志消息。 + public void Warning(string message) + { + _logger.Warn(message); + } + + /// + /// 记录信息级别的日志消息。 + /// + /// 日志消息。 + public void Info(string message) + { + _logger.Info(message); + } + + /// + /// 记录调试级别的日志消息。 + /// + /// 日志消息。 + public void Debug(string message) + { + _logger.Debug(message); + } + + /// + /// 记录错误级别的日志消息。 + /// + /// 日志消息。 + public void Error(string message) + { + _logger.Error(message); + } + + /// + /// 记录严重错误级别的日志消息。 + /// + /// 日志消息。 + public void Fatal(string message) + { + _logger.Fatal(message); + } + + /// + /// 记录跟踪级别的格式化日志消息。 + /// + /// 日志消息模板。 + /// 格式化参数。 + public void Trace(string message, params object[] args) + { + _logger.Trace(message, args); + } + + /// + /// 记录警告级别的格式化日志消息。 + /// + /// 日志消息模板。 + /// 格式化参数。 + public void Warning(string message, params object[] args) + { + _logger.Warn(message, args); + } + + /// + /// 记录信息级别的格式化日志消息。 + /// + /// 日志消息模板。 + /// 格式化参数。 + public void Info(string message, params object[] args) + { + _logger.Info(message, args); + } + + /// + /// 记录调试级别的格式化日志消息。 + /// + /// 日志消息模板。 + /// 格式化参数。 + public void Debug(string message, params object[] args) + { + _logger.Debug(message, args); + } + + /// + /// 记录错误级别的格式化日志消息。 + /// + /// 日志消息模板。 + /// 格式化参数。 + public void Error(string message, params object[] args) + { + _logger.Error(message, args); + } + + /// + /// 记录严重错误级别的格式化日志消息。 + /// + /// 日志消息模板。 + /// 格式化参数。 + public void Fatal(string message, params object[] args) + { + _logger.Fatal(message, args); + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.NLog/NLog.xsd b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.NLog/NLog.xsd new file mode 100644 index 0000000..63c9a0c --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.NLog/NLog.xsd @@ -0,0 +1,3483 @@ + + + + + + + + + + + + + + + Watch config file for changes and reload automatically. + + + + + Print internal NLog messages to the console. Default value is: false + + + + + Print internal NLog messages to the console error output. Default value is: false + + + + + Write internal NLog messages to the specified file. + + + + + Log level threshold for internal log messages. Default value is: Info. + + + + + Global log level threshold for application log messages. Messages below this level won't be logged. + + + + + Throw an exception when there is an internal error. Default value is: false. Not recommend to set to true in production! + + + + + Throw an exception when there is a configuration error. If not set, determined by throwExceptions. + + + + + Gets or sets a value indicating whether Variables should be kept on configuration reload. Default value is: false. + + + + + Write internal NLog messages to the System.Diagnostics.Trace. Default value is: false. + + + + + Write timestamps for internal NLog messages. Default value is: true. + + + + + Use InvariantCulture as default culture instead of CurrentCulture. Default value is: false. + + + + + Perform message template parsing and formatting of LogEvent messages (true = Always, false = Never, empty = Auto Detect). Default value is: empty. + + + + + + + + + + + + + + Make all targets within this section asynchronous (creates additional threads but the calling thread isn't blocked by any target writes). + + + + + + + + + + + + + + + + + Prefix for targets/layout renderers/filters/conditions loaded from this assembly. + + + + + Load NLog extensions from the specified file (*.dll) + + + + + Load NLog extensions from the specified assembly. Assembly name should be fully qualified. + + + + + + + + + + Filter on the name of the logger. May include wildcard characters ('*' or '?'). + + + + + Comma separated list of levels that this rule matches. + + + + + Minimum level that this rule matches. + + + + + Maximum level that this rule matches. + + + + + Level that this rule matches. + + + + + Comma separated list of target names. + + + + + Ignore further rules if this one matches. + + + + + Enable this rule. Note: disabled rules aren't available from the API. + + + + + Rule identifier to allow rule lookup with Configuration.FindRuleByName and Configuration.RemoveRuleByName. + + + + + Loggers matching will be restricted to specified minimum level for following rules. + + + + + + + + + + + + + + + Default action if none of the filters match. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Name of the file to be included. You could use * wildcard. The name is relative to the name of the current config file. + + + + + Ignore any errors in the include file. + + + + + + + + Variable value. Note, the 'value' attribute has precedence over this one. + + + + + + Variable name. + + + + + Variable value. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Action to be taken when the lazy writer thread request queue count exceeds the set limit. + + + + + Limit on the number of requests in the lazy writer thread request queue. + + + + + Number of log events that should be processed in a batch by the lazy writer thread. + + + + + Whether to use the locking queue, instead of a lock-free concurrent queue + + + + + Number of batches of P:NLog.Targets.Wrappers.AsyncTargetWrapper.BatchSize to write before yielding into P:NLog.Targets.Wrappers.AsyncTargetWrapper.TimeToSleepBetweenBatches + + + + + Time in milliseconds to sleep between batches. (1 or less means trigger on new activity) + + + + + + + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Delay the flush until the LogEvent has been confirmed as written + + + + + Condition expression. Log events who meet this condition will cause a flush on the wrapped target. + + + + + Only flush when LogEvent matches condition. Ignore explicit-flush, config-reload-flush and shutdown-flush + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Number of log events to be buffered. + + + + + Action to take if the buffer overflows. + + + + + Timeout (in milliseconds) after which the contents of buffer will be flushed if there's no write in the specified period of time. Use -1 to disable timed flushes. + + + + + Indicates whether to use sliding timeout. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Separator for T:NLog.ScopeContext operation-states-stack. + + + + + Stack separator for log4j:NDC in output from T:NLog.ScopeContext nested context. + + + + + Renderer for log4j:event logger-xml-attribute (Default ${logger}) + + + + + Whether to include the contents of the T:NLog.ScopeContext properties-dictionary. + + + + + Whether to include log4j:NDC in output from T:NLog.ScopeContext nested context. + + + + + Indicates whether to include source info (file name and line number) in the information sent over the network. + + + + + Whether to include log4j:NDC in output from T:NLog.ScopeContext nested context. + + + + + Option to include all properties from the log events + + + + + Indicates whether to include call site (class and method name) in the information sent over the network. + + + + + AppInfo field. By default it's the friendly name of the current AppDomain. + + + + + Instance of T:NLog.Layouts.Log4JXmlEventLayout that is used to format log messages. + + + + + Indicates whether to include NLog-specific extensions to log4j schema. + + + + + Action that should be taken, when more connections than P:NLog.Targets.NetworkTarget.MaxConnections. + + + + + SSL/TLS protocols. Default no SSL/TLS is used. Currently only implemented for TCP. + + + + + Action that should be taken, when more pending messages than P:NLog.Targets.NetworkTarget.MaxQueueSize. + + + + + Action that should be taken if the message is larger than P:NLog.Targets.NetworkTarget.MaxMessageSize + + + + + Maximum queue size for a single connection. Requires P:NLog.Targets.NetworkTarget.KeepConnection = true + + + + + Network address. + + + + + Indicates whether to keep connection open whenever possible. + + + + + The number of seconds a connection will remain idle before the first keep-alive probe is sent + + + + + Size of the connection cache (number of connections which are kept alive). Requires P:NLog.Targets.NetworkTarget.KeepConnection = true + + + + + Maximum simultaneous connections. Requires P:NLog.Targets.NetworkTarget.KeepConnection = false + + + + + Type of compression for protocol payload. Useful for UDP where datagram max-size is 8192 bytes. + + + + + Skip compression when protocol payload is below limit to reduce overhead in cpu-usage and additional headers + + + + + Maximum message size in bytes. On limit breach then P:NLog.Targets.NetworkTarget.OnOverflow action is activated. + + + + + Encoding to be used. + + + + + End of line value if a newline is appended at the end of log message P:NLog.Targets.NetworkTarget.NewLine. + + + + + Indicates whether to append newline at the end of log message. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Viewer parameter name. + + + + + Layout that should be use to calculate the value for the parameter. + + + + + Whether an attribute with empty value should be included in the output + + + + + + + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Text to be rendered. + + + + + Header. + + + + + Footer. + + + + + Indicates whether to auto-check if the console is available. - Disables console writing if Environment.UserInteractive = False (Windows Service) - Disables console writing if Console Standard Input is not available (Non-Console-App) + + + + + Enables output using ANSI Color Codes + + + + + The encoding for writing messages to the T:System.Console. + + + + + Indicates whether to send the log messages to the standard error instead of the standard output. + + + + + Indicates whether to auto-flush after M:System.Console.WriteLine + + + + + Indicates whether to auto-check if the console has been redirected to file - Disables coloring logic when System.Console.IsOutputRedirected = true + + + + + Indicates whether to use default row highlighting rules. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Background color. + + + + + Condition that must be met in order to set the specified foreground and background color. + + + + + Foreground color. + + + + + + + + + + + + + + + + + Background color. + + + + + Compile the P:NLog.Targets.ConsoleWordHighlightingRule.Regex? This can improve the performance, but at the costs of more memory usage. If false, the Regex Cache is used. + + + + + Condition that must be met before scanning the row for highlight of words + + + + + Foreground color. + + + + + Indicates whether to ignore case when comparing texts. + + + + + Regular expression to be matched. You must specify either text or regex. + + + + + Text to be matched. You must specify either text or regex. + + + + + Indicates whether to match whole words only. + + + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Text to be rendered. + + + + + Header. + + + + + Footer. + + + + + Indicates whether to auto-flush after M:System.Console.WriteLine + + + + + Indicates whether to auto-check if the console is available - Disables console writing if Environment.UserInteractive = False (Windows Service) - Disables console writing if Console Standard Input is not available (Non-Console-App) + + + + + The encoding for writing messages to the T:System.Console. + + + + + Indicates whether to send the log messages to the standard error instead of the standard output. + + + + + Whether to activate internal buffering to allow batch writing, instead of using M:System.Console.WriteLine + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Database user name. If the ConnectionString is not provided this value will be used to construct the "User ID=" part of the connection string. + + + + + Database password. If the ConnectionString is not provided this value will be used to construct the "Password=" part of the connection string. + + + + + Database name. If the ConnectionString is not provided this value will be used to construct the "Database=" part of the connection string. + + + + + Name of the connection string (as specified in <connectionStrings> configuration section. + + + + + Database host name. If the ConnectionString is not provided this value will be used to construct the "Server=" part of the connection string. + + + + + Indicates whether to keep the database connection open between the log events. + + + + + Name of the database provider. + + + + + Connection string. When provided, it overrides the values specified in DBHost, DBUserName, DBPassword, DBDatabase. + + + + + Connection string using for installation and uninstallation. If not provided, regular ConnectionString is being used. + + + + + Configures isolated transaction batch writing. If supported by the database, then it will improve insert performance. + + + + + Text of the SQL command to be run on each log level. + + + + + Type of the SQL command to be run on each log level. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Convert format of the property value + + + + + Culture used for parsing property string-value for type-conversion + + + + + Value to assign on the object-property + + + + + Name for the object-property + + + + + Type of the object-property + + + + + + + + + + + + + + Type of the command. + + + + + Connection string to run the command against. If not provided, connection string from the target is used. + + + + + Indicates whether to ignore failures. + + + + + Command text. + + + + + + + + + + + + + + + + + + + + Database parameter name. + + + + + Layout that should be use to calculate the value for the parameter. + + + + + Database parameter DbType. + + + + + Database parameter size. + + + + + Database parameter precision. + + + + + Database parameter scale. + + + + + Type of the parameter. + + + + + Fallback value when result value is not available + + + + + Convert format of the database parameter value. + + + + + Culture used for parsing parameter string-value for type-conversion + + + + + Whether empty value should translate into DbNull. Requires database column to allow NULL values. + + + + + + + + + + + + + + + Name of the target. + + + + + Text to be rendered. + + + + + Header. + + + + + Footer. + + + + + + + + + + + + + + + + + Name of the target. + + + + + Text to be rendered. + + + + + Header. + + + + + Footer. + + + + + + + + + + + + + + + Name of the target. + + + + + Layout used to format log messages. + + + + + + + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Layout used to format log messages. + + + + + Layout that renders event Category. + + + + + Optional entry type. When not set, or when not convertible to T:System.Diagnostics.EventLogEntryType then determined by T:NLog.LogLevel + + + + + Layout that renders event ID. + + + + + Name of the Event Log to write to. This can be System, Application or any user-defined name. + + + + + Name of the machine on which Event Log service is running. + + + + + Maximum Event log size in kilobytes. + + + + + Message length limit to write to the Event Log. + + + + + Value to be used as the event Source. + + + + + Action to take if the message is larger than the P:NLog.Targets.EventLogTarget.MaxMessageLength option. + + + + + + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Indicates whether to return to the first target after any successful write. + + + + + Whether to enable batching, but fallback will be handled individually + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Name of the file to write to. + + + + + Text to be rendered. + + + + + Header. + + + + + Footer. + + + + + Indicates whether the footer should be written only when the file is archived. + + + + + Maximum number of archive files that should be kept. + + + + + Maximum days of archive files that should be kept. + + + + + Value of the file size threshold to archive old log file on startup. + + + + + Indicates whether to archive old log file on startup. + + + + + Indicates whether to compress archive files into the zip archive format. + + + + + Name of the file to be used for an archive. + + + + + Is the P:NLog.Targets.FileTarget.ArchiveFileName an absolute or relative path? + + + + + Indicates whether to automatically archive log files every time the specified time passes. + + + + + Value specifying the date format to use when archiving files. + + + + + Size in bytes above which log files will be automatically archived. + + + + + Way file archives are numbered. + + + + + Indicates whether to create directories if they do not exist. + + + + + Indicates whether file creation calls should be synchronized by a system global mutex. + + + + + Gets or set a value indicating whether a managed file stream is forced, instead of using the native implementation. + + + + + Is the P:NLog.Targets.FileTarget.FileName an absolute or relative path? + + + + + File attributes (Windows only). + + + + + Cleanup invalid values in a filename, e.g. slashes in a filename. If set to true, this can impact the performance of massive writes. If set to false, nothing gets written when the filename is wrong. + + + + + Indicates whether to write BOM (byte order mark) in created files. Defaults to true for UTF-16 and UTF-32 + + + + + Indicates whether to enable log file(s) to be deleted. + + + + + Indicates whether to delete old log file on startup. + + + + + File encoding. + + + + + Indicates whether to replace file contents on each write instead of appending log message at the end. + + + + + Line ending mode. + + + + + Number of times the write is appended on the file before NLog discards the log message. + + + + + Delay in milliseconds to wait before attempting to write to the file again. + + + + + Maximum number of seconds before open files are flushed. Zero or negative means disabled. + + + + + Maximum number of seconds that files are kept open. Zero or negative means disabled. + + + + + Indicates whether concurrent writes to the log file by multiple processes on different network hosts. + + + + + Log file buffer size in bytes. + + + + + Indicates whether to automatically flush the file buffers after each log message. + + + + + Indicates whether to keep log file open instead of opening and closing it on each logging event. + + + + + Indicates whether concurrent writes to the log file by multiple processes on the same host. + + + + + Whether or not this target should just discard all data that its asked to write. Mostly used for when testing NLog Stack except final write + + + + + Number of files to be kept open. Setting this to a higher value may improve performance in a situation where a single File target is writing to many files (such as splitting by level or by logger). + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Condition expression. Log events who meet this condition will be forwarded to the wrapped target. + + + + + + + + + + + + + + + Name of the target. + + + + + Identifier to perform group-by + + + + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Windows domain name to change context to. + + + + + Required impersonation level. + + + + + Type of the logon provider. + + + + + Logon Type. + + + + + User account password. + + + + + Indicates whether to revert to the credentials of the process instead of impersonating another user. + + + + + Username to change context to. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Interval in which messages will be written up to the P:NLog.Targets.Wrappers.LimitingTargetWrapper.MessageLimit number of messages. + + + + + Maximum allowed number of messages written per P:NLog.Targets.Wrappers.LimitingTargetWrapper.Interval. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Text to be rendered. + + + + + Header. + + + + + Footer. + + + + + Indicates whether NewLine characters in the body should be replaced with tags. + + + + + Priority used for sending mails. + + + + + Encoding to be used for sending e-mail. + + + + + BCC email addresses separated by semicolons (e.g. john@domain.com;jane@domain.com). + + + + + CC email addresses separated by semicolons (e.g. john@domain.com;jane@domain.com). + + + + + Indicates whether to add new lines between log entries. + + + + + Indicates whether to send message as HTML instead of plain text. + + + + + Sender's email address (e.g. joe@domain.com). + + + + + Mail message body (repeated for each log message send in one mail). + + + + + Mail subject. + + + + + Recipients' email addresses separated by semicolons (e.g. john@domain.com;jane@domain.com). + + + + + Specifies how outgoing email messages will be handled. + + + + + SMTP Server to be used for sending. + + + + + SMTP Authentication mode. + + + + + Username used to connect to SMTP server (used when SmtpAuthentication is set to "basic"). + + + + + Password used to authenticate against SMTP server (used when SmtpAuthentication is set to "basic"). + + + + + Indicates whether SSL (secure sockets layer) should be used when communicating with SMTP server. + + + + + Port number that SMTP Server is listening on. + + + + + Indicates whether the default Settings from System.Net.MailSettings should be used. + + + + + Folder where applications save mail messages to be processed by the local SMTP server. + + + + + Indicates the SMTP client timeout. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Text to be rendered. + + + + + Header. + + + + + Footer. + + + + + Max number of items to have in memory + + + + + + + + + + + + + + + + + Name of the target. + + + + + Class name. + + + + + Method name. The method must be public and static. Use the AssemblyQualifiedName , https://msdn.microsoft.com/en-us/library/system.type.assemblyqualifiedname(v=vs.110).aspx e.g. + + + + + + + + + + + + + + + Name of the parameter. + + + + + Layout that should be use to calculate the value for the parameter. + + + + + Fallback value when result value is not available + + + + + Type of the parameter. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Layout used to format log messages. + + + + + SSL/TLS protocols. Default no SSL/TLS is used. Currently only implemented for TCP. + + + + + Action that should be taken, when more pending messages than P:NLog.Targets.NetworkTarget.MaxQueueSize. + + + + + Action that should be taken if the message is larger than P:NLog.Targets.NetworkTarget.MaxMessageSize + + + + + Maximum queue size for a single connection. Requires P:NLog.Targets.NetworkTarget.KeepConnection = true + + + + + Action that should be taken, when more connections than P:NLog.Targets.NetworkTarget.MaxConnections. + + + + + Indicates whether to keep connection open whenever possible. + + + + + The number of seconds a connection will remain idle before the first keep-alive probe is sent + + + + + Size of the connection cache (number of connections which are kept alive). Requires P:NLog.Targets.NetworkTarget.KeepConnection = true + + + + + Network address. + + + + + Maximum simultaneous connections. Requires P:NLog.Targets.NetworkTarget.KeepConnection = false + + + + + Type of compression for protocol payload. Useful for UDP where datagram max-size is 8192 bytes. + + + + + Skip compression when protocol payload is below limit to reduce overhead in cpu-usage and additional headers + + + + + Maximum message size in bytes. On limit breach then P:NLog.Targets.NetworkTarget.OnOverflow action is activated. + + + + + Encoding to be used. + + + + + End of line value if a newline is appended at the end of log message P:NLog.Targets.NetworkTarget.NewLine. + + + + + Indicates whether to append newline at the end of log message. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Separator for T:NLog.ScopeContext operation-states-stack. + + + + + Stack separator for log4j:NDC in output from T:NLog.ScopeContext nested context. + + + + + Renderer for log4j:event logger-xml-attribute (Default ${logger}) + + + + + Whether to include the contents of the T:NLog.ScopeContext properties-dictionary. + + + + + Whether to include log4j:NDC in output from T:NLog.ScopeContext nested context. + + + + + Indicates whether to include source info (file name and line number) in the information sent over the network. + + + + + Whether to include log4j:NDC in output from T:NLog.ScopeContext nested context. + + + + + Option to include all properties from the log events + + + + + Indicates whether to include call site (class and method name) in the information sent over the network. + + + + + AppInfo field. By default it's the friendly name of the current AppDomain. + + + + + Instance of T:NLog.Layouts.Log4JXmlEventLayout that is used to format log messages. + + + + + Indicates whether to include NLog-specific extensions to log4j schema. + + + + + Action that should be taken, when more connections than P:NLog.Targets.NetworkTarget.MaxConnections. + + + + + SSL/TLS protocols. Default no SSL/TLS is used. Currently only implemented for TCP. + + + + + Action that should be taken, when more pending messages than P:NLog.Targets.NetworkTarget.MaxQueueSize. + + + + + Action that should be taken if the message is larger than P:NLog.Targets.NetworkTarget.MaxMessageSize + + + + + Maximum queue size for a single connection. Requires P:NLog.Targets.NetworkTarget.KeepConnection = true + + + + + Network address. + + + + + Indicates whether to keep connection open whenever possible. + + + + + The number of seconds a connection will remain idle before the first keep-alive probe is sent + + + + + Size of the connection cache (number of connections which are kept alive). Requires P:NLog.Targets.NetworkTarget.KeepConnection = true + + + + + Maximum simultaneous connections. Requires P:NLog.Targets.NetworkTarget.KeepConnection = false + + + + + Type of compression for protocol payload. Useful for UDP where datagram max-size is 8192 bytes. + + + + + Skip compression when protocol payload is below limit to reduce overhead in cpu-usage and additional headers + + + + + Maximum message size in bytes. On limit breach then P:NLog.Targets.NetworkTarget.OnOverflow action is activated. + + + + + Encoding to be used. + + + + + End of line value if a newline is appended at the end of log message P:NLog.Targets.NetworkTarget.NewLine. + + + + + Indicates whether to append newline at the end of log message. + + + + + + + + + + + + + + + + Name of the target. + + + + + Layout used to format log messages. + + + + + Indicates whether to perform layout calculation. + + + + + + + + + + + + + + + + Name of the target. + + + + + Default filter to be applied when no specific rule matches. + + + + + + + + + + + + + Condition to be tested. + + + + + Resulting filter to be applied when the condition matches. + + + + + + + + + + + + Name of the target. + + + + + + + + + + + + + + + Name of the target. + + + + + Number of times to repeat each log message. + + + + + + + + + + + + + + + + + Name of the target. + + + + + Whether to enable batching, and only apply single delay when a whole batch fails + + + + + Number of retries that should be attempted on the wrapped target in case of a failure. + + + + + Time to wait between retries in milliseconds. + + + + + + + + + + + + + + Name of the target. + + + + + + + + + + + + + + Name of the target. + + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Text to be rendered. + + + + + Header. + + + + + Footer. + + + + + Forward F:NLog.LogLevel.Fatal to M:System.Diagnostics.Trace.Fail(System.String) (Instead of M:System.Diagnostics.Trace.TraceError(System.String)) + + + + + Force use M:System.Diagnostics.Trace.WriteLine(System.String) independent of T:NLog.LogLevel + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Indicates whether to pre-authenticate the HttpWebRequest (Requires 'Authorization' in P:NLog.Targets.WebServiceTarget.Headers parameters) + + + + + Value whether escaping be done according to Rfc3986 (Supports Internationalized Resource Identifiers - IRIs) + + + + + Value whether escaping be done according to the old NLog style (Very non-standard) + + + + + Value of the User-agent HTTP header. + + + + + Web service URL. + + + + + Proxy configuration when calling web service + + + + + Custom proxy address, include port separated by a colon + + + + + Protocol to be used when calling web service. + + + + + Web service namespace. Only used with Soap. + + + + + Web service method name. Only used with Soap. + + + + + Should we include the BOM (Byte-order-mark) for UTF? Influences the P:NLog.Targets.WebServiceTarget.Encoding property. This will only work for UTF-8. + + + + + Encoding. + + + + + Name of the root XML element, if POST of XML document chosen. If so, this property must not be null. (see P:NLog.Targets.WebServiceTarget.Protocol and F:NLog.Targets.WebServiceProtocol.XmlPost). + + + + + (optional) root namespace of the XML document, if POST of XML document chosen. (see P:NLog.Targets.WebServiceTarget.Protocol and F:NLog.Targets.WebServiceProtocol.XmlPost). + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Custom column delimiter value (valid when ColumnDelimiter is set to 'Custom'). + + + + + Column delimiter. + + + + + Footer layout. + + + + + Header layout. + + + + + Body layout (can be repeated multiple times). + + + + + Quote Character. + + + + + Quoting mode. + + + + + Indicates whether CVS should include header. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Name of the column. + + + + + Layout of the column. + + + + + Override of Quoting mode + + + + + + + + + + + + + + Option to render the empty object value {} + + + + + Option to suppress the extra spaces in the output json + + + + + + + + + + + + + + + + + + + + + + + Option to include all properties from the log event (as JSON) + + + + + Indicates whether to include contents of the T:NLog.GlobalDiagnosticsContext dictionary. + + + + + Whether to include the contents of the T:NLog.ScopeContext dictionary. + + + + + Should forward slashes be escaped? If true, / will be converted to \/ + + + + + Option to exclude null/empty properties from the log event (as JSON) + + + + + List of property names to exclude when P:NLog.Layouts.JsonLayout.IncludeAllProperties is true + + + + + How far should the JSON serializer follow object references before backing off + + + + + Option to render the empty object value {} + + + + + Option to suppress the extra spaces in the output json + + + + + + + + + + + + + + + + + + + Name of the attribute. + + + + + Layout that will be rendered as the attribute's value. + + + + + Fallback value when result value is not available + + + + + Determines whether or not this attribute will be Json encoded. + + + + + Should forward slashes be escaped? If true, / will be converted to \/ + + + + + Indicates whether to escape non-ascii characters + + + + + Whether an attribute with empty value should be included in the output + + + + + Result value type, for conversion of layout rendering output + + + + + + + + + + + + + + Footer layout. + + + + + Header layout. + + + + + Body layout (can be repeated multiple times). + + + + + + + + + + + + + + + + + + + + + + + Option to include all properties from the log events + + + + + Whether to include log4j:NDC in output from T:NLog.ScopeContext nested context. + + + + + Whether to include log4j:NDC in output from T:NLog.ScopeContext nested context. + + + + + Whether to include the contents of the T:NLog.ScopeContext properties-dictionary. + + + + + AppInfo field. By default it's the friendly name of the current AppDomain. + + + + + Indicates whether to include call site (class and method name) in the information sent over the network. + + + + + Indicates whether to include source info (file name and line number) in the information sent over the network. + + + + + Log4j:event logger-xml-attribute (Default ${logger}) + + + + + Whether the log4j:throwable xml-element should be written as CDATA + + + + + + + + + + + + + + Layout text. + + + + + + + + + + + + + + + + + + + + + + + + + + + + Name of the root XML element + + + + + Value inside the root XML element + + + + + Whether to include the contents of the T:NLog.ScopeContext dictionary. + + + + + Determines whether or not this attribute will be Xml encoded. + + + + + List of property names to exclude when P:NLog.Layouts.XmlElementBase.IncludeAllProperties is true + + + + + Whether a ElementValue with empty value should be included in the output + + + + + Auto indent and create new lines + + + + + How far should the XML serializer follow object references before backing off + + + + + XML element name to use for rendering IList-collections items + + + + + XML attribute name to use when rendering property-key When null (or empty) then key-attribute is not included + + + + + XML element name to use when rendering properties + + + + + XML attribute name to use when rendering property-value When null (or empty) then value-attribute is not included and value is formatted as XML-element-value + + + + + Option to include all properties from the log event (as XML) + + + + + + + + + + + + + + + + + Name of the attribute. + + + + + Layout that will be rendered as the attribute's value. + + + + + Fallback value when result value is not available + + + + + Determines whether or not this attribute will be Xml encoded. + + + + + Whether an attribute with empty value should be included in the output + + + + + Result value type, for conversion of layout rendering output + + + + + + + + + + + + + + + + + + + + + + + + Name of the element + + + + + Whether to include the contents of the T:NLog.ScopeContext dictionary. + + + + + Value inside the element + + + + + Determines whether or not this attribute will be Xml encoded. + + + + + List of property names to exclude when P:NLog.Layouts.XmlElementBase.IncludeAllProperties is true + + + + + Whether a ElementValue with empty value should be included in the output + + + + + Auto indent and create new lines + + + + + How far should the XML serializer follow object references before backing off + + + + + XML element name to use for rendering IList-collections items + + + + + XML attribute name to use when rendering property-key When null (or empty) then key-attribute is not included + + + + + XML element name to use when rendering properties + + + + + XML attribute name to use when rendering property-value When null (or empty) then value-attribute is not included and value is formatted as XML-element-value + + + + + Option to include all properties from the log event (as XML) + + + + + + + + + + + + + Action to be taken when filter matches. + + + + + Condition expression. + + + + + + + + + + + + + + + + + + + + + + + + + + Action to be taken when filter matches. + + + + + Indicates whether to ignore case when comparing strings. + + + + + Layout to be used to filter log messages. + + + + + Substring to be matched. + + + + + + + + + + + + + + + + + Action to be taken when filter matches. + + + + + String to compare the layout to. + + + + + Indicates whether to ignore case when comparing strings. + + + + + Layout to be used to filter log messages. + + + + + + + + + + + + + + + + + Action to be taken when filter matches. + + + + + Indicates whether to ignore case when comparing strings. + + + + + Layout to be used to filter log messages. + + + + + Substring to be matched. + + + + + + + + + + + + + + + + + Action to be taken when filter matches. + + + + + String to compare the layout to. + + + + + Indicates whether to ignore case when comparing strings. + + + + + Layout to be used to filter log messages. + + + + + + + + + + + + + + + + + + + + + + + Action to be taken when filter matches. + + + + + Append FilterCount to the P:NLog.LogEventInfo.Message when an event is no longer filtered + + + + + Insert FilterCount value into P:NLog.LogEventInfo.Properties when an event is no longer filtered + + + + + Applies the configured action to the initial logevent that starts the timeout period. Used to configure that it should ignore all events until timeout. + + + + + Layout to be used to filter log messages. + + + + + Max length of filter values, will truncate if above limit + + + + + How long before a filter expires, and logging is accepted again + + + + + Default number of unique filter values to expect, will automatically increase if needed + + + + + Max number of unique filter values to expect simultaneously + + + + + Default buffer size for the internal buffers + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.NLog/icon.png b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.NLog/icon.png new file mode 100644 index 0000000..8ae7488 Binary files /dev/null and b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Packages/Fantasy.NLog/icon.png differ diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Editor.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Editor.meta new file mode 100644 index 0000000..9ca6c08 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Editor.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 6deb0dcf8adbd4f8f92d5482999b05bf +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Editor/Runtime.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Editor/Runtime.meta new file mode 100644 index 0000000..de03432 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Editor/Runtime.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e8ba5b17cffbb4ffea892f674fc8629f +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Editor/Runtime/CheckUnityVersion.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Editor/Runtime/CheckUnityVersion.cs new file mode 100644 index 0000000..34f112c --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Editor/Runtime/CheckUnityVersion.cs @@ -0,0 +1,16 @@ +using System; +using UnityEditor; + +namespace Fantasy +{ + internal static class CheckUnityVersion + { + [InitializeOnLoadMethod] + private static void OnInitializeOnLoad() + { +#if !UNITY_2021_3_OR_NEWER + Debug.LogError("Fantasy支持的最低版本为Unity2021.3.14f1c1"); +#endif + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Editor/Runtime/CheckUnityVersion.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Editor/Runtime/CheckUnityVersion.cs.meta new file mode 100644 index 0000000..1f13ace --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Editor/Runtime/CheckUnityVersion.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 455f338921e74471841971fd6b79db01 +timeCreated: 1725943424 \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Editor/Runtime/Fantasy.Editor.asmdef b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Editor/Runtime/Fantasy.Editor.asmdef new file mode 100644 index 0000000..b6ddabb --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Editor/Runtime/Fantasy.Editor.asmdef @@ -0,0 +1,18 @@ +{ + "name": "Fantasy.Editor", + "rootNamespace": "", + "references": [ + "GUID:0b7224b83ba514121aa026f3857f820a" + ], + "includePlatforms": [ + "Editor" + ], + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": false, + "precompiledReferences": [], + "autoReferenced": true, + "defineConstraints": [], + "versionDefines": [], + "noEngineReferences": false +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Editor/Runtime/Fantasy.Editor.asmdef.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Editor/Runtime/Fantasy.Editor.asmdef.meta new file mode 100644 index 0000000..d5a4e8b --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Editor/Runtime/Fantasy.Editor.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 36410968656dd49358af485aad0b0c4c +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Editor/Runtime/FantasyStartup.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Editor/Runtime/FantasyStartup.cs new file mode 100644 index 0000000..c541657 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Editor/Runtime/FantasyStartup.cs @@ -0,0 +1,49 @@ +using System.IO; +using UnityEditor; +using UnityEngine; + +namespace Fantasy +{ + [InitializeOnLoad] + public static class FantasyStartup + { + private const string ScriptAssemblies = "Library/ScriptAssemblies/"; + + static FantasyStartup() + { + if (!FantasySettingsScriptableObject.Instance.autoCopyAssembly) + { + return; + } + + var hotUpdatePath = FantasySettingsScriptableObject.Instance.hotUpdatePath; + + if (string.IsNullOrEmpty(hotUpdatePath)) + { + Debug.LogError("请先在菜单Fantasy-Fantasy Settings里设置HotUpdatePath目录位置"); + return; + } + + if (!Directory.Exists(hotUpdatePath)) + { + Directory.CreateDirectory(hotUpdatePath); + } + + // ReSharper disable once StringLastIndexOfIsCultureSpecific.1 + if (hotUpdatePath.LastIndexOf("/") != hotUpdatePath.Length - 1) + { + FantasySettingsScriptableObject.Instance.hotUpdatePath += "/"; + hotUpdatePath = FantasySettingsScriptableObject.Instance.hotUpdatePath; + } + + foreach (var instanceHotUpdateAssemblyDefinition in FantasySettingsScriptableObject.Instance.hotUpdateAssemblyDefinitions) + { + var dll = instanceHotUpdateAssemblyDefinition.name; + File.Copy($"{ScriptAssemblies}{dll}.dll", $"{hotUpdatePath}/{dll}.dll.bytes", true); + File.Copy($"{ScriptAssemblies}{dll}.pdb", $"{hotUpdatePath}/{dll}.pdb.bytes", true); + } + + AssetDatabase.Refresh(); + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Editor/Runtime/FantasyStartup.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Editor/Runtime/FantasyStartup.cs.meta new file mode 100644 index 0000000..abcd77d --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Editor/Runtime/FantasyStartup.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 42156ba2865a4aa4a3e1e57b3ac9b984 +timeCreated: 1688276977 \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Editor/Runtime/LinkXmlGenerator.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Editor/Runtime/LinkXmlGenerator.cs new file mode 100644 index 0000000..4cfbda8 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Editor/Runtime/LinkXmlGenerator.cs @@ -0,0 +1,49 @@ +using System.IO; +using UnityEditor; +using UnityEngine; + +namespace Fantasy +{ + public class LinkXmlGenerator + { + private const string LinkPath = "Assets/link.xml"; + // 在Unity编辑器中运行该方法来生成link.xml文件 + [UnityEditor.MenuItem("Fantasy/Generate link.xml")] + public static void GenerateLinkXml() + { + using (var writer = new StreamWriter("Assets/link.xml")) + { + writer.WriteLine(""); + GenerateLinkXml(writer, "Assembly-CSharp", LinkPath); + Debug.Log("Assembly-CSharp Link generation completed"); + GenerateLinkXml(writer, "Fantasy.Unity", LinkPath); + Debug.Log("Fantasy.Unity Link generation completed"); + if (FantasySettingsScriptableObject.Instance?.linkAssemblyDefinitions != null) + { + foreach (var linkAssembly in FantasySettingsScriptableObject.Instance.linkAssemblyDefinitions) + { + GenerateLinkXml(writer, linkAssembly.name, LinkPath); + Debug.Log($"{linkAssembly.name} Link generation completed"); + } + } + writer.WriteLine(""); + } + + AssetDatabase.Refresh(); + Debug.Log("link.xml generated successfully!"); + } + + private static void GenerateLinkXml(StreamWriter writer, string assemblyName, string outputPath) + { + var assembly = System.Reflection.Assembly.Load(assemblyName); + var types = assembly.GetTypes(); + writer.WriteLine($" "); + foreach (var type in types) + { + var typeName = type.FullName.Replace('<', '+').Replace('>', '+'); + writer.WriteLine($" "); + } + writer.WriteLine(" "); + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Editor/Runtime/LinkXmlGenerator.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Editor/Runtime/LinkXmlGenerator.cs.meta new file mode 100644 index 0000000..dbab220 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Editor/Runtime/LinkXmlGenerator.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: cda4c9403de946df9c31654416193a21 +timeCreated: 1722743236 \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Editor/Runtime/Settings.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Editor/Runtime/Settings.meta new file mode 100644 index 0000000..6b097c8 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Editor/Runtime/Settings.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 3a6997d946f3400e8c423fe1b9245f65 +timeCreated: 1688277110 \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Editor/Runtime/Settings/FantasySettings.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Editor/Runtime/Settings/FantasySettings.cs new file mode 100644 index 0000000..4c85dc7 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Editor/Runtime/Settings/FantasySettings.cs @@ -0,0 +1,13 @@ +using UnityEditor; + +namespace Fantasy +{ + public class FantasySettings + { + [MenuItem("Fantasy/Fantasy Settings")] + public static void OpenFantasySettings() + { + SettingsService.OpenProjectSettings("Project/Fantasy Settings"); + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Editor/Runtime/Settings/FantasySettings.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Editor/Runtime/Settings/FantasySettings.cs.meta new file mode 100644 index 0000000..852e825 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Editor/Runtime/Settings/FantasySettings.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 977a7c172c30403da60286ba39b7bc72 +timeCreated: 1686913667 \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Editor/Runtime/Settings/FantasySettingsProvider.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Editor/Runtime/Settings/FantasySettingsProvider.cs new file mode 100644 index 0000000..d151144 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Editor/Runtime/Settings/FantasySettingsProvider.cs @@ -0,0 +1,99 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Reflection; +using UnityEditor; +using UnityEngine; +using UnityEngine.UIElements; + +namespace Fantasy +{ + public class FantasySettingsProvider : SettingsProvider + { + private SerializedObject _serializedObject; + private SerializedProperty _autoCopyAssembly; + private SerializedProperty _hotUpdatePath; + private SerializedProperty _hotUpdateAssemblyDefinitions; + private SerializedProperty _linkAssemblyDefinitions; + public FantasySettingsProvider() : base("Project/Fantasy Settings", SettingsScope.Project) { } + + public override void OnActivate(string searchContext, VisualElement rootElement) + { + Init(); + base.OnActivate(searchContext, rootElement); + } + + public override void OnDeactivate() + { + base.OnDeactivate(); + FantasySettingsScriptableObject.Save(); + } + + private void Init() + { + _serializedObject?.Dispose(); + _serializedObject = new SerializedObject(FantasySettingsScriptableObject.Instance); + _autoCopyAssembly = _serializedObject.FindProperty("autoCopyAssembly"); + _hotUpdatePath = _serializedObject.FindProperty("hotUpdatePath"); + _hotUpdateAssemblyDefinitions = _serializedObject.FindProperty("hotUpdateAssemblyDefinitions"); + _linkAssemblyDefinitions = _serializedObject.FindProperty("linkAssemblyDefinitions"); + } + + public override void OnGUI(string searchContext) + { + if (_serializedObject == null || !_serializedObject.targetObject) + { + Init(); + } + + using (CreateSettingsWindowGUIScope()) + { + _serializedObject!.Update(); + + EditorGUI.BeginChangeCheck(); + EditorGUILayout.PropertyField(_autoCopyAssembly); + EditorGUILayout.PropertyField(_hotUpdatePath); + EditorGUILayout.PropertyField(_hotUpdateAssemblyDefinitions); + EditorGUILayout.PropertyField(_linkAssemblyDefinitions); + EditorGUILayout.HelpBox("默认包括Assembly-CSharp和Fantasy.Unity,所以不需要再次指定。", MessageType.Info); + + if (GUILayout.Button("GenerateLinkXml")) + { + LinkXmlGenerator.GenerateLinkXml(); + } + + if (EditorGUI.EndChangeCheck()) + { + _serializedObject.ApplyModifiedProperties(); + FantasySettingsScriptableObject.Save(); + EditorApplication.RepaintHierarchyWindow(); + } + + base.OnGUI(searchContext); + } + } + + private IDisposable CreateSettingsWindowGUIScope() + { + var unityEditorAssembly = System.Reflection.Assembly.GetAssembly(typeof(EditorWindow)); + var type = unityEditorAssembly.GetType("UnityEditor.SettingsWindow+GUIScope"); + return Activator.CreateInstance(type) as IDisposable; + } + + static FantasySettingsProvider _provider; + + [SettingsProvider] + public static SettingsProvider CreateMyCustomSettingsProvider() + { + if (FantasySettingsScriptableObject.Instance && _provider == null) + { + _provider = new FantasySettingsProvider(); + using (var so = new SerializedObject(FantasySettingsScriptableObject.Instance)) + { + _provider.keywords = GetSearchKeywordsFromSerializedObject(so); + } + } + return _provider; + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Editor/Runtime/Settings/FantasySettingsProvider.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Editor/Runtime/Settings/FantasySettingsProvider.cs.meta new file mode 100644 index 0000000..72e475d --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Editor/Runtime/Settings/FantasySettingsProvider.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 047b2f13e73f413fa000bf7be979fb4a +timeCreated: 1688380387 \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Editor/Runtime/Settings/FantasySettingsScriptableObject.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Editor/Runtime/Settings/FantasySettingsScriptableObject.cs new file mode 100644 index 0000000..919285b --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Editor/Runtime/Settings/FantasySettingsScriptableObject.cs @@ -0,0 +1,21 @@ +using UnityEditorInternal; +using UnityEngine; +using UnityEngine.Serialization; + +namespace Fantasy +{ + [ScriptableObjectPath("ProjectSettings/FantasySettings.asset")] + public class FantasySettingsScriptableObject : ScriptableObjectSingleton, ISerializationCallbackReceiver + { + [FormerlySerializedAs("AutoCopyAssembly")] [Header("自动拷贝程序集到HotUpdatePath目录中")] + public bool autoCopyAssembly = false; + [FormerlySerializedAs("HotUpdatePath")] [Header("HotUpdate目录(Unity编译后会把所有HotUpdate程序集Copy一份到这个目录下)")] + public string hotUpdatePath; + [FormerlySerializedAs("HotUpdateAssemblyDefinitions")] [Header("HotUpdate程序集")] + public AssemblyDefinitionAsset[] hotUpdateAssemblyDefinitions; + [FormerlySerializedAs("LinkAssemblyDefinitions")] [Header("生成Link.xml的程序集")] + public AssemblyDefinitionAsset[] linkAssemblyDefinitions; + public void OnBeforeSerialize() { } + public void OnAfterDeserialize() { } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Editor/Runtime/Settings/FantasySettingsScriptableObject.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Editor/Runtime/Settings/FantasySettingsScriptableObject.cs.meta new file mode 100644 index 0000000..b5bae5a --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Editor/Runtime/Settings/FantasySettingsScriptableObject.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 27a37e930ca3454fb57bc895f50d2106 +timeCreated: 1688277120 \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Editor/Runtime/Settings/ScriptableObjectSingleton.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Editor/Runtime/Settings/ScriptableObjectSingleton.cs new file mode 100644 index 0000000..6206676 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Editor/Runtime/Settings/ScriptableObjectSingleton.cs @@ -0,0 +1,100 @@ +using System; +using System.IO; +using System.Linq; +using System.Reflection; +using UnityEditorInternal; +using UnityEngine; +// ReSharper disable AssignNullToNotNullAttribute + +namespace Fantasy +{ + public class ScriptableObjectSingleton : ScriptableObject where T : ScriptableObject + { + private static T _instance; + + public static T Instance + { + get + { + if (_instance == null) + { + _instance = Load(); + } + + return _instance; + } + } + + private static T Load() + { + var scriptableObjectPath = GetScriptableObjectPath(); + + if (string.IsNullOrEmpty(scriptableObjectPath)) + { + return null; + } + + var loadSerializedFileAndForget = InternalEditorUtility.LoadSerializedFileAndForget(scriptableObjectPath); + + if (loadSerializedFileAndForget.Length <= 0) + { + return CreateInstance(); + } + + return loadSerializedFileAndForget[0] as T; + } + + public static void Save(bool saveAsText = true) + { + if (_instance == null) + { + Debug.LogError("Cannot save ScriptableObjectSingleton: no instance!"); + return; + } + + var scriptableObjectPath = GetScriptableObjectPath(); + + if (string.IsNullOrEmpty(scriptableObjectPath)) + { + return; + } + + var directoryName = Path.GetDirectoryName(scriptableObjectPath); + + if (!Directory.Exists(directoryName)) + { + Directory.CreateDirectory(directoryName); + } + + UnityEngine.Object[] obj = { _instance }; + InternalEditorUtility.SaveToSerializedFileAndForget(obj, scriptableObjectPath, saveAsText); + } + + private static string GetScriptableObjectPath() + { + var scriptableObjectPathAttribute = typeof(T).GetCustomAttribute(typeof(ScriptableObjectPathAttribute)) as ScriptableObjectPathAttribute; + return scriptableObjectPathAttribute?.ScriptableObjectPath; + } + } + + [AttributeUsage(AttributeTargets.Class, Inherited = false)] + public class ScriptableObjectPathAttribute : Attribute + { + internal readonly string ScriptableObjectPath; + + public ScriptableObjectPathAttribute(string scriptableObjectPath) + { + if (string.IsNullOrEmpty(scriptableObjectPath)) + { + throw new ArgumentException("Invalid relative path (it is empty)"); + } + + if (scriptableObjectPath[0] == '/') + { + scriptableObjectPath = scriptableObjectPath.Substring(1); + } + + ScriptableObjectPath = scriptableObjectPath; + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Editor/Runtime/Settings/ScriptableObjectSingleton.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Editor/Runtime/Settings/ScriptableObjectSingleton.cs.meta new file mode 100644 index 0000000..5105c6f --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Editor/Runtime/Settings/ScriptableObjectSingleton.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 3c77f5208dc14542ae7497d59321ef76 +timeCreated: 1688278016 \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Editor/Runtime/WSocket.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Editor/Runtime/WSocket.meta new file mode 100644 index 0000000..21883b6 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Editor/Runtime/WSocket.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b9e5c7d1436ec414fa3f69a23aaafc3b +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Editor/Runtime/WSocket/SettingsWindow.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Editor/Runtime/WSocket/SettingsWindow.cs new file mode 100644 index 0000000..0313b0e --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Editor/Runtime/WSocket/SettingsWindow.cs @@ -0,0 +1,229 @@ +using UnityEngine; +using UnityEditor; +using UnityEngine.Networking; +using System.IO; +using System; + +namespace UnityWebSocket.Editor +{ + internal class SettingsWindow : EditorWindow + { + static SettingsWindow window = null; + [MenuItem("Tools/UnityWebSocket", priority = 100)] + internal static void Open() + { + if (window != null) + { + window.Close(); + } + + window = GetWindow(true, "UnityWebSocket"); + window.minSize = window.maxSize = new Vector2(600, 310); + window.Show(); + window.BeginCheck(); + } + + private void OnGUI() + { + DrawLogo(); + DrawVersion(); + DrawSeparator(80); + DrawSeparator(186); + DrawHelper(); + DrawFooter(); + } + + Texture2D logoTex = null; + private void DrawLogo() + { + if (logoTex == null) + { + logoTex = new Texture2D(66, 66); + logoTex.LoadImage(Convert.FromBase64String(LOGO_BASE64.VALUE)); + for (int i = 0; i < 66; i++) for (int j = 0; j < 15; j++) logoTex.SetPixel(i, j, Color.clear); + logoTex.Apply(); + } + + var logoPos = new Rect(10, 10, 66, 66); + GUI.DrawTexture(logoPos, logoTex); + var title = "UnityWebSocket"; + var titlePos = new Rect(80, 20, 500, 50); + GUI.Label(titlePos, title, TextStyle(24)); + } + + private void DrawSeparator(int y) + { + EditorGUI.DrawRect(new Rect(10, y, 580, 1), Color.white * 0.5f); + } + + private GUIStyle TextStyle(int fontSize = 10, TextAnchor alignment = TextAnchor.UpperLeft, float alpha = 0.85f) + { + var style = new GUIStyle(); + style.fontSize = fontSize; + style.normal.textColor = (EditorGUIUtility.isProSkin ? Color.white : Color.black) * alpha; + style.alignment = alignment; + style.richText = true; + return style; + } + + private void DrawVersion() + { + GUI.Label(new Rect(440, 10, 150, 10), "Current Version: " + Settings.VERSION, TextStyle(alignment: TextAnchor.MiddleLeft)); + if (string.IsNullOrEmpty(latestVersion)) + { + GUI.Label(new Rect(440, 30, 150, 10), "Checking for Updates...", TextStyle(alignment: TextAnchor.MiddleLeft)); + } + else if (latestVersion == "unknown") + { + + } + else + { + GUI.Label(new Rect(440, 30, 150, 10), "Latest Version: " + latestVersion, TextStyle(alignment: TextAnchor.MiddleLeft)); + if (Settings.VERSION == latestVersion) + { + if (GUI.Button(new Rect(440, 50, 150, 18), "Check Update")) + { + latestVersion = ""; + changeLog = ""; + BeginCheck(); + } + } + else + { + if (GUI.Button(new Rect(440, 50, 150, 18), "Update to | " + latestVersion)) + { + ShowUpdateDialog(); + } + } + } + } + + private void ShowUpdateDialog() + { + var isOK = EditorUtility.DisplayDialog("UnityWebSocket", + "Update UnityWebSocket now?\n" + changeLog, + "Update Now", "Cancel"); + + if (isOK) + { + UpdateVersion(); + } + } + + private void UpdateVersion() + { + Application.OpenURL(Settings.GITHUB + "/releases"); + } + + private void DrawHelper() + { + GUI.Label(new Rect(330, 200, 100, 18), "GitHub:", TextStyle(10, TextAnchor.MiddleRight)); + if (GUI.Button(new Rect(440, 200, 150, 18), "UnityWebSocket")) + { + Application.OpenURL(Settings.GITHUB); + } + + GUI.Label(new Rect(330, 225, 100, 18), "Report:", TextStyle(10, TextAnchor.MiddleRight)); + if (GUI.Button(new Rect(440, 225, 150, 18), "Report an Issue")) + { + Application.OpenURL(Settings.GITHUB + "/issues/new"); + } + + GUI.Label(new Rect(330, 250, 100, 18), "Email:", TextStyle(10, TextAnchor.MiddleRight)); + if (GUI.Button(new Rect(440, 250, 150, 18), Settings.EMAIL)) + { + var uri = new Uri(string.Format("mailto:{0}?subject={1}", Settings.EMAIL, "UnityWebSocket Feedback")); + Application.OpenURL(uri.AbsoluteUri); + } + + GUI.Label(new Rect(330, 275, 100, 18), "QQ群:", TextStyle(10, TextAnchor.MiddleRight)); + if (GUI.Button(new Rect(440, 275, 150, 18), Settings.QQ_GROUP)) + { + Application.OpenURL(Settings.QQ_GROUP_LINK); + } + } + + private void DrawFooter() + { + EditorGUI.DropShadowLabel(new Rect(10, 230, 400, 20), "Developed by " + Settings.AUHTOR); + EditorGUI.DropShadowLabel(new Rect(10, 250, 400, 20), "All rights reserved"); + } + + UnityWebRequest req; + string changeLog = ""; + string latestVersion = ""; + void BeginCheck() + { + EditorApplication.update -= VersionCheckUpdate; + EditorApplication.update += VersionCheckUpdate; + + req = UnityWebRequest.Get(Settings.GITHUB + "/releases/latest"); + req.SendWebRequest(); + } + + private void VersionCheckUpdate() + { +#if UNITY_2020_3_OR_NEWER + if (req == null + || req.result == UnityWebRequest.Result.ConnectionError + || req.result == UnityWebRequest.Result.DataProcessingError + || req.result == UnityWebRequest.Result.ProtocolError) +#elif UNITY_2018_1_OR_NEWER + if (req == null || req.isNetworkError || req.isHttpError) +#else + if (req == null || req.isError) +#endif + { + EditorApplication.update -= VersionCheckUpdate; + latestVersion = "unknown"; + return; + } + + if (req.isDone) + { + EditorApplication.update -= VersionCheckUpdate; + latestVersion = req.url.Substring(req.url.LastIndexOf("/") + 1).TrimStart('v'); + + if (Settings.VERSION != latestVersion) + { + var text = req.downloadHandler.text; + var st = text.IndexOf("content=\"" + latestVersion); + st = st > 0 ? text.IndexOf("\n", st) : -1; + var end = st > 0 ? text.IndexOf("\" />", st) : -1; + if (st > 0 && end > st) + { + changeLog = text.Substring(st + 1, end - st - 1).Trim(); + changeLog = changeLog.Replace("\r", ""); + changeLog = changeLog.Replace("\n", "\n- "); + changeLog = "\nCHANGE LOG: \n- " + changeLog + "\n"; + } + } + + Repaint(); + } + } + } + + internal static class LOGO_BASE64 + { + internal const string VALUE = "iVBORw0KGgoAAAANSUhEUgAAAEIAAABCCAMAAADUivDaAAAAq1BMVEUAAABKmtcvjtYzl" + + "9szmNszl9syl9k0mNs0mNwzmNs0mNszl9szl9s0mNs0mNwzmNw0mNwyltk0mNw0mNwzl9s0mNsymNs0mNszmNwzmNwzm" + + "NszmNs0mNwzl9w0mNwzmNw0mNs0mNs0mNwzl9wzmNs0mNwzmNs0mNwzl90zmNszmNszl9szmNsxmNszmNszmNw0mNwzm" + + "Nw0mNs2neM4pe41mt43ouo2oOY5qfM+UHlaAAAAMnRSTlMAAwXN3sgI+/069MSCK6M/MA74h9qfFHB8STWMJ9OSdmNcI" + + "8qya1IeF+/U0EIa57mqmFTYJe4AAAN3SURBVFjD7ZbpkppAFEa/bgVBREF2kEVGFNeZsM77P1kadURnJkr8k1Qlx1Khu" + + "/pw7+2lwH/+YcgfMBBLG7VocwDamzH+wJBB8Qhjve2f0TdrGwjei6o4Ub/nM/APw5Z7vvSB/qrCrqbD6fBEVtigeMxks" + + "fX9zWbj+z1jhqgSBplQ50eGo4614WXlRAzgrRhmtSfvxAn7pB0N5ObaKKZZuU5/d37IBcBgUQwqDuf7Z2gUmVAl4NGNr" + + "/UeHxV5n39ulbaKLI86h6HilmM5M1aN126lpNhtl59yeTsp8nUMvpNC1J3bh5FtfVRk+bJrJunn5d4U4piJ/Vw9eXgsj" + + "4ZpZaCjg9waZkIpnBWLJ44OwoNu60F2UnSaEkKv4XnAlCpm6B4F/aKMDiyGi2L8SEEAVdxNLuzmgV7nFwObEe2xQVuX+" + + "RV1lWetga3w+cN1sXgvm4cJH8OEgZC1DPKhfF/BIymmQrMjq/x65FUeEkDup8GxoexZmznHCvANtXU/CAq13yimhQGtm" + + "H4VCPnBBL1fTKo3CqEcvq7Lb/OwHxWTYlyw+JmjKoVvDLVOQB4pVsM8K8smgvLCxZDlIijwyOEc+nr/msMwK0+GQWGBd" + + "tmhjv8icTds1s2ammaFh04QLLe69NK7guP6mTDMaw3o6nAX/Z7EXUskPSvWEWg4srVlp5NTDXv9Lce9HGN5eeG4nj5Yz" + + "ACteU2wQLo4MBtJfd1nw5nG1/s9zwUQ6pykL1TQjqdeuvQW0naz2XKLYL4Cwzr4vj+OQdD96CSp7Lrynp4aeFF0xdm5q" + + "6OFtFfPv7URxpWJNjd/N+3+I9+1klMav12Qtgbt9R2JaIopjkzaPtOFq4KxUpqfUMSFnQrySWjLoQzRZS4HMH84ME1ej" + + "S1YJpQZ3B+sR1uCQJSBdGdCk1eAEgORR88KK05W8dh2MA+A/SKCYu3mCJ0Ek7HBx4HHeuwYy5G3x8hSMTJcOMFbinCsn" + + "hO1V1aszGULvA0g4UFsb4VA0hAFcyo6cgLsAoT7uUtGAH5wQKQle0wuLyxLTaNyJEYwxw4wSljLK1TP8CAaOyhBMMEsj" + + "OBoXgo7VGElFkSWL+vef1RF2YNXeRWYzQBTpkhC8KaZHhuIogArkQLKClBZjU26B2IZgGz+cpZkHl8g3fYUaW/YP2kb2" + + "M/V97JY/vZN859n+QmO7XtC9Bf2jAAAAABJRU5ErkJggg=="; + } +} diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Editor/Runtime/WSocket/SettingsWindow.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Editor/Runtime/WSocket/SettingsWindow.cs.meta new file mode 100644 index 0000000..7412468 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Editor/Runtime/WSocket/SettingsWindow.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 902614e06186a482f9e816e1d1984547 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Fantasy.Unity.asmdef b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Fantasy.Unity.asmdef new file mode 100644 index 0000000..d86404f --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Fantasy.Unity.asmdef @@ -0,0 +1,14 @@ +{ + "name": "Fantasy.Unity", + "rootNamespace": "", + "references": [], + "includePlatforms": [], + "excludePlatforms": [], + "allowUnsafeCode": true, + "overrideReferences": false, + "precompiledReferences": [], + "autoReferenced": true, + "defineConstraints": [], + "versionDefines": [], + "noEngineReferences": false +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Fantasy.Unity.asmdef.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Fantasy.Unity.asmdef.meta new file mode 100644 index 0000000..ac113c4 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Fantasy.Unity.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 0b7224b83ba514121aa026f3857f820a +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/LICENSE b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/LICENSE new file mode 100644 index 0000000..3c5a719 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/LICENSE @@ -0,0 +1,12 @@ +MIT License + +Copyright (c) 2023 qq362946 + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +However, the following entity is explicitly prohibited from using, copying, modifying, or distributing the Software or any of its portions: + +泰课在线(https://www.taikr.com/) +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/LICENSE.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/LICENSE.meta new file mode 100644 index 0000000..b6fff37 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/LICENSE.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: e68ec9986245d4ecfa0445bda8a7868d +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/README.md b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/README.md new file mode 100644 index 0000000..09d1c5e --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/README.md @@ -0,0 +1,45 @@ +# Fantasy +#### Fantasy是基于.NET的高性能网络开发框架,支持主流协议,前后端分离。 +#### 支持Unity/Godot/WinFrom/WPF/Console等C#客户端接入。 +#### 框架支持TCP\KCP\WebSocket\http(支持Unity发布成H5)三种网络协议。 +#### 适合需要快速上手、可扩展、分布式全平台商业级解决方案的框架。 +## 导航 +* [Fantasy介绍网站](https://www.code-fantasy.com/) +* [Fantasy的API文档](https://www.code-fantasy.com/doc/api/Fantasy.html) +* [入门视频观看地址](https://space.bilibili.com/382126312) +## 快速上手 +* 01.快速入门 + * [1.1.获得Fantasy](https://www.code-fantasy.com/top/download-fantasy/) + * [1.2.配置文件](https://www.code-fantasy.com/top/config-file/) + * [1.3.Fantasy的网络](https://www.code-fantasy.com/top/use-network/) + * [1.4.Fantasy的配置文件](https://www.code-fantasy.com/top/config-file/) + * [1.5.Fantasy的命令行参数](https://www.code-fantasy.com/top/command-line-parameter/) + * [1.6.如何升级到最新版](https://www.code-fantasy.com/top/upgrade/) +* 02.网络通信 + * [2.1.配置网络协议](https://www.code-fantasy.com/network/network-protocols/) + * [2.2.客户端服务器之间发送消息](https://www.code-fantasy.com/network/session/) + * [2.3.服务器之间发送消息](https://www.code-fantasy.com/network/networkmessagingomponent/) + * [2.4.Route通信协议](https://www.code-fantasy.com/network/network-route/) + * [2.5.Addressable通信协议](https://www.code-fantasy.com/network/network-addressable/) +* 03.系统组件 + * [3.1.ECS系统](https://www.code-fantasy.com/core/ecs/) + * [3.2.事件系统](https://www.code-fantasy.com/core/event/) + * [3.3.任务系统](https://www.code-fantasy.com/core/task/) + * [3.4.异步协程锁](https://www.code-fantasy.com/core/lock/) + * [3.5.数据库](https://www.code-fantasy.com/core/db/) +* [更新日志](https://www.code-fantasy.com/changelog/) +* [API文档](https://www.code-fantasy.com/doc/api/Fantasy.html) +* [常见问题](https://www.code-fantasy.com/question/) + +## 优质开源项目推荐 +#### ET - ET框架是一整套完善的游戏开发框架。 +#### TEngine - TEngine是一个简单(新手友好开箱即用)且强大的Unity框架全平台解决方案。 +#### Legends-Of-Heroes - 一个LOL风格的球球大作战游戏,基于ET,使用状态同步。 +## 交流与讨论: +__讨论QQ群 : Fantasy服务器开发交流群 569888673 __ +## 特别鸣谢 + +感谢JetBrains公司提供的使用许可证! + +

+JetBrains的Logo

diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/README.md.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/README.md.meta new file mode 100644 index 0000000..2ef7b6e --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/README.md.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: cf5443fd5b0e44724945a38cbd0fde13 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime.meta new file mode 100644 index 0000000..b559b16 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d4180ba95bb674e6488cd44665e784d6 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core.meta new file mode 100644 index 0000000..12f960b --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 076d59bda84794582abf2d7b23d3cc01 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Assembly.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Assembly.meta new file mode 100644 index 0000000..19f46f0 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Assembly.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b5b24e6eec64b4702b871053139f8add +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Assembly/AssemblyInfo.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Assembly/AssemblyInfo.cs new file mode 100644 index 0000000..3957539 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Assembly/AssemblyInfo.cs @@ -0,0 +1,89 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using Fantasy.DataStructure.Collection; + +// ReSharper disable CollectionNeverQueried.Global +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. + +namespace Fantasy.Assembly +{ + /// + /// AssemblyInfo提供有关程序集和类型的信息 + /// + public sealed class AssemblyInfo + { + /// + /// 唯一标识 + /// + public readonly long AssemblyIdentity; + /// + /// 获取或设置与此程序集相关联的 实例。 + /// + public System.Reflection.Assembly Assembly { get; private set; } + /// + /// 程序集类型集合,获取一个列表,包含从程序集加载的所有类型。 + /// + public readonly List AssemblyTypeList = new List(); + /// + /// 程序集类型分组集合,获取一个分组列表,将接口类型映射到实现这些接口的类型。 + /// + public readonly OneToManyList AssemblyTypeGroupList = new OneToManyList(); + + /// + /// 初始化 类的新实例。 + /// + /// + public AssemblyInfo(long assemblyIdentity) + { + AssemblyIdentity = assemblyIdentity; + } + + /// + /// 从指定的程序集加载类型信息并进行分类。 + /// + /// 要加载信息的程序集。 + public void Load(System.Reflection.Assembly assembly) + { + Assembly = assembly; + var assemblyTypes = assembly.GetTypes().ToList(); + + foreach (var type in assemblyTypes) + { + if (type.IsAbstract || type.IsInterface) + { + continue; + } + + var interfaces = type.GetInterfaces(); + + foreach (var interfaceType in interfaces) + { + AssemblyTypeGroupList.Add(interfaceType, type); + } + } + + AssemblyTypeList.AddRange(assemblyTypes); + } + + /// + /// 重新加载程序集的类型信息。 + /// + /// + public void ReLoad(System.Reflection.Assembly assembly) + { + Unload(); + Load(assembly); + } + + /// + /// 卸载程序集的类型信息。 + /// + public void Unload() + { + AssemblyTypeList.Clear(); + AssemblyTypeGroupList.Clear(); + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Assembly/AssemblyInfo.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Assembly/AssemblyInfo.cs.meta new file mode 100644 index 0000000..b5e3a28 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Assembly/AssemblyInfo.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6588e9470957646dfa79849126de341c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Assembly/AssemblySystem.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Assembly/AssemblySystem.cs new file mode 100644 index 0000000..2014429 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Assembly/AssemblySystem.cs @@ -0,0 +1,276 @@ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Security.Cryptography; +using System.Text; +using Fantasy.Async; +using Fantasy.Helper; +#pragma warning disable CS8604 // Possible null reference argument. +#pragma warning disable CS8602 // Dereference of a possibly null reference. +#pragma warning disable CS8603 +#pragma warning disable CS8618 +namespace Fantasy.Assembly +{ + /// + /// 管理程序集加载和卸载的帮助类。 + /// + public static class AssemblySystem + { +#if FANTASY_WEBGL + private static readonly List AssemblySystems = new List(); + private static readonly Dictionary AssemblyList = new Dictionary(); +#else + private static readonly ConcurrentBag AssemblySystems = new ConcurrentBag(); + private static readonly ConcurrentDictionary AssemblyList = new ConcurrentDictionary(); +#endif + /// + /// 初始化 AssemblySystem。(仅限内部) + /// + /// + internal static async FTask InnerInitialize(params System.Reflection.Assembly[] assemblies) + { + await LoadAssembly(typeof(AssemblySystem).Assembly); + foreach (var assembly in assemblies) + { + await LoadAssembly(assembly); + } + } + + /// + /// 加载指定的程序集,并触发相应的事件。 + /// + /// 要加载的程序集。 + /// 如果当前Domain中已经存在同名的Assembly,使用Domain中的程序集。 + public static async FTask LoadAssembly(System.Reflection.Assembly assembly, bool isCurrentDomain = true) + { + if (isCurrentDomain) + { + var currentDomainAssemblies = System.AppDomain.CurrentDomain.GetAssemblies(); + var currentAssembly = currentDomainAssemblies.FirstOrDefault(d => d.GetName().Name == assembly.GetName().Name); + if (currentAssembly != null) + { + assembly = currentAssembly; + } + } + + var assemblyIdentity = AssemblyIdentity(assembly); + + if (AssemblyList.TryGetValue(assemblyIdentity, out var assemblyInfo)) + { + assemblyInfo.ReLoad(assembly); + foreach (var assemblySystem in AssemblySystems) + { + await assemblySystem.ReLoad(assemblyIdentity); + } + } + else + { + assemblyInfo = new AssemblyInfo(assemblyIdentity); + assemblyInfo.Load(assembly); + AssemblyList.TryAdd(assemblyIdentity, assemblyInfo); + foreach (var assemblySystem in AssemblySystems) + { + await assemblySystem.Load(assemblyIdentity); + } + } + } + + /// + /// 卸载程序集 + /// + /// + public static async FTask UnLoadAssembly(System.Reflection.Assembly assembly) + { + var assemblyIdentity = AssemblyIdentity(assembly); + + if (!AssemblyList.Remove(assemblyIdentity, out var assemblyInfo)) + { + return; + } + + assemblyInfo.Unload(); + foreach (var assemblySystem in AssemblySystems) + { + await assemblySystem.OnUnLoad(assemblyIdentity); + } + } + + /// + /// 将AssemblySystem接口的object注册到程序集管理中心 + /// + /// + public static async FTask Register(object obj) + { + if (obj is not IAssembly assemblySystem) + { + return; + } + + AssemblySystems.Add(assemblySystem); + + foreach (var (assemblyIdentity, _) in AssemblyList) + { + await assemblySystem.Load(assemblyIdentity); + } + } + + /// + /// 程序集管理中心卸载注册的Load、ReLoad、UnLoad的接口 + /// + /// + public static void UnRegister(object obj) + { + if (obj is not IAssembly assemblySystem) + { + return; + } +#if FANTASY_WEBGL + AssemblySystems.Remove(assemblySystem); +#else + while (AssemblySystems.TryTake(out var removeAssemblySystem)) + { + if (removeAssemblySystem == assemblySystem) + { + continue; + } + + AssemblySystems.Add(removeAssemblySystem); + } +#endif + } + + /// + /// 获取所有已加载程序集中的所有类型。 + /// + /// 所有已加载程序集中的类型。 + public static IEnumerable ForEach() + { + foreach (var (_, assemblyInfo) in AssemblyList) + { + foreach (var type in assemblyInfo.AssemblyTypeList) + { + yield return type; + } + } + } + + /// + /// 获取指定程序集中的所有类型。 + /// + /// 程序集唯一标识。 + /// 指定程序集中的类型。 + public static IEnumerable ForEach(long assemblyIdentity) + { + if (!AssemblyList.TryGetValue(assemblyIdentity, out var assemblyInfo)) + { + yield break; + } + + foreach (var type in assemblyInfo.AssemblyTypeList) + { + yield return type; + } + } + + /// + /// 获取所有已加载程序集中实现指定类型的所有类型。 + /// + /// 要查找的基类或接口类型。 + /// 所有已加载程序集中实现指定类型的类型。 + public static IEnumerable ForEach(Type findType) + { + foreach (var (_, assemblyInfo) in AssemblyList) + { + if (!assemblyInfo.AssemblyTypeGroupList.TryGetValue(findType, out var assemblyLoad)) + { + continue; + } + + foreach (var type in assemblyLoad) + { + yield return type; + } + } + } + + /// + /// 获取指定程序集中实现指定类型的所有类型。 + /// + /// 程序集唯一标识。 + /// 要查找的基类或接口类型。 + /// 指定程序集中实现指定类型的类型。 + public static IEnumerable ForEach(long assemblyIdentity, Type findType) + { + if (!AssemblyList.TryGetValue(assemblyIdentity, out var assemblyInfo)) + { + yield break; + } + + if (!assemblyInfo.AssemblyTypeGroupList.TryGetValue(findType, out var assemblyLoad)) + { + yield break; + } + + foreach (var type in assemblyLoad) + { + yield return type; + } + } + + /// + /// 获取指定程序集的实例。 + /// + /// 程序集名称。 + /// 指定程序集的实例,如果未加载则返回 null。 + public static System.Reflection.Assembly GetAssembly(long assemblyIdentity) + { + return !AssemblyList.TryGetValue(assemblyIdentity, out var assemblyInfo) ? null : assemblyInfo.Assembly; + } + + /// + /// 获取当前框架注册的Assembly + /// + /// + public static IEnumerable ForEachAssembly + { + get + { + foreach (var (_, assemblyInfo) in AssemblyList) + { + yield return assemblyInfo.Assembly; + } + } + } + + /// + /// 根据Assembly的强命名计算唯一标识。 + /// + /// + /// + private static long AssemblyIdentity(System.Reflection.Assembly assembly) + { + return HashCodeHelper.ComputeHash64(assembly.GetName().Name); + } + + /// + /// 释放资源,卸载所有加载的程序集。 + /// + public static void Dispose() + { + DisposeAsync().Coroutine(); + } + + private static async FTask DisposeAsync() + { + foreach (var (_, assemblyInfo) in AssemblyList.ToArray()) + { + await UnLoadAssembly(assemblyInfo.Assembly); + } + + AssemblyList.Clear(); + AssemblySystems.Clear(); + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Assembly/AssemblySystem.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Assembly/AssemblySystem.cs.meta new file mode 100644 index 0000000..6474bd9 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Assembly/AssemblySystem.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6f06892fa649d49c287bf07095569ae0 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Assembly/IAssembly.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Assembly/IAssembly.cs new file mode 100644 index 0000000..185e037 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Assembly/IAssembly.cs @@ -0,0 +1,27 @@ +using System; +using Fantasy.Async; + +namespace Fantasy.Assembly +{ + /// + /// 实现这个接口、会再程序集首次加载、卸载、重载的时候调用 + /// + public interface IAssembly : IDisposable + { + /// + /// 程序集加载时调用 + /// + /// 程序集标识 + public FTask Load(long assemblyIdentity); + /// + /// 程序集重新加载的时候调用 + /// + /// 程序集标识 + public FTask ReLoad(long assemblyIdentity); + /// + /// 卸载的时候调用 + /// + /// 程序集标识 + public FTask OnUnLoad(long assemblyIdentity); + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Assembly/IAssembly.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Assembly/IAssembly.cs.meta new file mode 100644 index 0000000..11db0dc --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Assembly/IAssembly.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f14fcbf29decc4d47b6c548a3d5f2a3f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Benchmark.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Benchmark.meta new file mode 100644 index 0000000..cfe3201 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Benchmark.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 160974fcbccd74d0eafedf8762807588 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Benchmark/Handler.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Benchmark/Handler.meta new file mode 100644 index 0000000..cfda7e8 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Benchmark/Handler.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 91eb4278fcdd44b6d8a782ca42107e4c +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Benchmark/Handler/BenchmarkRequestHandler.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Benchmark/Handler/BenchmarkRequestHandler.cs new file mode 100644 index 0000000..8532547 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Benchmark/Handler/BenchmarkRequestHandler.cs @@ -0,0 +1,25 @@ +using Fantasy.Async; +using Fantasy.InnerMessage; +using Fantasy.Network.Interface; + +#if FANTASY_NET +namespace Fantasy.Network.Benchmark.Handler; + +/// +/// BenchmarkRequestHandler +/// +public sealed class BenchmarkRequestHandler : MessageRPC +{ + /// + /// Run方法 + /// + /// + /// + /// + /// + protected override async FTask Run(Session session, BenchmarkRequest request, BenchmarkResponse response, Action reply) + { + await FTask.CompletedTask; + } +} +#endif diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Benchmark/Handler/BenchmarkRequestHandler.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Benchmark/Handler/BenchmarkRequestHandler.cs.meta new file mode 100644 index 0000000..e0451e3 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Benchmark/Handler/BenchmarkRequestHandler.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0b5a936197cf64719b8d6b44158e0d91 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataBase.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataBase.meta new file mode 100644 index 0000000..5a4bdb5 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataBase.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 4961a2a852e804ad69bad45492f22555 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataBase/DataBaseType.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataBase/DataBaseType.cs new file mode 100644 index 0000000..2fb03ec --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataBase/DataBaseType.cs @@ -0,0 +1,20 @@ +// ReSharper disable CheckNamespace +// ReSharper disable InconsistentNaming +#if FANTASY_NET +namespace Fantasy.DataBase; + +/// +/// 数据库类型 +/// +public enum DataBaseType +{ + /// + /// 默认 + /// + None = 0, + /// + /// MongoDB + /// + MongoDB = 1 +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataBase/DataBaseType.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataBase/DataBaseType.cs.meta new file mode 100644 index 0000000..baac332 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataBase/DataBaseType.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: abd508d980707405bb2d5bbfee14b6b8 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataBase/IDataBase.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataBase/IDataBase.cs new file mode 100644 index 0000000..b87e86d --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataBase/IDataBase.cs @@ -0,0 +1,205 @@ +#if FANTASY_NET +using System; +using System.Collections.Generic; +using System.Linq.Expressions; +using Fantasy.Async; +using Fantasy.Entitas; +using MongoDB.Driver; +// ReSharper disable InconsistentNaming +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring as nullable. + +#pragma warning disable CS8625 + +namespace Fantasy.DataBase +{ + /// + /// 数据库设置助手 + /// + public static class DataBaseSetting + { + /// + /// 初始化自定义委托,当设置了这个委托后,就不会自动创建MongoClient,需要自己在委托里创建MongoClient。 + /// + public static Func? MongoDBCustomInitialize; + } + + /// + /// MongoDB自定义连接参数 + /// + public sealed class DataBaseCustomConfig + { + /// + /// 当前Scene + /// + public Scene Scene; + /// + /// 连接字符串 + /// + public string ConnectionString; + /// + /// 数据库名字 + /// + public string DBName; + } + + /// + /// 表示用于执行各种数据库操作的数据库接口。 + /// + public interface IDataBase : IDisposable + { + /// + /// 获得当前数据的类型 + /// + public DataBaseType GetDataBaseType { get;} + /// + /// 初始化数据库连接。 + /// + IDataBase Initialize(Scene scene, string connectionString, string dbName); + /// + /// 在指定的集合中检索类型 的实体数量。 + /// + FTask Count(string collection = null) where T : Entity; + /// + /// 在指定的集合中检索满足给定筛选条件的类型 的实体数量。 + /// + FTask Count(Expression> filter, string collection = null) where T : Entity; + /// + /// 检查指定集合中是否存在类型 的实体。 + /// + FTask Exist(string collection = null) where T : Entity; + /// + /// 检查指定集合中是否存在满足给定筛选条件的类型 的实体。 + /// + FTask Exist(Expression> filter, string collection = null) where T : Entity; + /// + /// 从指定集合中检索指定 ID 的类型 的实体,不锁定。 + /// + FTask QueryNotLock(long id, bool isDeserialize = false, string collection = null) where T : Entity; + /// + /// 从指定集合中检索指定 ID 的类型 的实体。 + /// + FTask Query(long id, bool isDeserialize = false, string collection = null) where T : Entity; + /// + /// 按页查询满足给定筛选条件的类型 的实体数量和日期。 + /// + FTask<(int count, List dates)> QueryCountAndDatesByPage(Expression> filter, int pageIndex, int pageSize, bool isDeserialize = false, string collection = null) where T : Entity; + /// + /// 按页查询满足给定筛选条件的类型 的实体数量和日期。 + /// + FTask<(int count, List dates)> QueryCountAndDatesByPage(Expression> filter, int pageIndex, int pageSize, string[] cols, bool isDeserialize = false, string collection = null) where T : Entity; + /// + /// 分页查询指定集合中满足给定筛选条件的类型 的实体列表。 + /// + FTask> QueryByPage(Expression> filter, int pageIndex, int pageSize, bool isDeserialize = false, string collection = null) where T : Entity; + /// + /// 分页查询指定集合中满足给定筛选条件的类型 的实体列表,仅返回指定列的数据。 + /// + FTask> QueryByPage(Expression> filter, int pageIndex, int pageSize, string[] cols, bool isDeserialize = false, string collection = null) where T : Entity; + /// + /// 从指定集合中按页查询满足给定筛选条件的类型 的实体列表,按指定字段排序。 + /// + FTask> QueryByPageOrderBy(Expression> filter, int pageIndex, int pageSize, Expression> orderByExpression, bool isAsc = true, bool isDeserialize = false, string collection = null) where T : Entity; + /// + /// 检索满足给定筛选条件的类型 的第一个实体,从指定集合中。 + /// + FTask First(Expression> filter, bool isDeserialize = false, string collection = null) where T : Entity; + /// + /// 查询指定集合中满足给定 JSON 查询字符串的类型 的第一个实体,仅返回指定列的数据。 + /// + FTask First(string json, string[] cols, bool isDeserialize = false, string collection = null) where T : Entity; + /// + /// 从指定集合中按页查询满足给定筛选条件的类型 的实体列表,按指定字段排序。 + /// + FTask> QueryOrderBy(Expression> filter, Expression> orderByExpression, bool isAsc = true, bool isDeserialize = false, string collection = null) where T : Entity; + /// + /// 从指定集合中按页查询满足给定筛选条件的类型 的实体列表。 + /// + FTask> Query(Expression> filter, bool isDeserialize = false, string collection = null) where T : Entity; + /// + /// 查询指定集合中满足给定筛选条件的类型 实体列表,仅返回指定字段的数据。 + /// + FTask> Query(Expression> filter, Expression>[] cols, bool isDeserialize = false, string collection = null) where T : Entity; + /// + /// 查询指定 ID 的多个集合,将结果存储在给定的实体列表中。 + /// + FTask Query(long id, List collectionNames, List result, bool isDeserialize = false); + /// + /// 根据给定的 JSON 查询字符串查询指定集合中的类型 实体列表。 + /// + FTask> QueryJson(string json, bool isDeserialize = false, string collection = null) where T : Entity; + /// + /// 根据给定的 JSON 查询字符串查询指定集合中的类型 实体列表,仅返回指定列的数据。 + /// + FTask> QueryJson(string json, string[] cols, bool isDeserialize = false, string collection = null) where T : Entity; + /// + /// 根据给定的 JSON 查询字符串查询指定集合中的类型 实体列表,通过指定的任务 ID 进行标识。 + /// + FTask> QueryJson(long taskId, string json, bool isDeserialize = false, string collection = null) where T : Entity; + /// + /// 查询指定集合中满足给定筛选条件的类型 实体列表,仅返回指定列的数据。 + /// + FTask> Query(Expression> filter, string[] cols, bool isDeserialize = false, string collection = null) where T : Entity; + /// + /// 保存类型 实体到指定集合中,如果集合不存在将自动创建。 + /// + FTask Save(T entity, string collection = null) where T : Entity, new(); + /// + /// 保存一组实体到数据库中,根据实体列表的 ID 进行区分和存储。 + /// + FTask Save(long id, List entities); + /// + /// 通过事务会话将类型 实体保存到指定集合中,如果集合不存在将自动创建。 + /// + FTask Save(object transactionSession, T entity, string collection = null) where T : Entity; + /// + /// 向指定集合中插入一个类型 实体,如果集合不存在将自动创建。 + /// + FTask Insert(T entity, string collection = null) where T : Entity, new(); + /// + /// 批量插入一组类型 实体到指定集合中,如果集合不存在将自动创建。 + /// + FTask InsertBatch(IEnumerable list, string collection = null) where T : Entity, new(); + /// + /// 通过事务会话,批量插入一组类型 实体到指定集合中,如果集合不存在将自动创建。 + /// + FTask InsertBatch(object transactionSession, IEnumerable list, string collection = null) where T : Entity, new(); + /// + /// 通过事务会话,根据指定的 ID 从数据库中删除指定类型 实体。 + /// + FTask Remove(object transactionSession, long id, string collection = null) where T : Entity, new(); + /// + /// 根据指定的 ID 从数据库中删除指定类型 实体。 + /// + FTask Remove(long id, string collection = null) where T : Entity, new(); + /// + /// 通过事务会话,根据给定的筛选条件从数据库中删除指定类型 实体。 + /// + FTask Remove(long coroutineLockQueueKey, object transactionSession, Expression> filter, string collection = null) where T : Entity, new(); + /// + /// 根据给定的筛选条件从数据库中删除指定类型 实体。 + /// + FTask Remove(long coroutineLockQueueKey, Expression> filter, string collection = null) where T : Entity, new(); + /// + /// 根据给定的筛选条件计算指定集合中类型 实体某个属性的总和。 + /// + FTask Sum(Expression> filter, Expression> sumExpression, string collection = null) where T : Entity; + /// + /// 在指定的集合中创建索引,以提高类型 实体的查询性能。 + /// + FTask CreateIndex(string collection, params object[] keys) where T : Entity; + /// + /// 在默认集合中创建索引,以提高类型 实体的查询性能。 + /// + FTask CreateIndex(params object[] keys) where T : Entity; + /// + /// 创建指定类型 的数据库,用于存储实体。 + /// + FTask CreateDB() where T : Entity; + /// + /// 根据指定类型创建数据库,用于存储实体。 + /// + FTask CreateDB(Type type); + } +} + +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataBase/IDataBase.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataBase/IDataBase.cs.meta new file mode 100644 index 0000000..9be13ba --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataBase/IDataBase.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 83202aeeb0df040de8735030956ca861 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataBase/MongoDataBase.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataBase/MongoDataBase.cs new file mode 100644 index 0000000..a9be75a --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataBase/MongoDataBase.cs @@ -0,0 +1,1078 @@ +#if FANTASY_NET +using System.Linq.Expressions; +using Fantasy.Async; +using Fantasy.DataStructure.Collection; +using Fantasy.Entitas; +using Fantasy.Helper; +using Fantasy.Serialize; +using MongoDB.Bson; +using MongoDB.Driver; +#pragma warning disable CS8602 // Dereference of a possibly null reference. +#pragma warning disable CS8603 // Possible null reference return. +#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. + +namespace Fantasy.DataBase +{ + /// + /// 使用 MongoDB 数据库的实现。 + /// + public sealed class MongoDataBase : IDataBase + { + private const int DefaultTaskSize = 1024; + private Scene _scene; + private MongoClient _mongoClient; + private ISerialize _serializer; + private IMongoDatabase _mongoDatabase; + private CoroutineLock _dataBaseLock; + private readonly HashSet _collections = new HashSet(); + /// + /// 获得当前数据的类型 + /// + public DataBaseType GetDataBaseType { get; } = DataBaseType.MongoDB; + + /// + /// 初始化 MongoDB 数据库连接并记录所有集合名。 + /// + /// 场景对象。 + /// 数据库连接字符串。 + /// 数据库名称。 + /// 初始化后的数据库实例。 + public IDataBase Initialize(Scene scene, string connectionString, string dbName) + { + _scene = scene; + _mongoClient = DataBaseSetting.MongoDBCustomInitialize != null + ? DataBaseSetting.MongoDBCustomInitialize(new DataBaseCustomConfig() + { + Scene = scene, ConnectionString = connectionString, DBName = dbName + }) + : new MongoClient(connectionString); + _mongoDatabase = _mongoClient.GetDatabase(dbName); + _dataBaseLock = scene.CoroutineLockComponent.Create(GetType().TypeHandle.Value.ToInt64()); + // 记录所有集合名 + _collections.UnionWith(_mongoDatabase.ListCollectionNames().ToList()); + _serializer = SerializerManager.GetSerializer(FantasySerializerType.Bson); + return this; + } + + /// + /// 销毁释放资源。 + /// + public void Dispose() + { + // 优先释放协程锁。 + _dataBaseLock.Dispose(); + // 清理资源。 + _scene = null; + _serializer = null; + _mongoDatabase = null; + _dataBaseLock = null; + _collections.Clear(); + _mongoClient.Dispose(); + } + + #region Other + + /// + /// 对满足条件的文档中的某个数值字段进行求和操作。 + /// + /// 实体类型。 + /// 用于筛选文档的表达式。 + /// 要对其进行求和的字段表达式。 + /// 集合名称,可选。如果未指定,将使用实体类型的名称。 + /// 满足条件的文档中指定字段的求和结果。 + public async FTask Sum(Expression> filter, Expression> sumExpression, string collection = null) where T : Entity + { + var member = (MemberExpression)((UnaryExpression)sumExpression.Body).Operand; + var projection = new BsonDocument("_id", "null").Add("Result", new BsonDocument("$sum", $"${member.Member.Name}")); + var data = await GetCollection(collection).Aggregate().Match(filter).Group(projection).FirstOrDefaultAsync(); + return data == null ? 0 : Convert.ToInt64(data["Result"]); + } + + #endregion + + #region GetCollection + + /// + /// 获取指定集合中的 MongoDB 文档的 IMongoCollection 对象。 + /// + /// 实体类型。 + /// 集合名称,可选。如果未指定,将使用实体类型的名称。 + /// IMongoCollection 对象。 + private IMongoCollection GetCollection(string collection = null) + { + return _mongoDatabase.GetCollection(collection ?? typeof(T).Name); + } + + /// + /// 获取指定集合中的 MongoDB 文档的 IMongoCollection 对象,其中实体类型为 Entity。 + /// + /// 集合名称。 + /// IMongoCollection 对象。 + private IMongoCollection GetCollection(string name) + { + return _mongoDatabase.GetCollection(name); + } + + #endregion + + #region Count + + /// + /// 统计指定集合中满足条件的文档数量。 + /// + /// 实体类型。 + /// 集合名称,可选。如果未指定,将使用实体类型的名称。 + /// 满足条件的文档数量。 + public async FTask Count(string collection = null) where T : Entity + { + return await GetCollection(collection).CountDocumentsAsync(d => true); + } + + /// + /// 统计指定集合中满足条件的文档数量。 + /// + /// 实体类型。 + /// 用于筛选文档的表达式。 + /// 集合名称,可选。如果未指定,将使用实体类型的名称。 + /// 满足条件的文档数量。 + public async FTask Count(Expression> filter, string collection = null) where T : Entity + { + return await GetCollection(collection).CountDocumentsAsync(filter); + } + + #endregion + + #region Exist + + /// + /// 判断指定集合中是否存在文档。 + /// + /// 实体类型。 + /// 集合名称,可选。如果未指定,将使用实体类型的名称。 + /// 如果存在文档则返回 true,否则返回 false。 + public async FTask Exist(string collection = null) where T : Entity + { + return await Count(collection) > 0; + } + + /// + /// 判断指定集合中是否存在满足条件的文档。 + /// + /// 实体类型。 + /// 用于筛选文档的表达式。 + /// 集合名称,可选。如果未指定,将使用实体类型的名称。 + /// 如果存在满足条件的文档则返回 true,否则返回 false。 + public async FTask Exist(Expression> filter, string collection = null) where T : Entity + { + return await Count(filter, collection) > 0; + } + + #endregion + + #region Query + + /// + /// 在不加数据库锁定的情况下,查询指定 ID 的文档。 + /// + /// 文档实体类型。 + /// 要查询的文档 ID。 + /// 是否在查询后反序列化,执行反序列化后会自动将实体注册到框架系统中,并且能正常使用组件相关功能。 + /// 集合名称。 + /// 查询到的文档。 + public async FTask QueryNotLock(long id, bool isDeserialize = false, string collection = null) where T : Entity + { + var cursor = await GetCollection(collection).FindAsync(d => d.Id == id); + var v = await cursor.FirstOrDefaultAsync(); + + if (isDeserialize && v != null) + { + v.Deserialize(_scene); + } + + return v; + } + + /// + /// 查询指定 ID 的文档,并加数据库锁定以确保数据一致性。 + /// + /// 文档实体类型。 + /// 要查询的文档 ID。 + /// 是否在查询后反序列化,执行反序列化后会自动将实体注册到框架系统中,并且能正常使用组件相关功能。 + /// 集合名称。 + /// 查询到的文档。 + public async FTask Query(long id, bool isDeserialize = false, string collection = null) where T : Entity + { + using (await _dataBaseLock.Wait(id)) + { + var cursor = await GetCollection(collection).FindAsync(d => d.Id == id); + var v = await cursor.FirstOrDefaultAsync(); + + if (isDeserialize && v != null) + { + v.Deserialize(_scene); + } + + return v; + } + } + + /// + /// 通过分页查询并返回满足条件的文档数量和日期列表(不加锁)。 + /// + /// 文档实体类型。 + /// 查询过滤条件。 + /// 页码。 + /// 每页大小。 + /// 是否在查询后反序列化,执行反序列化后会自动将实体注册到框架系统中,并且能正常使用组件相关功能。 + /// 集合名称。 + /// 满足条件的文档数量和日期列表。 + public async FTask<(int count, List dates)> QueryCountAndDatesByPage(Expression> filter, int pageIndex, int pageSize, bool isDeserialize = false, string collection = null) where T : Entity + { + using (await _dataBaseLock.Wait(RandomHelper.RandInt64() % DefaultTaskSize)) + { + var count = await Count(filter); + var dates = await QueryByPage(filter, pageIndex, pageSize, isDeserialize, collection); + return ((int)count, dates); + } + } + + /// + /// 通过分页查询并返回满足条件的文档数量和日期列表(加锁)。 + /// + /// 文档实体类型。 + /// 查询过滤条件。 + /// 页码。 + /// 每页大小。 + /// 要查询的列名称数组。 + /// 是否在查询后反序列化,执行反序列化后会自动将实体注册到框架系统中,并且能正常使用组件相关功能。 + /// 集合名称。 + /// 满足条件的文档数量和日期列表。 + public async FTask<(int count, List dates)> QueryCountAndDatesByPage(Expression> filter, int pageIndex, int pageSize, string[] cols, bool isDeserialize = false, string collection = null) where T : Entity + { + using (await _dataBaseLock.Wait(RandomHelper.RandInt64() % DefaultTaskSize)) + { + var count = await Count(filter); + var dates = await QueryByPage(filter, pageIndex, pageSize, cols, isDeserialize, collection); + return ((int)count, dates); + } + } + + /// + /// 通过分页查询并返回满足条件的文档列表(不加锁)。 + /// + /// 文档实体类型。 + /// 查询过滤条件。 + /// 页码。 + /// 每页大小。 + /// 是否在查询后反序列化,执行反序列化后会自动将实体注册到框架系统中,并且能正常使用组件相关功能。 + /// 集合名称。 + /// 满足条件的文档列表。 + public async FTask> QueryByPage(Expression> filter, int pageIndex, int pageSize, bool isDeserialize = false, string collection = null) where T : Entity + { + using (await _dataBaseLock.Wait(RandomHelper.RandInt64() % DefaultTaskSize)) + { + var list = await GetCollection(collection).Find(filter).Skip((pageIndex - 1) * pageSize) + .Limit(pageSize) + .ToListAsync(); + + if (!isDeserialize || list is not { Count: > 0 }) + { + return list; + } + + foreach (var entity in list) + { + entity.Deserialize(_scene); + } + + return list; + } + } + + /// + /// 通过分页查询并返回满足条件的文档列表(加锁)。 + /// + /// 文档实体类型。 + /// 查询过滤条件。 + /// 页码。 + /// 每页大小。 + /// 要查询的列名称数组。 + /// 是否在查询后反序列化,执行反序列化后会自动将实体注册到框架系统中,并且能正常使用组件相关功能。 + /// 集合名称。 + /// 满足条件的文档列表。 + public async FTask> QueryByPage(Expression> filter, int pageIndex, int pageSize, string[] cols, bool isDeserialize = false, string collection = null) where T : Entity + { + using (await _dataBaseLock.Wait(RandomHelper.RandInt64() % DefaultTaskSize)) + { + var projection = Builders.Projection.Include(""); + + foreach (var col in cols) + { + projection = projection.Include(col); + } + + var list = await GetCollection(collection).Find(filter).Project(projection) + .Skip((pageIndex - 1) * pageSize).Limit(pageSize).ToListAsync(); + + if (!isDeserialize || list is not { Count: > 0 }) + { + return list; + } + + foreach (var entity in list) + { + entity.Deserialize(_scene); + } + + return list; + } + } + + /// + /// 通过分页查询并返回满足条件的文档列表,并按指定表达式进行排序(加锁)。 + /// + /// 文档实体类型。 + /// 查询过滤条件。 + /// 页码。 + /// 每页大小。 + /// 排序表达式。 + /// 是否升序排序。 + /// 是否在查询后反序列化,执行反序列化后会自动将实体注册到框架系统中,并且能正常使用组件相关功能。 + /// 集合名称。 + /// 满足条件的文档列表。 + public async FTask> QueryByPageOrderBy(Expression> filter, int pageIndex, int pageSize, Expression> orderByExpression, bool isAsc = true, bool isDeserialize = false, string collection = null) where T : Entity + { + using (await _dataBaseLock.Wait(RandomHelper.RandInt64() % DefaultTaskSize)) + { + List list; + + if (isAsc) + { + list = await GetCollection(collection).Find(filter).SortBy(orderByExpression).Skip((pageIndex - 1) * pageSize).Limit(pageSize).ToListAsync(); + } + else + { + list = await GetCollection(collection).Find(filter).SortByDescending(orderByExpression).Skip((pageIndex - 1) * pageSize).Limit(pageSize).ToListAsync(); + } + + if (!isDeserialize || list is not { Count: > 0 }) + { + return list; + } + + foreach (var entity in list) + { + entity.Deserialize(_scene); + } + + return list; + } + } + + /// + /// 通过指定过滤条件查询并返回满足条件的第一个文档(加锁)。 + /// + /// 文档实体类型。 + /// 查询过滤条件。 + /// 是否在查询后反序列化,执行反序列化后会自动将实体注册到框架系统中,并且能正常使用组件相关功能。 + /// 集合名称。 + /// 满足条件的第一个文档,如果未找到则为 null。 + public async FTask First(Expression> filter, bool isDeserialize = false, string collection = null) where T : Entity + { + using (await _dataBaseLock.Wait(RandomHelper.RandInt64() % DefaultTaskSize)) + { + var cursor = await GetCollection(collection).FindAsync(filter); + var t = await cursor.FirstOrDefaultAsync(); + + if (isDeserialize && t != null) + { + t.Deserialize(_scene); + } + + return t; + } + } + + /// + /// 通过指定 JSON 格式查询并返回满足条件的第一个文档(加锁)。 + /// + /// 文档实体类型。 + /// JSON 查询条件。 + /// 要查询的列名称数组。 + /// 是否在查询后反序列化,执行反序列化后会自动将实体注册到框架系统中,并且能正常使用组件相关功能。 + /// 集合名称。 + /// 满足条件的第一个文档。 + public async FTask First(string json, string[] cols, bool isDeserialize = false, string collection = null) where T : Entity + { + using (await _dataBaseLock.Wait(RandomHelper.RandInt64() % DefaultTaskSize)) + { + var projection = Builders.Projection.Include(""); + + foreach (var col in cols) + { + projection = projection.Include(col); + } + + var options = new FindOptions { Projection = projection }; + + FilterDefinition filterDefinition = new JsonFilterDefinition(json); + + var cursor = await GetCollection(collection).FindAsync(filterDefinition, options); + var t = await cursor.FirstOrDefaultAsync(); + + if (isDeserialize && t != null) + { + t.Deserialize(_scene); + } + + return t; + } + } + + /// + /// 通过指定过滤条件查询并返回满足条件的文档列表,并按指定表达式进行排序(加锁)。 + /// + /// 文档实体类型。 + /// 查询过滤条件。 + /// 排序表达式。 + /// 是否升序排序。 + /// 是否在查询后反序列化,执行反序列化后会自动将实体注册到框架系统中,并且能正常使用组件相关功能。 + /// 集合名称。 + /// 满足条件的文档列表。 + public async FTask> QueryOrderBy(Expression> filter, Expression> orderByExpression, bool isAsc = true, bool isDeserialize = false, string collection = null) where T : Entity + { + using (await _dataBaseLock.Wait(RandomHelper.RandInt64() % DefaultTaskSize)) + { + List list; + + if (isAsc) + { + list = await GetCollection(collection).Find(filter).SortBy(orderByExpression).ToListAsync(); + } + else + { + list = await GetCollection(collection).Find(filter).SortByDescending(orderByExpression).ToListAsync(); + } + + if (!isDeserialize || list is not { Count: > 0 }) + { + return list; + } + + foreach (var entity in list) + { + entity.Deserialize(_scene); + } + + return list; + } + } + + /// + /// 通过指定过滤条件查询并返回满足条件的文档列表(加锁)。 + /// + /// 文档实体类型。 + /// 查询过滤条件。 + /// 是否在查询后反序列化,执行反序列化后会自动将实体注册到框架系统中,并且能正常使用组件相关功能。 + /// 集合名称。 + /// 满足条件的文档列表。 + public async FTask> Query(Expression> filter, bool isDeserialize = false, string collection = null) where T : Entity + { + using (await _dataBaseLock.Wait(RandomHelper.RandInt64() % DefaultTaskSize)) + { + var cursor = await GetCollection(collection).FindAsync(filter); + var list = await cursor.ToListAsync(); + + if (!isDeserialize || list is not { Count: > 0 }) + { + return list; + } + + foreach (var entity in list) + { + entity.Deserialize(_scene); + } + + return list; + } + } + + /// + /// 根据指定 ID 加锁查询多个集合中的文档。 + /// + /// 文档 ID。 + /// 要查询的集合名称列表。 + /// 查询结果存储列表。 + /// 是否在查询后反序列化,执行反序列化后会自动将实体注册到框架系统中,并且能正常使用组件相关功能。 + public async FTask Query(long id, List? collectionNames, List result, bool isDeserialize = false) + { + using (await _dataBaseLock.Wait(id)) + { + if (collectionNames == null || collectionNames.Count == 0) + { + return; + } + + foreach (var collectionName in collectionNames) + { + var cursor = await GetCollection(collectionName).FindAsync(d => d.Id == id); + + var e = await cursor.FirstOrDefaultAsync(); + + if (e == null) + { + continue; + } + + if (isDeserialize) + { + e.Deserialize(_scene); + } + + result.Add(e); + } + } + } + + /// + /// 根据指定的 JSON 查询条件查询并返回满足条件的文档列表(加锁)。 + /// + /// 文档实体类型。 + /// JSON 查询条件。 + /// 是否在查询后反序列化,执行反序列化后会自动将实体注册到框架系统中,并且能正常使用组件相关功能。 + /// 集合名称。 + /// 满足条件的文档列表。 + public async FTask> QueryJson(string json, bool isDeserialize = false, string collection = null) where T : Entity + { + using (await _dataBaseLock.Wait(RandomHelper.RandInt64() % DefaultTaskSize)) + { + FilterDefinition filterDefinition = new JsonFilterDefinition(json); + var cursor = await GetCollection(collection).FindAsync(filterDefinition); + var list = await cursor.ToListAsync(); + + if (!isDeserialize || list is not { Count: > 0 }) + { + return list; + } + + foreach (var entity in list) + { + entity.Deserialize(_scene); + } + + return list; + } + } + + /// + /// 根据指定的 JSON 查询条件查询并返回满足条件的文档列表,并选择指定的列(加锁)。 + /// + /// 文档实体类型。 + /// JSON 查询条件。 + /// 要查询的列名称数组。 + /// 是否在查询后反序列化,执行反序列化后会自动将实体注册到框架系统中,并且能正常使用组件相关功能。 + /// 集合名称。 + /// 满足条件的文档列表。 + public async FTask> QueryJson(string json, string[] cols, bool isDeserialize = false, string collection = null) where T : Entity + { + using (await _dataBaseLock.Wait(RandomHelper.RandInt64() % DefaultTaskSize)) + { + var projection = Builders.Projection.Include(""); + + foreach (var col in cols) + { + projection = projection.Include(col); + } + + var options = new FindOptions { Projection = projection }; + + FilterDefinition filterDefinition = new JsonFilterDefinition(json); + + var cursor = await GetCollection(collection).FindAsync(filterDefinition, options); + var list = await cursor.ToListAsync(); + + if (!isDeserialize || list is not { Count: > 0 }) + { + return list; + } + + foreach (var entity in list) + { + entity.Deserialize(_scene); + } + + return list; + } + } + + /// + /// 根据指定的 JSON 查询条件和任务 ID 查询并返回满足条件的文档列表(加锁)。 + /// + /// 文档实体类型。 + /// 任务 ID。 + /// JSON 查询条件。 + /// 是否在查询后反序列化,执行反序列化后会自动将实体注册到框架系统中,并且能正常使用组件相关功能。 + /// 集合名称。 + /// 满足条件的文档列表。 + public async FTask> QueryJson(long taskId, string json, bool isDeserialize = false, string collection = null) where T : Entity + { + using (await _dataBaseLock.Wait(taskId)) + { + FilterDefinition filterDefinition = new JsonFilterDefinition(json); + var cursor = await GetCollection(collection).FindAsync(filterDefinition); + var list = await cursor.ToListAsync(); + + if (!isDeserialize || list is not { Count: > 0 }) + { + return list; + } + + foreach (var entity in list) + { + entity.Deserialize(_scene); + } + + return list; + } + } + + /// + /// 根据指定过滤条件查询并返回满足条件的文档列表,选择指定的列(加锁)。 + /// + /// 文档实体类型。 + /// 查询过滤条件。 + /// 要查询的列名称数组。 + /// 是否在查询后反序列化,执行反序列化后会自动将实体注册到框架系统中,并且能正常使用组件相关功能。 + /// 集合名称。 + /// 满足条件的文档列表。 + public async FTask> Query(Expression> filter, string[] cols, bool isDeserialize = false, string collection = null) where T : Entity + { + using (await _dataBaseLock.Wait(RandomHelper.RandInt64() % DefaultTaskSize)) + { + var projection = Builders.Projection.Include("_id"); + + foreach (var t in cols) + { + projection = projection.Include(t); + } + + var list = await GetCollection(collection).Find(filter).Project(projection).ToListAsync(); + + if (!isDeserialize || list is not { Count: > 0 }) + { + return list; + } + + foreach (var entity in list) + { + entity.Deserialize(_scene); + } + + return list; + } + } + + /// + /// 根据指定过滤条件查询并返回满足条件的文档列表,选择指定的列(加锁)。 + /// + /// 文档实体类型。 + /// 查询过滤条件。 + /// 要查询的列名称数组。 + /// 是否在查询后反序列化,执行反序列化后会自动将实体注册到框架系统中,并且能正常使用组件相关功能。 + /// 集合名称。 + /// + public async FTask> Query(Expression> filter, Expression>[] cols, bool isDeserialize = false, string collection = null) where T : Entity + { + using (await _dataBaseLock.Wait(RandomHelper.RandInt64() % DefaultTaskSize)) + { + var projection = Builders.Projection.Include("_id"); + + foreach (var col in cols) + { + if (col.Body is not MemberExpression memberExpression) + { + throw new ArgumentException("Lambda expression must be a member access expression."); + } + + projection = projection.Include(memberExpression.Member.Name); + } + + var list = await GetCollection(collection).Find(filter).Project(projection).ToListAsync(); + + if (!isDeserialize || list is not { Count: > 0 }) + { + return list; + } + + foreach (var entity in list) + { + entity.Deserialize(_scene); + } + + return list; + } + } + + #endregion + + #region Save + + /// + /// 保存实体对象到数据库(加锁)。 + /// + /// 实体类型。 + /// 事务会话对象。 + /// 要保存的实体对象。 + /// 集合名称。 + public async FTask Save(object transactionSession, T? entity, string collection = null) where T : Entity + { + if (entity == null) + { + Log.Error($"save entity is null: {typeof(T).Name}"); + return; + } + + var clone = _serializer.Clone(entity); + + using (await _dataBaseLock.Wait(clone.Id)) + { + await GetCollection(collection).ReplaceOneAsync( + (IClientSessionHandle)transactionSession, d => d.Id == clone.Id, clone, + new ReplaceOptions { IsUpsert = true }); + } + } + + /// + /// 保存实体对象到数据库(加锁)。 + /// + /// 实体类型。 + /// 要保存的实体对象。 + /// 集合名称。 + public async FTask Save(T? entity, string collection = null) where T : Entity, new() + { + if (entity == null) + { + Log.Error($"save entity is null: {typeof(T).Name}"); + + return; + } + + var clone = _serializer.Clone(entity); + + using (await _dataBaseLock.Wait(clone.Id)) + { + await GetCollection(collection).ReplaceOneAsync(d => d.Id == clone.Id, clone, new ReplaceOptions { IsUpsert = true }); + } + } + + /// + /// 保存实体对象到数据库(加锁)。 + /// + /// 保存的条件表达式。 + /// 实体类型。 + /// 集合名称。 + /// + public async FTask Save(Expression> filter, T? entity, string collection = null) where T : Entity, new() + { + if (entity == null) + { + Log.Error($"save entity is null: {typeof(T).Name}"); + return; + } + + T clone = _serializer.Clone(entity); + + using (await _dataBaseLock.Wait(clone.Id)) + { + await GetCollection(collection).ReplaceOneAsync(filter, clone, new ReplaceOptions { IsUpsert = true }); + } + } + + /// + /// 保存多个实体对象到数据库(加锁)。 + /// + /// 文档 ID。 + /// 要保存的实体对象列表。 + public async FTask Save(long id, List? entities) + { + if (entities == null || entities.Count == 0) + { + Log.Error("save entity is null"); + return; + } + + using var listPool = ListPool.Create(); + + foreach (var entity in entities) + { + listPool.Add(_serializer.Clone(entity)); + } + + using (await _dataBaseLock.Wait(id)) + { + foreach (var clone in listPool) + { + try + { + await GetCollection(clone.GetType().Name).ReplaceOneAsync(d => d.Id == clone.Id, clone, new ReplaceOptions { IsUpsert = true }); + } + catch (Exception e) + { + Log.Error($"Save List Entity Error: {clone.GetType().Name} {clone}\n{e}"); + } + } + } + } + + #endregion + + #region Insert + + /// + /// 插入单个实体对象到数据库(加锁)。 + /// + /// 实体类型。 + /// 要插入的实体对象。 + /// 集合名称。 + public async FTask Insert(T? entity, string collection = null) where T : Entity, new() + { + if (entity == null) + { + Log.Error($"insert entity is null: {typeof(T).Name}"); + return; + } + + var clone = _serializer.Clone(entity); + + using (await _dataBaseLock.Wait(entity.Id)) + { + await GetCollection(collection).InsertOneAsync(clone); + } + } + + /// + /// 批量插入实体对象列表到数据库(加锁)。 + /// + /// 实体类型。 + /// 要插入的实体对象列表。 + /// 集合名称。 + public async FTask InsertBatch(IEnumerable list, string collection = null) where T : Entity, new() + { + using (await _dataBaseLock.Wait(RandomHelper.RandInt64() % DefaultTaskSize)) + { + await GetCollection(collection).InsertManyAsync(list); + } + } + + /// + /// 批量插入实体对象列表到数据库(加锁)。 + /// + /// 实体类型。 + /// 事务会话对象。 + /// 要插入的实体对象列表。 + /// 集合名称。 + public async FTask InsertBatch(object transactionSession, IEnumerable list, string collection = null) + where T : Entity, new() + { + using (await _dataBaseLock.Wait(RandomHelper.RandInt64() % DefaultTaskSize)) + { + await GetCollection(collection).InsertManyAsync((IClientSessionHandle)transactionSession, list); + } + } + + /// + /// 插入BsonDocument到数据库(加锁)。 + /// + /// + /// + /// + public async Task Insert(BsonDocument bsonDocument, long taskId) where T : Entity + { + using (await _dataBaseLock.Wait(taskId)) + { + await GetCollection(typeof(T).Name).InsertOneAsync(bsonDocument); + } + } + + #endregion + + #region Remove + + /// + /// 根据ID删除单个实体对象(加锁)。 + /// + /// 实体类型。 + /// 事务会话对象。 + /// 要删除的实体的ID。 + /// 集合名称。 + /// 删除的实体数量。 + public async FTask Remove(object transactionSession, long id, string collection = null) + where T : Entity, new() + { + using (await _dataBaseLock.Wait(id)) + { + var result = await GetCollection(collection) + .DeleteOneAsync((IClientSessionHandle)transactionSession, d => d.Id == id); + return result.DeletedCount; + } + } + + /// + /// 根据ID删除单个实体对象(加锁)。 + /// + /// 实体类型。 + /// 要删除的实体的ID。 + /// 集合名称。 + /// 删除的实体数量。 + public async FTask Remove(long id, string collection = null) where T : Entity, new() + { + using (await _dataBaseLock.Wait(id)) + { + var result = await GetCollection(collection).DeleteOneAsync(d => d.Id == id); + return result.DeletedCount; + } + } + + /// + /// 根据ID和筛选条件删除多个实体对象(加锁)。 + /// + /// 实体类型。 + /// 异步锁Id。 + /// 事务会话对象。 + /// 筛选条件。 + /// 集合名称。 + /// 删除的实体数量。 + public async FTask Remove(long coroutineLockQueueKey, object transactionSession, + Expression> filter, string collection = null) where T : Entity, new() + { + using (await _dataBaseLock.Wait(coroutineLockQueueKey)) + { + var result = await GetCollection(collection) + .DeleteManyAsync((IClientSessionHandle)transactionSession, filter); + return result.DeletedCount; + } + } + + /// + /// 根据ID和筛选条件删除多个实体对象(加锁)。 + /// + /// 实体类型。 + /// 异步锁Id。 + /// 筛选条件。 + /// 集合名称。 + /// 删除的实体数量。 + public async FTask Remove(long coroutineLockQueueKey, Expression> filter, + string collection = null) where T : Entity, new() + { + using (await _dataBaseLock.Wait(coroutineLockQueueKey)) + { + var result = await GetCollection(collection).DeleteManyAsync(filter); + return result.DeletedCount; + } + } + + #endregion + + #region Index + + /// + /// 创建数据库索引(加锁)。 + /// + /// + /// + /// + /// + /// 使用例子(可多个): + /// 1 : Builders.IndexKeys.Ascending(d=>d.Id) + /// 2 : Builders.IndexKeys.Descending(d=>d.Id).Ascending(d=>d.Name) + /// 3 : Builders.IndexKeys.Descending(d=>d.Id),Builders.IndexKeys.Descending(d=>d.Name) + /// + public async FTask CreateIndex(string collection, params object[]? keys) where T : Entity + { + if (keys == null || keys.Length <= 0) + { + return; + } + + var indexModels = new List>(); + + foreach (object key in keys) + { + IndexKeysDefinition indexKeysDefinition = (IndexKeysDefinition)key; + + indexModels.Add(new CreateIndexModel(indexKeysDefinition)); + } + + await GetCollection(collection).Indexes.CreateManyAsync(indexModels); + } + + /// + /// 创建数据库的索引(加锁)。 + /// + /// 实体类型。 + /// 索引键定义。 + public async FTask CreateIndex(params object[]? keys) where T : Entity + { + if (keys == null) + { + return; + } + + List> indexModels = new List>(); + + foreach (object key in keys) + { + IndexKeysDefinition indexKeysDefinition = (IndexKeysDefinition)key; + + indexModels.Add(new CreateIndexModel(indexKeysDefinition)); + } + + await GetCollection().Indexes.CreateManyAsync(indexModels); + } + + #endregion + + #region CreateDB + + /// + /// 创建数据库集合(如果不存在)。 + /// + /// 实体类型。 + public async FTask CreateDB() where T : Entity + { + // 已经存在数据库表 + string name = typeof(T).Name; + + if (_collections.Contains(name)) + { + return; + } + + await _mongoDatabase.CreateCollectionAsync(name); + + _collections.Add(name); + } + + /// + /// 创建数据库集合(如果不存在)。 + /// + /// 实体类型。 + public async FTask CreateDB(Type type) + { + string name = type.Name; + + if (_collections.Contains(name)) + { + return; + } + + await _mongoDatabase.CreateCollectionAsync(name); + + _collections.Add(name); + } + + #endregion + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataBase/MongoDataBase.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataBase/MongoDataBase.cs.meta new file mode 100644 index 0000000..b26748a --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataBase/MongoDataBase.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 366dcc82090f0466da2c2b8d0e6fa2c2 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataBase/World.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataBase/World.cs new file mode 100644 index 0000000..c53351f --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataBase/World.cs @@ -0,0 +1,77 @@ +#pragma warning disable CS8603 // Possible null reference return. +#if FANTASY_NET +using Fantasy.Platform.Net; + +namespace Fantasy.DataBase +{ + /// + /// 表示一个游戏世界。 + /// + public sealed class World : IDisposable + { + /// + /// 获取游戏世界的唯一标识。 + /// + public byte Id { get; private init; } + /// + /// 获取游戏世界的数据库接口。 + /// + public IDataBase DataBase { get; private init; } + /// + /// 获取游戏世界的配置信息。 + /// + public WorldConfig Config => WorldConfigData.Instance.Get(Id); + + /// + /// 使用指定的配置信息创建一个游戏世界实例。 + /// + /// + /// + private World(Scene scene, byte worldConfigId) + { + Id = worldConfigId; + var worldConfig = Config; + var dbType = worldConfig.DbType.ToLower(); + + switch (dbType) + { + case "mongodb": + { + DataBase = new MongoDataBase(); + DataBase.Initialize(scene, worldConfig.DbConnection, worldConfig.DbName); + break; + } + default: + { + throw new Exception("No supported database"); + } + } + } + + /// + /// 创建一个指定唯一标识的游戏世界实例。 + /// + /// + /// 游戏世界的唯一标识。 + /// 游戏世界实例。 + internal static World Create(Scene scene, byte id) + { + if (!WorldConfigData.Instance.TryGet(id, out var worldConfigData)) + { + return null; + } + + return string.IsNullOrEmpty(worldConfigData.DbConnection) ? null : new World(scene, id); + } + + /// + /// 释放游戏世界资源。 + /// + public void Dispose() + { + DataBase.Dispose(); + } + } +} + +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataBase/World.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataBase/World.cs.meta new file mode 100644 index 0000000..00bf052 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataBase/World.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6f02362ef34274e508386e3cdc247927 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure.meta new file mode 100644 index 0000000..9aa09d4 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: afe876696fb5f4779abe3289a3bf4f9f +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/Collection.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/Collection.meta new file mode 100644 index 0000000..04e1280 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/Collection.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 0b3d477f03f404310b5ad48f89d1f193 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/Collection/CircularBuffer.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/Collection/CircularBuffer.cs new file mode 100644 index 0000000..d80ec55 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/Collection/CircularBuffer.cs @@ -0,0 +1,346 @@ +using System; +using System.Collections.Generic; +using System.IO; +#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. + +namespace Fantasy.DataStructure.Collection +{ + /// 环形缓存(自增式缓存,自动扩充、不会收缩缓存、所以不要用这个操作过大的IO流) + /// 1、环大小8192,溢出的会自动增加环的大小。 + /// 2、每个块都是一个环形缓存,当溢出的时候会自动添加到下一个环中。 + /// 3、当读取完成后用过的环会放在缓存中,不会销毁掉。 + /// + /// 自增式缓存类,继承自 Stream 和 IDisposable 接口。 + /// 环形缓存具有自动扩充的特性,但不会收缩,适用于操作不过大的 IO 流。 + /// + public sealed class CircularBuffer : Stream, IDisposable + { + private byte[] _lastBuffer; + /// + /// 环形缓存块的默认大小 + /// + public const int ChunkSize = 8192; + private readonly Queue _bufferCache = new Queue(); + private readonly Queue _bufferQueue = new Queue(); + /// + /// 获取或设置环形缓存的第一个索引位置 + /// + public int FirstIndex { get; set; } + /// + /// 获取或设置环形缓存的最后一个索引位置 + /// + public int LastIndex { get; set; } + /// + /// 获取环形缓存的总长度 + /// + public override long Length + { + get + { + if (_bufferQueue.Count == 0) + { + return 0; + } + + return (_bufferQueue.Count - 1) * ChunkSize + LastIndex - FirstIndex; + } + } + + /// + /// 获取环形缓存的第一个块 + /// + public byte[] First + { + get + { + if (_bufferQueue.Count == 0) + { + AddLast(); + } + + return _bufferQueue.Peek(); + } + } + + /// + /// 获取环形缓存的最后一个块 + /// + public byte[] Last + { + get + { + if (_bufferQueue.Count == 0) + { + AddLast(); + } + + return _lastBuffer; + } + } + /// + /// 向环形缓存中添加一个新的块 + /// + public void AddLast() + { + var buffer = _bufferCache.Count > 0 ? _bufferCache.Dequeue() : new byte[ChunkSize]; + _bufferQueue.Enqueue(buffer); + _lastBuffer = buffer; + } + /// + /// 从环形缓存中移除第一个块 + /// + public void RemoveFirst() + { + _bufferCache.Enqueue(_bufferQueue.Dequeue()); + } + + /// + /// 从流中读取指定数量的数据到缓存。 + /// + /// 源数据流。 + /// 要读取的字节数。 + public void Read(Stream stream, int count) + { + if (count > Length) + { + throw new Exception($"bufferList length < count, {Length} {count}"); + } + + var copyCount = 0; + while (copyCount < count) + { + var n = count - copyCount; + if (ChunkSize - FirstIndex > n) + { + stream.Write(First, FirstIndex, n); + FirstIndex += n; + copyCount += n; + } + else + { + stream.Write(First, FirstIndex, ChunkSize - FirstIndex); + copyCount += ChunkSize - FirstIndex; + FirstIndex = 0; + RemoveFirst(); + } + } + } + + /// + /// 从缓存中读取指定数量的数据到内存。 + /// + /// 目标内存。 + /// 要读取的字节数。 + public void Read(Memory memory, int count) + { + if (count > Length) + { + throw new Exception($"bufferList length < count, {Length} {count}"); + } + + var copyCount = 0; + while (copyCount < count) + { + var n = count - copyCount; + var asMemory = First.AsMemory(); + + if (ChunkSize - FirstIndex > n) + { + var slice = asMemory.Slice(FirstIndex, n); + slice.CopyTo(memory.Slice(copyCount, n)); + FirstIndex += n; + copyCount += n; + } + else + { + var length = ChunkSize - FirstIndex; + var slice = asMemory.Slice(FirstIndex, length); + slice.CopyTo(memory.Slice(copyCount, length)); + copyCount += ChunkSize - FirstIndex; + FirstIndex = 0; + RemoveFirst(); + } + } + } + + /// + /// 从自定义流中读取数据到指定的缓冲区。 + /// + /// 目标缓冲区,用于存储读取的数据。 + /// 目标缓冲区中的起始偏移量。 + /// 要读取的字节数。 + /// 实际读取的字节数。 + public override int Read(byte[] buffer, int offset, int count) + { + if (buffer.Length < offset + count) + { + throw new Exception($"buffer length < count, buffer length: {buffer.Length} {offset} {count}"); + } + + var length = Length; + if (length < count) + { + count = (int) length; + } + + var copyCount = 0; + + // 循环直到成功读取所需的字节数 + while (copyCount < count) + { + var copyLength = count - copyCount; + + if (ChunkSize - FirstIndex > copyLength) + { + // 将数据从当前块的缓冲区复制到目标缓冲区 + Array.Copy(First, FirstIndex, buffer, copyCount + offset, copyLength); + + FirstIndex += copyLength; + copyCount += copyLength; + continue; + } + + // 复制当前块中剩余的数据,并切换到下一个块 + Array.Copy(First, FirstIndex, buffer, copyCount + offset, ChunkSize - FirstIndex); + copyCount += ChunkSize - FirstIndex; + FirstIndex = 0; + + RemoveFirst(); + } + + return count; + } + + /// + /// 将数据从给定的字节数组写入流中。 + /// + /// 包含要写入的数据的字节数组。 + public void Write(byte[] buffer) + { + Write(buffer, 0, buffer.Length); + } + + /// + /// 将数据从给定的流写入流中。 + /// + /// 包含要写入的数据的流。 + public void Write(Stream stream) + { + var copyCount = 0; + var count = (int) (stream.Length - stream.Position); + + while (copyCount < count) + { + if (LastIndex == ChunkSize) + { + AddLast(); + LastIndex = 0; + } + + var n = count - copyCount; + + if (ChunkSize - LastIndex > n) + { + _ = stream.Read(Last, LastIndex, n); + LastIndex += count - copyCount; + copyCount += n; + } + else + { + _ = stream.Read(Last, LastIndex, ChunkSize - LastIndex); + copyCount += ChunkSize - LastIndex; + LastIndex = ChunkSize; + } + } + } + + /// + /// 将数据从给定的字节数组写入流中。 + /// + /// 包含要写入的数据的字节数组。 + /// 开始写入的缓冲区中的索引。 + /// 要写入的字节数。 + public override void Write(byte[] buffer, int offset, int count) + { + var copyCount = 0; + + while (copyCount < count) + { + if (ChunkSize == LastIndex) + { + AddLast(); + LastIndex = 0; + } + + var byteLength = count - copyCount; + + if (ChunkSize - LastIndex > byteLength) + { + Array.Copy(buffer, copyCount + offset, Last, LastIndex, byteLength); + LastIndex += byteLength; + copyCount += byteLength; + } + else + { + Array.Copy(buffer, copyCount + offset, Last, LastIndex, ChunkSize - LastIndex); + copyCount += ChunkSize - LastIndex; + LastIndex = ChunkSize; + } + } + } + + /// + /// 获取一个值,指示流是否支持读取操作。 + /// + public override bool CanRead { get; } = true; + /// + /// 获取一个值,指示流是否支持寻找操作。 + /// + public override bool CanSeek { get; } = false; + /// + /// 获取一个值,指示流是否支持写入操作。 + /// + public override bool CanWrite { get; } = true; + /// + /// 获取或设置流中的位置。 + /// + public override long Position { get; set; } + + /// + /// 刷新流(在此实现中引发未实现异常)。 + /// + public override void Flush() + { + throw new NotImplementedException(); + } + + /// + /// 在流中寻找特定位置(在此实现中引发未实现异常)。 + /// + public override long Seek(long offset, SeekOrigin origin) + { + throw new NotImplementedException(); + } + + /// + /// 设置流的长度(在此实现中引发未实现异常)。 + /// + public override void SetLength(long value) + { + throw new NotImplementedException(); + } + + /// + /// 释放 CustomStream 使用的所有资源。 + /// + public new void Dispose() + { + _bufferQueue.Clear(); + _lastBuffer = null; + FirstIndex = 0; + LastIndex = 0; + base.Dispose(); + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/Collection/CircularBuffer.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/Collection/CircularBuffer.cs.meta new file mode 100644 index 0000000..ee284a2 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/Collection/CircularBuffer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 38264758f23d1448a975efc4f4b7da63 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/Collection/ConcurrentOneToManyListPool.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/Collection/ConcurrentOneToManyListPool.cs new file mode 100644 index 0000000..e110a0b --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/Collection/ConcurrentOneToManyListPool.cs @@ -0,0 +1,197 @@ +#if !FANTASY_WEBGL +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Linq; +using Fantasy.Pool; + +#pragma warning disable CS8603 // Possible null reference return. + +namespace Fantasy.DataStructure.Collection +{ + /// + /// 并发的一对多列表池,用于维护具有相同键的多个值的关联关系,实现了 接口。 + /// + /// 关键字的类型,不能为空。 + /// 值的类型。 + public class ConcurrentOneToManyListPool : ConcurrentOneToManyList, IDisposable, IPool where TKey : notnull + { + private bool _isPool; + private bool _isDispose; + + /// + /// 创建一个 的实例。 + /// + /// 创建的实例。 + public static ConcurrentOneToManyListPool Create() + { + var a = MultiThreadPool.Rent>(); + a._isDispose = false; + a._isPool = true; + return a; + } + + /// + /// 释放实例占用的资源。 + /// + public void Dispose() + { + if (_isDispose) + { + return; + } + + _isDispose = true; + // 清空实例的数据 + Clear(); + // 将实例返回到池中以便重用 + MultiThreadPool.Return(this); + } + + /// + /// 获取一个值,该值指示当前实例是否为对象池中的实例。 + /// + /// + public bool IsPool() + { + return _isPool; + } + + /// + /// 设置一个值,该值指示当前实例是否为对象池中的实例。 + /// + /// + public void SetIsPool(bool isPool) + { + _isPool = isPool; + } + } + + /// + /// 并发的一对多列表,用于维护具有相同键的多个值的关联关系。 + /// + /// 关键字的类型,不能为空。 + /// 值的类型。 + public class ConcurrentOneToManyList : ConcurrentDictionary> where TKey : notnull + { + private readonly Queue> _queue = new Queue>(); + private readonly int _recyclingLimit = 120; + + /// + /// 初始化 类的新实例。 + /// + public ConcurrentOneToManyList() + { + } + + /// + /// 设置最大缓存数量 + /// + /// + /// 1:防止数据量过大、所以超过recyclingLimit的数据还是走GC. + /// 2:设置成0不控制数量,全部缓存 + /// + public ConcurrentOneToManyList(int recyclingLimit) + { + _recyclingLimit = recyclingLimit; + } + + /// + /// 判断指定键的列表是否包含指定值。 + /// + /// 要搜索的键。 + /// 要搜索的值。 + /// 如果列表包含值,则为 true;否则为 false。 + public bool Contains(TKey key, TValue value) + { + TryGetValue(key, out var list); + + return list != null && list.Contains(value); + } + + /// + /// 向指定键的列表中添加一个值。 + /// + /// 要添加值的键。 + /// 要添加的值。 + public void Add(TKey key, TValue value) + { + if (!TryGetValue(key, out var list)) + { + list = Fetch(); + list.Add(value); + base[key] = list; + return; + } + + list.Add(value); + } + + /// + /// 获取指定键的列表中的第一个值。 + /// + /// 要获取第一个值的键。 + /// 指定键的列表中的第一个值,如果不存在则为默认值。 + public TValue First(TKey key) + { + return !TryGetValue(key, out var list) ? default : list.FirstOrDefault(); + } + + /// + /// 从指定键的列表中移除一个值。 + /// + /// 要移除值的键。 + /// 要移除的值。 + public void RemoveValue(TKey key, TValue value) + { + if (!TryGetValue(key, out var list)) return; + + list.Remove(value); + + if (list.Count == 0) RemoveKey(key); + } + + /// + /// 从字典中移除指定键以及其关联的列表。 + /// + /// 要移除的键。 + public void RemoveKey(TKey key) + { + if (!TryRemove(key, out var list)) return; + + Recycle(list); + } + + /// + /// 从队列中获取一个列表,如果队列为空则创建一个新的列表。 + /// + /// 获取的列表。 + private List Fetch() + { + return _queue.Count <= 0 ? new List() : _queue.Dequeue(); + } + + /// + /// 将一个列表回收到队列中。 + /// + /// 要回收的列表。 + private void Recycle(List list) + { + list.Clear(); + + if (_recyclingLimit != 0 && _queue.Count > _recyclingLimit) return; + + _queue.Enqueue(list); + } + + /// + /// 清空当前类的数据,包括从基类继承的数据以及自定义的数据队列。 + /// + protected new void Clear() + { + base.Clear(); + _queue.Clear(); + } + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/Collection/ConcurrentOneToManyListPool.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/Collection/ConcurrentOneToManyListPool.cs.meta new file mode 100644 index 0000000..3b3b7d2 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/Collection/ConcurrentOneToManyListPool.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 21b2d3135b133441aa08c5eb1768a103 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/Collection/ConcurrentOneToManyQueuePool.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/Collection/ConcurrentOneToManyQueuePool.cs new file mode 100644 index 0000000..59c4367 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/Collection/ConcurrentOneToManyQueuePool.cs @@ -0,0 +1,194 @@ +#if !FANTASY_WEBGL +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using Fantasy.Pool; + +#pragma warning disable CS8603 + +namespace Fantasy.DataStructure.Collection +{ + /// + /// 表示一个并发的一对多队列池,用于维护具有相同键的多个值的关联关系,实现了 接口。 + /// + /// 关键字的类型,不能为空。 + /// 值的类型。 + public class ConcurrentOneToManyQueuePool : ConcurrentOneToManyQueue, IDisposable, IPool where TKey : notnull + { + private bool _isPool; + private bool _isDispose; + + /// + /// 创建并返回一个 的实例。 + /// + /// 创建的实例。 + public static ConcurrentOneToManyQueuePool Create() + { + var a = MultiThreadPool.Rent>(); + a._isDispose = false; + a._isPool = true; + return a; + } + + /// + /// 释放当前实例所占用的资源,并将实例返回到对象池中,以便重用。 + /// + public void Dispose() + { + if (_isDispose) + { + return; + } + + _isDispose = true; + Clear(); + // 将实例返回到对象池中,以便重用 + MultiThreadPool.Return(this); + } + + /// + /// 获取一个值,该值指示当前实例是否为对象池中的实例。 + /// + /// + public bool IsPool() + { + return _isPool; + } + + /// + /// 设置一个值,该值指示当前实例是否为对象池中的实例。 + /// + /// + public void SetIsPool(bool isPool) + { + _isPool = isPool; + } + } + + /// + /// 表示一个并发的一对多队列,用于维护具有相同键的多个值的关联关系。 + /// + /// 关键字的类型,不能为空。 + /// 值的类型。 + public class ConcurrentOneToManyQueue : ConcurrentDictionary> where TKey : notnull + { + private readonly Queue> _queue = new Queue>(); + private readonly int _recyclingLimit; + + /// + /// 设置最大缓存数量 + /// + /// + /// 1:防止数据量过大、所以超过recyclingLimit的数据还是走GC. + /// 2:设置成0不控制数量,全部缓存 + /// + public ConcurrentOneToManyQueue(int recyclingLimit = 0) + { + _recyclingLimit = recyclingLimit; + } + + /// + /// 判断指定键的队列是否包含指定值。 + /// + /// 要搜索的键。 + /// 要搜索的值。 + /// 如果队列包含值,则为 true;否则为 false。 + public bool Contains(TKey key, TValue value) + { + TryGetValue(key, out var list); + + return list != null && list.Contains(value); + } + + /// + /// 向指定键的队列中添加一个值。 + /// + /// 要添加值的键。 + /// 要添加的值。 + public void Enqueue(TKey key, TValue value) + { + if (!TryGetValue(key, out var list)) + { + list = Fetch(); + list.Enqueue(value); + TryAdd(key, list); + return; + } + + list.Enqueue(value); + } + + /// + /// 从指定键的队列中出队并返回一个值。 + /// + /// 要出队的键。 + /// 出队的值,如果队列为空则为默认值。 + public TValue Dequeue(TKey key) + { + if (!TryGetValue(key, out var list) || list.Count == 0) return default; + + var value = list.Dequeue(); + + if (list.Count == 0) RemoveKey(key); + + return value; + } + + /// + /// 尝试从指定键的队列中出队一个值。 + /// + /// 要出队的键。 + /// 出队的值,如果队列为空则为默认值。 + /// 如果成功出队,则为 true;否则为 false。 + public bool TryDequeue(TKey key, out TValue value) + { + value = Dequeue(key); + + return value != null; + } + + /// + /// 从字典中移除指定键以及其关联的队列。 + /// + /// 要移除的键。 + public void RemoveKey(TKey key) + { + if (!TryGetValue(key, out var list)) return; + + TryRemove(key, out _); + Recycle(list); + } + + /// + /// 从队列中获取一个新的队列,如果队列为空则创建一个新的队列。 + /// + /// 获取的队列。 + private Queue Fetch() + { + return _queue.Count <= 0 ? new Queue() : _queue.Dequeue(); + } + + /// + /// 将一个队列回收到队列池中。 + /// + /// 要回收的队列。 + private void Recycle(Queue list) + { + list.Clear(); + + if (_recyclingLimit != 0 && _queue.Count > _recyclingLimit) return; + + _queue.Enqueue(list); + } + + /// + /// 清空当前类的数据,包括从基类继承的键值对字典中的数据以及自定义的队列池。 + /// + protected new void Clear() + { + base.Clear(); + _queue.Clear(); + } + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/Collection/ConcurrentOneToManyQueuePool.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/Collection/ConcurrentOneToManyQueuePool.cs.meta new file mode 100644 index 0000000..1497661 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/Collection/ConcurrentOneToManyQueuePool.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 50a0f004d8b7b4075a4ce01376e49375 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/Collection/HashSetPool.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/Collection/HashSetPool.cs new file mode 100644 index 0000000..bb64ae8 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/Collection/HashSetPool.cs @@ -0,0 +1,134 @@ +using System; +using System.Collections.Generic; +using Fantasy.Pool; + +namespace Fantasy.DataStructure.Collection +{ + /// + /// 可释放的哈希集合对象池。 + /// + /// 哈希集合中元素的类型。 + public sealed class HashSetPool : HashSet, IDisposable, IPool + { + private bool _isPool; + private bool _isDispose; + + /// + /// 释放实例所占用的资源,并将实例返回到对象池中,以便重用。 + /// + public void Dispose() + { + if (_isDispose) + { + return; + } + + _isDispose = true; + Clear(); +#if FANTASY_WEBGL + Pool>.Return(this); +#else + MultiThreadPool.Return(this); +#endif + } + + /// + /// 创建一个 哈希集合池的实例。 + /// + /// 创建的实例。 + public static HashSetPool Create() + { +#if FANTASY_WEBGL + var list = Pool>.Rent(); + list._isDispose = false; + list._isPool = true; + return list; +#else + var list = MultiThreadPool.Rent>(); + list._isDispose = false; + list._isPool = true; + return list; +#endif + } + + /// + /// 获取一个值,该值指示当前实例是否为对象池中的实例。 + /// + /// + public bool IsPool() + { + return _isPool; + } + + /// + /// 设置一个值,该值指示当前实例是否为对象池中的实例。 + /// + /// + public void SetIsPool(bool isPool) + { + _isPool = isPool; + } + } + + /// + /// 基本哈希集合对象池,他自持有实际的哈希集合。 + /// + /// 哈希集合中元素的类型。 + public sealed class HashSetBasePool : IDisposable, IPool + { + private bool _isPool; + + /// + /// 存储实际的哈希集合 + /// + public HashSet Set = new HashSet(); + + /// + /// 创建一个 基本哈希集合对象池的实例。 + /// + /// 创建的实例。 + public static HashSetBasePool Create() + { +#if FANTASY_WEBGL + var hashSetBasePool = Pool>.Rent(); + hashSetBasePool._isPool = true; + return hashSetBasePool; +#else + var hashSetBasePool = MultiThreadPool.Rent>(); + hashSetBasePool._isPool = true; + return hashSetBasePool; +#endif + } + + /// + /// 释放实例所占用的资源,并将实例返回到对象池中,以便重用。 + /// + public void Dispose() + { + Set.Clear(); +#if FANTASY_WEBGL + Pool>.Return(this); +#else + MultiThreadPool.Return(this); +#endif + } + + /// + /// 获取一个值,该值指示当前实例是否为对象池中的实例。 + /// + /// + public bool IsPool() + { + return _isPool; + } + + /// + /// 设置一个值,该值指示当前实例是否为对象池中的实例。 + /// + /// + public void SetIsPool(bool isPool) + { + throw new NotImplementedException(); + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/Collection/HashSetPool.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/Collection/HashSetPool.cs.meta new file mode 100644 index 0000000..27aadf4 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/Collection/HashSetPool.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c49468bddc6524c419ace92b9ad68a5d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/Collection/ListPool.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/Collection/ListPool.cs new file mode 100644 index 0000000..de70fe2 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/Collection/ListPool.cs @@ -0,0 +1,101 @@ +using System; +using System.Collections.Generic; +using Fantasy.Pool; + +// ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract + +namespace Fantasy.DataStructure.Collection +{ + /// + /// 可释放的列表(List)对象池。 + /// + /// 列表中元素的类型。 + public sealed class ListPool : List, IDisposable, IPool + { + private bool _isPool; + private bool _isDispose; + + /// + /// 释放实例所占用的资源,并将实例返回到对象池中,以便重用。 + /// + public void Dispose() + { + if (_isDispose) + { + return; + } + + _isDispose = true; + Clear(); +#if FANTASY_WEBGL + Pool>.Return(this); +#else + MultiThreadPool.Return(this); +#endif + } + + /// + /// 使用指定的元素创建一个 列表(List)对象池的实例。 + /// + /// 要添加到列表的元素。 + /// 创建的实例。 + public static ListPool Create(params T[] args) + { +#if FANTASY_WEBGL + var list = Pool>.Rent(); +#else + var list = MultiThreadPool.Rent>(); +#endif + list._isDispose = false; + list._isPool = true; + + if (args != null) + { + list.AddRange(args); + } + + return list; + } + + /// + /// 使用指定的列表创建一个 列表(List)对象池的实例。 + /// + /// 要添加到列表的元素列表。 + /// 创建的实例。 + public static ListPool Create(List args) + { +#if FANTASY_WEBGL + var list = Pool>.Rent(); +#else + var list = MultiThreadPool.Rent>(); +#endif + list._isDispose = false; + list._isPool = true; + + if (args != null) + { + list.AddRange(args); + } + + return list; + } + + /// + /// 获取一个值,该值指示当前实例是否为对象池中的实例。 + /// + /// + public bool IsPool() + { + return _isPool; + } + + /// + /// 设置一个值,该值指示当前实例是否为对象池中的实例。 + /// + /// + public void SetIsPool(bool isPool) + { + _isPool = isPool; + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/Collection/ListPool.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/Collection/ListPool.cs.meta new file mode 100644 index 0000000..5827c4a --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/Collection/ListPool.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f629886e3686046c6b00225679a7dbf5 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/Collection/OneToManyHashSetPool.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/Collection/OneToManyHashSetPool.cs new file mode 100644 index 0000000..8a5766c --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/Collection/OneToManyHashSetPool.cs @@ -0,0 +1,208 @@ +using System; +using System.Collections.Generic; +using Fantasy.Pool; + +#pragma warning disable CS8600 // Converting null literal or possible null value to non-nullable type. + +namespace Fantasy.DataStructure.Collection +{ + /// + /// 一对多哈希集合(OneToManyHashSet)对象池。 + /// + /// 键的类型。 + /// 值的类型。 + public class OneToManyHashSetPool : OneToManyHashSet, IDisposable, IPool where TKey : notnull + { + private bool _isPool; + private bool _isDispose; + + /// + /// 创建一个 一对多哈希集合(OneToManyHashSet)对象池的实例。 + /// + /// 创建的实例。 + public static OneToManyHashSetPool Create() + { +#if FANTASY_WEBGL + var a = Pool>.Rent(); +#else + var a = MultiThreadPool.Rent>(); +#endif + a._isDispose = false; + a._isPool = true; + return a; + } + + /// + /// 释放实例所占用的资源,并将实例返回到对象池中,以便重用。 + /// + public void Dispose() + { + if (_isDispose) + { + return; + } + + _isDispose = true; + Clear(); +#if FANTASY_WEBGL + Pool>.Return(this); +#else + MultiThreadPool.Return(this); +#endif + } + + /// + /// 获取一个值,该值指示当前实例是否为对象池中的实例。 + /// + /// + public bool IsPool() + { + return _isPool; + } + + /// + /// 设置一个值,该值指示当前实例是否为对象池中的实例。 + /// + /// + public void SetIsPool(bool isPool) + { + _isPool = isPool; + } + } + + /// + /// 一对多哈希集合(OneToManyHashSet),用于创建和管理键对应多个值的集合。 + /// + /// 键的类型。 + /// 值的类型。 + public class OneToManyHashSet : Dictionary> where TKey : notnull + { + /// 用于回收和重用的空闲值集合队列。 + private readonly Queue> _queue = new Queue>(); + /// 设置最大回收限制,用于控制值集合的最大数量。 + private readonly int _recyclingLimit = 120; + /// 一个空的、不包含任何元素的哈希集合,用于在查找失败时返回。 + private static HashSet _empty = new HashSet(); + + /// + /// 初始化 类的新实例。 + /// + public OneToManyHashSet() { } + + /// + /// 设置最大缓存数量 + /// + /// + /// 1:防止数据量过大、所以超过recyclingLimit的数据还是走GC. + /// 2:设置成0不控制数量,全部缓存 + /// + public OneToManyHashSet(int recyclingLimit) + { + _recyclingLimit = recyclingLimit; + } + + /// + /// 判断指定的键值对是否存在于集合中。 + /// + /// 键。 + /// 值。 + /// 如果存在则为 true,否则为 false。 + public bool Contains(TKey key, TValue value) + { + TryGetValue(key, out var list); + + return list != null && list.Contains(value); + } + + /// + /// 添加指定的键值对到集合中。 + /// + /// 键。 + /// 值。 + public void Add(TKey key, TValue value) + { + if (!TryGetValue(key, out var list)) + { + list = Fetch(); + list.Add(value); + Add(key, list); + + return; + } + + list.Add(value); + } + + /// + /// 从集合中移除指定键对应的值。 + /// + /// 键。 + /// 要移除的值。 + public void RemoveValue(TKey key, TValue value) + { + if (!TryGetValue(key, out var list)) return; + + list.Remove(value); + + if (list.Count == 0) RemoveKey(key); + } + + /// + /// 从集合中移除指定键及其对应的值集合。 + /// + /// 键。 + public void RemoveKey(TKey key) + { + if (!TryGetValue(key, out var list)) return; + + Remove(key); + Recycle(list); + } + + /// + /// 获取指定键对应的值集合,如果不存在则返回一个空的哈希集合。 + /// + /// 键。 + /// 对应的值集合或空的哈希集合。 + public HashSet GetValue(TKey key) + { + if (TryGetValue(key, out HashSet value)) + { + return value; + } + + return _empty; + } + + /// + /// 从队列中获取一个空闲的值集合,或者创建一个新的。 + /// + /// 值集合。 + private HashSet Fetch() + { + return _queue.Count <= 0 ? new HashSet() : _queue.Dequeue(); + } + + /// + /// 回收值集合到队列中,以便重复利用。 + /// + /// 要回收的值集合。 + private void Recycle(HashSet list) + { + list.Clear(); + + if (_recyclingLimit != 0 && _queue.Count > _recyclingLimit) return; + + _queue.Enqueue(list); + } + + /// + /// 清空集合中的数据并和队列。 + /// + protected new void Clear() + { + base.Clear(); + _queue.Clear(); + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/Collection/OneToManyHashSetPool.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/Collection/OneToManyHashSetPool.cs.meta new file mode 100644 index 0000000..445c83d --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/Collection/OneToManyHashSetPool.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4e0cac58c09d6429faba279d03ef2317 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/Collection/OneToManyListPool.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/Collection/OneToManyListPool.cs new file mode 100644 index 0000000..80568ef --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/Collection/OneToManyListPool.cs @@ -0,0 +1,232 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Fantasy.Pool; + +#pragma warning disable CS8600 // Converting null literal or possible null value to non-nullable type. +#pragma warning disable CS8603 // Possible null reference return. + +namespace Fantasy.DataStructure.Collection +{ + /// + /// 可回收的、一对多关系的列表池。 + /// + /// 键的类型。 + /// 值的类型。 + public class OneToManyListPool : OneToManyList, IDisposable, IPool where TKey : notnull + { + private bool _isPool; + private bool _isDispose; + + /// + /// 创建一个 一对多关系的列表池的实例。 + /// + /// 创建的实例。 + public static OneToManyListPool Create() + { +#if FANTASY_WEBGL || FANTASY_EXPORTER + var list = Pool>.Rent(); +#else + var list = MultiThreadPool.Rent>(); +#endif + list._isDispose = false; + list._isPool = true; + return list; + } + + /// + /// 释放当前对象所占用的资源,并将对象回收到对象池中。 + /// + public void Dispose() + { + if (_isDispose) + { + return; + } + + _isDispose = true; + Clear(); +#if FANTASY_WEBGL || FANTASY_EXPORTER + Pool>.Return(this); +#else + MultiThreadPool.Return(this); +#endif + } + + /// + /// 获取一个值,该值指示当前实例是否为对象池中的实例。 + /// + /// + public bool IsPool() + { + return _isPool; + } + + /// + /// 设置一个值,该值指示当前实例是否为对象池中的实例。 + /// + /// + public void SetIsPool(bool isPool) + { + _isPool = isPool; + } + } + + /// + /// 一对多关系的列表字典。 + /// + /// 键的类型。 + /// 值的类型。 + public class OneToManyList : Dictionary> where TKey : notnull + { + private readonly int _recyclingLimit = 120; + private static readonly List Empty = new List(); + private readonly Queue> _queue = new Queue>(); + + /// + /// 初始化一个新的 实例。 + /// + public OneToManyList() { } + + /// + /// 设置最大缓存数量 + /// + /// + /// 1:防止数据量过大、所以超过recyclingLimit的数据还是走GC. + /// 2:设置成0不控制数量,全部缓存 + /// + public OneToManyList(int recyclingLimit) + { + _recyclingLimit = recyclingLimit; + } + + /// + /// 判断给定的键和值是否存在于列表中。 + /// + /// 要搜索的键。 + /// 要搜索的值。 + /// 如果存在则为 ,否则为 + public bool Contains(TKey key, TValue value) + { + TryGetValue(key, out var list); + + return list != null && list.Contains(value); + } + + /// + /// 向列表中添加指定键和值。 + /// + /// 要添加值的键。 + /// 要添加的值。 + public void Add(TKey key, TValue value) + { + if (!TryGetValue(key, out var list)) + { + list = Fetch(); + list.Add(value); + Add(key, list); + + return; + } + + list.Add(value); + } + + /// + /// 获取指定键对应的列表中的第一个值。 + /// + /// 要获取值的键。 + /// 键对应的列表中的第一个值。 + public TValue First(TKey key) + { + return !TryGetValue(key, out var list) ? default : list.FirstOrDefault(); + } + + /// + /// 从列表中移除指定键和值。 + /// + /// 要移除值的键。 + /// 要移除的值。 + /// 如果成功移除则为 ,否则为 + public bool RemoveValue(TKey key, TValue value) + { + if (!TryGetValue(key, out var list)) + { + return true; + } + + var isRemove = list.Remove(value); + + if (list.Count == 0) + { + isRemove = RemoveByKey(key); + } + + return isRemove; + } + + /// + /// 从列表中移除指定键及其关联的所有值。 + /// + /// 要移除的键。 + /// 如果成功移除则为 ,否则为 + public bool RemoveByKey(TKey key) + { + if (!TryGetValue(key, out var list)) + { + return false; + } + + Remove(key); + Recycle(list); + return true; + } + + /// + /// 获取指定键关联的所有值的列表。 + /// + /// 要获取值的键。 + /// 键关联的所有值的列表。 + public List GetValues(TKey key) + { + if (TryGetValue(key, out List list)) + { + return list; + } + + return Empty; + } + + /// + /// 清除字典中的所有键值对,并回收相关的值集合。 + /// + public new void Clear() + { + foreach (var keyValuePair in this) Recycle(keyValuePair.Value); + + base.Clear(); + } + + /// + /// 从空闲值集合队列中获取一个值集合,如果队列为空则创建一个新的值集合。 + /// + /// 从队列中获取的值集合。 + private List Fetch() + { + return _queue.Count <= 0 ? new List() : _queue.Dequeue(); + } + + /// + /// 回收一个不再使用的值集合到空闲值集合队列中。 + /// + /// 要回收的值集合。 + private void Recycle(List list) + { + list.Clear(); + + if (_recyclingLimit != 0 && _queue.Count > _recyclingLimit) return; + + _queue.Enqueue(list); + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/Collection/OneToManyListPool.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/Collection/OneToManyListPool.cs.meta new file mode 100644 index 0000000..b1bbb98 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/Collection/OneToManyListPool.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2c48383c842aa40b683f03b79f845932 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/Collection/OneToManyQueuePool.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/Collection/OneToManyQueuePool.cs new file mode 100644 index 0000000..222576e --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/Collection/OneToManyQueuePool.cs @@ -0,0 +1,204 @@ +using System; +using System.Collections.Generic; +using Fantasy.Pool; + +#pragma warning disable CS8603 + +namespace Fantasy.DataStructure.Collection +{ + /// + /// 支持一对多关系的队列池,用于存储具有相同键的值的队列集合。 + /// + /// 键的类型。 + /// 值的类型。 + public class OneToManyQueuePool : OneToManyQueue, IDisposable, IPool where TKey : notnull + { + private bool _isPool; + private bool _isDispose; + + /// + /// 创建一个 一对多关系的队列池的实例。 + /// + /// 创建的实例。 + public static OneToManyQueuePool Create() + { +#if FANTASY_WEBGL + var a = Pool>.Rent(); +#else + var a = MultiThreadPool.Rent>(); +#endif + a._isDispose = false; + a._isPool = true; + return a; + } + + /// + /// 释放当前实例所占用的资源,并将实例回收到对象池中。 + /// + public void Dispose() + { + if (_isDispose) + { + return; + } + + _isDispose = true; + Clear(); +#if FANTASY_WEBGL + Pool>.Return(this); +#else + MultiThreadPool.Return(this); +#endif + } + + /// + /// 获取一个值,该值指示当前实例是否为对象池中的实例。 + /// + /// + public bool IsPool() + { + return _isPool; + } + + /// + /// 设置一个值,该值指示当前实例是否为对象池中的实例。 + /// + /// + public void SetIsPool(bool isPool) + { + _isPool = isPool; + } + } + + /// + /// 支持一对多关系的队列,用于存储具有相同键的值的队列集合。 + /// + /// 键的类型。 + /// 值的类型。 + public class OneToManyQueue : Dictionary> where TKey : notnull + { + private readonly Queue> _queue = new Queue>(); + private readonly int _recyclingLimit; + + /// + /// 创建一个 一对多关系的队列的实例。设置最大缓存数量 + /// + /// + /// 1:防止数据量过大、所以超过recyclingLimit的数据还是走GC. + /// 2:设置成0不控制数量,全部缓存 + /// + public OneToManyQueue(int recyclingLimit = 0) + { + _recyclingLimit = recyclingLimit; + } + + /// + /// 判断指定键的值队列是否包含指定的值。 + /// + /// 要查找的键。 + /// 要查找的值。 + /// 如果存在,则为 true;否则为 false + public bool Contains(TKey key, TValue value) + { + TryGetValue(key, out var list); + + return list != null && list.Contains(value); + } + + /// + /// 将指定的值添加到指定键的值队列中。 + /// + /// 要添加值的键。 + /// 要添加的值。 + public void Enqueue(TKey key, TValue value) + { + if (!TryGetValue(key, out var list)) + { + list = Fetch(); + list.Enqueue(value); + Add(key, list); + return; + } + + list.Enqueue(value); + } + + /// + /// 从指定键的值队列中出队一个值。 + /// + /// 要出队的键。 + /// 出队的值。 + public TValue Dequeue(TKey key) + { + if (!TryGetValue(key, out var list) || list.Count == 0) + { + return default; + } + + var value = list.Dequeue(); + + if (list.Count == 0) + { + RemoveKey(key); + } + + return value; + } + + /// + /// 尝试从指定键的值队列中出队一个值。 + /// + /// 要出队的键。 + /// 出队的值。 + /// 如果成功出队,则为 true;否则为 false + public bool TryDequeue(TKey key, out TValue value) + { + value = Dequeue(key); + + return value != null; + } + + /// + /// 从字典中移除指定键及其对应的值队列。 + /// + /// 要移除的键。 + public void RemoveKey(TKey key) + { + if (!TryGetValue(key, out var list)) return; + + Remove(key); + Recycle(list); + } + + /// + /// 从队列池中获取一个值队列。如果队列池为空,则创建一个新的值队列。 + /// + /// 获取的值队列。 + private Queue Fetch() + { + return _queue.Count <= 0 ? new Queue() : _queue.Dequeue(); + } + + /// + /// 回收一个不再使用的值队列到队列池中,以便重用。 + /// + /// 要回收的值队列。 + private void Recycle(Queue list) + { + list.Clear(); + + if (_recyclingLimit != 0 && _queue.Count > _recyclingLimit) return; + + _queue.Enqueue(list); + } + + /// + /// 清空当前实例的数据,同时回收所有值队列。 + /// + protected new void Clear() + { + base.Clear(); + _queue.Clear(); + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/Collection/OneToManyQueuePool.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/Collection/OneToManyQueuePool.cs.meta new file mode 100644 index 0000000..b90e2c1 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/Collection/OneToManyQueuePool.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8b6455b3359394987af4c0a4855189e9 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/Collection/ReuseList.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/Collection/ReuseList.cs new file mode 100644 index 0000000..b4395e8 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/Collection/ReuseList.cs @@ -0,0 +1,69 @@ +using System; +using System.Collections.Generic; +using Fantasy.Pool; + +namespace Fantasy.DataStructure.Collection +{ + /// + /// 可重用的列表,继承自 类。该类支持通过对象池重用列表实例,以减少对象分配和释放的开销。 + /// + /// 列表中元素的类型。 + public sealed class ReuseList : List, IDisposable, IPool + { + private bool _isPool; + private bool _isDispose; + + /// + /// 创建一个 可重用的列表的实例。 + /// + /// 创建的实例。 + public static ReuseList Create() + { +#if FANTASY_WEBGL + var list = Pool>.Rent(); +#else + var list = MultiThreadPool.Rent>(); +#endif + list._isDispose = false; + list._isPool = true; + return list; + } + + /// + /// 释放该实例所占用的资源,并将实例返回到对象池中,以便重用。 + /// + public void Dispose() + { + if (_isDispose) + { + return; + } + + _isDispose = true; + Clear(); +#if FANTASY_WEBGL + Pool>.Return(this); +#else + MultiThreadPool.Return(this); +#endif + } + + /// + /// 获取一个值,该值指示当前实例是否为对象池中的实例。 + /// + /// + public bool IsPool() + { + return _isPool; + } + + /// + /// 设置一个值,该值指示当前实例是否为对象池中的实例。 + /// + /// + public void SetIsPool(bool isPool) + { + _isPool = isPool; + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/Collection/ReuseList.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/Collection/ReuseList.cs.meta new file mode 100644 index 0000000..1b600f7 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/Collection/ReuseList.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9826877496b99479892a7359519298d5 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/Collection/SortedConcurrentOneToManyListPool.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/Collection/SortedConcurrentOneToManyListPool.cs new file mode 100644 index 0000000..464ab58 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/Collection/SortedConcurrentOneToManyListPool.cs @@ -0,0 +1,226 @@ +#if !FANTASY_WEBGL +using System; +using System.Collections.Generic; +using System.Linq; +using Fantasy.Pool; + +#pragma warning disable CS8603 + +namespace Fantasy.DataStructure.Collection +{ + /// + /// 基于排序字典和并发集合实现的一对多映射列表的对象池包装类,继承自 类, + /// 同时实现了 接口,以支持对象的重用和释放。 + /// + /// 键的类型。 + /// 值的类型。 + public class SortedConcurrentOneToManyListPool : SortedConcurrentOneToManyList, IDisposable, IPool where TKey : notnull + { + private bool _isPool; + private bool _isDispose; + + /// + /// 创建一个新的 实例,使用默认的参数设置。 + /// + /// 新创建的 实例。 + public static SortedConcurrentOneToManyListPool Create() + { + var a = MultiThreadPool.Rent>(); + a._isDispose = false; + a._isPool = true; + return a; + } + + /// + /// 释放当前对象池实例,将其返回到对象池以供重用。 + /// + public void Dispose() + { + if (_isDispose) + { + return; + } + + _isDispose = true; + Clear(); + MultiThreadPool.Return(this); + } + + /// + /// 获取一个值,该值指示当前实例是否为对象池中的实例。 + /// + /// + public bool IsPool() + { + return _isPool; + } + + /// + /// 设置一个值,该值指示当前实例是否为对象池中的实例。 + /// + /// + public void SetIsPool(bool isPool) + { + _isPool = isPool; + } + } + + /// + /// 基于排序字典和并发集合实现的一多对映射列表类,继承自 类, + /// 用于在多个值与一个键关联的情况下进行管理和存储。该类支持并发操作,适用于多线程环境。 + /// + /// 键的类型。 + /// 值的类型。 + public class SortedConcurrentOneToManyList : SortedDictionary> where TKey : notnull + { + /// 用于同步操作的锁对象,它确保在多线程环境下对数据的安全访问。 + private readonly object _lockObject = new object(); + /// 用于存储缓存的队列。 + private readonly Queue> _queue = new Queue>(); + /// 控制缓存回收的限制。当缓存的数量超过此限制时,旧的缓存将会被回收。 + private readonly int _recyclingLimit; + + /// + /// 初始化一个新的 类的实例,使用默认的参数设置。 + /// + public SortedConcurrentOneToManyList() + { + } + + /// + /// 初始化一个新的 类的实例,指定最大缓存数量。 + /// + /// + /// 1:防止数据量过大、所以超过recyclingLimit的数据还是走GC. + /// 2:设置成0不控制数量,全部缓存 + /// + public SortedConcurrentOneToManyList(int recyclingLimit = 0) + { + _recyclingLimit = recyclingLimit; + } + + /// + /// 检查指定的键和值是否存在于映射列表中。 + /// + /// 要检查的键。 + /// 要检查的值。 + /// 如果存在,则为 true;否则为 false。 + public bool Contains(TKey key, TValue value) + { + lock (_lockObject) + { + TryGetValue(key, out var list); + + return list != null && list.Contains(value); + } + } + + /// + /// 将指定的值添加到与指定键关联的列表中。 + /// + /// 要关联值的键。 + /// 要添加到列表的值。 + public void Add(TKey key, TValue value) + { + lock (_lockObject) + { + if (!TryGetValue(key, out var list)) + { + list = Fetch(); + list.Add(value); + base[key] = list; + return; + } + + list.Add(value); + } + } + + /// + /// 获取与指定键关联的列表中的第一个值。 + /// 如果列表不存在或为空,则返回默认值。 + /// + /// 要获取第一个值的键。 + /// 第一个值,或默认值。 + public TValue First(TKey key) + { + lock (_lockObject) + { + return !TryGetValue(key, out var list) ? default : list.FirstOrDefault(); + } + } + + /// + /// 从与指定键关联的列表中移除指定的值。 + /// 如果列表不存在或值不存在于列表中,则不执行任何操作。 + /// + /// 要移除值的键。 + /// 要移除的值。 + public void RemoveValue(TKey key, TValue value) + { + lock (_lockObject) + { + if (!TryGetValue(key, out var list)) return; + + list.Remove(value); + + if (list.Count == 0) RemoveKey(key); + } + } + + /// + /// 从映射列表中移除指定的键及其关联的列表。 + /// 如果键不存在于映射列表中,则不执行任何操作。 + /// + /// 要移除的键。 + public void RemoveKey(TKey key) + { + lock (_lockObject) + { + if (!TryGetValue(key, out var list)) return; + + Remove(key); + + Recycle(list); + } + } + + /// + /// 从缓存中获取一个可重用的列表。如果缓存中不存在列表,则创建一个新的列表并返回。 + /// + /// 可重用的列表。 + private List Fetch() + { + lock (_lockObject) + { + return _queue.Count <= 0 ? new List() : _queue.Dequeue(); + } + } + + /// + /// 将不再使用的列表回收到缓存中,以便重复利用。如果缓存数量超过限制,则丢弃列表而不进行回收。 + /// + /// 要回收的列表。 + private void Recycle(List list) + { + lock (_lockObject) + { + list.Clear(); + + if (_recyclingLimit != 0 && _queue.Count > _recyclingLimit) return; + + _queue.Enqueue(list); + } + } + + /// + /// 清空映射列表以及队列。 + /// + protected new void Clear() + { + base.Clear(); + _queue.Clear(); + } + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/Collection/SortedConcurrentOneToManyListPool.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/Collection/SortedConcurrentOneToManyListPool.cs.meta new file mode 100644 index 0000000..2ca59b2 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/Collection/SortedConcurrentOneToManyListPool.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: fef1d9dea81914fcf9fc9f5b1e5989d5 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/Collection/SortedOneToManyHashSetPool.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/Collection/SortedOneToManyHashSetPool.cs new file mode 100644 index 0000000..8158db5 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/Collection/SortedOneToManyHashSetPool.cs @@ -0,0 +1,192 @@ +using System; +using System.Collections.Generic; +using Fantasy.Pool; + +namespace Fantasy.DataStructure.Collection +{ + /// + /// 基于排序字典实现的一对多关系的映射哈希集合的对象池包装类,将唯一键映射到多个值的哈希集合。 + /// 同时实现了 接口,以支持对象的重用和释放。 + /// + /// 字典中键的类型。 + /// 哈希集合中值的类型。 + public class SortedOneToManyHashSetPool : SortedOneToManyHashSet, IDisposable, IPool where TKey : notnull + { + private bool _isPool; + private bool _isDispose; + + /// + /// 创建一个 实例。 + /// + /// 新创建的实例。 + public static SortedOneToManyHashSetPool Create() + { +#if FANTASY_WEBGL + var a = Pool>.Rent(); +#else + var a = MultiThreadPool.Rent>(); +#endif + a._isDispose = false; + a._isPool = true; + return a; + } + + /// + /// 释放当前对象池实例,将其返回到对象池以供重用。 + /// + public void Dispose() + { + if (_isDispose) + { + return; + } + + _isDispose = true; + Clear(); +#if FANTASY_WEBGL + Pool>.Return(this); +#else + MultiThreadPool.Return(this); +#endif + } + + /// + /// 获取一个值,该值指示当前实例是否为对象池中的实例。 + /// + /// + public bool IsPool() + { + return _isPool; + } + + /// + /// 设置一个值,该值指示当前实例是否为对象池中的实例。 + /// + /// + public void SetIsPool(bool isPool) + { + _isPool = isPool; + } + } + + /// + /// 基于排序字典实现的一对多关系的映射哈希集合类,将唯一键映射到多个值的哈希集合。 + /// 用于在多个值与一个键关联的情况下进行管理和存储。 + /// + /// 字典中键的类型。 + /// 集合中值的类型。 + public class SortedOneToManyHashSet : SortedDictionary> where TKey : notnull + { + private readonly Queue> _queue = new Queue>(); + private readonly int _recyclingLimit = 120; + + /// + /// 创建一个新的 实例。 + /// + public SortedOneToManyHashSet() { } + + /// + /// 创建一个新的 实例,设置最大缓存数量 + /// + /// + /// 1:防止数据量过大、所以超过recyclingLimit的数据还是走GC. + /// 2:设置成0不控制数量,全部缓存 + /// + public SortedOneToManyHashSet(int recyclingLimit) + { + _recyclingLimit = recyclingLimit; + } + + /// + /// 判断哈希集合中是否包含指定的键值对。 + /// + /// 要查找的键。 + /// 要查找的值。 + /// 如果键值对存在,则为 true;否则为 false。 + public bool Contains(TKey key, TValue value) + { + TryGetValue(key, out var list); + + return list != null && list.Contains(value); + } + + /// + /// 将指定值添加到给定键关联的哈希集合中。 + /// + /// 要添加值的键。 + /// 要添加的值。 + public void Add(TKey key, TValue value) + { + if (!TryGetValue(key, out var list)) + { + list = Fetch(); + list.Add(value); + Add(key, list); + + return; + } + + list.Add(value); + } + + /// + /// 从指定键关联的哈希集合中移除特定值。 + /// 如果哈希集合不存在或值不存在于集合中,则不执行任何操作。 + /// + /// 要移除值的键。 + /// 要移除的值。 + public void RemoveValue(TKey key, TValue value) + { + if (!TryGetValue(key, out var list)) return; + + list.Remove(value); + + if (list.Count == 0) RemoveKey(key); + } + + /// + /// 从字典中移除指定键以及关联的哈希集合,并将集合进行回收。 + /// 如果键不存在于映射列表中,则不执行任何操作。 + /// + /// 要移除的键。 + public void RemoveKey(TKey key) + { + if (!TryGetValue(key, out var list)) return; + + Remove(key); + + Recycle(list); + } + + /// + /// 获取一个空的或回收的哈希集合。 + /// + /// 获取的哈希集合实例。 + private HashSet Fetch() + { + return _queue.Count <= 0 ? new HashSet() : _queue.Dequeue(); + } + + /// + /// 回收一个哈希集合,将其清空并放入回收队列中。 + /// + /// 要回收的哈希集合。 + private void Recycle(HashSet list) + { + list.Clear(); + + if (_recyclingLimit != 0 && _queue.Count > _recyclingLimit) return; + + _queue.Enqueue(list); + } + + /// + /// 重写 Clear 方法,清空字典并清空回收队列。 + /// + protected new void Clear() + { + base.Clear(); + _queue.Clear(); + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/Collection/SortedOneToManyHashSetPool.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/Collection/SortedOneToManyHashSetPool.cs.meta new file mode 100644 index 0000000..13e463b --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/Collection/SortedOneToManyHashSetPool.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4fe9032846c3f4a11be30459a9e12d7a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/Collection/SortedOneToManyListPool.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/Collection/SortedOneToManyListPool.cs new file mode 100644 index 0000000..f0bae12 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/Collection/SortedOneToManyListPool.cs @@ -0,0 +1,217 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Fantasy.Pool; + +#pragma warning disable CS8603 + +namespace Fantasy.DataStructure.Collection +{ + /// + /// 基于排序字典实现的一对多映射列表的对象池包装类,继承自 类, + /// 同时实现了 接口,以支持对象的重用和释放。 + /// + /// 字典中键的类型。 + /// 列表中值的类型。 + public class SortedOneToManyListPool : SortedOneToManyList, IDisposable, IPool where TKey : notnull + { + private bool _isPool; + private bool _isDispose; + + /// + /// 创建一个 实例。 + /// + /// 新创建的实例。 + public static SortedOneToManyListPool Create() + { +#if FANTASY_WEBGL + var a = Pool>.Rent(); +#else + var a = MultiThreadPool.Rent>(); +#endif + a._isDispose = false; + a._isPool = true; + return a; + } + + /// + /// 释放当前对象池实例,将其返回到对象池以供重用。 + /// + public void Dispose() + { + if (_isDispose) + { + return; + } + + _isDispose = true; + Clear(); +#if FANTASY_WEBGL + Pool>.Return(this); +#else + MultiThreadPool.Return(this); +#endif + } + + /// + /// 获取一个值,该值指示当前实例是否为对象池中的实例。 + /// + /// + public bool IsPool() + { + return _isPool; + } + + /// + /// 设置一个值,该值指示当前实例是否为对象池中的实例。 + /// + /// + public void SetIsPool(bool isPool) + { + _isPool = isPool; + } + } + + /// + /// 基于排序字典实现的一对多关系的映射列表类,将唯一键映射到包含多个值的列表。 + /// 用于在多个值与一个键关联的情况下进行管理和存储。 + /// + /// 字典中键的类型。 + /// 列表中值的类型。 + public class SortedOneToManyList : SortedDictionary> where TKey : notnull + { + private readonly Queue> _queue = new Queue>(); + private readonly int _recyclingLimit; + + /// + /// 创建一个新的 实例。 + /// + public SortedOneToManyList() + { + } + + /// + /// 创建一个新的 实例,设置最大缓存数量 + /// + /// + /// 1:防止数据量过大、所以超过recyclingLimit的数据还是走GC. + /// 2:设置成0不控制数量,全部缓存 + /// + public SortedOneToManyList(int recyclingLimit = 0) + { + _recyclingLimit = recyclingLimit; + } + + /// + /// 判断列表中是否包含指定的键值对。 + /// + /// 要查找的键。 + /// 要查找的值。 + /// 如果键值对存在,则为 true;否则为 false。 + public bool Contains(TKey key, TValue value) + { + TryGetValue(key, out var list); + + return list != null && list.Contains(value); + } + + /// + /// 将指定值添加到给定键关联的列表中。 + /// + /// 要添加值的键。 + /// 要添加的值。 + public void Add(TKey key, TValue value) + { + if (!TryGetValue(key, out var list)) + { + list = Fetch(); + list.Add(value); + base[key] = list; + return; + } + + list.Add(value); + } + + /// + /// 获取指定键关联的列表中的第一个值。 + /// + /// 要查找值的键。 + /// 指定键关联的列表中的第一个值,如果列表为空则返回默认值。 + public TValue First(TKey key) + { + return !TryGetValue(key, out var list) ? default : list.FirstOrDefault(); + } + + /// + /// 从指定键关联的列表中移除特定值。 + /// + /// 要移除值的键。 + /// 要移除的值。 + + public void RemoveValue(TKey key, TValue value) + { + if (!TryGetValue(key, out var list)) + { + return; + } + + list.Remove(value); + + if (list.Count == 0) + { + RemoveKey(key); + } + } + + /// + /// 从字典中移除指定键以及关联的列表,并将列表进行回收。 + /// + /// 要移除的键。 + + public void RemoveKey(TKey key) + { + if (!TryGetValue(key, out var list)) + { + return; + } + + Remove(key); + Recycle(list); + } + + /// + /// 获取一个空的或回收的列表。 + /// + /// 获取的列表实例。 + private List Fetch() + { + return _queue.Count <= 0 ? new List() : _queue.Dequeue(); + } + + /// + /// 回收一个列表,将其清空并放入回收队列中。如果缓存数量超过限制,则丢弃列表而不进行回收 + /// + /// 要回收的列表。 + private void Recycle(List list) + { + list.Clear(); + + if (_recyclingLimit != 0 && _queue.Count > _recyclingLimit) + { + return; + } + + _queue.Enqueue(list); + } + + /// + /// 重写 Clear 方法,清空字典并清空回收队列。 + /// + protected new void Clear() + { + base.Clear(); + _queue.Clear(); + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/Collection/SortedOneToManyListPool.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/Collection/SortedOneToManyListPool.cs.meta new file mode 100644 index 0000000..c428dcc --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/Collection/SortedOneToManyListPool.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8e0621d52f951402daa68b108d7129f4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/Dictionary.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/Dictionary.meta new file mode 100644 index 0000000..3ffb966 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/Dictionary.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 4a444c902ff594bbaa3a3fb394e7f53a +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/Dictionary/DictionaryExtensions.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/Dictionary/DictionaryExtensions.cs new file mode 100644 index 0000000..ed0aa57 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/Dictionary/DictionaryExtensions.cs @@ -0,0 +1,31 @@ +using System.Collections.Generic; +#pragma warning disable CS8601 // Possible null reference assignment. + +namespace Fantasy.DataStructure.Dictionary +{ + /// + /// 提供对字典的扩展方法。 + /// + public static class DictionaryExtensions + { + /// + /// 尝试从字典中移除指定键,并返回相应的值。 + /// + /// 字典中键的类型。 + /// 字典中值的类型。 + /// 要操作的字典实例。 + /// 要移除的键。 + /// 从字典中移除的值(如果成功移除)。 + /// 如果成功移除键值对,则为 true;否则为 false。 + public static bool TryRemove(this IDictionary self, T key, out TV value) + { + if (!self.TryGetValue(key, out value)) + { + return false; + } + + self.Remove(key); + return true; + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/Dictionary/DictionaryExtensions.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/Dictionary/DictionaryExtensions.cs.meta new file mode 100644 index 0000000..d3c3a07 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/Dictionary/DictionaryExtensions.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6975fd47ec81d474cbd1ba996d01e864 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/Dictionary/DictionaryPool.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/Dictionary/DictionaryPool.cs new file mode 100644 index 0000000..567901c --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/Dictionary/DictionaryPool.cs @@ -0,0 +1,70 @@ +using System; +using System.Collections.Generic; +using Fantasy.Pool; + +namespace Fantasy.DataStructure.Dictionary +{ + /// + /// 提供一个可以使用对象池管理的字典类。 + /// + /// 字典中键的类型。 + /// 字典中值的类型。 + public sealed class DictionaryPool : Dictionary, IDisposable, IPool where TM : notnull + { + private bool _isPool; + private bool _isDispose; + + /// + /// 释放实例占用的资源。 + /// + public void Dispose() + { + if (_isDispose) + { + return; + } + + _isDispose = true; + Clear(); +#if FANTASY_WEBGL + Pool>.Return(this); +#else + MultiThreadPool.Return(this); +#endif + } + + /// + /// 创建一个新的 实例。 + /// + /// 新创建的实例。 + public static DictionaryPool Create() + { +#if FANTASY_WEBGL + var dictionary = Pool>.Rent(); +#else + var dictionary = MultiThreadPool.Rent>(); +#endif + dictionary._isDispose = false; + dictionary._isPool = true; + return dictionary; + } + + /// + /// 获取一个值,该值指示当前实例是否为对象池中的实例。 + /// + /// + public bool IsPool() + { + return _isPool; + } + + /// + /// 设置一个值,该值指示当前实例是否为对象池中的实例。 + /// + /// + public void SetIsPool(bool isPool) + { + _isPool = isPool; + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/Dictionary/DictionaryPool.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/Dictionary/DictionaryPool.cs.meta new file mode 100644 index 0000000..861c20a --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/Dictionary/DictionaryPool.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 421f6528d2cff461dab994c2f358f24d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/Dictionary/DoubleMapDictionaryPool.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/Dictionary/DoubleMapDictionaryPool.cs new file mode 100644 index 0000000..e868710 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/Dictionary/DoubleMapDictionaryPool.cs @@ -0,0 +1,289 @@ +using System; +using System.Collections.Generic; +using Fantasy.Pool; + +#pragma warning disable CS8601 // Possible null reference assignment. +#pragma warning disable CS8604 // Possible null reference argument. +#pragma warning disable CS8603 // Possible null reference return. + +namespace Fantasy.DataStructure.Dictionary +{ + /// + /// 提供一个双向映射字典对象池类,用于双向键值对映射。 + /// + /// 字典中键的类型。 + /// 字典中值的类型。 + public class DoubleMapDictionaryPool : DoubleMapDictionary, IDisposable, IPool where TKey : notnull where TValue : notnull + { + private bool _isPool; + private bool _isDispose; + + /// + /// 创建一个新的 实例。 + /// + /// 新创建的实例。 + public static DoubleMapDictionaryPool Create() + { +#if FANTASY_WEBGL + var a = Pool>.Rent(); +#else + var a = MultiThreadPool.Rent>(); +#endif + a._isDispose = false; + a._isPool = true; + return a; + } + + /// + /// 释放实例占用的资源。 + /// + public void Dispose() + { + if (_isDispose) + { + return; + } + + _isDispose = true; + Clear(); +#if FANTASY_WEBGL + Pool>.Return(this); +#else + MultiThreadPool.Return(this); +#endif + } + + /// + /// 获取一个值,该值指示当前实例是否为对象池中的实例。 + /// + /// + public bool IsPool() + { + return _isPool; + } + + /// + /// 设置一个值,该值指示当前实例是否为对象池中的实例。 + /// + /// + public void SetIsPool(bool isPool) + { + _isPool = isPool; + } + } + + /// + /// 可以实现双向映射的字典类,用于将键和值进行双向映射。 + /// + /// 键的类型,不能为 null。 + /// 值的类型,不能为 null。 + public class DoubleMapDictionary where TK : notnull where TV : notnull + { + private readonly Dictionary _kv = new Dictionary(); + private readonly Dictionary _vk = new Dictionary(); + + /// + /// 创建一个新的空的 实例。 + /// + public DoubleMapDictionary() { } + + /// + /// 创建一个新的具有指定初始容量的 实例。 + /// + /// 初始容量。 + public DoubleMapDictionary(int capacity) + { + _kv = new Dictionary(capacity); + _vk = new Dictionary(capacity); + } + + /// + /// 获取包含字典中所有键的列表。 + /// + public List Keys => new List(_kv.Keys); + + /// + /// 获取包含字典中所有值的列表。 + /// + public List Values => new List(_vk.Keys); + + /// + /// 对字典中的每个键值对执行指定的操作。 + /// + /// 要执行的操作。 + public void ForEach(Action action) + { + if (action == null) + { + return; + } + + var keys = _kv.Keys; + foreach (var key in keys) + { + action(key, _kv[key]); + } + } + + /// + /// 将指定的键值对添加到字典中。 + /// + /// 要添加的键。 + /// 要添加的值。 + public void Add(TK key, TV value) + { + if (key == null || value == null || _kv.ContainsKey(key) || _vk.ContainsKey(value)) + { + return; + } + + _kv.Add(key, value); + _vk.Add(value, key); + } + + /// + /// 根据指定的键获取相应的值。 + /// + /// 要查找值的键。 + /// 与指定键关联的值,如果找不到键,则返回默认值。 + public TV GetValueByKey(TK key) + { + if (key != null && _kv.ContainsKey(key)) + { + return _kv[key]; + } + + return default; + } + + /// + /// 尝试根据指定的键获取相应的值。 + /// + /// 要查找值的键。 + /// 如果找到,则为与指定键关联的值;否则为值的默认值。 + /// 如果找到键,则为 true;否则为 false。 + public bool TryGetValueByKey(TK key, out TV value) + { + var result = key != null && _kv.ContainsKey(key); + + value = result ? _kv[key] : default; + + return result; + } + + /// + /// 根据指定的值获取相应的键。 + /// + /// 要查找键的值。 + /// 与指定值关联的键,如果找不到值,则返回默认键。 + public TK GetKeyByValue(TV value) + { + if (value != null && _vk.ContainsKey(value)) + { + return _vk[value]; + } + + return default; + } + + /// + /// 尝试根据指定的值获取相应的键。 + /// + /// 要查找键的值。 + /// 如果找到,则为与指定值关联的键;否则为键的默认值。 + /// 如果找到值,则为 true;否则为 false。 + public bool TryGetKeyByValue(TV value, out TK key) + { + var result = value != null && _vk.ContainsKey(value); + + key = result ? _vk[value] : default; + + return result; + } + + /// + /// 根据指定的键移除键值对。 + /// + /// 要移除的键。 + public void RemoveByKey(TK key) + { + if (key == null) + { + return; + } + + if (!_kv.TryGetValue(key, out var value)) + { + return; + } + + _kv.Remove(key); + _vk.Remove(value); + } + + /// + /// 根据指定的值移除键值对。 + /// + /// 要移除的值。 + public void RemoveByValue(TV value) + { + if (value == null) + { + return; + } + + if (!_vk.TryGetValue(value, out var key)) + { + return; + } + + _kv.Remove(key); + _vk.Remove(value); + } + + /// + /// 清空字典中的所有键值对。 + /// + public void Clear() + { + _kv.Clear(); + _vk.Clear(); + } + + /// + /// 判断字典是否包含指定的键。 + /// + /// 要检查的键。 + /// 如果字典包含指定的键,则为 true;否则为 false。 + public bool ContainsKey(TK key) + { + return key != null && _kv.ContainsKey(key); + } + + /// + /// 判断字典是否包含指定的值。 + /// + /// 要检查的值。 + /// 如果字典包含指定的值,则为 true;否则为 false。 + public bool ContainsValue(TV value) + { + return value != null && _vk.ContainsKey(value); + } + + /// + /// 判断字典是否包含指定的键值对。 + /// + /// 要检查的键。 + /// 要检查的值。 + /// 如果字典包含指定的键值对,则为 true;否则为 false。 + public bool Contains(TK key, TV value) + { + if (key == null || value == null) + { + return false; + } + + return _kv.ContainsKey(key) && _vk.ContainsKey(value); + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/Dictionary/DoubleMapDictionaryPool.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/Dictionary/DoubleMapDictionaryPool.cs.meta new file mode 100644 index 0000000..a0beca0 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/Dictionary/DoubleMapDictionaryPool.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a23375ac49ac64827a5d2e6ae476bbab +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/Dictionary/EntityDictionary.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/Dictionary/EntityDictionary.cs new file mode 100644 index 0000000..fc4d44f --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/Dictionary/EntityDictionary.cs @@ -0,0 +1,91 @@ +using System; +using System.Collections.Generic; +using Fantasy.Pool; + +namespace Fantasy.DataStructure.Dictionary +{ + /// + /// 提供一个带资源释放功能的实体字典类,支持使用对象池管理。 + /// + /// 字典中键的类型。 + /// 字典中值的类型,必须实现 IDisposable 接口。 + public sealed class EntityDictionary : Dictionary, IDisposable, IPool where TN : IDisposable where TM : notnull + { + private bool _isPool; + private bool _isDispose; + + /// + /// 创建一个新的 实例。 + /// + /// 新创建的实例。 + public static EntityDictionary Create() + { +#if FANTASY_WEBGL + var entityDictionary = Pool>.Rent(); +#else + var entityDictionary = MultiThreadPool.Rent>(); +#endif + entityDictionary._isDispose = false; + entityDictionary._isPool = true; + return entityDictionary; + } + + /// + /// 清空字典中的所有键值对,并释放值的资源。 + /// + public new void Clear() + { + foreach (var keyValuePair in this) + { + keyValuePair.Value.Dispose(); + } + + base.Clear(); + } + + /// + /// 清空字典中的所有键值对,但不释放值的资源。 + /// + public void ClearNotDispose() + { + base.Clear(); + } + + /// + /// 释放实例占用的资源。 + /// + public void Dispose() + { + if (_isDispose) + { + return; + } + + _isDispose = true; + Clear(); +#if FANTASY_WEBGL + Pool>.Return(this); +#else + MultiThreadPool.Return(this); +#endif + } + + /// + /// 获取一个值,该值指示当前实例是否为对象池中的实例。 + /// + /// + public bool IsPool() + { + return _isPool; + } + + /// + /// 设置一个值,该值指示当前实例是否为对象池中的实例。 + /// + /// + public void SetIsPool(bool isPool) + { + _isPool = isPool; + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/Dictionary/EntityDictionary.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/Dictionary/EntityDictionary.cs.meta new file mode 100644 index 0000000..35b066a --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/Dictionary/EntityDictionary.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 30708df4a385e4aee83551b3371240fe +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/Dictionary/OneToManyDictionaryPool.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/Dictionary/OneToManyDictionaryPool.cs new file mode 100644 index 0000000..0515423 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/Dictionary/OneToManyDictionaryPool.cs @@ -0,0 +1,247 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Fantasy.Pool; + +#pragma warning disable CS8603 +#pragma warning disable CS8601 + +namespace Fantasy.DataStructure.Dictionary +{ + /// + /// 一对多映射关系的字典对象池。 + /// + /// 外部字典中的键类型。 + /// 内部字典中的键类型。 + /// 内部字典中的值类型。 + public class OneToManyDictionaryPool : OneToManyDictionary, IDisposable, IPool where TKey : notnull where TValueKey : notnull + { + private bool _isPool; + private bool _isDispose; + + /// + /// 创建一个 的实例。 + /// + /// 新创建的 OneToManyDictionaryPool 实例。 + public static OneToManyDictionaryPool Create() + { +#if FANTASY_WEBGL + var a = Pool>.Rent(); +#else + var a = MultiThreadPool.Rent>(); +#endif + a._isDispose = false; + a._isPool = true; + return a; + } + + /// + /// 释放当前实例及其资源。 + /// + public void Dispose() + { + if (_isDispose) + { + return; + } + + _isDispose = true; + Clear(); +#if FANTASY_WEBGL + Pool>.Return(this); +#else + MultiThreadPool.Return(this); +#endif + } + + /// + /// 获取一个值,该值指示当前实例是否为对象池中的实例。 + /// + /// + public bool IsPool() + { + return _isPool; + } + + /// + /// 设置一个值,该值指示当前实例是否为对象池中的实例。 + /// + /// + public void SetIsPool(bool isPool) + { + _isPool = isPool; + } + } + + /// + /// 一对多映射关系的字典。每个键都对应一个内部字典,该内部字典将键值映射到相应的值。 + /// + /// 外部字典中的键类型。 + /// 内部字典中的键类型。 + /// 内部字典中的值类型。 + public class OneToManyDictionary : Dictionary> + where TKey : notnull where TValueKey : notnull + { + private readonly Queue> _queue = new Queue>(); + private readonly int _recyclingLimit = 120; + + /// + /// 创建一个新的 实例。 + /// + public OneToManyDictionary() { } + + /// + /// 创建一个新的 实例,并指定最大缓存数量。 + /// + /// + /// 1:防止数据量过大、所以超过recyclingLimit的数据还是走GC. + /// 2:设置成0不控制数量,全部缓存 + /// + public OneToManyDictionary(int recyclingLimit = 0) + { + _recyclingLimit = recyclingLimit; + } + + /// + /// 检查是否包含指定的键值对。 + /// + /// 外部字典中的键。 + /// 内部字典中的键。 + /// 如果包含指定的键值对,则为 true;否则为 false。 + public bool Contains(TKey key, TValueKey valueKey) + { + TryGetValue(key, out var dic); + + return dic != null && dic.ContainsKey(valueKey); + } + + /// + /// 尝试获取指定键值对的值。 + /// + /// 外部字典中的键。 + /// 内部字典中的键。 + /// 获取的值,如果操作成功,则为值;否则为默认值。 + /// 如果操作成功,则为 true;否则为 false。 + public bool TryGetValue(TKey key, TValueKey valueKey, out TValue value) + { + value = default; + return TryGetValue(key, out var dic) && dic.TryGetValue(valueKey, out value); + } + + /// + /// 获取指定键的第一个值。 + /// + /// 要获取第一个值的键。 + public TValue First(TKey key) + { + return !TryGetValue(key, out var dic) ? default : dic.First().Value; + } + + /// + /// 向字典中添加指定的键值对。 + /// + /// 要添加键值对的键。 + /// 要添加键值对的内部字典键。 + /// 要添加的值。 + public void Add(TKey key, TValueKey valueKey, TValue value) + { + if (!TryGetValue(key, out var dic)) + { + dic = Fetch(); + dic[valueKey] = value; + // dic.Add(valueKey, value); + Add(key, dic); + + return; + } + + dic[valueKey] = value; + // dic.Add(valueKey, value); + } + + /// + /// 从字典中移除指定的键值对。 + /// + /// 要移除键值对的键。 + /// 要移除键值对的内部字典键。 + /// 如果成功移除键值对,则为 true;否则为 false。 + public bool Remove(TKey key, TValueKey valueKey) + { + if (!TryGetValue(key, out var dic)) return false; + + var result = dic.Remove(valueKey); + + if (dic.Count == 0) RemoveKey(key); + + return result; + } + + /// + /// 从字典中移除指定的键值对。 + /// + /// 要移除键值对的键。 + /// 要移除键值对的内部字典键。 + /// 如果成功移除键值对,则为移除的值;否则为默认值。 + /// 如果成功移除键值对,则为 true;否则为 false。 + public bool Remove(TKey key, TValueKey valueKey, out TValue value) + { + if (!TryGetValue(key, out var dic)) + { + value = default; + return false; + } + + var result = dic.TryGetValue(valueKey, out value); + + if (result) dic.Remove(valueKey); + + if (dic.Count == 0) RemoveKey(key); + + return result; + } + + /// + /// 移除字典中的指定键及其相关的所有键值对。 + /// + /// 要移除的键。 + public void RemoveKey(TKey key) + { + if (!TryGetValue(key, out var dic)) return; + + Remove(key); + Recycle(dic); + } + + /// + /// 从对象池中获取一个内部字典实例,如果池中没有,则创建一个新实例。 + /// + /// 获取的内部字典实例。 + private Dictionary Fetch() + { + return _queue.Count <= 0 ? new Dictionary() : _queue.Dequeue(); + } + + /// + /// 将不再使用的内部字典实例放回对象池中,以便后续重用。 + /// + /// 要放回对象池的内部字典实例。 + private void Recycle(Dictionary dic) + { + dic.Clear(); + + if (_recyclingLimit != 0 && _queue.Count > _recyclingLimit) return; + + _queue.Enqueue(dic); + } + + /// + /// 清空字典中的所有键值对,并将不再使用的内部字典实例放回对象池中。 + /// + public new void Clear() + { + foreach (var keyValuePair in this) Recycle(keyValuePair.Value); + + base.Clear(); + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/Dictionary/OneToManyDictionaryPool.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/Dictionary/OneToManyDictionaryPool.cs.meta new file mode 100644 index 0000000..7db27fa --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/Dictionary/OneToManyDictionaryPool.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4cd83a6bbc1914aa4bf1f94f1cba1c47 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/Dictionary/OneToManySortedDictionaryPool.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/Dictionary/OneToManySortedDictionaryPool.cs new file mode 100644 index 0000000..127a8ac --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/Dictionary/OneToManySortedDictionaryPool.cs @@ -0,0 +1,250 @@ +using System; +using System.Collections.Generic; +using Fantasy.Pool; + +#pragma warning disable CS8601 + +namespace Fantasy.DataStructure.Dictionary +{ + /// + /// 一对多映射关系的排序字典对象池。 + /// + /// 外部字典中的键类型。 + /// 内部字典中的排序键类型。 + /// 内部字典中的值类型。 + public class OneToManySortedDictionaryPool : OneToManySortedDictionary, IDisposable, IPool where TKey : notnull where TSortedKey : notnull + { + private bool _isPool; + private bool _isDispose; + + /// + /// 创建一个 的实例。 + /// + /// 新创建的 OneToManySortedDictionaryPool 实例。 + public static OneToManySortedDictionaryPool Create() + { +#if FANTASY_WEBGL + var a = Pool>.Rent(); +#else + var a = MultiThreadPool.Rent>(); +#endif + a._isDispose = false; + a._isPool = true; + return a; + } + + /// + /// 释放当前实例及其资源。 + /// + public void Dispose() + { + if (_isDispose) + { + return; + } + + _isDispose = true; + Clear(); +#if FANTASY_WEBGL + Pool>.Return(this); +#else + MultiThreadPool.Return(this); +#endif + } + + /// + /// 获取一个值,该值指示当前实例是否为对象池中的实例。 + /// + /// + public bool IsPool() + { + return _isPool; + } + + /// + /// 设置一个值,该值指示当前实例是否为对象池中的实例。 + /// + /// + public void SetIsPool(bool isPool) + { + _isPool = isPool; + } + } + + /// + /// 一对多映射关系的排序字典。每个外部键映射到一个内部排序字典,该内部排序字典将排序键映射到相应的值。 + /// + /// 外部字典中的键类型。 + /// 内部字典中的排序键类型。 + /// 内部字典中的值类型。 + public class + OneToManySortedDictionary : Dictionary> + where TSortedKey : notnull where TKey : notnull + { + /// 缓存队列的回收限制 + private readonly int _recyclingLimit = 120; + /// 缓存队列,用于存储已回收的内部排序字典 + private readonly Queue> _queue = new Queue>(); + + /// + /// 创建一个新的 实例。 + /// + protected OneToManySortedDictionary() { } + + /// + /// 创建一个新的 实例。设置最大缓存数量 + /// + /// + /// 1:防止数据量过大、所以超过recyclingLimit的数据还是走GC. + /// 2:设置成0不控制数量,全部缓存 + /// + public OneToManySortedDictionary(int recyclingLimit) + { + _recyclingLimit = recyclingLimit; + } + + /// + /// 检查字典是否包含指定的外部键。 + /// + /// 要检查的外部键。 + /// 如果字典包含指定的外部键,则为 true;否则为 false。 + public bool Contains(TKey key) + { + return this.ContainsKey(key); + } + + /// + /// 检查字典是否包含指定的外部键和排序键。 + /// + /// 要检查的外部键。 + /// 要检查的排序键。 + /// 如果字典包含指定的外部键和排序键,则为 true;否则为 false。 + public bool Contains(TKey key, TSortedKey sortedKey) + { + return TryGetValue(key, out var dic) && dic.ContainsKey(sortedKey); + } + + /// + /// 尝试从字典中获取指定外部键对应的内部排序字典。 + /// + /// 要获取内部排序字典的外部键。 + /// 获取到的内部排序字典,如果找不到则为 null。 + /// 如果找到内部排序字典,则为 true;否则为 false。 + public new bool TryGetValue(TKey key, out SortedDictionary dic) + { + return base.TryGetValue(key, out dic); + } + + /// + /// 尝试从字典中获取指定外部键和排序键对应的值。 + /// + /// 要获取值的外部键。 + /// 要获取值的排序键。 + /// 获取到的值,如果找不到则为 default。 + /// 如果找到值,则为 true;否则为 false。 + public bool TryGetValueBySortedKey(TKey key, TSortedKey sortedKey, out TValue value) + { + if (base.TryGetValue(key, out var dic)) + { + return dic.TryGetValue(sortedKey, out value); + } + + value = default; + return false; + } + + /// + /// 向字典中添加一个值,关联到指定的外部键和排序键。 + /// + /// 要关联值的外部键。 + /// 要关联值的排序键。 + /// 要添加的值。 + public void Add(TKey key, TSortedKey sortedKey, TValue value) + { + if (!TryGetValue(key, out var dic)) + { + dic = Fetch(); + dic.Add(sortedKey, value); + Add(key, dic); + + return; + } + + dic.Add(sortedKey, value); + } + + /// + /// 从字典中移除指定外部键和排序键关联的值。 + /// + /// 要移除值的外部键。 + /// 要移除值的排序键。 + /// 如果成功移除值,则为 true;否则为 false。 + public bool RemoveSortedKey(TKey key, TSortedKey sortedKey) + { + if (!TryGetValue(key, out var dic)) + { + return false; + } + + var isRemove = dic.Remove(sortedKey); + + if (dic.Count == 0) + { + isRemove = RemoveKey(key); + } + + return isRemove; + } + + /// + /// 从字典中移除指定外部键及其关联的所有值。 + /// + /// 要移除的外部键。 + /// 如果成功移除外部键及其关联的所有值,则为 true;否则为 false。 + public bool RemoveKey(TKey key) + { + if (!TryGetValue(key, out var list)) + { + return false; + } + + Remove(key); + Recycle(list); + return true; + } + + /// + /// 从缓存队列中获取一个内部排序字典。 + /// + /// 一个内部排序字典。 + private SortedDictionary Fetch() + { + return _queue.Count <= 0 ? new SortedDictionary() : _queue.Dequeue(); + } + + /// + /// 回收一个内部排序字典到缓存队列。 + /// + /// 要回收的内部排序字典。 + private void Recycle(SortedDictionary dic) + { + dic.Clear(); + + if (_recyclingLimit != 0 && _queue.Count > _recyclingLimit) + { + return; + } + + _queue.Enqueue(dic); + } + + /// + /// 清空字典以及内部排序字典缓存队列,释放所有资源。 + /// + protected new void Clear() + { + base.Clear(); + _queue.Clear(); + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/Dictionary/OneToManySortedDictionaryPool.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/Dictionary/OneToManySortedDictionaryPool.cs.meta new file mode 100644 index 0000000..12b4b35 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/Dictionary/OneToManySortedDictionaryPool.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ece24c9ac70d549ea953523c0e5f7337 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/Dictionary/ReuseDictionary.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/Dictionary/ReuseDictionary.cs new file mode 100644 index 0000000..ebe12e9 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/Dictionary/ReuseDictionary.cs @@ -0,0 +1,70 @@ +using System; +using System.Collections.Generic; +using Fantasy.Pool; + +namespace Fantasy.DataStructure.Dictionary +{ + /// + /// 提供一个可以重用的字典类,支持使用对象池管理。 + /// + /// 字典中键的类型。 + /// 字典中值的类型。 + public sealed class ReuseDictionary : Dictionary, IDisposable, IPool where TM : notnull + { + private bool _isPool; + private bool _isDispose; + + /// + /// 创建一个新的 实例。 + /// + /// 新创建的实例。 + public static ReuseDictionary Create() + { +#if FANTASY_WEBGL + var entityDictionary = Pool>.Rent(); +#else + var entityDictionary = MultiThreadPool.Rent>(); +#endif + entityDictionary._isDispose = false; + entityDictionary._isPool = true; + return entityDictionary; + } + + /// + /// 释放实例占用的资源。 + /// + public void Dispose() + { + if (_isDispose) + { + return; + } + + _isDispose = true; + Clear(); +#if FANTASY_WEBGL + Pool>.Return(this); +#else + MultiThreadPool.Return(this); +#endif + } + + /// + /// 获取一个值,该值指示当前实例是否为对象池中的实例。 + /// + /// + public bool IsPool() + { + return _isPool; + } + + /// + /// 设置一个值,该值指示当前实例是否为对象池中的实例。 + /// + /// + public void SetIsPool(bool isPool) + { + _isPool = isPool; + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/Dictionary/ReuseDictionary.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/Dictionary/ReuseDictionary.cs.meta new file mode 100644 index 0000000..974258d --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/Dictionary/ReuseDictionary.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 882f28b6907a3465dbf9df04603f74b5 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/Dictionary/SortedDictionaryPool.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/Dictionary/SortedDictionaryPool.cs new file mode 100644 index 0000000..8db66a8 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/Dictionary/SortedDictionaryPool.cs @@ -0,0 +1,70 @@ +using System; +using System.Collections.Generic; +using Fantasy.Pool; + +namespace Fantasy.DataStructure.Dictionary +{ + /// + /// 提供一个可以使用对象池管理的排序字典类。 + /// + /// + /// + public sealed class SortedDictionaryPool : SortedDictionary, IDisposable, IPool where TM : notnull + { + private bool _isPool; + private bool _isDispose; + + /// + /// 释放实例占用的资源。 + /// + public void Dispose() + { + if (_isDispose) + { + return; + } + + _isDispose = true; + Clear(); +#if FANTASY_WEBGL + Pool>.Return(this); +#else + MultiThreadPool.Return(this); +#endif + } + + /// + /// 创建一个新的 实例。 + /// + /// 新创建的实例。 + public static SortedDictionaryPool Create() + { +#if FANTASY_WEBGL + var dictionary = Pool>.Rent(); +#else + var dictionary = MultiThreadPool.Rent>(); +#endif + dictionary._isDispose = false; + dictionary._isPool = true; + return dictionary; + } + + /// + /// 获取一个值,该值指示当前实例是否为对象池中的实例。 + /// + /// + public bool IsPool() + { + return _isPool; + } + + /// + /// 设置一个值,该值指示当前实例是否为对象池中的实例。 + /// + /// + public void SetIsPool(bool isPool) + { + _isPool = isPool; + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/Dictionary/SortedDictionaryPool.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/Dictionary/SortedDictionaryPool.cs.meta new file mode 100644 index 0000000..a194859 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/Dictionary/SortedDictionaryPool.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 060121583adb64f03973db7e623b91de +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections.meta new file mode 100644 index 0000000..fa09ab3 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 6e0c05d3a90bc4c5d88144a87507f06d +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/LICENSE b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/LICENSE new file mode 100644 index 0000000..2ca2248 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 Nevin + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/LICENSE.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/LICENSE.meta new file mode 100644 index 0000000..6dcaebd --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/LICENSE.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 7e1846e320c8146de9a12ee013d7f387 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections.meta new file mode 100644 index 0000000..4a1da86 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 7c8784e99a0cb4cea8ad217cf8c094b1 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/BitOperationsHelpers.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/BitOperationsHelpers.cs new file mode 100644 index 0000000..3b88929 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/BitOperationsHelpers.cs @@ -0,0 +1,325 @@ +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +#if NET7_0_OR_GREATER +using System.Numerics; +using System.Runtime.Intrinsics; +#else +using System; +#endif + +// ReSharper disable ALL + +namespace NativeCollections +{ + /// + /// BitOperations helpers + /// + internal static class BitOperationsHelpers + { +#if !NET7_0_OR_GREATER + /// + /// DeBruijn sequence + /// + private static ReadOnlySpan Log2DeBruijn => new byte[32] + { + 0, 9, 1, 10, 13, 21, 2, 29, + 11, 14, 16, 18, 22, 25, 3, 30, + 8, 12, 20, 28, 15, 17, 24, 7, + 19, 27, 23, 6, 26, 5, 4, 31 + }; +#endif + + /// + /// Log2 + /// + /// Value + /// Log2 + public static int Log2(int value) => Log2((uint)value); + + /// + /// Log2 + /// + /// Value + /// Log2 + public static int Log2(uint value) + { +#if NET7_0_OR_GREATER + return BitOperations.Log2(value); +#else + value |= 1; + value |= value >> 1; + value |= value >> 2; + value |= value >> 4; + value |= value >> 8; + value |= value >> 16; + return Unsafe.AddByteOffset(ref MemoryMarshal.GetReference(Log2DeBruijn), (nint)(int)((value * 130329821U) >> 27)); +#endif + } + + /// + /// And + /// + /// Destination + /// Source + /// Count + public static void And(Span destination, Span source, uint count) + { + switch (count) + { + case 7: + destination[6] &= source[6]; + goto case 6; + case 6: + destination[5] &= source[5]; + goto case 5; + case 5: + destination[4] &= source[4]; + goto case 4; + case 4: + destination[3] &= source[3]; + goto case 3; + case 3: + destination[2] &= source[2]; + goto case 2; + case 2: + destination[1] &= source[1]; + goto case 1; + case 1: + destination[0] &= source[0]; + return; + case 0: + return; + } + + ref var left = ref MemoryMarshal.GetReference(destination); + ref var right = ref MemoryMarshal.GetReference(source); +#if NET7_0_OR_GREATER + uint i = 0; + if (Vector256.IsHardwareAccelerated) + { + var n = count - 7; + for (; i < n; i += 8) + { + var result = Vector256.LoadUnsafe(ref left, i) & Vector256.LoadUnsafe(ref right, i); + result.StoreUnsafe(ref left, i); + } + } + else if (Vector128.IsHardwareAccelerated) + { + var n = count - 3; + for (; i < n; i += 4) + { + var result = Vector128.LoadUnsafe(ref left, i) & Vector128.LoadUnsafe(ref right, i); + result.StoreUnsafe(ref left, i); + } + } + + for (; i < count; ++i) + Unsafe.Add(ref left, i) &= Unsafe.Add(ref right, i); +#else + var i = 0; + for (; i < count; ++i) + Unsafe.Add(ref left, i) &= Unsafe.Add(ref right, i); +#endif + } + + /// + /// Or + /// + /// Destination + /// Source + /// Count + public static void Or(Span destination, Span source, uint count) + { + switch (count) + { + case 7: + destination[6] |= source[6]; + goto case 6; + case 6: + destination[5] |= source[5]; + goto case 5; + case 5: + destination[4] |= source[4]; + goto case 4; + case 4: + destination[3] |= source[3]; + goto case 3; + case 3: + destination[2] |= source[2]; + goto case 2; + case 2: + destination[1] |= source[1]; + goto case 1; + case 1: + destination[0] |= source[0]; + return; + case 0: + return; + } + + ref var left = ref MemoryMarshal.GetReference(destination); + ref var right = ref MemoryMarshal.GetReference(source); +#if NET7_0_OR_GREATER + uint i = 0; + if (Vector256.IsHardwareAccelerated) + { + var n = count - 7; + for (; i < n; i += 8) + { + var result = Vector256.LoadUnsafe(ref left, i) | Vector256.LoadUnsafe(ref right, i); + result.StoreUnsafe(ref left, i); + } + } + else if (Vector128.IsHardwareAccelerated) + { + var n = count - 3; + for (; i < n; i += 4) + { + var result = Vector128.LoadUnsafe(ref left, i) | Vector128.LoadUnsafe(ref right, i); + result.StoreUnsafe(ref left, i); + } + } + + for (; i < count; ++i) + Unsafe.Add(ref left, i) |= Unsafe.Add(ref right, i); +#else + var i = 0; + for (; i < count; ++i) + Unsafe.Add(ref left, i) |= Unsafe.Add(ref right, i); +#endif + } + + /// + /// Xor + /// + /// Destination + /// Source + /// Count + public static void Xor(Span destination, Span source, uint count) + { + switch (count) + { + case 7: + destination[6] ^= source[6]; + goto case 6; + case 6: + destination[5] ^= source[5]; + goto case 5; + case 5: + destination[4] ^= source[4]; + goto case 4; + case 4: + destination[3] ^= source[3]; + goto case 3; + case 3: + destination[2] ^= source[2]; + goto case 2; + case 2: + destination[1] ^= source[1]; + goto case 1; + case 1: + destination[0] ^= source[0]; + return; + case 0: + return; + } + + ref var left = ref MemoryMarshal.GetReference(destination); + ref var right = ref MemoryMarshal.GetReference(source); +#if NET7_0_OR_GREATER + uint i = 0; + if (Vector256.IsHardwareAccelerated) + { + var n = count - 7; + for (; i < n; i += 8) + { + var result = Vector256.LoadUnsafe(ref left, i) ^ Vector256.LoadUnsafe(ref right, i); + result.StoreUnsafe(ref left, i); + } + } + else if (Vector128.IsHardwareAccelerated) + { + var n = count - 3; + for (; i < n; i += 4) + { + var result = Vector128.LoadUnsafe(ref left, i) ^ Vector128.LoadUnsafe(ref right, i); + result.StoreUnsafe(ref left, i); + } + } + + for (; i < count; ++i) + Unsafe.Add(ref left, i) ^= Unsafe.Add(ref right, i); +#else + var i = 0; + for (; i < count; ++i) + Unsafe.Add(ref left, i) ^= Unsafe.Add(ref right, i); +#endif + } + + /// + /// Not + /// + /// Destination + /// Count + public static void Not(Span destination, uint count) + { + switch (count) + { + case 7: + destination[6] = ~destination[6]; + goto case 6; + case 6: + destination[5] = ~destination[5]; + goto case 5; + case 5: + destination[4] = ~destination[4]; + goto case 4; + case 4: + destination[3] = ~destination[3]; + goto case 3; + case 3: + destination[2] = ~destination[2]; + goto case 2; + case 2: + destination[1] = ~destination[1]; + goto case 1; + case 1: + destination[0] = ~destination[0]; + return; + case 0: + return; + } + + ref var value = ref MemoryMarshal.GetReference(destination); +#if NET7_0_OR_GREATER + uint i = 0; + if (Vector256.IsHardwareAccelerated) + { + var n = count - 7; + for (; i < n; i += 8) + { + var result = ~Vector256.LoadUnsafe(ref value, i); + result.StoreUnsafe(ref value, i); + } + } + else if (Vector128.IsHardwareAccelerated) + { + var n = count - 3; + for (; i < n; i += 4) + { + var result = ~Vector128.LoadUnsafe(ref value, i); + result.StoreUnsafe(ref value, i); + } + } + + for (; i < count; ++i) + Unsafe.Add(ref value, i) = ~ Unsafe.Add(ref value, i); +#else + var i = 0; + for (; i < count; ++i) + Unsafe.Add(ref value, i) = ~ Unsafe.Add(ref value, i); +#endif + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/BitOperationsHelpers.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/BitOperationsHelpers.cs.meta new file mode 100644 index 0000000..5680378 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/BitOperationsHelpers.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a92934f7689f140088cf35008fc577a9 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/HashHelpers.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/HashHelpers.cs new file mode 100644 index 0000000..fedc510 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/HashHelpers.cs @@ -0,0 +1,125 @@ +#if UNITY_2021_3_OR_NEWER || GODOT +using System; +#endif +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// ReSharper disable ALL + +namespace NativeCollections +{ + /// + /// Hash helpers + /// + internal static class HashHelpers + { + /// + /// Primes + /// + private static ReadOnlySpan Primes => new int[72] + { + 3, 7, 11, 17, 23, 29, 37, 47, 59, 71, 89, 107, 131, 163, 197, 239, 293, 353, 431, 521, 631, 761, 919, + 1103, 1327, 1597, 1931, 2333, 2801, 3371, 4049, 4861, 5839, 7013, 8419, 10103, 12143, 14591, + 17519, 21023, 25229, 30293, 36353, 43627, 52361, 62851, 75431, 90523, 108631, 130363, 156437, + 187751, 225307, 270371, 324449, 389357, 467237, 560689, 672827, 807403, 968897, 1162687, 1395263, + 1674319, 2009191, 2411033, 2893249, 3471899, 4166287, 4999559, 5999471, 7199369 + }; + + /// + /// Binary search + /// + /// Min + /// Prime + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static int BinarySearch(int min) + { + var left = 0; + var right = 71; + ref var value = ref MemoryMarshal.GetReference(Primes); + while (left <= right) + { + var mid = left + (right - left) / 2; + if (Unsafe.Add(ref value, mid) >= min) + right = mid - 1; + else + left = mid + 1; + } + + return Unsafe.Add(ref value, left); + } + + /// + /// Is prime + /// + /// Candidate + /// Is prime + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool IsPrime(int candidate) + { + if ((candidate & 1) != 0) + { + var limit = (int)Math.Sqrt(candidate); + for (var divisor = 3; divisor <= limit; divisor += 2) + { + if (candidate % divisor == 0) + return false; + } + + return true; + } + + return candidate == 2; + } + + /// + /// Get prime + /// + /// Min + /// Prime + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int GetPrime(int min) + { + if (min < 0) + throw new ArgumentException("HTCapacityOverflow"); + if (min <= 7199369) + return BinarySearch(min); + for (var i = min | 1; i < int.MaxValue; i += 2) + { + if (IsPrime(i) && (i - 1) % 101 != 0) + return i; + } + + return min; + } + + /// + /// Expand prime + /// + /// Old size + /// Prime + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int ExpandPrime(int oldSize) + { + var newSize = 2 * oldSize; + return (uint)newSize > 2147483587 && 2147483587 > oldSize ? 2147483587 : GetPrime(newSize); + } + + /// + /// Get fast mod multiplier + /// + /// Divisor + /// Fast mod multiplier + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ulong GetFastModMultiplier(uint divisor) => ulong.MaxValue / divisor + 1; + + /// + /// Fast mod + /// + /// Value + /// Divisor + /// Multiplier + /// Mod + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static uint FastMod(uint value, uint divisor, ulong multiplier) => (uint)(((((multiplier * value) >> 32) + 1) * divisor) >> 32); + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/HashHelpers.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/HashHelpers.cs.meta new file mode 100644 index 0000000..b50cbe2 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/HashHelpers.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 06d18d662209a4e2f8fecbe95ed58edf +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeArray.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeArray.cs new file mode 100644 index 0000000..e8c372e --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeArray.cs @@ -0,0 +1,297 @@ +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +#if UNITY_2021_3_OR_NEWER || GODOT +using System; +#endif + +#pragma warning disable CA2208 +#pragma warning disable CS8632 + +// ReSharper disable ALL + +namespace NativeCollections +{ + /// + /// Native array + /// + /// Type + [StructLayout(LayoutKind.Sequential)] + public readonly unsafe struct NativeArray : IDisposable, IEquatable> where T : unmanaged + { + /// + /// Array + /// + private readonly T* _array; + + /// + /// Length + /// + private readonly int _length; + + /// + /// Structure + /// + /// Length + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public NativeArray(int length) + { + if (length < 0) + throw new ArgumentOutOfRangeException(nameof(length), length, "MustBeNonNegative"); + _array = (T*)NativeMemoryAllocator.Alloc((uint)(length * sizeof(T))); + _length = length; + } + + /// + /// Structure + /// + /// Length + /// Zeroed + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public NativeArray(int length, bool zeroed) + { + if (length < 0) + throw new ArgumentOutOfRangeException(nameof(length), length, "MustBeNonNegative"); + _array = zeroed ? (T*)NativeMemoryAllocator.AllocZeroed((uint)(length * sizeof(T))) : (T*)NativeMemoryAllocator.Alloc((uint)(length * sizeof(T))); + _length = length; + } + + /// + /// Structure + /// + /// Array + /// Length + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public NativeArray(T* array, int length) + { + if (length < 0) + throw new ArgumentOutOfRangeException(nameof(length), length, "MustBeNonNegative"); + _array = array; + _length = length; + } + + /// + /// Is created + /// + public bool IsCreated => _array != null; + + /// + /// Is empty + /// + public bool IsEmpty => _length == 0; + + /// + /// Get reference + /// + /// Index + public ref T this[int index] + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => ref _array[index]; + } + + /// + /// Get reference + /// + /// Index + public ref T this[uint index] + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => ref _array[index]; + } + + /// + /// Array + /// + public T* Array => _array; + + /// + /// Length + /// + public int Length => _length; + + /// + /// Equals + /// + /// Other + /// Equals + public bool Equals(NativeArray other) => other == this; + + /// + /// Equals + /// + /// object + /// Equals + public override bool Equals(object? obj) => obj is NativeArray nativeArray && nativeArray == this; + + /// + /// Get hashCode + /// + /// HashCode + public override int GetHashCode() => (int)(nint)_array; + + /// + /// To string + /// + /// String + public override string ToString() => $"NativeArray<{typeof(T).Name}>[{_length}]"; + + /// + /// As span + /// + /// Span + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator Span(NativeArray nativeArray) => nativeArray.AsSpan(); + + /// + /// As readOnly span + /// + /// ReadOnlySpan + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator ReadOnlySpan(NativeArray nativeArray) => nativeArray.AsReadOnlySpan(); + + /// + /// Equals + /// + /// Left + /// Right + /// Equals + public static bool operator ==(NativeArray left, NativeArray right) => left._length == right._length && left._array == right._array; + + /// + /// Not equals + /// + /// Left + /// Right + /// Not equals + public static bool operator !=(NativeArray left, NativeArray right) => left._length != right._length || left._array != right._array; + + /// + /// Dispose + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Dispose() + { + if (_array == null) + return; + NativeMemoryAllocator.Free(_array); + } + + /// + /// Clear + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Clear() => Unsafe.InitBlockUnaligned(_array, 0, (uint)(_length * sizeof(T))); + + /// + /// As span + /// + /// Span + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Span AsSpan() => MemoryMarshal.CreateSpan(ref *_array, _length); + + /// + /// As span + /// + /// Length + /// Span + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Span AsSpan(int length) => MemoryMarshal.CreateSpan(ref *_array, length); + + /// + /// As span + /// + /// Start + /// Length + /// Span + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Span AsSpan(int start, int length) => MemoryMarshal.CreateSpan(ref *(_array + start), length); + + /// + /// As readOnly span + /// + /// ReadOnlySpan + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public ReadOnlySpan AsReadOnlySpan() => MemoryMarshal.CreateReadOnlySpan(ref *_array, _length); + + /// + /// As readOnly span + /// + /// Length + /// ReadOnlySpan + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public ReadOnlySpan AsReadOnlySpan(int length) => MemoryMarshal.CreateReadOnlySpan(ref *_array, length); + + /// + /// As readOnly span + /// + /// Start + /// Length + /// ReadOnlySpan + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public ReadOnlySpan AsReadOnlySpan(int start, int length) => MemoryMarshal.CreateReadOnlySpan(ref *(_array + start), length); + + /// + /// Empty + /// + public static NativeArray Empty => new(); + + /// + /// Get enumerator + /// + /// Enumerator + public Enumerator GetEnumerator() => new(this); + + /// + /// Enumerator + /// + public ref struct Enumerator + { + /// + /// NativeArray + /// + private readonly NativeArray _nativeArray; + + /// + /// Index + /// + private int _index; + + /// + /// Structure + /// + /// NativeArray + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal Enumerator(NativeArray nativeArray) + { + _nativeArray = nativeArray; + _index = -1; + } + + /// + /// Move next + /// + /// Moved + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool MoveNext() + { + var index = _index + 1; + if (index < _nativeArray._length) + { + _index = index; + return true; + } + + return false; + } + + /// + /// Current + /// + public ref T Current + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => ref _nativeArray[_index]; + } + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeArray.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeArray.cs.meta new file mode 100644 index 0000000..b5e3b89 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeArray.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 44a472b0265094fccbc88f3691985d78 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeArrayPool.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeArrayPool.cs new file mode 100644 index 0000000..b31e428 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeArrayPool.cs @@ -0,0 +1,372 @@ +#if UNITY_2021_3_OR_NEWER || GODOT +using System; +using System.Threading; +#endif +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +#if NET5_0_OR_GREATER +#endif + +#pragma warning disable CA2208 +#pragma warning disable CS8632 + +// ReSharper disable ALL + +namespace NativeCollections +{ + /// + /// NativeMemoryPool + /// + [StructLayout(LayoutKind.Sequential)] + public readonly unsafe struct NativeArrayPool : IDisposable, IEquatable> where T : unmanaged + { + /// + /// Buckets + /// + private readonly NativeArrayPoolBucket* _buckets; + + /// + /// Length + /// + private readonly int _length; + + /// + /// Size + /// + private readonly int _size; + + /// + /// Structure + /// + /// Size + /// Max length + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public NativeArrayPool(int size, int maxLength) + { + if (size <= 0) + throw new ArgumentOutOfRangeException(nameof(size), size, "MustBePositive"); + if (maxLength < 0) + throw new ArgumentOutOfRangeException(nameof(maxLength), maxLength, "MustBeNonNegative"); + if (maxLength > 1073741824) + maxLength = 1073741824; + else if (maxLength < 16) + maxLength = 16; + var length = SelectBucketIndex(maxLength) + 1; + var buckets = (NativeArrayPoolBucket*)NativeMemoryAllocator.Alloc((uint)(length * sizeof(NativeArrayPoolBucket))); + for (var i = 0; i < length; ++i) + buckets[i].Initialize(size, 16 << i); + _buckets = buckets; + _length = length; + _size = size; + } + + /// + /// Is created + /// + public bool IsCreated => _buckets != null; + + /// + /// Size + /// + public int Size => _size; + + /// + /// Max length + /// + public int MaxLength => 16 << (_length - 1); + + /// + /// Equals + /// + /// Other + /// Equals + public bool Equals(NativeArrayPool other) => other == this; + + /// + /// Equals + /// + /// object + /// Equals + public override bool Equals(object? obj) => obj is NativeArrayPool nativeArrayPool && nativeArrayPool == this; + + /// + /// Get hashCode + /// + /// HashCode + public override int GetHashCode() => (int)(nint)_buckets; + + /// + /// To string + /// + /// String + public override string ToString() => $"NativeArrayPool<{typeof(T).Name}>"; + + /// + /// Equals + /// + /// Left + /// Right + /// Equals + public static bool operator ==(NativeArrayPool left, NativeArrayPool right) => left._buckets == right._buckets; + + /// + /// Not equals + /// + /// Left + /// Right + /// Not equals + public static bool operator !=(NativeArrayPool left, NativeArrayPool right) => left._buckets != right._buckets; + + /// + /// Dispose + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Dispose() + { + if (_buckets == null) + return; + for (var i = 0; i < _length; ++i) + _buckets[i].Dispose(); + NativeMemoryAllocator.Free(_buckets); + } + + /// + /// Rent buffer + /// + /// Minimum buffer length + /// Buffer + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public NativeArray Rent(int minimumLength) + { + if (minimumLength < 0) + throw new ArgumentOutOfRangeException(nameof(minimumLength), minimumLength, "MustBeNonNegative"); + var index = SelectBucketIndex(minimumLength); + if (index < _length) + return _buckets[index].Rent(); + throw new ArgumentOutOfRangeException(nameof(minimumLength), minimumLength, "BiggerThanCollection"); + } + + /// + /// Rent buffer + /// + /// Minimum buffer length + /// Buffer + /// Rented + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool TryRent(int minimumLength, out NativeArray array) + { + if (minimumLength < 0) + { + array = default; + return false; + } + + var index = SelectBucketIndex(minimumLength); + if (index < _length) + { + array = _buckets[index].Rent(); + return true; + } + + array = default; + return false; + } + + /// + /// Return buffer + /// + /// Buffer + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Return(in NativeArray array) + { + var length = array.Length; + if (length < 16 || (length & (length - 1)) != 0) + throw new ArgumentException("BufferNotFromPool", nameof(array)); + var bucket = SelectBucketIndex(length); + if (bucket >= _length) + throw new ArgumentException("BufferNotFromPool", nameof(array)); + _buckets[bucket].Return(array.Array); + } + + /// + /// Try return buffer + /// + /// Buffer + /// Returned + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool TryReturn(in NativeArray array) + { + var length = array.Length; + if (length < 16 || (length & (length - 1)) != 0) + return false; + var bucket = SelectBucketIndex(length); + if (bucket >= _length) + return false; + _buckets[bucket].Return(array.Array); + return true; + } + + /// + /// Return buffer + /// + /// Length + /// Buffer + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Return(int length, T* array) + { + if (length < 16 || (length & (length - 1)) != 0) + throw new ArgumentException("BufferNotFromPool", nameof(array)); + var bucket = SelectBucketIndex(length); + if (bucket >= _length) + throw new ArgumentException("BufferNotFromPool", nameof(array)); + _buckets[bucket].Return(array); + } + + /// + /// Try return buffer + /// + /// Length + /// Buffer + /// Returned + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool TryReturn(int length, T* array) + { + if (length < 16 || (length & (length - 1)) != 0) + return false; + var bucket = SelectBucketIndex(length); + if (bucket >= _length) + return false; + _buckets[bucket].Return(array); + return true; + } + + /// + /// Select bucket index + /// + /// Buffer size + /// Bucket index + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static int SelectBucketIndex(int bufferSize) => BitOperationsHelpers.Log2(((uint)bufferSize - 1) | 15) - 3; + + /// + /// Empty + /// + public static NativeArrayPool Empty => new(); + + /// + /// NativeArrayPool bucket + /// + [StructLayout(LayoutKind.Sequential)] + private struct NativeArrayPoolBucket : IDisposable + { + /// + /// Size + /// + private int _size; + + /// + /// Length + /// + private int _length; + + /// + /// Buffers + /// + private T** _array; + + /// + /// Index + /// + private int _index; + + /// + /// Memory pool + /// + private NativeMemoryPool _memoryPool; + + /// + /// State lock + /// + private SpinLock _lock; + + /// + /// Structure + /// + /// Size + /// Length + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Initialize(int size, int length) + { + _size = size; + _length = length; + _array = (T**)NativeMemoryAllocator.AllocZeroed((uint)(size * sizeof(T*))); + _index = 0; + _memoryPool = new NativeMemoryPool(size, length * sizeof(T), 0); + _lock = new SpinLock(); + } + + /// + /// Dispose + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Dispose() + { + NativeMemoryAllocator.Free(_array); + _memoryPool.Dispose(); + } + + /// + /// Rent buffer + /// + /// Buffer + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public NativeArray Rent() + { + T* ptr = null; + var lockTaken = false; + try + { + _lock.Enter(ref lockTaken); + if (_index < _size) + { + ptr = _array[_index]; + _array[_index++] = null; + } + + if (ptr == null) + ptr = (T*)_memoryPool.Rent(); + } + finally + { + if (lockTaken) + _lock.Exit(false); + } + + return new NativeArray(ptr, _length); + } + + /// + /// Return buffer + /// + /// Pointer + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Return(T* ptr) + { + var lockTaken = false; + try + { + _lock.Enter(ref lockTaken); + if (_index != 0) + _array[--_index] = ptr; + else + _memoryPool.Return(ptr); + } + finally + { + if (lockTaken) + _lock.Exit(false); + } + } + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeArrayPool.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeArrayPool.cs.meta new file mode 100644 index 0000000..e126f15 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeArrayPool.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e0181fd493dbd46abb66ae1d7619eaae +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeArrayReference.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeArrayReference.cs new file mode 100644 index 0000000..62a62da --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeArrayReference.cs @@ -0,0 +1,248 @@ +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +#if UNITY_2021_3_OR_NEWER || GODOT +using System; +#endif + +#pragma warning disable CA2208 +#pragma warning disable CS8600 +#pragma warning disable CS8603 +#pragma warning disable CS8632 + +// ReSharper disable ALL + +namespace NativeCollections +{ + /// + /// Native array reference + /// + /// Type + [StructLayout(LayoutKind.Sequential)] + public struct NativeArrayReference : IDisposable, IEquatable> + { + /// + /// Handle + /// + private GCHandle _handle; + + /// + /// Length + /// + private readonly int _length; + + /// + /// Structure + /// + /// Length + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public NativeArrayReference(int length) + { + if (length < 0) + throw new ArgumentOutOfRangeException(nameof(length), length, "MustBeNonNegative"); + _handle = GCHandle.Alloc(new T[length], GCHandleType.Normal); + _length = length; + } + + /// + /// Structure + /// + /// Length + /// GCHandle type + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public NativeArrayReference(int length, GCHandleType type) + { + if (length < 0) + throw new ArgumentOutOfRangeException(nameof(length), length, "MustBeNonNegative"); + _handle = GCHandle.Alloc(new T[length], type); + _length = length; + } + + /// + /// Structure + /// + /// Array + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public NativeArrayReference(T[] array) + { + if (array == null) + throw new ArgumentNullException(nameof(array), "MustBeNotNull"); + _handle = GCHandle.Alloc(array, GCHandleType.Normal); + _length = array.Length; + } + + /// + /// Structure + /// + /// Array + /// GCHandle type + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public NativeArrayReference(T[] array, GCHandleType type) + { + if (array == null) + throw new ArgumentNullException(nameof(array), "MustBeNotNull"); + _handle = GCHandle.Alloc(array, type); + _length = array.Length; + } + + /// + /// Is created + /// + public bool IsCreated => _handle.IsAllocated; + + /// + /// Is empty + /// + public bool IsEmpty => _length == 0; + + /// + /// Get reference + /// + /// Index + public ref T this[int index] + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => ref Array[index]; + } + + /// + /// Get reference + /// + /// Index + public ref T this[uint index] + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => ref Array[index]; + } + + /// + /// Array + /// + public T[] Array + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => (T[])_handle.Target; + } + + /// + /// Length + /// + public int Length => _length; + + /// + /// Equals + /// + /// Other + /// Equals + public bool Equals(NativeArrayReference other) => other == this; + + /// + /// Equals + /// + /// object + /// Equals + public override bool Equals(object? obj) => obj is NativeArrayReference nativeArrayReference && nativeArrayReference == this; + + /// + /// Get hashCode + /// + /// HashCode + public override int GetHashCode() => (int)(nint)_handle; + + /// + /// To string + /// + /// String + public override string ToString() => $"NativeArrayReference<{typeof(T).Name}>"; + + /// + /// Equals + /// + /// Left + /// Right + /// Equals + public static bool operator ==(NativeArrayReference left, NativeArrayReference right) => left._handle == right._handle; + + /// + /// Not equals + /// + /// Left + /// Right + /// Not equals + public static bool operator !=(NativeArrayReference left, NativeArrayReference right) => left._handle != right._handle; + + /// + /// Dispose + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Dispose() + { + if (!_handle.IsAllocated) + return; + _handle.Free(); + } + + /// + /// Empty + /// + public static NativeArrayReference Empty => new(); + + /// + /// Get enumerator + /// + /// Enumerator + public Enumerator GetEnumerator() => new(Array); + + /// + /// Enumerator + /// + public ref struct Enumerator + { + /// + /// Array + /// + private readonly T[] _array; + + /// + /// Index + /// + private int _index; + + /// + /// Structure + /// + /// Array + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal Enumerator(T[] array) + { + _array = array; + _index = -1; + } + + /// + /// Move next + /// + /// Moved + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool MoveNext() + { + var index = _index + 1; + if (index < _array.Length) + { + _index = index; + return true; + } + + return false; + } + + /// + /// Current + /// + public ref T Current + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => ref _array[_index]; + } + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeArrayReference.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeArrayReference.cs.meta new file mode 100644 index 0000000..bfc5500 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeArrayReference.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d9f0b1359e8a5465cbc412dccdb1fb8d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeArraySegment.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeArraySegment.cs new file mode 100644 index 0000000..aeac3df --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeArraySegment.cs @@ -0,0 +1,386 @@ +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +#if UNITY_2021_3_OR_NEWER || GODOT +using System; +#endif + +#pragma warning disable CA2208 +#pragma warning disable CS8632 + +// ReSharper disable ALL + +namespace NativeCollections +{ + /// + /// Native array segment + /// + /// Type + [StructLayout(LayoutKind.Sequential)] + public readonly unsafe struct NativeArraySegment : IDisposable, IEquatable> where T : unmanaged + { + /// + /// Array + /// + private readonly T* _array; + + /// + /// Offset + /// + private readonly int _offset; + + /// + /// Count + /// + private readonly int _count; + + /// + /// Structure + /// + /// Array + /// Count + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public NativeArraySegment(T* array, int count) + { + if (count < 0) + throw new ArgumentOutOfRangeException(nameof(count), count, "MustBeNonNegative"); + _array = array; + _offset = 0; + _count = count; + } + + /// + /// Structure + /// + /// Array + /// Offset + /// Count + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public NativeArraySegment(T* array, int offset, int count) + { + if (offset < 0) + throw new ArgumentOutOfRangeException(nameof(offset), offset, "MustBeNonNegative"); + if (count < 0) + throw new ArgumentOutOfRangeException(nameof(count), count, "MustBeNonNegative"); + _array = array; + _offset = offset; + _count = count; + } + + /// + /// Structure + /// + /// Array + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public NativeArraySegment(NativeArray array) + { + _array = array.Array; + _offset = 0; + _count = array.Length; + } + + /// + /// Structure + /// + /// Array + /// Offset + /// Count + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public NativeArraySegment(NativeArray array, int offset, int count) + { + _array = array.Array; + _offset = offset; + _count = count; + } + + /// + /// Structure + /// + /// Array + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public NativeArraySegment(NativeMemoryArray array) + { + _array = array.Array; + _offset = 0; + _count = array.Length; + } + + /// + /// Structure + /// + /// Array + /// Offset + /// Count + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public NativeArraySegment(NativeMemoryArray array, int offset, int count) + { + _array = array.Array; + _offset = offset; + _count = count; + } + + /// + /// Is created + /// + public bool IsCreated => _array != null; + + /// + /// Is empty + /// + public bool IsEmpty => _count == 0; + + /// + /// Get reference + /// + /// Index + public ref T this[int index] + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => ref _array[_offset + index]; + } + + /// + /// Get reference + /// + /// Index + public ref T this[uint index] + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => ref _array[_offset + index]; + } + + /// + /// Array + /// + public T* Array => _array; + + /// + /// Offset + /// + public int Offset => _offset; + + /// + /// Count + /// + public int Count => _count; + + /// + /// Equals + /// + /// Other + /// Equals + public bool Equals(NativeArraySegment other) => other == this; + + /// + /// Equals + /// + /// object + /// Equals + public override bool Equals(object? obj) => obj is NativeArraySegment nativeArraySegment && nativeArraySegment == this; + + /// + /// Get hashCode + /// + /// HashCode + public override int GetHashCode() => (int)(nint)_array; + + /// + /// To string + /// + /// String + public override string ToString() => $"NativeArraySegment<{typeof(T).Name}>[{_offset}, {_count}]"; + + /// + /// As span + /// + /// Span + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator Span(NativeArraySegment nativeArraySegment) => nativeArraySegment.AsSpan(); + + /// + /// As readOnly span + /// + /// ReadOnlySpan + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator ReadOnlySpan(NativeArraySegment nativeArraySegment) => nativeArraySegment.AsReadOnlySpan(); + + /// + /// As native array + /// + /// Native array segment + /// NativeArray + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator NativeArray(NativeArraySegment nativeArraySegment) => new(nativeArraySegment._array, nativeArraySegment._offset + nativeArraySegment._count); + + /// + /// As native array segment + /// + /// Native array + /// NativeArraySegment + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator NativeArraySegment(NativeArray nativeArray) => new(nativeArray); + + /// + /// As native array segment + /// + /// Native array + /// NativeArraySegment + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator NativeArraySegment(NativeMemoryArray nativeArray) => new(nativeArray); + + /// + /// Equals + /// + /// Left + /// Right + /// Equals + public static bool operator ==(NativeArraySegment left, NativeArraySegment right) => left._offset == right._offset && left._count == right._count && left._array == right._array; + + /// + /// Not equals + /// + /// Left + /// Right + /// Not equals + public static bool operator !=(NativeArraySegment left, NativeArraySegment right) => left._offset != right._offset || left._count != right._count || left._array != right._array; + + /// + /// Dispose + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Dispose() + { + if (_array == null) + return; + NativeMemoryAllocator.Free(_array); + } + + /// + /// As span + /// + /// Span + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Span AsSpan() => MemoryMarshal.CreateSpan(ref *(_array + _offset), _count); + + /// + /// As span + /// + /// Count + /// Span + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Span AsSpan(int count) => MemoryMarshal.CreateSpan(ref *(_array + _offset), count); + + /// + /// As span + /// + /// Start + /// Count + /// Span + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Span AsSpan(int start, int count) => MemoryMarshal.CreateSpan(ref *(_array + _offset + start), count); + + /// + /// As readOnly span + /// + /// ReadOnlySpan + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public ReadOnlySpan AsReadOnlySpan() => MemoryMarshal.CreateReadOnlySpan(ref *(_array + _offset), _count); + + /// + /// As readOnly span + /// + /// Count + /// ReadOnlySpan + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public ReadOnlySpan AsReadOnlySpan(int count) => MemoryMarshal.CreateReadOnlySpan(ref *(_array + _offset), count); + + /// + /// As readOnly span + /// + /// Start + /// Count + /// ReadOnlySpan + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public ReadOnlySpan AsReadOnlySpan(int start, int count) => MemoryMarshal.CreateReadOnlySpan(ref *(_array + _offset + start), count); + + /// + /// Slice + /// + /// Start + /// NativeArraySegment + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public NativeArraySegment Slice(int start) => new(_array, _offset + start, _count - start); + + /// + /// Slice + /// + /// Start + /// Count + /// NativeArraySegment + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public NativeArraySegment Slice(int start, int count) => new(_array, _offset + start, count); + + /// + /// Empty + /// + public static NativeArraySegment Empty => new(); + + /// + /// Get enumerator + /// + /// Enumerator + public Enumerator GetEnumerator() => new(this); + + /// + /// Enumerator + /// + public ref struct Enumerator + { + /// + /// NativeArraySegment + /// + private readonly NativeArraySegment _nativeArraySegment; + + /// + /// Index + /// + private int _index; + + /// + /// Structure + /// + /// NativeArraySegment + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal Enumerator(NativeArraySegment nativeArraySegment) + { + _nativeArraySegment = nativeArraySegment; + _index = -1; + } + + /// + /// Move next + /// + /// Moved + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool MoveNext() + { + var index = _index + 1; + if (index < _nativeArraySegment._count) + { + _index = index; + return true; + } + + return false; + } + + /// + /// Current + /// + public ref T Current + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => ref _nativeArraySegment[_index]; + } + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeArraySegment.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeArraySegment.cs.meta new file mode 100644 index 0000000..7430177 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeArraySegment.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3865e132548ee4d8481ddd5a49107ec3 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeBitArray.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeBitArray.cs new file mode 100644 index 0000000..aa192e7 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeBitArray.cs @@ -0,0 +1,590 @@ +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +#if UNITY_2021_3_OR_NEWER || GODOT +using System; +#endif + +#pragma warning disable CA2208 +#pragma warning disable CS8632 + +// ReSharper disable ALL + +namespace NativeCollections +{ + /// + /// Native bit array + /// + [StructLayout(LayoutKind.Sequential)] + public readonly unsafe struct NativeBitArray : IDisposable, IEquatable + { + /// + /// Handle + /// + [StructLayout(LayoutKind.Sequential)] + private struct NativeBitArrayHandle + { + /// + /// Array + /// + public NativeArray Array; + + /// + /// Length + /// + public int Length; + } + + /// + /// Handle + /// + private readonly NativeBitArrayHandle* _handle; + + /// + /// Structure + /// + /// Length + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public NativeBitArray(int length) + { + if (length < 0) + throw new ArgumentOutOfRangeException(nameof(length), length, "MustBeNonNegative"); + _handle = (NativeBitArrayHandle*)NativeMemoryAllocator.Alloc((uint)sizeof(NativeBitArrayHandle)); + _handle->Array = new NativeArray(GetInt32ArrayLengthFromBitLength(length)); + _handle->Length = length; + } + + /// + /// Structure + /// + /// Length + /// Default value + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public NativeBitArray(int length, bool defaultValue) + { + if (length < 0) + throw new ArgumentOutOfRangeException(nameof(length), length, "MustBeNonNegative"); + _handle = (NativeBitArrayHandle*)NativeMemoryAllocator.Alloc((uint)sizeof(NativeBitArrayHandle)); + _handle->Array = new NativeArray(GetInt32ArrayLengthFromBitLength(length)); + _handle->Length = length; + if (defaultValue) + { + _handle->Array.AsSpan().Fill(-1); + Div32Rem(length, out var extraBits); + if (extraBits > 0) + _handle->Array[^1] = (1 << extraBits) - 1; + } + else + { + _handle->Array.Clear(); + } + } + + /// + /// Structure + /// + /// Array + /// Length + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public NativeBitArray(int* array, int length) + { + if (length < 0) + throw new ArgumentOutOfRangeException(nameof(length), length, "MustBeNonNegative"); + _handle = (NativeBitArrayHandle*)NativeMemoryAllocator.Alloc((uint)sizeof(NativeBitArrayHandle)); + _handle->Array = new NativeArray(array, GetInt32ArrayLengthFromBitLength(length)); + _handle->Length = length; + } + + /// + /// Structure + /// + /// Array + /// Length + /// Default value + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public NativeBitArray(int* array, int length, bool defaultValue) + { + if (length < 0) + throw new ArgumentOutOfRangeException(nameof(length), length, "MustBeNonNegative"); + _handle = (NativeBitArrayHandle*)NativeMemoryAllocator.Alloc((uint)sizeof(NativeBitArrayHandle)); + _handle->Array = new NativeArray(array, GetInt32ArrayLengthFromBitLength(length)); + _handle->Length = length; + if (defaultValue) + { + _handle->Array.AsSpan().Fill(-1); + Div32Rem(length, out var extraBits); + if (extraBits > 0) + _handle->Array[^1] = (1 << extraBits) - 1; + } + else + { + _handle->Array.Clear(); + } + } + + /// + /// Structure + /// + /// Array + /// Length + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public NativeBitArray(NativeArray array, int length) + { + if (length < 0) + throw new ArgumentOutOfRangeException(nameof(length), length, "MustBeNonNegative"); + var intCount = GetInt32ArrayLengthFromBitLength(length); + if (array.Length < intCount) + throw new ArgumentOutOfRangeException(nameof(array), array.Length, $"Requires size is {intCount}, but buffer length is {array.Length}."); + _handle = (NativeBitArrayHandle*)NativeMemoryAllocator.Alloc((uint)sizeof(NativeBitArrayHandle)); + _handle->Array = array; + _handle->Length = length; + } + + /// + /// Structure + /// + /// Array + /// Length + /// Default value + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public NativeBitArray(NativeArray array, int length, bool defaultValue) + { + if (length < 0) + throw new ArgumentOutOfRangeException(nameof(length), length, "MustBeNonNegative"); + var intCount = GetInt32ArrayLengthFromBitLength(length); + if (array.Length < intCount) + throw new ArgumentOutOfRangeException(nameof(array), array.Length, $"Requires size is {intCount}, but buffer length is {array.Length}."); + _handle = (NativeBitArrayHandle*)NativeMemoryAllocator.Alloc((uint)sizeof(NativeBitArrayHandle)); + _handle->Array = array; + _handle->Length = length; + if (defaultValue) + { + _handle->Array.AsSpan().Fill(-1); + Div32Rem(length, out var extraBits); + if (extraBits > 0) + _handle->Array[^1] = (1 << extraBits) - 1; + } + else + { + _handle->Array.Clear(); + } + } + + /// + /// Is created + /// + public bool IsCreated => _handle != null; + + /// + /// Array + /// + public NativeArray Array => _handle->Array; + + /// + /// Length + /// + public int Length + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _handle->Length; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + set + { + if (value < 0) + throw new ArgumentOutOfRangeException(nameof(value), value, "MustBeNonNegative"); + var newLength = GetInt32ArrayLengthFromBitLength(value); + if (newLength > _handle->Array.Length || newLength + 256 < _handle->Array.Length) + { + var array = new NativeArray(newLength); + Unsafe.CopyBlockUnaligned(array.Array, _handle->Array.Array, (uint)(_handle->Array.Length * sizeof(int))); + Unsafe.InitBlockUnaligned(array.Array + _handle->Array.Length, 0, (uint)(newLength - _handle->Array.Length)); + _handle->Array.Dispose(); + _handle->Array = array; + } + + if (value > _handle->Length) + { + var last = (_handle->Length - 1) >> 5; + Div32Rem(_handle->Length, out var bits); + if (bits > 0) + _handle->Array[last] &= (1 << bits) - 1; + _handle->Array.AsSpan(last + 1, newLength - last - 1).Clear(); + } + + _handle->Length = value; + } + } + + /// + /// Get or set value + /// + /// Index + public bool this[int index] + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => Get(index); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + set => Set(index, value); + } + + /// + /// Equals + /// + /// Other + /// Equals + public bool Equals(NativeBitArray other) => other == this; + + /// + /// Equals + /// + /// object + /// Equals + public override bool Equals(object? obj) => obj is NativeBitArray nativeBitArray && nativeBitArray == this; + + /// + /// Get hashCode + /// + /// HashCode + public override int GetHashCode() => (int)(nint)_handle; + + /// + /// To string + /// + /// String + public override string ToString() => "NativeBitArray"; + + /// + /// Equals + /// + /// Left + /// Right + /// Equals + public static bool operator ==(NativeBitArray left, NativeBitArray right) => left._handle == right._handle; + + /// + /// Not equals + /// + /// Left + /// Right + /// Not equals + public static bool operator !=(NativeBitArray left, NativeBitArray right) => left._handle != right._handle; + + /// + /// Dispose + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Dispose() + { + if (_handle == null) + return; + _handle->Array.Dispose(); + NativeMemoryAllocator.Free(_handle); + } + + /// + /// Get + /// + /// Index + /// Value + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool Get(int index) + { + if ((uint)index >= (uint)_handle->Length) + throw new ArgumentOutOfRangeException(nameof(index), index, "IndexMustBeLess"); + return (_handle->Array[index >> 5] & (1 << index)) != 0; + } + + /// + /// + /// Index + /// Value + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Set(int index, bool value) + { + if ((uint)index >= (uint)_handle->Length) + throw new ArgumentOutOfRangeException(nameof(index), index, "IndexMustBeLess"); + var bitMask = 1 << index; + ref var segment = ref _handle->Array[index >> 5]; + if (value) + segment |= bitMask; + else + segment &= ~bitMask; + } + + /// + /// Set all + /// + /// Value + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void SetAll(bool value) + { + var arrayLength = GetInt32ArrayLengthFromBitLength(Length); + var span = _handle->Array.AsSpan(0, arrayLength); + if (value) + { + span.Fill(-1); + Div32Rem(_handle->Length, out var extraBits); + if (extraBits > 0) + span[^1] &= (1 << extraBits) - 1; + } + else + { + span.Clear(); + } + } + + /// + /// And + /// + /// Value + /// NativeBitArray + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public NativeBitArray And(NativeBitArray value) + { + if (!value.IsCreated) + throw new ArgumentNullException(nameof(value)); + var count = GetInt32ArrayLengthFromBitLength(Length); + if (Length != value.Length || (uint)count > (uint)_handle->Array.Length || (uint)count > (uint)value._handle->Array.Length) + throw new ArgumentException("ArrayLengthsDiffer"); + BitOperationsHelpers.And(_handle->Array, value._handle->Array, (uint)count); + return this; + } + + /// + /// Or + /// + /// Value + /// NativeBitArray + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public NativeBitArray Or(NativeBitArray value) + { + if (!value.IsCreated) + throw new ArgumentNullException(nameof(value)); + var count = GetInt32ArrayLengthFromBitLength(Length); + if (Length != value.Length || (uint)count > (uint)_handle->Array.Length || (uint)count > (uint)value._handle->Array.Length) + throw new ArgumentException("ArrayLengthsDiffer"); + BitOperationsHelpers.Or(_handle->Array, value._handle->Array, (uint)count); + return this; + } + + /// + /// Xor + /// + /// Value + /// NativeBitArray + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public NativeBitArray Xor(NativeBitArray value) + { + if (!value.IsCreated) + throw new ArgumentNullException(nameof(value)); + var count = GetInt32ArrayLengthFromBitLength(Length); + if (Length != value.Length || (uint)count > (uint)_handle->Array.Length || (uint)count > (uint)value._handle->Array.Length) + throw new ArgumentException("ArrayLengthsDiffer"); + BitOperationsHelpers.Xor(_handle->Array, value._handle->Array, (uint)count); + return this; + } + + /// + /// Not + /// + /// NativeBitArray + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public NativeBitArray Not() + { + var count = GetInt32ArrayLengthFromBitLength(Length); + BitOperationsHelpers.Not(_handle->Array, (uint)count); + return this; + } + + /// + /// Right shift + /// + /// Count + /// NativeBitArray + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public NativeBitArray RightShift(int count) + { + if (count < 0) + throw new ArgumentOutOfRangeException(nameof(count), count, "MustBeNonNegative"); + if (count == 0) + return this; + var toIndex = 0; + var length = GetInt32ArrayLengthFromBitLength(_handle->Length); + if (count < _handle->Length) + { + var fromIndex = Div32Rem(count, out var shiftCount); + Div32Rem(_handle->Length, out var extraBits); + if (shiftCount == 0) + { + unchecked + { + var mask = uint.MaxValue >> (32 - extraBits); + _handle->Array[length - 1] &= (int)mask; + } + + Unsafe.CopyBlockUnaligned(_handle->Array.Array, _handle->Array.Array + fromIndex, (uint)((length - fromIndex) * sizeof(int))); + toIndex = length - fromIndex; + } + else + { + var lastIndex = length - 1; + unchecked + { + while (fromIndex < lastIndex) + { + var right = (uint)_handle->Array[fromIndex] >> shiftCount; + var left = _handle->Array[++fromIndex] << (32 - shiftCount); + _handle->Array[toIndex++] = left | (int)right; + } + + var mask = uint.MaxValue >> (32 - extraBits); + mask &= (uint)_handle->Array[fromIndex]; + _handle->Array[toIndex++] = (int)(mask >> shiftCount); + } + } + } + + _handle->Array.AsSpan(toIndex, length - toIndex).Clear(); + return this; + } + + /// + /// Left shift + /// + /// Count + /// NativeBitArray + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public NativeBitArray LeftShift(int count) + { + if (count < 0) + throw new ArgumentOutOfRangeException(nameof(count), count, "MustBeNonNegative"); + if (count == 0) + return this; + int lengthToClear; + if (count < _handle->Length) + { + var lastIndex = (_handle->Length - 1) >> 5; + lengthToClear = Div32Rem(count, out var shiftCount); + if (shiftCount == 0) + { + Unsafe.CopyBlockUnaligned(_handle->Array.Array + lengthToClear, _handle->Array.Array, (uint)((lastIndex + 1 - lengthToClear) * sizeof(int))); + } + else + { + var fromIndex = lastIndex - lengthToClear; + unchecked + { + while (fromIndex > 0) + { + var left = _handle->Array[fromIndex] << shiftCount; + var right = (uint)_handle->Array[--fromIndex] >> (32 - shiftCount); + _handle->Array[lastIndex] = left | (int)right; + lastIndex--; + } + + _handle->Array[lastIndex] = _handle->Array[fromIndex] << shiftCount; + } + } + } + else + { + lengthToClear = GetInt32ArrayLengthFromBitLength(_handle->Length); + } + + _handle->Array.AsSpan(0, lengthToClear).Clear(); + return this; + } + + /// + /// Has all set + /// + /// All set + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool HasAllSet() + { + Div32Rem(_handle->Length, out var extraBits); + var intCount = GetInt32ArrayLengthFromBitLength(_handle->Length); + if (extraBits != 0) + intCount--; +#if NET8_0_OR_GREATER + if (_handle->Array.AsSpan(0, intCount).ContainsAnyExcept(-1)) + return false; +#elif NET7_0_OR_GREATER + if (_handle->Array.AsSpan(0, intCount).IndexOfAnyExcept(-1) >= 0) + return false; +#else + for (var i = 0; i < intCount; ++i) + { + if (_handle->Array[i] != -1) + return false; + } +#endif + if (extraBits == 0) + return true; + var mask = (1 << extraBits) - 1; + return (_handle->Array[intCount] & mask) == mask; + } + + /// + /// Has any set + /// + /// Any set + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool HasAnySet() + { + Div32Rem(_handle->Length, out var extraBits); + var intCount = GetInt32ArrayLengthFromBitLength(_handle->Length); + if (extraBits != 0) + intCount--; +#if NET8_0_OR_GREATER + if (_handle->Array.AsSpan(0, intCount).ContainsAnyExcept(0)) + return true; +#elif NET7_0_OR_GREATER + if (_handle->Array.AsSpan(0, intCount).IndexOfAnyExcept(0) >= 0) + return true; +#else + for (var i = 0; i < intCount; ++i) + { + if (_handle->Array[i] != 0) + return true; + } +#endif + if (extraBits == 0) + return false; + return (_handle->Array[intCount] & ((1 << extraBits) - 1)) != 0; + } + + /// + /// Get int32 array length from bit length + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static int GetInt32ArrayLengthFromBitLength(int n) + { +#if NET7_0_OR_GREATER + return (n - 1 + (1 << 5)) >>> 5; +#else + return (int)((uint)(n - 1 + (1 << 5)) >> 5); +#endif + } + + /// + /// Divide by 32 and get remainder + /// + /// Number + /// Remainder + /// Quotient + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static int Div32Rem(int number, out int remainder) + { + var quotient = (uint)number / 32; + remainder = number & (32 - 1); + return (int)quotient; + } + + /// + /// Empty + /// + public static NativeBitArray Empty => new(); + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeBitArray.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeBitArray.cs.meta new file mode 100644 index 0000000..96e72be --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeBitArray.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: def81b20d63004ed795b4d605ce3d0c3 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeBuddyMemoryPool.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeBuddyMemoryPool.cs new file mode 100644 index 0000000..b0c1631 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeBuddyMemoryPool.cs @@ -0,0 +1,227 @@ +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +#if UNITY_2021_3_OR_NEWER || GODOT +using System; +#endif + +#pragma warning disable CA2208 +#pragma warning disable CS8632 + +// ReSharper disable ALL + +namespace NativeCollections +{ + /// + /// Native buddy memory pool + /// + [StructLayout(LayoutKind.Sequential)] + public readonly unsafe struct NativeBuddyMemoryPool : IDisposable, IEquatable + { + /// + /// Min block size + /// + private readonly int _minBlockSize; + + /// + /// Max block size + /// + private readonly int _maxBlockSize; + + /// + /// Bit map + /// + private readonly int* _bitmap; + + /// + /// Memory + /// + private readonly byte* _memory; + + /// + /// Structure + /// + /// Min block size + /// Max block size + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public NativeBuddyMemoryPool(int minBlockSize, int maxBlockSize) + { + if (minBlockSize > maxBlockSize) + throw new ArgumentException($"{minBlockSize} cannot be greater than {maxBlockSize}."); + if (minBlockSize <= 0) + throw new ArgumentOutOfRangeException(nameof(minBlockSize), minBlockSize, "MustBePositive"); + if ((minBlockSize & (minBlockSize - 1)) != 0) + throw new ArgumentOutOfRangeException(nameof(minBlockSize), minBlockSize, "MustBePowOf2"); + if ((maxBlockSize & (maxBlockSize - 1)) != 0) + throw new ArgumentOutOfRangeException(nameof(maxBlockSize), maxBlockSize, "MustBePowOf2"); + _minBlockSize = minBlockSize; + _maxBlockSize = maxBlockSize; + var bitmapSize = ((1 << (BitOperationsHelpers.Log2(maxBlockSize / minBlockSize) + 1)) + 31) / 32 * sizeof(int); + var array = (byte*)NativeMemoryAllocator.Alloc((uint)(bitmapSize + maxBlockSize)); + _bitmap = (int*)array; + _memory = array + bitmapSize; + Unsafe.InitBlockUnaligned(array, 0, (uint)bitmapSize); + } + + /// + /// Is created + /// + public bool IsCreated => _bitmap != null; + + /// + /// Min block size + /// + public int MinBlockSize => _minBlockSize; + + /// + /// Max block size + /// + public int MaxBlockSize => _maxBlockSize; + + /// + /// Equals + /// + /// Other + /// Equals + public bool Equals(NativeBuddyMemoryPool other) => other == this; + + /// + /// Equals + /// + /// object + /// Equals + public override bool Equals(object? obj) => obj is NativeBuddyMemoryPool nativeBuddyMemoryPool && nativeBuddyMemoryPool == this; + + /// + /// Get hashCode + /// + /// HashCode + public override int GetHashCode() => (int)(nint)_bitmap; + + /// + /// To string + /// + /// String + public override string ToString() => "NativeBuddyMemoryPool"; + + /// + /// Equals + /// + /// Left + /// Right + /// Equals + public static bool operator ==(NativeBuddyMemoryPool left, NativeBuddyMemoryPool right) => left._bitmap == right._bitmap; + + /// + /// Not equals + /// + /// Left + /// Right + /// Not equals + public static bool operator !=(NativeBuddyMemoryPool left, NativeBuddyMemoryPool right) => left._bitmap != right._bitmap; + + /// + /// Dispose + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Dispose() + { + if (_bitmap == null) + return; + NativeMemoryAllocator.Free(_bitmap); + } + + /// + /// Get layer + /// + /// Size + /// Layer + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private int GetLayer(int size) => size <= _minBlockSize ? 0 : BitOperationsHelpers.Log2((uint)((size - 1) / _minBlockSize)) + 1; + + /// + /// Find free block + /// + /// Layer + /// Free block + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private int FindFreeBlock(int layer) + { + var blocksInLayer = 1 << layer; + var offset = blocksInLayer - 1; + for (var i = 0; i < blocksInLayer; ++i) + { + var index = offset + i; + if ((_bitmap[index / 32] & (1 << (index % 32))) == 0) + return index; + } + + return -1; + } + + /// + /// Merge blocks + /// + /// Layer + /// Index + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void MergeBlocks(int layer, int index) + { + while (layer != 0) + { + var buddyIndex = index % 2 == 0 ? index + 1 : index - 1; + var bitMask = buddyIndex % 32; + ref var segment = ref _bitmap[buddyIndex / 32]; + if ((segment & (1 << bitMask)) != 0) + break; + var parentIndex = index / 2 + ((1 << (layer - 1)) - 1); + (*(_bitmap + index / 32)) &= ~(1 << (index % 32)); + segment &= ~(1 << bitMask); + (*(_bitmap + parentIndex / 32)) |= 1 << (parentIndex % 32); + --layer; + index = parentIndex; + } + } + + /// + /// Rent buffer + /// + /// Buffer + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void* Rent(int size) + { + if (size > _maxBlockSize) + throw new ArgumentOutOfRangeException(nameof(size), $"{size} cannot be greater than {_maxBlockSize}."); + if (size <= 0) + throw new ArgumentOutOfRangeException(nameof(size), size, "MustBePositive"); + var layer = GetLayer(size); + var blockIndex = FindFreeBlock(layer); + if (blockIndex == -1) + return null; + _bitmap[blockIndex / 32] |= 1 << (blockIndex % 32); + return _memory + (_minBlockSize << layer) * (blockIndex - ((1 << layer) - 1)); + } + + /// + /// Return buffer + /// + /// Pointer + /// Size + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Return(void* ptr, int size) + { + if (size > _maxBlockSize) + throw new ArgumentOutOfRangeException(nameof(size), $"{size} cannot be greater than {_maxBlockSize}."); + if (size <= 0) + throw new ArgumentOutOfRangeException(nameof(size), size, "MustBePositive"); + var layer = GetLayer(size); + var blockIndex = (int)((byte*)ptr - _memory) / (_minBlockSize << layer) + ((1 << layer) - 1); + _bitmap[blockIndex / 32] &= ~(1 << (blockIndex % 32)); + MergeBlocks(layer, blockIndex); + } + + /// + /// Empty + /// + public static NativeBuddyMemoryPool Empty => new(); + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeBuddyMemoryPool.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeBuddyMemoryPool.cs.meta new file mode 100644 index 0000000..cbf44d9 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeBuddyMemoryPool.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3b90a427863934c509f20fdc258b14f8 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeConcurrentDictionary.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeConcurrentDictionary.cs new file mode 100644 index 0000000..ae09294 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeConcurrentDictionary.cs @@ -0,0 +1,1458 @@ +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +#if UNITY_2021_3_OR_NEWER || GODOT +using System; +using System.Threading; +using System.Collections.Generic; +#endif + +#pragma warning disable CA2208 +#pragma warning disable CS8632 + +// ReSharper disable ALL + +namespace NativeCollections +{ + /// + /// Native concurrentDictionary + /// (Slower than ConcurrentDictionary) + /// + /// Type + /// Type + [StructLayout(LayoutKind.Sequential)] + public readonly unsafe struct NativeConcurrentDictionary : IDisposable, IEquatable> where TKey : unmanaged, IEquatable where TValue : unmanaged, IEquatable + { + /// + /// Handle + /// + [StructLayout(LayoutKind.Sequential)] + private struct NativeConcurrentDictionaryHandle + { + /// + /// Tables + /// + public volatile Tables* Tables; + + /// + /// Budget + /// + public int Budget; + + /// + /// Grow lock array + /// + public bool GrowLockArray; + + /// + /// Node pool + /// + public NativeMemoryPool NodePool; + + /// + /// Node lock + /// + public NativeConcurrentSpinLock NodeLock; + + /// + /// Keys + /// + public KeyCollection Keys; + + /// + /// Values + /// + public ValueCollection Values; + } + + /// + /// Handle + /// + private readonly NativeConcurrentDictionaryHandle* _handle; + + /// + /// Keys + /// + public KeyCollection Keys => _handle->Keys; + + /// + /// Values + /// + public ValueCollection Values => _handle->Values; + + /// + /// Structure + /// + /// Size + /// Max free slabs + /// Concurrency level + /// Capacity + /// Grow lock array + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public NativeConcurrentDictionary(int size, int maxFreeSlabs, int concurrencyLevel, int capacity, bool growLockArray) + { + var nodePool = new NativeMemoryPool(size, sizeof(Node), maxFreeSlabs); + if (concurrencyLevel <= 0) + concurrencyLevel = Environment.ProcessorCount; + if (capacity < concurrencyLevel) + capacity = concurrencyLevel; + capacity = HashHelpers.GetPrime(capacity); + var locks = new NativeArrayReference(concurrencyLevel); + for (var i = 0; i < locks.Length; ++i) + locks[i] = new object(); + var countPerLock = new NativeArray(locks.Length, true); + var buckets = new NativeArray(capacity, true); + _handle = (NativeConcurrentDictionaryHandle*)NativeMemoryAllocator.Alloc((uint)sizeof(NativeConcurrentDictionaryHandle)); + _handle->Tables = (Tables*)NativeMemoryAllocator.Alloc((uint)sizeof(Tables)); + _handle->Tables->Initialize(buckets, locks, countPerLock); + _handle->GrowLockArray = growLockArray; + _handle->Budget = buckets.Length / locks.Length; + _handle->NodePool = nodePool; + _handle->NodeLock = new NativeConcurrentSpinLock(-1); + _handle->Keys = new KeyCollection(this); + _handle->Values = new ValueCollection(this); + } + + /// + /// Is created + /// + public bool IsCreated => _handle != null; + + /// + /// Is created + /// + public bool IsEmpty + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get + { + if (!AreAllBucketsEmpty()) + return false; + var locksAcquired = 0; + try + { + AcquireAllLocks(ref locksAcquired); + return AreAllBucketsEmpty(); + } + finally + { + ReleaseLocks(locksAcquired); + } + } + } + + /// + /// Get or set value + /// + /// Key + public TValue this[in TKey key] + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get + { + if (!TryGetValue(key, out var value)) + throw new KeyNotFoundException(key.ToString()); + return value; + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + set => TryAddInternal(_handle->Tables, key, value, true, true, out _); + } + + /// + /// Count + /// + public int Count + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get + { + var locksAcquired = 0; + try + { + AcquireAllLocks(ref locksAcquired); + return GetCountNoLocks(); + } + finally + { + ReleaseLocks(locksAcquired); + } + } + } + + /// + /// Equals + /// + /// Other + /// Equals + public bool Equals(NativeConcurrentDictionary other) => other == this; + + /// + /// Equals + /// + /// object + /// Equals + public override bool Equals(object? obj) => obj is NativeConcurrentDictionary nativeConcurrentDictionary && nativeConcurrentDictionary == this; + + /// + /// Get hashCode + /// + /// HashCode + public override int GetHashCode() => (int)(nint)_handle; + + /// + /// To string + /// + /// String + public override string ToString() => $"NativeConcurrentDictionary<{typeof(TKey).Name}, {typeof(TValue).Name}>"; + + /// + /// Equals + /// + /// Left + /// Right + /// Equals + public static bool operator ==(NativeConcurrentDictionary left, NativeConcurrentDictionary right) => left._handle == right._handle; + + /// + /// Not equals + /// + /// Left + /// Right + /// Not equals + public static bool operator !=(NativeConcurrentDictionary left, NativeConcurrentDictionary right) => left._handle != right._handle; + + /// + /// Dispose + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Dispose() + { + if (_handle == null) + return; + _handle->Tables->Dispose(); + _handle->NodePool.Dispose(); + _handle->NodeLock.Dispose(); + NativeMemoryAllocator.Free(_handle); + } + + /// + /// Clear + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Clear() + { + var locksAcquired = 0; + try + { + AcquireAllLocks(ref locksAcquired); + if (AreAllBucketsEmpty()) + return; + foreach (var bucket in _handle->Tables->Buckets) + { + var node = (Node*)bucket.Node; + while (node != null) + { + var temp = node; + node = node->Next; + _handle->NodePool.Return(temp); + } + } + + var length = HashHelpers.GetPrime(31); + if (_handle->Tables->Buckets.Length != length) + { + _handle->Tables->Buckets.Dispose(); + _handle->Tables->Buckets = new NativeArray(length, true); + } + else + { + _handle->Tables->Buckets.Clear(); + } + + _handle->Tables->CountPerLock.Clear(); + var budget = _handle->Tables->Buckets.Length / _handle->Tables->Locks.Length; + _handle->Budget = budget >= 1 ? budget : 1; + } + finally + { + ReleaseLocks(locksAcquired); + } + } + + /// + /// Try add + /// + /// Key + /// Value + /// Added + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool TryAdd(in TKey key, in TValue value) => TryAddInternal(_handle->Tables, key, value, false, true, out _); + + /// + /// Try remove + /// + /// Key + /// Value + /// Removed + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool TryRemove(in TKey key, out TValue value) + { + var tables = _handle->Tables; + var hashCode = key.GetHashCode(); + while (true) + { + var locks = tables->Locks; + ref var bucket = ref GetBucketAndLock(tables, hashCode, out var lockNo); + if (tables->CountPerLock[lockNo] != 0) + { + Monitor.Enter(locks[lockNo]); + try + { + if (tables != _handle->Tables) + { + tables = _handle->Tables; + continue; + } + + Node* prev = null; + for (var curr = (Node*)bucket; curr != null; curr = curr->Next) + { + if (hashCode == curr->HashCode && curr->Key.Equals(key)) + { + if (prev == null) + Volatile.Write(ref bucket, (nint)curr->Next); + else + prev->Next = curr->Next; + value = curr->Value; + _handle->NodeLock.Enter(); + try + { + _handle->NodePool.Return(curr); + } + finally + { + _handle->NodeLock.Exit(); + } + + tables->CountPerLock[lockNo]--; + return true; + } + + prev = curr; + } + } + finally + { + Monitor.Exit(locks[lockNo]); + } + } + + value = default; + return false; + } + } + + /// + /// Try remove + /// + /// Key value pair + /// Removed + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool TryRemove(in KeyValuePair keyValuePair) + { + var key = keyValuePair.Key; + var oldValue = keyValuePair.Value; + var tables = _handle->Tables; + var hashCode = key.GetHashCode(); + while (true) + { + var locks = tables->Locks; + ref var bucket = ref GetBucketAndLock(tables, hashCode, out var lockNo); + if (tables->CountPerLock[lockNo] != 0) + { + Monitor.Enter(locks[lockNo]); + try + { + if (tables != _handle->Tables) + { + tables = _handle->Tables; + continue; + } + + Node* prev = null; + for (var curr = (Node*)bucket; curr != null; curr = curr->Next) + { + if (hashCode == curr->HashCode && curr->Key.Equals(key)) + { + if (!oldValue.Equals(curr->Value)) + return false; + if (prev == null) + Volatile.Write(ref bucket, (nint)curr->Next); + else + prev->Next = curr->Next; + _handle->NodeLock.Enter(); + try + { + _handle->NodePool.Return(curr); + } + finally + { + _handle->NodeLock.Exit(); + } + + tables->CountPerLock[lockNo]--; + return true; + } + + prev = curr; + } + } + finally + { + Monitor.Exit(locks[lockNo]); + } + } + + return false; + } + } + + /// + /// Contains key + /// + /// Key + /// Contains key + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool ContainsKey(in TKey key) + { + var tables = _handle->Tables; + var hashCode = key.GetHashCode(); + for (var node = (Node*)GetBucket(tables, hashCode); node != null; node = node->Next) + { + if (hashCode == node->HashCode && node->Key.Equals(key)) + return true; + } + + return false; + } + + /// + /// Try to get the value + /// + /// Key + /// Value + /// Got + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool TryGetValue(in TKey key, out TValue value) + { + var tables = _handle->Tables; + var hashCode = key.GetHashCode(); + for (var node = (Node*)GetBucket(tables, hashCode); node != null; node = node->Next) + { + if (hashCode == node->HashCode && node->Key.Equals(key)) + { + value = node->Value; + return true; + } + } + + value = default; + return false; + } + + /// + /// Try update + /// + /// Key + /// New value + /// Comparison value + /// Updated + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool TryUpdate(in TKey key, in TValue newValue, in TValue comparisonValue) => TryUpdateInternal(_handle->Tables, key, newValue, comparisonValue); + + /// + /// Get or add value + /// + /// Key + /// Value + /// Value + public TValue GetOrAdd(in TKey key, in TValue value) + { + var tables = _handle->Tables; + var hashCode = key.GetHashCode(); + if (!TryGetValueInternal(tables, key, hashCode, out var resultingValue)) + TryAddInternal(tables, key, value, false, true, out resultingValue); + return resultingValue; + } + + /// + /// Check all buckets are empty + /// + /// All buckets are empty + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private bool AreAllBucketsEmpty() + { +#if NET8_0_OR_GREATER + return !_handle->Tables->CountPerLock.AsSpan().ContainsAnyExcept(0); +#elif NET7_0_OR_GREATER + return !(_handle->Tables->CountPerLock.AsSpan().IndexOfAnyExcept(0) >= 0); +#else + for (var i = 0; i < _handle->Tables->CountPerLock.Length; ++i) + { + if (_handle->Tables->CountPerLock[i] != 0) + return false; + } + + return true; +#endif + } + + /// + /// Grow table + /// + /// Tables + /// Resize desired + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void GrowTable(Tables* tables, bool resizeDesired) + { + var locksAcquired = 0; + try + { + AcquireFirstLock(ref locksAcquired); + if (tables != _handle->Tables) + return; + var newLength = tables->Buckets.Length; + if (resizeDesired) + { + if (GetCountNoLocks() < tables->Buckets.Length / 4) + { + _handle->Budget = 2 * _handle->Budget; + if (_handle->Budget < 0) + _handle->Budget = int.MaxValue; + return; + } + + if ((newLength = tables->Buckets.Length * 2) < 0 || (newLength = HashHelpers.GetPrime(newLength)) > 2147483591) + { + newLength = 2147483591; + _handle->Budget = int.MaxValue; + } + } + + var newLocks = tables->Locks; + if (_handle->GrowLockArray && tables->Locks.Length < 1024) + { + newLocks = new NativeArrayReference(tables->Locks.Length * 2); + Array.Copy(tables->Locks.Array, newLocks.Array, tables->Locks.Length); + for (var i = tables->Locks.Length; i < newLocks.Length; ++i) + newLocks[i] = new NativeMonitorLock(new object()); + } + + var newBuckets = new NativeArray(newLength, true); + var newCountPerLock = new NativeArray(newLocks.Length, true); + var newTables = (Tables*)NativeMemoryAllocator.Alloc((uint)sizeof(Tables)); + newTables->Initialize(newBuckets, newLocks, newCountPerLock); + AcquirePostFirstLock(tables, ref locksAcquired); + foreach (var bucket in tables->Buckets) + { + var current = (Node*)bucket.Node; + while (current != null) + { + var hashCode = current->HashCode; + var next = current->Next; + ref var newBucket = ref GetBucketAndLock(newTables, hashCode, out var newLockNo); + var newNode = current; + newNode->Initialize(current->Key, current->Value, hashCode, (Node*)newBucket); + newBucket = (nint)newNode; + checked + { + newCountPerLock[newLockNo]++; + } + + current = next; + } + } + + var budget = newBuckets.Length / newLocks.Length; + _handle->Budget = budget >= 1 ? budget : 1; + _handle->Tables->Buckets.Dispose(); + if (_handle->Tables->Locks != newLocks) + _handle->Tables->Locks.Dispose(); + _handle->Tables->CountPerLock.Dispose(); + NativeMemoryAllocator.Free(_handle->Tables); + _handle->Tables = newTables; + } + finally + { + ReleaseLocks(locksAcquired); + } + } + + /// + /// Acquire all locks + /// + /// Locks acquired + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void AcquireAllLocks(ref int locksAcquired) + { + AcquireFirstLock(ref locksAcquired); + AcquirePostFirstLock(_handle->Tables, ref locksAcquired); + } + + /// + /// Acquire first lock + /// + /// Locks acquired + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void AcquireFirstLock(ref int locksAcquired) + { + var locks = _handle->Tables->Locks; + Monitor.Enter(locks[0]); + locksAcquired = 1; + } + + /// + /// Acquire post first locks + /// + /// Tables + /// Locks acquired + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static void AcquirePostFirstLock(Tables* tables, ref int locksAcquired) + { + var locks = tables->Locks; + for (var i = 1; i < locks.Length; ++i) + { + Monitor.Enter(locks[i]); + locksAcquired++; + } + } + + /// + /// Release locks + /// + /// Locks acquired + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void ReleaseLocks(int locksAcquired) + { + var locks = _handle->Tables->Locks; + for (var i = 0; i < locksAcquired; ++i) + Monitor.Exit(locks[i]); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private bool TryAddInternal(Tables* tables, in TKey key, in TValue value, bool updateIfExists, bool acquireLock, out TValue resultingValue) + { + var hashCode = key.GetHashCode(); + while (true) + { + var locks = tables->Locks; + ref var bucket = ref GetBucketAndLock(tables, hashCode, out var lockNo); + var resizeDesired = false; + var lockTaken = false; + try + { + if (acquireLock) + Monitor.Enter(locks[lockNo], ref lockTaken); + if (tables != _handle->Tables) + { + tables = _handle->Tables; + continue; + } + + Node* prev = null; + for (var node = (Node*)bucket; node != null; node = node->Next) + { + if (hashCode == node->HashCode && node->Key.Equals(key)) + { + if (updateIfExists) + { + if (NativeConcurrentDictionaryTypeProps.IsWriteAtomic) + { + node->Value = value; + } + else + { + Node* newNode; + _handle->NodeLock.Enter(); + try + { + newNode = (Node*)_handle->NodePool.Rent(); + } + finally + { + _handle->NodeLock.Exit(); + } + + newNode->Initialize(node->Key, value, hashCode, node->Next); + if (prev == null) + Volatile.Write(ref bucket, (nint)newNode); + else + prev->Next = newNode; + _handle->NodeLock.Enter(); + try + { + _handle->NodePool.Return(node); + } + finally + { + _handle->NodeLock.Exit(); + } + } + + resultingValue = value; + } + else + { + resultingValue = node->Value; + } + + return false; + } + + prev = node; + } + + Node* resultNode; + _handle->NodeLock.Enter(); + try + { + resultNode = (Node*)_handle->NodePool.Rent(); + } + finally + { + _handle->NodeLock.Exit(); + } + + resultNode->Initialize(key, value, hashCode, (Node*)bucket); + Volatile.Write(ref bucket, (nint)resultNode); + checked + { + tables->CountPerLock[lockNo]++; + } + + if (tables->CountPerLock[lockNo] > _handle->Budget) + resizeDesired = true; + } + finally + { + if (lockTaken) + Monitor.Exit(locks[lockNo]); + } + + if (resizeDesired) + GrowTable(tables, resizeDesired); + resultingValue = value; + return true; + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private bool TryUpdateInternal(Tables* tables, in TKey key, in TValue newValue, in TValue comparisonValue) + { + var hashCode = key.GetHashCode(); + while (true) + { + var locks = tables->Locks; + ref var bucket = ref GetBucketAndLock(tables, hashCode, out var lockNo); + Monitor.Enter(locks[lockNo]); + try + { + if (tables != _handle->Tables) + { + tables = _handle->Tables; + continue; + } + + Node* prev = null; + for (var node = (Node*)bucket; node != null; node = node->Next) + { + if (hashCode == node->HashCode && node->Key.Equals(key)) + { + if (node->Value.Equals(comparisonValue)) + { + if (NativeConcurrentDictionaryTypeProps.IsWriteAtomic) + { + node->Value = newValue; + } + else + { + Node* newNode; + _handle->NodeLock.Enter(); + try + { + newNode = (Node*)_handle->NodePool.Rent(); + } + finally + { + _handle->NodeLock.Exit(); + } + + newNode->Initialize(node->Key, newValue, hashCode, node->Next); + if (prev == null) + Volatile.Write(ref bucket, (nint)newNode); + else + prev->Next = newNode; + _handle->NodeLock.Enter(); + try + { + _handle->NodePool.Return(node); + } + finally + { + _handle->NodeLock.Exit(); + } + } + + return true; + } + + return false; + } + + prev = node; + } + + return false; + } + finally + { + Monitor.Exit(locks[lockNo]); + } + } + } + + /// + /// Try to get the value + /// + /// Tables + /// Key + /// HashCode + /// Value + /// Got + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static bool TryGetValueInternal(Tables* tables, in TKey key, int hashCode, out TValue value) + { + for (var node = (Node*)GetBucket(tables, hashCode); node != null; node = node->Next) + { + if (hashCode == node->HashCode && node->Key.Equals(key)) + { + value = node->Value; + return true; + } + } + + value = default; + return false; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private int GetCountNoLocks() + { + var count = 0; + foreach (var value in _handle->Tables->CountPerLock) + { + checked + { + count += value; + } + } + + return count; + } + + /// + /// Get bucket + /// + /// Tables + /// HashCode + /// Bucket + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static nint GetBucket(Tables* tables, int hashCode) + { + var buckets = tables->Buckets; + return IntPtr.Size == 8 ? buckets[HashHelpers.FastMod((uint)hashCode, (uint)buckets.Length, tables->FastModBucketsMultiplier)].Node : buckets[(uint)hashCode % (uint)buckets.Length].Node; + } + + /// + /// Get bucket and lock + /// + /// Tables + /// HashCode + /// Lock no + /// Bucket + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static ref nint GetBucketAndLock(Tables* tables, int hashCode, out uint lockNo) + { + var buckets = tables->Buckets; + var bucketNo = IntPtr.Size == 8 ? HashHelpers.FastMod((uint)hashCode, (uint)buckets.Length, tables->FastModBucketsMultiplier) : (uint)hashCode % (uint)buckets.Length; + lockNo = bucketNo % (uint)tables->Locks.Length; + return ref buckets[bucketNo].Node; + } + + /// + /// Volatile node + /// + private struct VolatileNode + { + /// + /// Node + /// + public volatile nint Node; + } + + /// + /// Node + /// + private struct Node + { + /// + /// Key + /// + public TKey Key; + + /// + /// Value + /// + public TValue Value; + + /// + /// Next + /// + public volatile Node* Next; + + /// + /// HashCode + /// + public int HashCode; + + /// + /// Initialize + /// + /// Key + /// Value + /// HashCode + /// Next + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Initialize(in TKey key, in TValue value, int hashCode, Node* next) + { + Key = key; + Value = value; + Next = next; + HashCode = hashCode; + } + } + + /// + /// Tables + /// + private struct Tables + { + /// + /// Buckets + /// + public NativeArray Buckets; + + /// + /// Fast mod buckets multiplier + /// + public ulong FastModBucketsMultiplier; + + /// + /// Locks + /// + public NativeArrayReference Locks; + + /// + /// Count per lock + /// + public NativeArray CountPerLock; + + /// + /// Initialize + /// + /// Buckets + /// Locks + /// Count per lock + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Initialize(in NativeArray buckets, in NativeArrayReference locks, in NativeArray countPerLock) + { + Buckets = buckets; + Locks = locks; + CountPerLock = countPerLock; + FastModBucketsMultiplier = IntPtr.Size == 8 ? HashHelpers.GetFastModMultiplier((uint)buckets.Length) : 0; + } + + /// + /// Dispose + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Dispose() + { + Buckets.Dispose(); + Locks.Dispose(); + CountPerLock.Dispose(); + } + } + + /// + /// Empty + /// + public static NativeConcurrentDictionary Empty => new(); + + /// + /// Get enumerator + /// + /// Enumerator + public Enumerator GetEnumerator() => new(this); + + /// + /// Enumerator + /// + public struct Enumerator + { + /// + /// NativeConcurrentDictionary + /// + private readonly NativeConcurrentDictionary _nativeConcurrentDictionary; + + /// + /// Buckets + /// + private NativeArray _buckets; + + /// + /// Node + /// + private Node* _node; + + /// + /// Index + /// + private int _index; + + /// + /// State + /// + private int _state; + + /// + /// State uninitialized + /// + private const int STATE_UNINITIALIZED = 0; + + /// + /// State outer loop + /// + private const int STATE_OUTER_LOOP = 1; + + /// + /// State inner loop + /// + private const int STATE_INNER_LOOP = 2; + + /// + /// State done + /// + private const int STATE_DONE = 3; + + /// + /// Current + /// + private KeyValuePair _current; + + /// + /// Structure + /// + /// NativeConcurrentDictionary + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal Enumerator(NativeConcurrentDictionary nativeConcurrentDictionary) + { + _nativeConcurrentDictionary = nativeConcurrentDictionary; + _index = -1; + _buckets = default; + _node = null; + _state = 0; + _current = default; + } + + /// + /// Move next + /// + /// Moved + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool MoveNext() + { + switch (_state) + { + case STATE_UNINITIALIZED: + _buckets = _nativeConcurrentDictionary._handle->Tables->Buckets; + _index = -1; + goto case STATE_OUTER_LOOP; + case STATE_OUTER_LOOP: + var buckets = _buckets; + var i = ++_index; + if ((uint)i < (uint)buckets.Length) + { + _node = (Node*)buckets[i].Node; + _state = STATE_INNER_LOOP; + goto case STATE_INNER_LOOP; + } + + goto default; + case STATE_INNER_LOOP: + if (_node != null) + { + var node = _node; + _current = new KeyValuePair(node->Key, node->Value); + _node = node->Next; + return true; + } + + goto case STATE_OUTER_LOOP; + default: + _state = STATE_DONE; + return false; + } + } + + /// + /// Current + /// + public KeyValuePair Current + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _current; + } + } + + /// + /// Key collection + /// + [StructLayout(LayoutKind.Sequential)] + public readonly struct KeyCollection + { + /// + /// NativeConcurrentDictionary + /// + private readonly NativeConcurrentDictionary _nativeConcurrentDictionary; + + /// + /// Structure + /// + /// NativeConcurrentDictionary + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal KeyCollection(in NativeConcurrentDictionary nativeConcurrentDictionary) => _nativeConcurrentDictionary = nativeConcurrentDictionary; + + /// + /// Get enumerator + /// + /// Enumerator + public Enumerator GetEnumerator() => new(_nativeConcurrentDictionary); + + /// + /// Enumerator + /// + public struct Enumerator + { + /// + /// NativeConcurrentDictionary + /// + private readonly NativeConcurrentDictionary _nativeConcurrentDictionary; + + /// + /// Buckets + /// + private NativeArray _buckets; + + /// + /// Node + /// + private Node* _node; + + /// + /// Index + /// + private int _index; + + /// + /// State + /// + private int _state; + + /// + /// State uninitialized + /// + private const int STATE_UNINITIALIZED = 0; + + /// + /// State outer loop + /// + private const int STATE_OUTER_LOOP = 1; + + /// + /// State inner loop + /// + private const int STATE_INNER_LOOP = 2; + + /// + /// State done + /// + private const int STATE_DONE = 3; + + /// + /// Current + /// + private TKey _current; + + /// + /// Structure + /// + /// NativeConcurrentDictionary + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal Enumerator(NativeConcurrentDictionary nativeConcurrentDictionary) + { + _nativeConcurrentDictionary = nativeConcurrentDictionary; + _index = -1; + _buckets = default; + _node = null; + _state = 0; + _current = default; + } + + /// + /// Move next + /// + /// Moved + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool MoveNext() + { + switch (_state) + { + case STATE_UNINITIALIZED: + _buckets = _nativeConcurrentDictionary._handle->Tables->Buckets; + _index = -1; + goto case STATE_OUTER_LOOP; + case STATE_OUTER_LOOP: + var buckets = _buckets; + var i = ++_index; + if ((uint)i < (uint)buckets.Length) + { + _node = (Node*)buckets[i].Node; + _state = STATE_INNER_LOOP; + goto case STATE_INNER_LOOP; + } + + goto default; + case STATE_INNER_LOOP: + if (_node != null) + { + var node = _node; + _current = node->Key; + _node = node->Next; + return true; + } + + goto case STATE_OUTER_LOOP; + default: + _state = STATE_DONE; + return false; + } + } + + /// + /// Current + /// + public TKey Current + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _current; + } + } + } + + /// + /// Value collection + /// + [StructLayout(LayoutKind.Sequential)] + public readonly struct ValueCollection + { + /// + /// NativeConcurrentDictionary + /// + private readonly NativeConcurrentDictionary _nativeConcurrentDictionary; + + /// + /// Structure + /// + /// NativeConcurrentDictionary + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal ValueCollection(in NativeConcurrentDictionary nativeConcurrentDictionary) => _nativeConcurrentDictionary = nativeConcurrentDictionary; + + /// + /// Get enumerator + /// + /// Enumerator + public Enumerator GetEnumerator() => new(_nativeConcurrentDictionary); + + /// + /// Enumerator + /// + public struct Enumerator + { + /// + /// NativeConcurrentDictionary + /// + private readonly NativeConcurrentDictionary _nativeConcurrentDictionary; + + /// + /// Buckets + /// + private NativeArray _buckets; + + /// + /// Node + /// + private Node* _node; + + /// + /// Index + /// + private int _index; + + /// + /// State + /// + private int _state; + + /// + /// State uninitialized + /// + private const int STATE_UNINITIALIZED = 0; + + /// + /// State outer loop + /// + private const int STATE_OUTER_LOOP = 1; + + /// + /// State inner loop + /// + private const int STATE_INNER_LOOP = 2; + + /// + /// State done + /// + private const int STATE_DONE = 3; + + /// + /// Current + /// + private TValue _current; + + /// + /// Structure + /// + /// NativeConcurrentDictionary + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal Enumerator(NativeConcurrentDictionary nativeConcurrentDictionary) + { + _nativeConcurrentDictionary = nativeConcurrentDictionary; + _index = -1; + _buckets = default; + _node = null; + _state = 0; + _current = default; + } + + /// + /// Move next + /// + /// Moved + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool MoveNext() + { + switch (_state) + { + case STATE_UNINITIALIZED: + _buckets = _nativeConcurrentDictionary._handle->Tables->Buckets; + _index = -1; + goto case STATE_OUTER_LOOP; + case STATE_OUTER_LOOP: + var buckets = _buckets; + var i = ++_index; + if ((uint)i < (uint)buckets.Length) + { + _node = (Node*)buckets[i].Node; + _state = STATE_INNER_LOOP; + goto case STATE_INNER_LOOP; + } + + goto default; + case STATE_INNER_LOOP: + if (_node != null) + { + var node = _node; + _current = node->Value; + _node = node->Next; + return true; + } + + goto case STATE_OUTER_LOOP; + default: + _state = STATE_DONE; + return false; + } + } + + /// + /// Current + /// + public TValue Current + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _current; + } + } + } + } + + /// + /// Native concurrentDictionary type props + /// + /// Type + internal static class NativeConcurrentDictionaryTypeProps where T : unmanaged, IEquatable + { + /// + /// Is write atomic + /// + public static readonly bool IsWriteAtomic = IsWriteAtomicPrivate(); + + /// + /// Is write atomic + /// + /// Is write atomic + private static bool IsWriteAtomicPrivate() + { + if (typeof(T) == typeof(IntPtr) || typeof(T) == typeof(UIntPtr)) + return true; + switch (Type.GetTypeCode(typeof(T))) + { + case TypeCode.Boolean: + case TypeCode.Byte: + case TypeCode.Char: + case TypeCode.Int16: + case TypeCode.Int32: + case TypeCode.SByte: + case TypeCode.Single: + case TypeCode.UInt16: + case TypeCode.UInt32: + return true; + case TypeCode.Double: + case TypeCode.Int64: + case TypeCode.UInt64: + return IntPtr.Size == 8; + default: + return false; + } + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeConcurrentDictionary.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeConcurrentDictionary.cs.meta new file mode 100644 index 0000000..b5ea2aa --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeConcurrentDictionary.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 148579b61de314722b9c426d716b6ec3 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeConcurrentHashSet.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeConcurrentHashSet.cs new file mode 100644 index 0000000..1bfb7b3 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeConcurrentHashSet.cs @@ -0,0 +1,878 @@ +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +#if UNITY_2021_3_OR_NEWER || GODOT +using System; +using System.Threading; +#endif + +#pragma warning disable CA2208 +#pragma warning disable CS8632 + +// ReSharper disable ALL + +namespace NativeCollections +{ + /// + /// Native concurrentHashSet + /// (Slower than ConcurrentHashSet) + /// + /// Type + [StructLayout(LayoutKind.Sequential)] + public readonly unsafe struct NativeConcurrentHashSet : IDisposable, IEquatable> where T : unmanaged, IEquatable + { + /// + /// Handle + /// + [StructLayout(LayoutKind.Sequential)] + private struct NativeConcurrentHashSetHandle + { + /// + /// Tables + /// + public volatile Tables* Tables; + + /// + /// Budget + /// + public int Budget; + + /// + /// Grow lock array + /// + public bool GrowLockArray; + + /// + /// Node pool + /// + public NativeMemoryPool NodePool; + + /// + /// Node lock + /// + public NativeConcurrentSpinLock NodeLock; + } + + /// + /// Handle + /// + private readonly NativeConcurrentHashSetHandle* _handle; + + /// + /// Structure + /// + /// Size + /// Max free slabs + /// Concurrency level + /// Capacity + /// Grow lock array + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public NativeConcurrentHashSet(int size, int maxFreeSlabs, int concurrencyLevel, int capacity, bool growLockArray) + { + var nodePool = new NativeMemoryPool(size, sizeof(Node), maxFreeSlabs); + if (concurrencyLevel <= 0) + concurrencyLevel = Environment.ProcessorCount; + if (capacity < concurrencyLevel) + capacity = concurrencyLevel; + capacity = HashHelpers.GetPrime(capacity); + var locks = new NativeArrayReference(concurrencyLevel); + for (var i = 0; i < locks.Length; ++i) + locks[i] = new object(); + var countPerLock = new NativeArray(locks.Length, true); + var buckets = new NativeArray(capacity, true); + _handle = (NativeConcurrentHashSetHandle*)NativeMemoryAllocator.Alloc((uint)sizeof(NativeConcurrentHashSetHandle)); + _handle->Tables = (Tables*)NativeMemoryAllocator.Alloc((uint)sizeof(Tables)); + _handle->Tables->Initialize(buckets, locks, countPerLock); + _handle->GrowLockArray = growLockArray; + _handle->Budget = buckets.Length / locks.Length; + _handle->NodePool = nodePool; + _handle->NodeLock = new NativeConcurrentSpinLock(-1); + } + + /// + /// Is created + /// + public bool IsCreated => _handle != null; + + /// + /// Is created + /// + public bool IsEmpty + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get + { + if (!AreAllBucketsEmpty()) + return false; + var locksAcquired = 0; + try + { + AcquireAllLocks(ref locksAcquired); + return AreAllBucketsEmpty(); + } + finally + { + ReleaseLocks(locksAcquired); + } + } + } + + /// + /// Count + /// + public int Count + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get + { + var locksAcquired = 0; + try + { + AcquireAllLocks(ref locksAcquired); + return GetCountNoLocks(); + } + finally + { + ReleaseLocks(locksAcquired); + } + } + } + + /// + /// Equals + /// + /// Other + /// Equals + public bool Equals(NativeConcurrentHashSet other) => other == this; + + /// + /// Equals + /// + /// object + /// Equals + public override bool Equals(object? obj) => obj is NativeConcurrentHashSet nativeConcurrentHashSet && nativeConcurrentHashSet == this; + + /// + /// Get hashCode + /// + /// HashCode + public override int GetHashCode() => (int)(nint)_handle; + + /// + /// To string + /// + /// String + public override string ToString() => $"NativeConcurrentHashSet<{typeof(T).Name}>"; + + /// + /// Equals + /// + /// Left + /// Right + /// Equals + public static bool operator ==(NativeConcurrentHashSet left, NativeConcurrentHashSet right) => left._handle == right._handle; + + /// + /// Not equals + /// + /// Left + /// Right + /// Not equals + public static bool operator !=(NativeConcurrentHashSet left, NativeConcurrentHashSet right) => left._handle != right._handle; + + /// + /// Dispose + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Dispose() + { + if (_handle == null) + return; + _handle->Tables->Dispose(); + _handle->NodePool.Dispose(); + _handle->NodeLock.Dispose(); + NativeMemoryAllocator.Free(_handle); + } + + /// + /// Clear + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Clear() + { + var locksAcquired = 0; + try + { + AcquireAllLocks(ref locksAcquired); + if (AreAllBucketsEmpty()) + return; + foreach (var bucket in _handle->Tables->Buckets) + { + var node = (Node*)bucket.Node; + while (node != null) + { + var temp = node; + node = node->Next; + _handle->NodePool.Return(temp); + } + } + + var length = HashHelpers.GetPrime(31); + if (_handle->Tables->Buckets.Length != length) + { + _handle->Tables->Buckets.Dispose(); + _handle->Tables->Buckets = new NativeArray(length, true); + } + else + { + _handle->Tables->Buckets.Clear(); + } + + _handle->Tables->CountPerLock.Clear(); + var budget = _handle->Tables->Buckets.Length / _handle->Tables->Locks.Length; + _handle->Budget = budget >= 1 ? budget : 1; + } + finally + { + ReleaseLocks(locksAcquired); + } + } + + /// + /// Add + /// + /// Key + /// Added + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool Add(in T key) => TryAddInternal(_handle->Tables, key); + + /// + /// Remove + /// + /// Key + /// Removed + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool Remove(in T key) + { + var tables = _handle->Tables; + var hashCode = key.GetHashCode(); + while (true) + { + var locks = tables->Locks; + ref var bucket = ref GetBucketAndLock(tables, hashCode, out var lockNo); + if (tables->CountPerLock[lockNo] != 0) + { + Monitor.Enter(locks[lockNo]); + try + { + if (tables != _handle->Tables) + { + tables = _handle->Tables; + continue; + } + + Node* prev = null; + for (var curr = (Node*)bucket; curr != null; curr = curr->Next) + { + if (hashCode == curr->HashCode && curr->Key.Equals(key)) + { + if (prev == null) + Volatile.Write(ref bucket, (nint)curr->Next); + else + prev->Next = curr->Next; + _handle->NodeLock.Enter(); + try + { + _handle->NodePool.Return(curr); + } + finally + { + _handle->NodeLock.Exit(); + } + + tables->CountPerLock[lockNo]--; + return true; + } + + prev = curr; + } + } + finally + { + Monitor.Exit(locks[lockNo]); + } + } + + return false; + } + } + + /// + /// Contains key + /// + /// Key + /// Contains key + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool Contains(in T key) + { + var tables = _handle->Tables; + var hashCode = key.GetHashCode(); + for (var node = (Node*)GetBucket(tables, hashCode); node != null; node = node->Next) + { + if (hashCode == node->HashCode && node->Key.Equals(key)) + return true; + } + + return false; + } + + /// + /// Try to get the actual value + /// + /// Equal value + /// Actual value + /// Got + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool TryGetValue(in T equalValue, out T actualValue) + { + var tables = _handle->Tables; + var hashCode = equalValue.GetHashCode(); + for (var node = (Node*)GetBucket(tables, hashCode); node != null; node = node->Next) + { + if (hashCode == node->HashCode && node->Key.Equals(equalValue)) + { + actualValue = node->Key; + return true; + } + } + + actualValue = default; + return false; + } + + /// + /// Check all buckets are empty + /// + /// All buckets are empty + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private bool AreAllBucketsEmpty() + { +#if NET8_0_OR_GREATER + return !_handle->Tables->CountPerLock.AsSpan().ContainsAnyExcept(0); +#elif NET7_0_OR_GREATER + return !(_handle->Tables->CountPerLock.AsSpan().IndexOfAnyExcept(0) >= 0); +#else + for (var i = 0; i < _handle->Tables->CountPerLock.Length; ++i) + { + if (_handle->Tables->CountPerLock[i] != 0) + return false; + } + + return true; +#endif + } + + /// + /// Grow table + /// + /// Tables + /// Resize desired + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void GrowTable(Tables* tables, bool resizeDesired) + { + var locksAcquired = 0; + try + { + AcquireFirstLock(ref locksAcquired); + if (tables != _handle->Tables) + return; + var newLength = tables->Buckets.Length; + if (resizeDesired) + { + if (GetCountNoLocks() < tables->Buckets.Length / 4) + { + _handle->Budget = 2 * _handle->Budget; + if (_handle->Budget < 0) + _handle->Budget = int.MaxValue; + return; + } + + if ((newLength = tables->Buckets.Length * 2) < 0 || (newLength = HashHelpers.GetPrime(newLength)) > 2147483591) + { + newLength = 2147483591; + _handle->Budget = int.MaxValue; + } + } + + var newLocks = tables->Locks; + if (_handle->GrowLockArray && tables->Locks.Length < 1024) + { + newLocks = new NativeArrayReference(tables->Locks.Length * 2); + Array.Copy(tables->Locks.Array, newLocks.Array, tables->Locks.Length); + for (var i = tables->Locks.Length; i < newLocks.Length; ++i) + newLocks[i] = new NativeMonitorLock(new object()); + } + + var newBuckets = new NativeArray(newLength, true); + var newCountPerLock = new NativeArray(newLocks.Length, true); + var newTables = (Tables*)NativeMemoryAllocator.Alloc((uint)sizeof(Tables)); + newTables->Initialize(newBuckets, newLocks, newCountPerLock); + AcquirePostFirstLock(tables, ref locksAcquired); + foreach (var bucket in tables->Buckets) + { + var current = (Node*)bucket.Node; + while (current != null) + { + var hashCode = current->HashCode; + var next = current->Next; + ref var newBucket = ref GetBucketAndLock(newTables, hashCode, out var newLockNo); + var newNode = current; + newNode->Initialize(current->Key, hashCode, (Node*)newBucket); + newBucket = (nint)newNode; + checked + { + newCountPerLock[newLockNo]++; + } + + current = next; + } + } + + var budget = newBuckets.Length / newLocks.Length; + _handle->Budget = budget >= 1 ? budget : 1; + _handle->Tables->Buckets.Dispose(); + if (_handle->Tables->Locks != newLocks) + _handle->Tables->Locks.Dispose(); + _handle->Tables->CountPerLock.Dispose(); + NativeMemoryAllocator.Free(_handle->Tables); + _handle->Tables = newTables; + } + finally + { + ReleaseLocks(locksAcquired); + } + } + + /// + /// Acquire all locks + /// + /// Locks acquired + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void AcquireAllLocks(ref int locksAcquired) + { + AcquireFirstLock(ref locksAcquired); + AcquirePostFirstLock(_handle->Tables, ref locksAcquired); + } + + /// + /// Acquire first lock + /// + /// Locks acquired + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void AcquireFirstLock(ref int locksAcquired) + { + var locks = _handle->Tables->Locks; + Monitor.Enter(locks[0]); + locksAcquired = 1; + } + + /// + /// Acquire post first locks + /// + /// Tables + /// Locks acquired + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static void AcquirePostFirstLock(Tables* tables, ref int locksAcquired) + { + var locks = tables->Locks; + for (var i = 1; i < locks.Length; ++i) + { + Monitor.Enter(locks[i]); + locksAcquired++; + } + } + + /// + /// Release locks + /// + /// Locks acquired + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void ReleaseLocks(int locksAcquired) + { + var locks = _handle->Tables->Locks; + for (var i = 0; i < locksAcquired; ++i) + Monitor.Exit(locks[i]); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private bool TryAddInternal(Tables* tables, in T key) + { + var hashCode = key.GetHashCode(); + while (true) + { + var locks = tables->Locks; + ref var bucket = ref GetBucketAndLock(tables, hashCode, out var lockNo); + var resizeDesired = false; + var lockTaken = false; + try + { + Monitor.Enter(locks[lockNo], ref lockTaken); + if (tables != _handle->Tables) + { + tables = _handle->Tables; + continue; + } + + for (var node = (Node*)bucket; node != null; node = node->Next) + { + if (hashCode == node->HashCode && node->Key.Equals(key)) + return false; + } + + Node* resultNode; + _handle->NodeLock.Enter(); + try + { + resultNode = (Node*)_handle->NodePool.Rent(); + } + finally + { + _handle->NodeLock.Exit(); + } + + resultNode->Initialize(key, hashCode, (Node*)bucket); + Volatile.Write(ref bucket, (nint)resultNode); + checked + { + tables->CountPerLock[lockNo]++; + } + + if (tables->CountPerLock[lockNo] > _handle->Budget) + resizeDesired = true; + } + finally + { + if (lockTaken) + Monitor.Exit(locks[lockNo]); + } + + if (resizeDesired) + GrowTable(tables, resizeDesired); + return true; + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private int GetCountNoLocks() + { + var count = 0; + foreach (var value in _handle->Tables->CountPerLock) + { + checked + { + count += value; + } + } + + return count; + } + + /// + /// Get bucket + /// + /// Tables + /// HashCode + /// Bucket + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static nint GetBucket(Tables* tables, int hashCode) + { + var buckets = tables->Buckets; + return IntPtr.Size == 8 ? buckets[HashHelpers.FastMod((uint)hashCode, (uint)buckets.Length, tables->FastModBucketsMultiplier)].Node : buckets[(uint)hashCode % (uint)buckets.Length].Node; + } + + /// + /// Get bucket and lock + /// + /// Tables + /// HashCode + /// Lock no + /// Bucket + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static ref nint GetBucketAndLock(Tables* tables, int hashCode, out uint lockNo) + { + var buckets = tables->Buckets; + var bucketNo = IntPtr.Size == 8 ? HashHelpers.FastMod((uint)hashCode, (uint)buckets.Length, tables->FastModBucketsMultiplier) : (uint)hashCode % (uint)buckets.Length; + lockNo = bucketNo % (uint)tables->Locks.Length; + return ref buckets[bucketNo].Node; + } + + /// + /// Volatile node + /// + private struct VolatileNode + { + /// + /// Node + /// + public volatile nint Node; + } + + /// + /// Node + /// + private struct Node + { + /// + /// Key + /// + public T Key; + + /// + /// Next + /// + public volatile Node* Next; + + /// + /// HashCode + /// + public int HashCode; + + /// + /// Initialize + /// + /// Key + /// HashCode + /// Next + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Initialize(in T key, int hashCode, Node* next) + { + Key = key; + Next = next; + HashCode = hashCode; + } + } + + /// + /// Tables + /// + private struct Tables + { + /// + /// Buckets + /// + public NativeArray Buckets; + + /// + /// Fast mod buckets multiplier + /// + public ulong FastModBucketsMultiplier; + + /// + /// Locks + /// + public NativeArrayReference Locks; + + /// + /// Count per lock + /// + public NativeArray CountPerLock; + + /// + /// Initialize + /// + /// Buckets + /// Locks + /// Count per lock + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Initialize(in NativeArray buckets, in NativeArrayReference locks, in NativeArray countPerLock) + { + Buckets = buckets; + Locks = locks; + CountPerLock = countPerLock; + FastModBucketsMultiplier = IntPtr.Size == 8 ? HashHelpers.GetFastModMultiplier((uint)buckets.Length) : 0; + } + + /// + /// Dispose + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Dispose() + { + Buckets.Dispose(); + Locks.Dispose(); + CountPerLock.Dispose(); + } + } + + /// + /// Empty + /// + public static NativeConcurrentHashSet Empty => new(); + + /// + /// Get enumerator + /// + /// Enumerator + public Enumerator GetEnumerator() => new(this); + + /// + /// Enumerator + /// + public struct Enumerator + { + /// + /// NativeConcurrentHashSet + /// + private readonly NativeConcurrentHashSet _nativeConcurrentHashSet; + + /// + /// Buckets + /// + private NativeArray _buckets; + + /// + /// Node + /// + private Node* _node; + + /// + /// Index + /// + private int _index; + + /// + /// State + /// + private int _state; + + /// + /// State uninitialized + /// + private const int STATE_UNINITIALIZED = 0; + + /// + /// State outer loop + /// + private const int STATE_OUTER_LOOP = 1; + + /// + /// State inner loop + /// + private const int STATE_INNER_LOOP = 2; + + /// + /// State done + /// + private const int STATE_DONE = 3; + + /// + /// Current + /// + private T _current; + + /// + /// Structure + /// + /// NativeConcurrentHashSet + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal Enumerator(NativeConcurrentHashSet nativeConcurrentHashSet) + { + _nativeConcurrentHashSet = nativeConcurrentHashSet; + _index = -1; + _buckets = default; + _node = null; + _state = 0; + _current = default; + } + + /// + /// Move next + /// + /// Moved + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool MoveNext() + { + switch (_state) + { + case STATE_UNINITIALIZED: + _buckets = _nativeConcurrentHashSet._handle->Tables->Buckets; + _index = -1; + goto case STATE_OUTER_LOOP; + case STATE_OUTER_LOOP: + var buckets = _buckets; + var i = ++_index; + if ((uint)i < (uint)buckets.Length) + { + _node = (Node*)buckets[i].Node; + _state = STATE_INNER_LOOP; + goto case STATE_INNER_LOOP; + } + + goto default; + case STATE_INNER_LOOP: + if (_node != null) + { + var node = _node; + _current = node->Key; + _node = node->Next; + return true; + } + + goto case STATE_OUTER_LOOP; + default: + _state = STATE_DONE; + return false; + } + } + + /// + /// Current + /// + public T Current + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _current; + } + } + } + + /// + /// Native concurrentHashSet type props + /// + /// Type + internal static class NativeConcurrentHashSetTypeProps where T : unmanaged, IEquatable + { + /// + /// Is write atomic + /// + public static readonly bool IsWriteAtomic = IsWriteAtomicPrivate(); + + /// + /// Is write atomic + /// + /// Is write atomic + private static bool IsWriteAtomicPrivate() + { + if (typeof(T) == typeof(IntPtr) || typeof(T) == typeof(UIntPtr)) + return true; + switch (Type.GetTypeCode(typeof(T))) + { + case TypeCode.Boolean: + case TypeCode.Byte: + case TypeCode.Char: + case TypeCode.Int16: + case TypeCode.Int32: + case TypeCode.SByte: + case TypeCode.Single: + case TypeCode.UInt16: + case TypeCode.UInt32: + return true; + case TypeCode.Double: + case TypeCode.Int64: + case TypeCode.UInt64: + return IntPtr.Size == 8; + default: + return false; + } + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeConcurrentHashSet.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeConcurrentHashSet.cs.meta new file mode 100644 index 0000000..cd168a9 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeConcurrentHashSet.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 31e6b58873f1646e39361da0083d3fb2 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeConcurrentQueue.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeConcurrentQueue.cs new file mode 100644 index 0000000..9ecc2b9 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeConcurrentQueue.cs @@ -0,0 +1,1288 @@ +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +#if UNITY_2021_3_OR_NEWER || GODOT +using System; +using System.Threading; +#endif + +#pragma warning disable CA2208 +#pragma warning disable CS8632 + +// ReSharper disable ALL + +namespace NativeCollections +{ + /// + /// Native concurrentQueue + /// (Slower than ConcurrentQueue, disable Enumerator, try peek either) + /// + /// Type + [StructLayout(LayoutKind.Sequential)] + public unsafe struct NativeConcurrentQueue : IDisposable, IEquatable> where T : unmanaged + { + /// + /// Handle + /// + private void* _handle; + + /// + /// Not arm64 + /// + private NativeConcurrentQueueNotArm64* NotArm64Handle + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => (NativeConcurrentQueueNotArm64*)_handle; + } + + /// + /// Arm64 + /// + private NativeConcurrentQueueArm64* Arm64Handle + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => (NativeConcurrentQueueArm64*)_handle; + } + + /// + /// Structure + /// + /// Size + /// Max free slabs + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public NativeConcurrentQueue(int size, int maxFreeSlabs) + { + if (RuntimeInformation.ProcessArchitecture != Architecture.Arm64) + { + var segmentPool = new NativeMemoryPool(size, sizeof(NativeConcurrentQueueSegmentNotArm64) + NativeConcurrentQueueSegmentNotArm64.LENGTH * sizeof(NativeConcurrentQueueSegmentNotArm64.Slot), maxFreeSlabs); + _handle = NativeMemoryAllocator.Alloc((uint)sizeof(NativeConcurrentQueueNotArm64)); + NotArm64Handle->Initialize(segmentPool); + } + else + { + var segmentPool = new NativeMemoryPool(size, sizeof(NativeConcurrentQueueSegmentArm64) + NativeConcurrentQueueSegmentArm64.LENGTH * sizeof(NativeConcurrentQueueSegmentArm64.Slot), maxFreeSlabs); + _handle = NativeMemoryAllocator.Alloc((uint)sizeof(NativeConcurrentQueueArm64)); + Arm64Handle->Initialize(segmentPool); + } + } + + /// + /// Is created + /// + public bool IsCreated => _handle != null; + + /// + /// IsEmpty + /// + public bool IsEmpty + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => RuntimeInformation.ProcessArchitecture != Architecture.Arm64 ? NotArm64Handle->IsEmpty : Arm64Handle->IsEmpty; + } + + /// + /// Count + /// + public int Count + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => RuntimeInformation.ProcessArchitecture != Architecture.Arm64 ? NotArm64Handle->Count : Arm64Handle->Count; + } + + /// + /// Equals + /// + /// Other + /// Equals + public bool Equals(NativeConcurrentQueue other) => other == this; + + /// + /// Equals + /// + /// object + /// Equals + public override bool Equals(object? obj) => obj is NativeConcurrentQueue nativeConcurrentQueue && nativeConcurrentQueue == this; + + /// + /// Get hashCode + /// + /// HashCode + public override int GetHashCode() => (int)(nint)_handle; + + /// + /// To string + /// + /// String + public override string ToString() => $"NativeConcurrentQueue<{typeof(T).Name}>"; + + /// + /// Equals + /// + /// Left + /// Right + /// Equals + public static bool operator ==(NativeConcurrentQueue left, NativeConcurrentQueue right) => left._handle == right._handle; + + /// + /// Not equals + /// + /// Left + /// Right + /// Not equals + public static bool operator !=(NativeConcurrentQueue left, NativeConcurrentQueue right) => left._handle != right._handle; + + /// + /// Dispose + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Dispose() + { + if (_handle == null) + return; + if (RuntimeInformation.ProcessArchitecture != Architecture.Arm64) + NotArm64Handle->Dispose(); + else + Arm64Handle->Dispose(); + NativeMemoryAllocator.Free(_handle); + } + + /// + /// Clear + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Clear() + { + if (RuntimeInformation.ProcessArchitecture != Architecture.Arm64) + NotArm64Handle->Clear(); + else + Arm64Handle->Clear(); + } + + /// + /// Enqueue + /// + /// Item + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Enqueue(in T item) + { + if (RuntimeInformation.ProcessArchitecture != Architecture.Arm64) + NotArm64Handle->Enqueue(item); + else + Arm64Handle->Enqueue(item); + } + + /// + /// Try dequeue + /// + /// Item + /// Dequeued + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool TryDequeue(out T result) => RuntimeInformation.ProcessArchitecture != Architecture.Arm64 ? NotArm64Handle->TryDequeue(out result) : Arm64Handle->TryDequeue(out result); + + /// + /// Empty + /// + public static NativeConcurrentQueue Empty => new(); + } + + /// + /// Native concurrentQueue + /// (Slower than ConcurrentQueue, disable Enumerator, try peek either) + /// + /// Type + [StructLayout(LayoutKind.Sequential)] + internal unsafe struct NativeConcurrentQueueNotArm64 : IDisposable where T : unmanaged + { + /// + /// Cross segment lock + /// + private NativeMonitorLock _crossSegmentLock; + + /// + /// Segment pool + /// + private NativeMemoryPool _segmentPool; + + /// + /// Tail + /// + private volatile NativeConcurrentQueueSegmentNotArm64* _tail; + + /// + /// Head + /// + private volatile NativeConcurrentQueueSegmentNotArm64* _head; + + /// + /// IsEmpty + /// + public bool IsEmpty + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get + { + var segment = _head; + while (true) + { + var next = Volatile.Read(ref segment->NextSegment); + if (segment->TryPeek()) + return false; + if (next != IntPtr.Zero) + segment = (NativeConcurrentQueueSegmentNotArm64*)next; + else if (Volatile.Read(ref segment->NextSegment) == IntPtr.Zero) + break; + } + + return true; + } + } + + /// + /// Count + /// + public int Count + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get + { + var spinCount = 0; + while (true) + { + var head = _head; + var tail = _tail; + var headHead = Volatile.Read(ref head->HeadAndTail.Head); + var headTail = Volatile.Read(ref head->HeadAndTail.Tail); + if (head == tail) + { + if (head == _head && tail == _tail && headHead == Volatile.Read(ref head->HeadAndTail.Head) && headTail == Volatile.Read(ref head->HeadAndTail.Tail)) + return GetCount(head, headHead, headTail); + } + else if ((NativeConcurrentQueueSegmentNotArm64*)head->NextSegment == tail) + { + var tailHead = Volatile.Read(ref tail->HeadAndTail.Head); + var tailTail = Volatile.Read(ref tail->HeadAndTail.Tail); + if (head == _head && tail == _tail && headHead == Volatile.Read(ref head->HeadAndTail.Head) && headTail == Volatile.Read(ref head->HeadAndTail.Tail) && tailHead == Volatile.Read(ref tail->HeadAndTail.Head) && tailTail == Volatile.Read(ref tail->HeadAndTail.Tail)) + return GetCount(head, headHead, headTail) + GetCount(tail, tailHead, tailTail); + } + else + { + _crossSegmentLock.Enter(); + try + { + if (head == _head && tail == _tail) + { + var tailHead = Volatile.Read(ref tail->HeadAndTail.Head); + var tailTail = Volatile.Read(ref tail->HeadAndTail.Tail); + if (headHead == Volatile.Read(ref head->HeadAndTail.Head) && headTail == Volatile.Read(ref head->HeadAndTail.Tail) && tailHead == Volatile.Read(ref tail->HeadAndTail.Head) && tailTail == Volatile.Read(ref tail->HeadAndTail.Tail)) + { + var count = GetCount(head, headHead, headTail) + GetCount(tail, tailHead, tailTail); + for (var s = (NativeConcurrentQueueSegmentNotArm64*)head->NextSegment; s != tail; s = (NativeConcurrentQueueSegmentNotArm64*)s->NextSegment) + count += s->HeadAndTail.Tail - NativeConcurrentQueueSegmentNotArm64.FREEZE_OFFSET; + return count; + } + } + } + finally + { + _crossSegmentLock.Exit(); + } + } + + if ((spinCount >= 10 && (spinCount - 10) % 2 == 0) || Environment.ProcessorCount == 1) + { + var yieldsSoFar = spinCount >= 10 ? (spinCount - 10) / 2 : spinCount; + if (yieldsSoFar % 5 == 4) + Thread.Sleep(0); + else + Thread.Yield(); + } + else + { + var iterations = Environment.ProcessorCount / 2; + if (spinCount <= 30 && 1 << spinCount < iterations) + iterations = 1 << spinCount; + Thread.SpinWait(iterations); + } + + spinCount = spinCount == int.MaxValue ? 10 : spinCount + 1; + } + } + } + + /// + /// Structure + /// + /// Segment pool + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Initialize(NativeMemoryPool segmentPool) + { + _crossSegmentLock = new NativeMonitorLock(new object()); + _segmentPool = segmentPool; + var segment = (NativeConcurrentQueueSegmentNotArm64*)_segmentPool.Rent(); + var array = (byte*)segment + sizeof(NativeConcurrentQueueSegmentNotArm64); + segment->Initialize((NativeConcurrentQueueSegmentNotArm64.Slot*)array); + _tail = _head = segment; + } + + /// + /// Dispose + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Dispose() + { + _crossSegmentLock.Dispose(); + _segmentPool.Dispose(); + } + + /// + /// Clear + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Clear() + { + _crossSegmentLock.Enter(); + try + { + _tail->EnsureFrozenForEnqueues(); + var node = _head; + while (node != null) + { + var temp = node; + node = (NativeConcurrentQueueSegmentNotArm64*)node->NextSegment; + _segmentPool.Return(temp); + } + + var segment = (NativeConcurrentQueueSegmentNotArm64*)_segmentPool.Rent(); + var array = (byte*)segment + sizeof(NativeConcurrentQueueSegmentNotArm64); + segment->Initialize((NativeConcurrentQueueSegmentNotArm64.Slot*)array); + _tail = _head = segment; + } + finally + { + _crossSegmentLock.Exit(); + } + } + + /// + /// Enqueue + /// + /// Item + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Enqueue(in T item) + { + if (!_tail->TryEnqueue(item)) + { + while (true) + { + var tail = _tail; + if (tail->TryEnqueue(item)) + return; + _crossSegmentLock.Enter(); + try + { + if (tail == _tail) + { + tail->EnsureFrozenForEnqueues(); + var newTail = (NativeConcurrentQueueSegmentNotArm64*)_segmentPool.Rent(); + var array = (byte*)newTail + sizeof(NativeConcurrentQueueSegmentNotArm64); + newTail->Initialize((NativeConcurrentQueueSegmentNotArm64.Slot*)array); + tail->NextSegment = (nint)newTail; + _tail = newTail; + } + } + finally + { + _crossSegmentLock.Exit(); + } + } + } + } + + /// + /// Try dequeue + /// + /// Item + /// Dequeued + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool TryDequeue(out T result) + { + var head = _head; + if (head->TryDequeue(out result)) + return true; + if (head->NextSegment == IntPtr.Zero) + { + result = default; + return false; + } + + while (true) + { + head = _head; + if (head->TryDequeue(out result)) + return true; + if (head->NextSegment == IntPtr.Zero) + { + result = default; + return false; + } + + if (head->TryDequeue(out result)) + return true; + _crossSegmentLock.Enter(); + try + { + if (head == _head) + { + _head = (NativeConcurrentQueueSegmentNotArm64*)head->NextSegment; + _segmentPool.Return(head); + } + } + finally + { + _crossSegmentLock.Exit(); + } + } + } + + /// + /// Get count + /// + /// Segment + /// Head + /// Tail + /// Count + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static int GetCount(NativeConcurrentQueueSegmentNotArm64* segment, int head, int tail) + { + if (head != tail && head != tail - NativeConcurrentQueueSegmentNotArm64.FREEZE_OFFSET) + { + head &= NativeConcurrentQueueSegmentNotArm64.SLOTS_MASK; + tail &= NativeConcurrentQueueSegmentNotArm64.SLOTS_MASK; + return head < tail ? tail - head : NativeConcurrentQueueSegmentNotArm64.LENGTH - head + tail; + } + + return 0; + } + + /// + /// Get count + /// + /// Head + /// Head head + /// Tail + /// Tail tail + /// Count + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static long GetCount(NativeConcurrentQueueSegmentNotArm64* head, int headHead, NativeConcurrentQueueSegmentNotArm64* tail, int tailTail) + { + long count = 0; + var headTail = (head == tail ? tailTail : Volatile.Read(ref head->HeadAndTail.Tail)) - NativeConcurrentQueueSegmentNotArm64.FREEZE_OFFSET; + if (headHead < headTail) + { + headHead &= NativeConcurrentQueueSegmentNotArm64.SLOTS_MASK; + headTail &= NativeConcurrentQueueSegmentNotArm64.SLOTS_MASK; + count += headHead < headTail ? headTail - headHead : NativeConcurrentQueueSegmentNotArm64.LENGTH - headHead + headTail; + } + + if (head != tail) + { + for (var s = (NativeConcurrentQueueSegmentNotArm64*)head->NextSegment; s != tail; s = (NativeConcurrentQueueSegmentNotArm64*)s->NextSegment) + count += s->HeadAndTail.Tail - NativeConcurrentQueueSegmentNotArm64.FREEZE_OFFSET; + count += tailTail - NativeConcurrentQueueSegmentNotArm64.FREEZE_OFFSET; + } + + return count; + } + } + + /// + /// Native concurrentQueue segment + /// + /// Type + [StructLayout(LayoutKind.Sequential)] + internal unsafe struct NativeConcurrentQueueSegmentNotArm64 where T : unmanaged + { + /// + /// Slots + /// + public Slot* Slots; + + /// + /// Length + /// + public const int LENGTH = 1024; + + /// + /// Slots mask + /// + public const int SLOTS_MASK = LENGTH - 1; + + /// + /// Head and tail + /// + public NativeConcurrentQueuePaddedHeadAndTailNotArm64 HeadAndTail; + + /// + /// Frozen for enqueues + /// + public bool FrozenForEnqueues; + + /// + /// Next segment + /// + public nint NextSegment; + + /// + /// Initialize + /// + /// Slots + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Initialize(Slot* slots) + { + Slots = slots; + for (var i = 0; i < LENGTH; ++i) + Slots[i].SequenceNumber = i; + HeadAndTail = new NativeConcurrentQueuePaddedHeadAndTailNotArm64(); + FrozenForEnqueues = false; + NextSegment = IntPtr.Zero; + } + + /// + /// Freeze offset + /// + public const int FREEZE_OFFSET = LENGTH * 2; + + /// + /// Ensure frozen for enqueues + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void EnsureFrozenForEnqueues() + { + if (!FrozenForEnqueues) + { + FrozenForEnqueues = true; + Interlocked.Add(ref HeadAndTail.Tail, FREEZE_OFFSET); + } + } + + /// + /// Try dequeue + /// + /// Item + /// Dequeued + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool TryDequeue(out T result) + { + var slots = Slots; + var count = 0; + while (true) + { + var currentHead = Volatile.Read(ref HeadAndTail.Head); + var slotsIndex = currentHead & SLOTS_MASK; + var sequenceNumber = Volatile.Read(ref slots[slotsIndex].SequenceNumber); + var diff = sequenceNumber - (currentHead + 1); + if (diff == 0) + { + if (Interlocked.CompareExchange(ref HeadAndTail.Head, currentHead + 1, currentHead) == currentHead) + { + result = slots[slotsIndex].Item; + Volatile.Write(ref slots[slotsIndex].SequenceNumber, currentHead + LENGTH); + return true; + } + } + else if (diff < 0) + { + var frozen = FrozenForEnqueues; + var currentTail = Volatile.Read(ref HeadAndTail.Tail); + if (currentTail - currentHead <= 0 || (frozen && currentTail - FREEZE_OFFSET - currentHead <= 0)) + { + result = default; + return false; + } + + if ((count >= 10 && (count - 10) % 2 == 0) || Environment.ProcessorCount == 1) + { + var yieldsSoFar = count >= 10 ? (count - 10) / 2 : count; + if (yieldsSoFar % 5 == 4) + Thread.Sleep(0); + else + Thread.Yield(); + } + else + { + var iterations = Environment.ProcessorCount / 2; + if (count <= 30 && 1 << count < iterations) + iterations = 1 << count; + Thread.SpinWait(iterations); + } + + count = count == int.MaxValue ? 10 : count + 1; + } + } + } + + /// + /// Try peek + /// + /// Peeked + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool TryPeek() + { + var slots = Slots; + var count = 0; + while (true) + { + var currentHead = Volatile.Read(ref HeadAndTail.Head); + var slotsIndex = currentHead & SLOTS_MASK; + var sequenceNumber = Volatile.Read(ref slots[slotsIndex].SequenceNumber); + var diff = sequenceNumber - (currentHead + 1); + if (diff == 0) + return true; + if (diff < 0) + { + var frozen = FrozenForEnqueues; + var currentTail = Volatile.Read(ref HeadAndTail.Tail); + if (currentTail - currentHead <= 0 || (frozen && currentTail - FREEZE_OFFSET - currentHead <= 0)) + return false; + if ((count >= 10 && (count - 10) % 2 == 0) || Environment.ProcessorCount == 1) + { + var yieldsSoFar = count >= 10 ? (count - 10) / 2 : count; + if (yieldsSoFar % 5 == 4) + Thread.Sleep(0); + else + Thread.Yield(); + } + else + { + var iterations = Environment.ProcessorCount / 2; + if (count <= 30 && 1 << count < iterations) + iterations = 1 << count; + Thread.SpinWait(iterations); + } + + count = count == int.MaxValue ? 10 : count + 1; + } + } + } + + /// + /// Try enqueue + /// + /// Item + /// Enqueued + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool TryEnqueue(in T item) + { + var slots = Slots; + while (true) + { + var currentTail = Volatile.Read(ref HeadAndTail.Tail); + var slotsIndex = currentTail & SLOTS_MASK; + var sequenceNumber = Volatile.Read(ref slots[slotsIndex].SequenceNumber); + var diff = sequenceNumber - currentTail; + if (diff == 0) + { + if (Interlocked.CompareExchange(ref HeadAndTail.Tail, currentTail + 1, currentTail) == currentTail) + { + slots[slotsIndex].Item = item; + Volatile.Write(ref slots[slotsIndex].SequenceNumber, currentTail + 1); + return true; + } + } + else if (diff < 0) + { + return false; + } + } + } + + /// + /// Slot + /// + [StructLayout(LayoutKind.Sequential)] + public struct Slot + { + /// + /// Item + /// + public T Item; + + /// + /// Sequence number + /// + public int SequenceNumber; + } + } + + /// + /// NativeConcurrentQueue padded head and tail + /// + [StructLayout(LayoutKind.Explicit, Size = 3 * CACHE_LINE_SIZE)] + internal struct NativeConcurrentQueuePaddedHeadAndTailNotArm64 + { + /// + /// Head + /// + [FieldOffset(1 * CACHE_LINE_SIZE)] public int Head; + + /// + /// Tail + /// + [FieldOffset(2 * CACHE_LINE_SIZE)] public int Tail; + + /// + /// Catch line size + /// + public const int CACHE_LINE_SIZE = 64; + } + + /// + /// Native concurrentQueue + /// (Slower than ConcurrentQueue, disable Enumerator, try peek either) + /// + /// Type + [StructLayout(LayoutKind.Sequential)] + internal unsafe struct NativeConcurrentQueueArm64 : IDisposable where T : unmanaged + { + /// + /// Cross segment lock + /// + private NativeMonitorLock _crossSegmentLock; + + /// + /// Segment pool + /// + private NativeMemoryPool _segmentPool; + + /// + /// Tail + /// + private volatile NativeConcurrentQueueSegmentArm64* _tail; + + /// + /// Head + /// + private volatile NativeConcurrentQueueSegmentArm64* _head; + + /// + /// IsEmpty + /// + public bool IsEmpty + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get + { + var segment = _head; + while (true) + { + var next = Volatile.Read(ref segment->NextSegment); + if (segment->TryPeek()) + return false; + if (next != IntPtr.Zero) + segment = (NativeConcurrentQueueSegmentArm64*)next; + else if (Volatile.Read(ref segment->NextSegment) == IntPtr.Zero) + break; + } + + return true; + } + } + + /// + /// Count + /// + public int Count + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get + { + var spinCount = 0; + while (true) + { + var head = _head; + var tail = _tail; + var headHead = Volatile.Read(ref head->HeadAndTail.Head); + var headTail = Volatile.Read(ref head->HeadAndTail.Tail); + if (head == tail) + { + if (head == _head && tail == _tail && headHead == Volatile.Read(ref head->HeadAndTail.Head) && headTail == Volatile.Read(ref head->HeadAndTail.Tail)) + return GetCount(head, headHead, headTail); + } + else if ((NativeConcurrentQueueSegmentArm64*)head->NextSegment == tail) + { + var tailHead = Volatile.Read(ref tail->HeadAndTail.Head); + var tailTail = Volatile.Read(ref tail->HeadAndTail.Tail); + if (head == _head && tail == _tail && headHead == Volatile.Read(ref head->HeadAndTail.Head) && headTail == Volatile.Read(ref head->HeadAndTail.Tail) && tailHead == Volatile.Read(ref tail->HeadAndTail.Head) && tailTail == Volatile.Read(ref tail->HeadAndTail.Tail)) + return GetCount(head, headHead, headTail) + GetCount(tail, tailHead, tailTail); + } + else + { + _crossSegmentLock.Enter(); + try + { + if (head == _head && tail == _tail) + { + var tailHead = Volatile.Read(ref tail->HeadAndTail.Head); + var tailTail = Volatile.Read(ref tail->HeadAndTail.Tail); + if (headHead == Volatile.Read(ref head->HeadAndTail.Head) && headTail == Volatile.Read(ref head->HeadAndTail.Tail) && tailHead == Volatile.Read(ref tail->HeadAndTail.Head) && tailTail == Volatile.Read(ref tail->HeadAndTail.Tail)) + { + var count = GetCount(head, headHead, headTail) + GetCount(tail, tailHead, tailTail); + for (var s = (NativeConcurrentQueueSegmentArm64*)head->NextSegment; s != tail; s = (NativeConcurrentQueueSegmentArm64*)s->NextSegment) + count += s->HeadAndTail.Tail - NativeConcurrentQueueSegmentArm64.FREEZE_OFFSET; + return count; + } + } + } + finally + { + _crossSegmentLock.Exit(); + } + } + + if ((spinCount >= 10 && (spinCount - 10) % 2 == 0) || Environment.ProcessorCount == 1) + { + var yieldsSoFar = spinCount >= 10 ? (spinCount - 10) / 2 : spinCount; + if (yieldsSoFar % 5 == 4) + Thread.Sleep(0); + else + Thread.Yield(); + } + else + { + var iterations = Environment.ProcessorCount / 2; + if (spinCount <= 30 && 1 << spinCount < iterations) + iterations = 1 << spinCount; + Thread.SpinWait(iterations); + } + + spinCount = spinCount == int.MaxValue ? 10 : spinCount + 1; + } + } + } + + /// + /// Structure + /// + /// Segment pool + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Initialize(NativeMemoryPool segmentPool) + { + _crossSegmentLock = new NativeMonitorLock(new object()); + _segmentPool = segmentPool; + var segment = (NativeConcurrentQueueSegmentArm64*)_segmentPool.Rent(); + var array = (byte*)segment + sizeof(NativeConcurrentQueueSegmentArm64); + segment->Initialize((NativeConcurrentQueueSegmentArm64.Slot*)array); + _tail = _head = segment; + } + + /// + /// Dispose + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Dispose() + { + _crossSegmentLock.Dispose(); + _segmentPool.Dispose(); + } + + /// + /// Clear + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Clear() + { + _crossSegmentLock.Enter(); + try + { + _tail->EnsureFrozenForEnqueues(); + var node = _head; + while (node != null) + { + var temp = node; + node = (NativeConcurrentQueueSegmentArm64*)node->NextSegment; + _segmentPool.Return(temp); + } + + var segment = (NativeConcurrentQueueSegmentArm64*)_segmentPool.Rent(); + var array = (byte*)segment + sizeof(NativeConcurrentQueueSegmentArm64); + segment->Initialize((NativeConcurrentQueueSegmentArm64.Slot*)array); + _tail = _head = segment; + } + finally + { + _crossSegmentLock.Exit(); + } + } + + /// + /// Enqueue + /// + /// Item + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Enqueue(in T item) + { + if (!_tail->TryEnqueue(item)) + { + while (true) + { + var tail = _tail; + if (tail->TryEnqueue(item)) + return; + _crossSegmentLock.Enter(); + try + { + if (tail == _tail) + { + tail->EnsureFrozenForEnqueues(); + var newTail = (NativeConcurrentQueueSegmentArm64*)_segmentPool.Rent(); + var array = (byte*)newTail + sizeof(NativeConcurrentQueueSegmentArm64); + newTail->Initialize((NativeConcurrentQueueSegmentArm64.Slot*)array); + tail->NextSegment = (nint)newTail; + _tail = newTail; + } + } + finally + { + _crossSegmentLock.Exit(); + } + } + } + } + + /// + /// Try dequeue + /// + /// Item + /// Dequeued + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool TryDequeue(out T result) + { + var head = _head; + if (head->TryDequeue(out result)) + return true; + if (head->NextSegment == IntPtr.Zero) + { + result = default; + return false; + } + + while (true) + { + head = _head; + if (head->TryDequeue(out result)) + return true; + if (head->NextSegment == IntPtr.Zero) + { + result = default; + return false; + } + + if (head->TryDequeue(out result)) + return true; + _crossSegmentLock.Enter(); + try + { + if (head == _head) + { + _head = (NativeConcurrentQueueSegmentArm64*)head->NextSegment; + _segmentPool.Return(head); + } + } + finally + { + _crossSegmentLock.Exit(); + } + } + } + + /// + /// Get count + /// + /// Segment + /// Head + /// Tail + /// Count + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static int GetCount(NativeConcurrentQueueSegmentArm64* segment, int head, int tail) + { + if (head != tail && head != tail - NativeConcurrentQueueSegmentArm64.FREEZE_OFFSET) + { + head &= NativeConcurrentQueueSegmentArm64.SLOTS_MASK; + tail &= NativeConcurrentQueueSegmentArm64.SLOTS_MASK; + return head < tail ? tail - head : NativeConcurrentQueueSegmentArm64.LENGTH - head + tail; + } + + return 0; + } + + /// + /// Get count + /// + /// Head + /// Head head + /// Tail + /// Tail tail + /// Count + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static long GetCount(NativeConcurrentQueueSegmentArm64* head, int headHead, NativeConcurrentQueueSegmentArm64* tail, int tailTail) + { + long count = 0; + var headTail = (head == tail ? tailTail : Volatile.Read(ref head->HeadAndTail.Tail)) - NativeConcurrentQueueSegmentArm64.FREEZE_OFFSET; + if (headHead < headTail) + { + headHead &= NativeConcurrentQueueSegmentArm64.SLOTS_MASK; + headTail &= NativeConcurrentQueueSegmentArm64.SLOTS_MASK; + count += headHead < headTail ? headTail - headHead : NativeConcurrentQueueSegmentArm64.LENGTH - headHead + headTail; + } + + if (head != tail) + { + for (var s = (NativeConcurrentQueueSegmentArm64*)head->NextSegment; s != tail; s = (NativeConcurrentQueueSegmentArm64*)s->NextSegment) + count += s->HeadAndTail.Tail - NativeConcurrentQueueSegmentArm64.FREEZE_OFFSET; + count += tailTail - NativeConcurrentQueueSegmentArm64.FREEZE_OFFSET; + } + + return count; + } + } + + /// + /// Native concurrentQueue segment + /// + /// Type + [StructLayout(LayoutKind.Sequential)] + internal unsafe struct NativeConcurrentQueueSegmentArm64 where T : unmanaged + { + /// + /// Slots + /// + public Slot* Slots; + + /// + /// Length + /// + public const int LENGTH = 1024; + + /// + /// Slots mask + /// + public const int SLOTS_MASK = LENGTH - 1; + + /// + /// Head and tail + /// + public NativeConcurrentQueuePaddedHeadAndTailArm64 HeadAndTail; + + /// + /// Frozen for enqueues + /// + public bool FrozenForEnqueues; + + /// + /// Next segment + /// + public nint NextSegment; + + /// + /// Initialize + /// + /// Slots + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Initialize(Slot* slots) + { + Slots = slots; + for (var i = 0; i < LENGTH; ++i) + Slots[i].SequenceNumber = i; + HeadAndTail = new NativeConcurrentQueuePaddedHeadAndTailArm64(); + FrozenForEnqueues = false; + NextSegment = IntPtr.Zero; + } + + /// + /// Freeze offset + /// + public const int FREEZE_OFFSET = LENGTH * 2; + + /// + /// Ensure frozen for enqueues + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void EnsureFrozenForEnqueues() + { + if (!FrozenForEnqueues) + { + FrozenForEnqueues = true; + Interlocked.Add(ref HeadAndTail.Tail, FREEZE_OFFSET); + } + } + + /// + /// Try dequeue + /// + /// Item + /// Dequeued + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool TryDequeue(out T result) + { + var slots = Slots; + var count = 0; + while (true) + { + var currentHead = Volatile.Read(ref HeadAndTail.Head); + var slotsIndex = currentHead & SLOTS_MASK; + var sequenceNumber = Volatile.Read(ref slots[slotsIndex].SequenceNumber); + var diff = sequenceNumber - (currentHead + 1); + if (diff == 0) + { + if (Interlocked.CompareExchange(ref HeadAndTail.Head, currentHead + 1, currentHead) == currentHead) + { + result = slots[slotsIndex].Item; + Volatile.Write(ref slots[slotsIndex].SequenceNumber, currentHead + LENGTH); + return true; + } + } + else if (diff < 0) + { + var frozen = FrozenForEnqueues; + var currentTail = Volatile.Read(ref HeadAndTail.Tail); + if (currentTail - currentHead <= 0 || (frozen && currentTail - FREEZE_OFFSET - currentHead <= 0)) + { + result = default; + return false; + } + + if ((count >= 10 && (count - 10) % 2 == 0) || Environment.ProcessorCount == 1) + { + var yieldsSoFar = count >= 10 ? (count - 10) / 2 : count; + if (yieldsSoFar % 5 == 4) + Thread.Sleep(0); + else + Thread.Yield(); + } + else + { + var iterations = Environment.ProcessorCount / 2; + if (count <= 30 && 1 << count < iterations) + iterations = 1 << count; + Thread.SpinWait(iterations); + } + + count = count == int.MaxValue ? 10 : count + 1; + } + } + } + + /// + /// Try peek + /// + /// Peeked + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool TryPeek() + { + var slots = Slots; + var count = 0; + while (true) + { + var currentHead = Volatile.Read(ref HeadAndTail.Head); + var slotsIndex = currentHead & SLOTS_MASK; + var sequenceNumber = Volatile.Read(ref slots[slotsIndex].SequenceNumber); + var diff = sequenceNumber - (currentHead + 1); + if (diff == 0) + return true; + if (diff < 0) + { + var frozen = FrozenForEnqueues; + var currentTail = Volatile.Read(ref HeadAndTail.Tail); + if (currentTail - currentHead <= 0 || (frozen && currentTail - FREEZE_OFFSET - currentHead <= 0)) + return false; + if ((count >= 10 && (count - 10) % 2 == 0) || Environment.ProcessorCount == 1) + { + var yieldsSoFar = count >= 10 ? (count - 10) / 2 : count; + if (yieldsSoFar % 5 == 4) + Thread.Sleep(0); + else + Thread.Yield(); + } + else + { + var iterations = Environment.ProcessorCount / 2; + if (count <= 30 && 1 << count < iterations) + iterations = 1 << count; + Thread.SpinWait(iterations); + } + + count = count == int.MaxValue ? 10 : count + 1; + } + } + } + + /// + /// Try enqueue + /// + /// Item + /// Enqueued + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool TryEnqueue(in T item) + { + var slots = Slots; + while (true) + { + var currentTail = Volatile.Read(ref HeadAndTail.Tail); + var slotsIndex = currentTail & SLOTS_MASK; + var sequenceNumber = Volatile.Read(ref slots[slotsIndex].SequenceNumber); + var diff = sequenceNumber - currentTail; + if (diff == 0) + { + if (Interlocked.CompareExchange(ref HeadAndTail.Tail, currentTail + 1, currentTail) == currentTail) + { + slots[slotsIndex].Item = item; + Volatile.Write(ref slots[slotsIndex].SequenceNumber, currentTail + 1); + return true; + } + } + else if (diff < 0) + { + return false; + } + } + } + + /// + /// Slot + /// + [StructLayout(LayoutKind.Sequential)] + public struct Slot + { + /// + /// Item + /// + public T Item; + + /// + /// Sequence number + /// + public int SequenceNumber; + } + } + + /// + /// NativeConcurrentQueue padded head and tail + /// + [StructLayout(LayoutKind.Explicit, Size = 3 * CACHE_LINE_SIZE)] + internal struct NativeConcurrentQueuePaddedHeadAndTailArm64 + { + /// + /// Head + /// + [FieldOffset(1 * CACHE_LINE_SIZE)] public int Head; + + /// + /// Tail + /// + [FieldOffset(2 * CACHE_LINE_SIZE)] public int Tail; + + /// + /// Catch line size + /// + public const int CACHE_LINE_SIZE = 128; + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeConcurrentQueue.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeConcurrentQueue.cs.meta new file mode 100644 index 0000000..a06a5ca --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeConcurrentQueue.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2e4c721bccdf648baad2f6e70fe8b32a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeConcurrentSpinLock.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeConcurrentSpinLock.cs new file mode 100644 index 0000000..a42b93d --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeConcurrentSpinLock.cs @@ -0,0 +1,180 @@ +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +#if UNITY_2021_3_OR_NEWER || GODOT +using System; +using System.Threading; +#endif + +#pragma warning disable CA2208 +#pragma warning disable CS8632 + +// ReSharper disable ALL + +namespace NativeCollections +{ + /// + /// Native concurrent spinLock + /// + [StructLayout(LayoutKind.Sequential)] + public readonly unsafe struct NativeConcurrentSpinLock : IDisposable, IEquatable + { + /// + /// Handle + /// + [StructLayout(LayoutKind.Sequential)] + private struct NativeConcurrentSpinLockHandle + { + /// + /// Sequence number + /// + public int SequenceNumber; + + /// + /// Next sequence number + /// + public int NextSequenceNumber; + + /// + /// Sleep threshold + /// + public int SleepThreshold; + } + + /// + /// Handle + /// + private readonly NativeConcurrentSpinLockHandle* _handle; + + /// + /// Structure + /// + /// Sleep threshold + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public NativeConcurrentSpinLock(int sleepThreshold) + { + if (sleepThreshold < -1) + sleepThreshold = -1; + else if (sleepThreshold >= 0 && sleepThreshold < 10) + sleepThreshold = 10; + _handle = (NativeConcurrentSpinLockHandle*)NativeMemoryAllocator.Alloc((uint)sizeof(NativeConcurrentSpinLockHandle)); + _handle->SequenceNumber = 0; + _handle->NextSequenceNumber = 1; + _handle->SleepThreshold = sleepThreshold; + } + + /// + /// Is created + /// + public bool IsCreated => _handle != null; + + /// + /// Sleep threshold + /// + public int SleepThreshold => _handle->SleepThreshold; + + /// + /// Equals + /// + /// Other + /// Equals + public bool Equals(NativeConcurrentSpinLock other) => other == this; + + /// + /// Equals + /// + /// object + /// Equals + public override bool Equals(object? obj) => obj is NativeConcurrentSpinLock nativeConcurrentSpinLock && nativeConcurrentSpinLock == this; + + /// + /// Get hashCode + /// + /// HashCode + public override int GetHashCode() => (int)(nint)_handle; + + /// + /// To string + /// + /// String + public override string ToString() => "NativeConcurrentSpinLock"; + + /// + /// Equals + /// + /// Left + /// Right + /// Equals + public static bool operator ==(NativeConcurrentSpinLock left, NativeConcurrentSpinLock right) => left._handle == right._handle; + + /// + /// Not equals + /// + /// Left + /// Right + /// Not equals + public static bool operator !=(NativeConcurrentSpinLock left, NativeConcurrentSpinLock right) => left._handle != right._handle; + + /// + /// Dispose + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Dispose() + { + if (_handle == null) + return; + NativeMemoryAllocator.Free(_handle); + } + + /// + /// Enter + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Enter() + { + var sequenceNumber = Interlocked.Add(ref _handle->SequenceNumber, 1); + if (sequenceNumber != _handle->NextSequenceNumber) + { + var count = 0; + var sleepThreshold = _handle->SleepThreshold; + do + { + if ((count >= 10 && ((count >= sleepThreshold && sleepThreshold >= 0) || (count - 10) % 2 == 0)) || Environment.ProcessorCount == 1) + { + if (count >= sleepThreshold && sleepThreshold >= 0) + { + Thread.Sleep(1); + } + else + { + var yieldsSoFar = count >= 10 ? (count - 10) / 2 : count; + if (yieldsSoFar % 5 == 4) + Thread.Sleep(0); + else + Thread.Yield(); + } + } + else + { + var iterations = Environment.ProcessorCount / 2; + if (count <= 30 && 1 << count < iterations) + iterations = 1 << count; + Thread.SpinWait(iterations); + } + + count = count == int.MaxValue ? 10 : count + 1; + } while (sequenceNumber != _handle->NextSequenceNumber); + } + } + + /// + /// Exit + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Exit() => Interlocked.Add(ref _handle->NextSequenceNumber, 1); + + /// + /// Empty + /// + public static NativeConcurrentSpinLock Empty => new(); + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeConcurrentSpinLock.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeConcurrentSpinLock.cs.meta new file mode 100644 index 0000000..86c97f7 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeConcurrentSpinLock.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1a76d3296d0fe4349b1247bf3b0050a5 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeConcurrentStack.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeConcurrentStack.cs new file mode 100644 index 0000000..8f98177 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeConcurrentStack.cs @@ -0,0 +1,338 @@ +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +#if !NET6_0_OR_GREATER +using System.Security.Cryptography; +#endif + +#if UNITY_2021_3_OR_NEWER || GODOT +using System; +using System.Threading; +#endif + +#pragma warning disable CA2208 +#pragma warning disable CS8632 + +// ReSharper disable ALL + +namespace NativeCollections +{ + /// + /// Native concurrentStack + /// (Slower than ConcurrentStack, disable Enumerator, try peek, push/pop range either) + /// + /// Type + [StructLayout(LayoutKind.Sequential)] + public readonly unsafe struct NativeConcurrentStack : IDisposable, IEquatable> where T : unmanaged + { + /// + /// Handle + /// + [StructLayout(LayoutKind.Sequential)] + private struct NativeConcurrentStackHandle + { + /// + /// Head + /// + public volatile nint Head; + + /// + /// Node pool + /// + public NativeMemoryPool NodePool; + + /// + /// Node pool lock + /// + public NativeConcurrentSpinLock NodePoolLock; + } + + /// + /// Handle + /// + private readonly NativeConcurrentStackHandle* _handle; + + /// + /// Structure + /// + /// Size + /// Max free slabs + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public NativeConcurrentStack(int size, int maxFreeSlabs) + { + var nodePool = new NativeMemoryPool(size, sizeof(Node), maxFreeSlabs); + _handle = (NativeConcurrentStackHandle*)NativeMemoryAllocator.Alloc((uint)sizeof(NativeConcurrentStackHandle)); + _handle->Head = IntPtr.Zero; + _handle->NodePool = nodePool; + _handle->NodePoolLock = new NativeConcurrentSpinLock(-1); + } + + /// + /// Is created + /// + public bool IsCreated => _handle != null; + + /// + /// IsEmpty + /// + public bool IsEmpty => _handle->Head == IntPtr.Zero; + + /// + /// Count + /// + public int Count + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get + { + var count = 0; + for (var node = (Node*)_handle->Head; node != null; node = node->Next) + count++; + return count; + } + } + + /// + /// Equals + /// + /// Other + /// Equals + public bool Equals(NativeConcurrentStack other) => other == this; + + /// + /// Equals + /// + /// object + /// Equals + public override bool Equals(object? obj) => obj is NativeConcurrentStack nativeConcurrentStack && nativeConcurrentStack == this; + + /// + /// Get hashCode + /// + /// HashCode + public override int GetHashCode() => (int)(nint)_handle; + + /// + /// To string + /// + /// String + public override string ToString() => $"NativeConcurrentStack<{typeof(T).Name}>"; + + /// + /// Equals + /// + /// Left + /// Right + /// Equals + public static bool operator ==(NativeConcurrentStack left, NativeConcurrentStack right) => left._handle == right._handle; + + /// + /// Not equals + /// + /// Left + /// Right + /// Not equals + public static bool operator !=(NativeConcurrentStack left, NativeConcurrentStack right) => left._handle != right._handle; + + /// + /// Dispose + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Dispose() + { + if (_handle == null) + return; + _handle->NodePool.Dispose(); + _handle->NodePoolLock.Dispose(); + NativeMemoryAllocator.Free(_handle); + } + + /// + /// Clear + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Clear() + { + _handle->NodePoolLock.Enter(); + try + { + var node = (Node*)_handle->Head; + while (node != null) + { + var temp = node; + node = node->Next; + _handle->NodePool.Return(temp); + } + } + finally + { + _handle->NodePoolLock.Exit(); + } + } + + /// + /// Push + /// + /// Item + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Push(in T item) + { + Node* newNode; + _handle->NodePoolLock.Enter(); + try + { + newNode = (Node*)_handle->NodePool.Rent(); + } + finally + { + _handle->NodePoolLock.Exit(); + } + + newNode->Value = item; + newNode->Next = (Node*)_handle->Head; + if (Interlocked.CompareExchange(ref _handle->Head, (nint)newNode, (nint)newNode->Next) == (nint)newNode->Next) + return; + var count = 0; + do + { + if ((count >= 10 && (count - 10) % 2 == 0) || Environment.ProcessorCount == 1) + { + var yieldsSoFar = count >= 10 ? (count - 10) / 2 : count; + if (yieldsSoFar % 5 == 4) + Thread.Sleep(0); + else + Thread.Yield(); + } + else + { + var iterations = Environment.ProcessorCount / 2; + if (count <= 30 && 1 << count < iterations) + iterations = 1 << count; + Thread.SpinWait(iterations); + } + + count = count == int.MaxValue ? 10 : count + 1; + newNode->Next = (Node*)_handle->Head; + } while (Interlocked.CompareExchange(ref _handle->Head, (nint)newNode, (nint)newNode->Next) != (nint)newNode->Next); + } + + /// + /// Try pop + /// + /// Item + /// Popped + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool TryPop(out T result) + { + var head = (Node*)_handle->Head; + if (head == null) + { + result = default; + return false; + } + + if (Interlocked.CompareExchange(ref _handle->Head, (nint)head->Next, (nint)head) == (nint)head) + { + result = head->Value; + _handle->NodePoolLock.Enter(); + try + { + _handle->NodePool.Return(head); + } + finally + { + _handle->NodePoolLock.Exit(); + } + + return true; + } + + var count = 0; + var backoff = 1; +#if !NET6_0_OR_GREATER + Span random = stackalloc byte[1]; +#endif + while (true) + { + head = (Node*)_handle->Head; + if (head == null) + { + result = default; + return false; + } + + if (Interlocked.CompareExchange(ref _handle->Head, (nint)head->Next, (nint)head) == (nint)head) + { + result = head->Value; + _handle->NodePoolLock.Enter(); + try + { + _handle->NodePool.Return(head); + } + finally + { + _handle->NodePoolLock.Exit(); + } + + return true; + } + + for (var i = 0; i < backoff; ++i) + { + if ((count >= 10 && (count - 10) % 2 == 0) || Environment.ProcessorCount == 1) + { + var yieldsSoFar = count >= 10 ? (count - 10) / 2 : count; + if (yieldsSoFar % 5 == 4) + Thread.Sleep(0); + else + Thread.Yield(); + } + else + { + var iterations = Environment.ProcessorCount / 2; + if (count <= 30 && 1 << count < iterations) + iterations = 1 << count; + Thread.SpinWait(iterations); + } + + count = count == int.MaxValue ? 10 : count + 1; + } + + if (count >= 10 || Environment.ProcessorCount == 1) + { +#if NET6_0_OR_GREATER + backoff = Random.Shared.Next(1, 8); +#else + RandomNumberGenerator.Fill(random); + backoff = random[0] % 7 + 1; +#endif + } + else + { + backoff *= 2; + } + } + } + + /// + /// Empty + /// + public static NativeConcurrentStack Empty => new(); + + /// + /// Node + /// + [StructLayout(LayoutKind.Sequential)] + private struct Node + { + /// + /// Value + /// + public T Value; + + /// + /// Next + /// + public Node* Next; + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeConcurrentStack.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeConcurrentStack.cs.meta new file mode 100644 index 0000000..cad9f46 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeConcurrentStack.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: fb99d22c8b973459292145f9fb620e54 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeDictionary.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeDictionary.cs new file mode 100644 index 0000000..173a9fb --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeDictionary.cs @@ -0,0 +1,971 @@ +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +#if UNITY_2021_3_OR_NEWER || GODOT +using System; +using System.Collections.Generic; +#endif + +#pragma warning disable CA2208 +#pragma warning disable CS8632 + +// ReSharper disable ALL + +namespace NativeCollections +{ + /// + /// Native dictionary + /// + /// Type + /// Type + [StructLayout(LayoutKind.Sequential)] + public readonly unsafe struct NativeDictionary : IDisposable, IEquatable> where TKey : unmanaged, IEquatable where TValue : unmanaged + { + /// + /// Handle + /// + [StructLayout(LayoutKind.Sequential)] + private struct NativeDictionaryHandle + { + /// + /// Buckets + /// + public int* Buckets; + + /// + /// Entries + /// + public Entry* Entries; + + /// + /// BucketsLength + /// + public int BucketsLength; + + /// + /// EntriesLength + /// + public int EntriesLength; + + /// + /// FastModMultiplier + /// + public ulong FastModMultiplier; + + /// + /// Count + /// + public int Count; + + /// + /// FreeList + /// + public int FreeList; + + /// + /// FreeCount + /// + public int FreeCount; + + /// + /// Version + /// + public int Version; + + /// + /// Keys + /// + public KeyCollection Keys; + + /// + /// Values + /// + public ValueCollection Values; + } + + /// + /// Handle + /// + private readonly NativeDictionaryHandle* _handle; + + /// + /// Keys + /// + public KeyCollection Keys => _handle->Keys; + + /// + /// Values + /// + public ValueCollection Values => _handle->Values; + + /// + /// Structure + /// + /// Capacity + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public NativeDictionary(int capacity) + { + if (capacity < 0) + throw new ArgumentOutOfRangeException(nameof(capacity), capacity, "MustBeNonNegative"); + if (capacity < 4) + capacity = 4; + _handle = (NativeDictionaryHandle*)NativeMemoryAllocator.Alloc((uint)sizeof(NativeDictionaryHandle)); + _handle->Count = 0; + _handle->FreeCount = 0; + _handle->Version = 0; + Initialize(capacity); + _handle->Keys = new KeyCollection(this); + _handle->Values = new ValueCollection(this); + } + + /// + /// Is created + /// + public bool IsCreated => _handle != null; + + /// + /// Is empty + /// + public bool IsEmpty => _handle->Count - _handle->FreeCount == 0; + + /// + /// Get or set value + /// + /// Key + public TValue this[in TKey key] + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get + { + ref var value = ref FindValue(key); + if (Unsafe.AsPointer(ref Unsafe.AsRef(in value)) != null) + return value; + throw new KeyNotFoundException(key.ToString()); + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + set => TryInsertOverwriteExisting(key, value); + } + + /// + /// Count + /// + public int Count => _handle->Count - _handle->FreeCount; + + /// + /// Equals + /// + /// Other + /// Equals + public bool Equals(NativeDictionary other) => other == this; + + /// + /// Equals + /// + /// object + /// Equals + public override bool Equals(object? obj) => obj is NativeDictionary nativeDictionary && nativeDictionary == this; + + /// + /// Get hashCode + /// + /// HashCode + public override int GetHashCode() => (int)(nint)_handle; + + /// + /// To string + /// + /// String + public override string ToString() => $"NativeDictionary<{typeof(TKey).Name}, {typeof(TValue).Name}>"; + + /// + /// Equals + /// + /// Left + /// Right + /// Equals + public static bool operator ==(NativeDictionary left, NativeDictionary right) => left._handle == right._handle; + + /// + /// Not equals + /// + /// Left + /// Right + /// Not equals + public static bool operator !=(NativeDictionary left, NativeDictionary right) => left._handle != right._handle; + + /// + /// Dispose + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Dispose() + { + if (_handle == null) + return; + NativeMemoryAllocator.Free(_handle->Buckets); + NativeMemoryAllocator.Free(_handle->Entries); + NativeMemoryAllocator.Free(_handle); + } + + /// + /// Clear + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Clear() + { + var count = _handle->Count; + if (count > 0) + { + Unsafe.InitBlockUnaligned(_handle->Buckets, 0, (uint)(count * sizeof(int))); + _handle->Count = 0; + _handle->FreeList = -1; + _handle->FreeCount = 0; + Unsafe.InitBlockUnaligned(_handle->Entries, 0, (uint)(count * sizeof(Entry))); + } + } + + /// + /// Add + /// + /// Key + /// Value + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Add(in TKey key, in TValue value) => TryInsertThrowOnExisting(key, value); + + /// + /// Try add + /// + /// Key + /// Value + /// Added + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool TryAdd(in TKey key, in TValue value) => TryInsertNone(key, value); + + /// + /// Remove + /// + /// Key + /// Removed + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool Remove(in TKey key) + { + uint collisionCount = 0; + var hashCode = (uint)key.GetHashCode(); + ref var bucket = ref GetBucket(hashCode); + var last = -1; + var i = bucket - 1; + while (i >= 0) + { + ref var entry = ref _handle->Entries[i]; + if (entry.HashCode == hashCode && entry.Key.Equals(key)) + { + if (last < 0) + bucket = entry.Next + 1; + else + _handle->Entries[last].Next = entry.Next; + entry.Next = -3 - _handle->FreeList; + _handle->FreeList = i; + _handle->FreeCount++; + return true; + } + + last = i; + i = entry.Next; + collisionCount++; + if (collisionCount > (uint)_handle->EntriesLength) + throw new InvalidOperationException("ConcurrentOperationsNotSupported"); + } + + return false; + } + + /// + /// Remove + /// + /// Key + /// Value + /// Removed + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool Remove(in TKey key, out TValue value) + { + uint collisionCount = 0; + var hashCode = (uint)key.GetHashCode(); + ref var bucket = ref GetBucket(hashCode); + var last = -1; + var i = bucket - 1; + while (i >= 0) + { + ref var entry = ref _handle->Entries[i]; + if (entry.HashCode == hashCode && entry.Key.Equals(key)) + { + if (last < 0) + bucket = entry.Next + 1; + else + _handle->Entries[last].Next = entry.Next; + value = entry.Value; + entry.Next = -3 - _handle->FreeList; + _handle->FreeList = i; + _handle->FreeCount++; + return true; + } + + last = i; + i = entry.Next; + collisionCount++; + if (collisionCount > (uint)_handle->EntriesLength) + throw new InvalidOperationException("ConcurrentOperationsNotSupported"); + } + + value = default; + return false; + } + + /// + /// Contains key + /// + /// Key + /// Contains key + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool ContainsKey(in TKey key) => Unsafe.AsPointer(ref Unsafe.AsRef(in FindValue(key))) != null; + + /// + /// Try to get the value + /// + /// Key + /// Value + /// Got + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool TryGetValue(in TKey key, out TValue value) + { + ref var valRef = ref FindValue(key); + if (Unsafe.AsPointer(ref Unsafe.AsRef(in valRef)) != null) + { + value = valRef; + return true; + } + + value = default; + return false; + } + + /// + /// Ensure capacity + /// + /// Capacity + /// New capacity + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public int EnsureCapacity(int capacity) + { + if (capacity < 0) + throw new ArgumentOutOfRangeException(nameof(capacity), capacity, "MustBeNonNegative"); + var currentCapacity = _handle->EntriesLength; + if (currentCapacity >= capacity) + return currentCapacity; + _handle->Version++; + var newSize = HashHelpers.GetPrime(capacity); + Resize(newSize); + return newSize; + } + + /// + /// Trim excess + /// + /// New capacity + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public int TrimExcess() => TrimExcess(Count); + + /// + /// Trim excess + /// + /// Capacity + /// New capacity + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public int TrimExcess(int capacity) + { + if (capacity < 0) + throw new ArgumentOutOfRangeException(nameof(capacity), capacity, "MustBeNonNegative"); + var newSize = HashHelpers.GetPrime(capacity); + var oldEntries = _handle->Entries; + var currentCapacity = _handle->EntriesLength; + if (newSize >= currentCapacity) + return currentCapacity; + var oldCount = _handle->Count; + _handle->Version++; + NativeMemoryAllocator.Free(_handle->Buckets); + Initialize(newSize); + var newEntries = _handle->Entries; + var newCount = 0; + for (var i = 0; i < oldCount; ++i) + { + var hashCode = oldEntries[i].HashCode; + if (oldEntries[i].Next >= -1) + { + ref var entry = ref newEntries[newCount]; + entry = oldEntries[i]; + ref var bucket = ref GetBucket(hashCode); + entry.Next = bucket - 1; + bucket = newCount + 1; + newCount++; + } + } + + NativeMemoryAllocator.Free(oldEntries); + _handle->Count = newCount; + _handle->FreeCount = 0; + return newSize; + } + + /// + /// Find value + /// + /// Key + /// Value + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private ref TValue FindValue(in TKey key) + { + var hashCode = (uint)key.GetHashCode(); + var i = GetBucket(hashCode); + uint collisionCount = 0; + i--; + do + { + if ((uint)i >= (uint)_handle->EntriesLength) + return ref Unsafe.AsRef(null); + ref var entry = ref _handle->Entries[i]; + if (entry.HashCode == hashCode && entry.Key.Equals(key)) + return ref entry.Value; + i = entry.Next; + collisionCount++; + } while (collisionCount <= (uint)_handle->EntriesLength); + + throw new InvalidOperationException("ConcurrentOperationsNotSupported"); + } + + /// + /// Initialize + /// + /// Capacity + /// New capacity + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void Initialize(int capacity) + { + var size = HashHelpers.GetPrime(capacity); + _handle->FreeList = -1; + _handle->Buckets = (int*)NativeMemoryAllocator.AllocZeroed((uint)(size * sizeof(int))); + _handle->Entries = (Entry*)NativeMemoryAllocator.AllocZeroed((uint)(size * sizeof(Entry))); + _handle->BucketsLength = size; + _handle->EntriesLength = size; + _handle->FastModMultiplier = IntPtr.Size == 8 ? HashHelpers.GetFastModMultiplier((uint)size) : 0; + } + + /// + /// Resize + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void Resize() => Resize(HashHelpers.ExpandPrime(_handle->Count)); + + /// + /// Resize + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void Resize(int newSize) + { + var entries = (Entry*)NativeMemoryAllocator.AllocZeroed((uint)(newSize * sizeof(Entry))); + var count = _handle->Count; + Unsafe.CopyBlockUnaligned(entries, _handle->Entries, (uint)(count * sizeof(Entry))); + var buckets = (int*)NativeMemoryAllocator.AllocZeroed((uint)(newSize * sizeof(int))); + NativeMemoryAllocator.Free(_handle->Buckets); + _handle->Buckets = buckets; + _handle->BucketsLength = newSize; + _handle->FastModMultiplier = IntPtr.Size == 8 ? HashHelpers.GetFastModMultiplier((uint)newSize) : 0; + for (var i = 0; i < count; ++i) + { + if (entries[i].Next >= -1) + { + ref var bucket = ref GetBucket(entries[i].HashCode); + entries[i].Next = bucket - 1; + bucket = i + 1; + } + } + + NativeMemoryAllocator.Free(_handle->Entries); + _handle->Entries = entries; + _handle->EntriesLength = newSize; + } + + /// + /// Insert + /// + /// Key + /// Value + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void TryInsertOverwriteExisting(in TKey key, in TValue value) + { + var hashCode = (uint)key.GetHashCode(); + uint collisionCount = 0; + ref var bucket = ref GetBucket(hashCode); + var i = bucket - 1; + while (true) + { + if ((uint)i >= (uint)_handle->EntriesLength) + break; + if (_handle->Entries[i].HashCode == hashCode && _handle->Entries[i].Key.Equals(key)) + { + _handle->Entries[i].Value = value; + return; + } + + i = _handle->Entries[i].Next; + collisionCount++; + if (collisionCount > (uint)_handle->EntriesLength) + throw new InvalidOperationException("ConcurrentOperationsNotSupported"); + } + + int index; + if (_handle->FreeCount > 0) + { + index = _handle->FreeList; + _handle->FreeList = -3 - _handle->Entries[_handle->FreeList].Next; + _handle->FreeCount--; + } + else + { + var count = _handle->Count; + if (count == _handle->EntriesLength) + { + Resize(); + bucket = ref GetBucket(hashCode); + } + + index = count; + _handle->Count = count + 1; + } + + ref var entry = ref _handle->Entries[index]; + entry.HashCode = hashCode; + entry.Next = bucket - 1; + entry.Key = key; + entry.Value = value; + bucket = index + 1; + _handle->Version++; + } + + /// + /// Insert + /// + /// Key + /// Value + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private bool TryInsertThrowOnExisting(in TKey key, in TValue value) + { + var hashCode = (uint)key.GetHashCode(); + uint collisionCount = 0; + ref var bucket = ref GetBucket(hashCode); + var i = bucket - 1; + while (true) + { + if ((uint)i >= (uint)_handle->EntriesLength) + break; + if (_handle->Entries[i].HashCode == hashCode && _handle->Entries[i].Key.Equals(key)) + throw new ArgumentException($"Argument_AddingDuplicateWithKey, {key}"); + i = _handle->Entries[i].Next; + collisionCount++; + if (collisionCount > (uint)_handle->EntriesLength) + throw new InvalidOperationException("ConcurrentOperationsNotSupported"); + } + + int index; + if (_handle->FreeCount > 0) + { + index = _handle->FreeList; + _handle->FreeList = -3 - _handle->Entries[_handle->FreeList].Next; + _handle->FreeCount--; + } + else + { + var count = _handle->Count; + if (count == _handle->EntriesLength) + { + Resize(); + bucket = ref GetBucket(hashCode); + } + + index = count; + _handle->Count = count + 1; + } + + ref var entry = ref _handle->Entries[index]; + entry.HashCode = hashCode; + entry.Next = bucket - 1; + entry.Key = key; + entry.Value = value; + bucket = index + 1; + _handle->Version++; + return true; + } + + /// + /// Insert + /// + /// Key + /// Value + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private bool TryInsertNone(in TKey key, in TValue value) + { + var hashCode = (uint)key.GetHashCode(); + uint collisionCount = 0; + ref var bucket = ref GetBucket(hashCode); + var i = bucket - 1; + while (true) + { + if ((uint)i >= (uint)_handle->EntriesLength) + break; + if (_handle->Entries[i].HashCode == hashCode && _handle->Entries[i].Key.Equals(key)) + return false; + i = _handle->Entries[i].Next; + collisionCount++; + if (collisionCount > (uint)_handle->EntriesLength) + throw new InvalidOperationException("ConcurrentOperationsNotSupported"); + } + + int index; + if (_handle->FreeCount > 0) + { + index = _handle->FreeList; + _handle->FreeList = -3 - _handle->Entries[_handle->FreeList].Next; + _handle->FreeCount--; + } + else + { + var count = _handle->Count; + if (count == _handle->EntriesLength) + { + Resize(); + bucket = ref GetBucket(hashCode); + } + + index = count; + _handle->Count = count + 1; + } + + ref var entry = ref _handle->Entries[index]; + entry.HashCode = hashCode; + entry.Next = bucket - 1; + entry.Key = key; + entry.Value = value; + bucket = index + 1; + _handle->Version++; + return true; + } + + /// + /// Get bucket ref + /// + /// HashCode + /// Bucket ref + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private ref int GetBucket(uint hashCode) => ref IntPtr.Size == 8 ? ref _handle->Buckets[HashHelpers.FastMod(hashCode, (uint)_handle->BucketsLength, _handle->FastModMultiplier)] : ref _handle->Buckets[hashCode % _handle->BucketsLength]; + + /// + /// Entry + /// + private struct Entry + { + /// + /// HashCode + /// + public uint HashCode; + + /// + /// Next + /// + public int Next; + + /// + /// Key + /// + public TKey Key; + + /// + /// Value + /// + public TValue Value; + } + + /// + /// Empty + /// + public static NativeDictionary Empty => new(); + + /// + /// Get enumerator + /// + /// Enumerator + public Enumerator GetEnumerator() => new(this); + + /// + /// Enumerator + /// + public struct Enumerator + { + /// + /// NativeDictionary + /// + private readonly NativeDictionary _nativeDictionary; + + /// + /// Version + /// + private readonly int _version; + + /// + /// Index + /// + private int _index; + + /// + /// Current + /// + private KeyValuePair _current; + + /// + /// Structure + /// + /// NativeDictionary + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal Enumerator(in NativeDictionary nativeDictionary) + { + _nativeDictionary = nativeDictionary; + _version = nativeDictionary._handle->Version; + _index = 0; + _current = default; + } + + /// + /// Move next + /// + /// Moved + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool MoveNext() + { + if (_version != _nativeDictionary._handle->Version) + throw new InvalidOperationException("EnumFailedVersion"); + while ((uint)_index < (uint)_nativeDictionary._handle->Count) + { + ref var entry = ref _nativeDictionary._handle->Entries[_index++]; + if (entry.Next >= -1) + { + _current = new KeyValuePair(entry.Key, entry.Value); + return true; + } + } + + _index = _nativeDictionary._handle->Count + 1; + _current = default; + return false; + } + + /// + /// Current + /// + public KeyValuePair Current + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _current; + } + } + + /// + /// Key collection + /// + [StructLayout(LayoutKind.Sequential)] + public readonly struct KeyCollection + { + /// + /// NativeDictionary + /// + private readonly NativeDictionary _nativeDictionary; + + /// + /// Structure + /// + /// NativeDictionary + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal KeyCollection(in NativeDictionary nativeDictionary) => _nativeDictionary = nativeDictionary; + + /// + /// Get enumerator + /// + /// Enumerator + public Enumerator GetEnumerator() => new(_nativeDictionary); + + /// + /// Enumerator + /// + public struct Enumerator + { + /// + /// NativeDictionary + /// + private readonly NativeDictionary _nativeDictionary; + + /// + /// Index + /// + private int _index; + + /// + /// Version + /// + private readonly int _version; + + /// + /// Current + /// + private TKey _currentKey; + + /// + /// Structure + /// + /// NativeDictionary + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal Enumerator(in NativeDictionary nativeDictionary) + { + _nativeDictionary = nativeDictionary; + _version = nativeDictionary._handle->Version; + _index = 0; + _currentKey = default; + } + + /// + /// Move next + /// + /// Moved + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool MoveNext() + { + if (_version != _nativeDictionary._handle->Version) + throw new InvalidOperationException("EnumFailedVersion"); + while ((uint)_index < (uint)_nativeDictionary._handle->Count) + { + ref var entry = ref _nativeDictionary._handle->Entries[_index++]; + if (entry.Next >= -1) + { + _currentKey = entry.Key; + return true; + } + } + + _index = _nativeDictionary._handle->Count + 1; + _currentKey = default; + return false; + } + + /// + /// Current + /// + public TKey Current + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _currentKey; + } + } + } + + /// + /// Value collection + /// + [StructLayout(LayoutKind.Sequential)] + public readonly struct ValueCollection + { + /// + /// NativeDictionary + /// + private readonly NativeDictionary _nativeDictionary; + + /// + /// Structure + /// + /// NativeDictionary + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal ValueCollection(in NativeDictionary nativeDictionary) => _nativeDictionary = nativeDictionary; + + /// + /// Get enumerator + /// + /// Enumerator + public Enumerator GetEnumerator() => new(_nativeDictionary); + + /// + /// Enumerator + /// + public struct Enumerator + { + /// + /// NativeDictionary + /// + private readonly NativeDictionary _nativeDictionary; + + /// + /// Index + /// + private int _index; + + /// + /// Version + /// + private readonly int _version; + + /// + /// Current + /// + private TValue _currentValue; + + /// + /// Structure + /// + /// NativeDictionary + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal Enumerator(in NativeDictionary nativeDictionary) + { + _nativeDictionary = nativeDictionary; + _version = nativeDictionary._handle->Version; + _index = 0; + _currentValue = default; + } + + /// + /// Move next + /// + /// Moved + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool MoveNext() + { + if (_version != _nativeDictionary._handle->Version) + throw new InvalidOperationException("EnumFailedVersion"); + while ((uint)_index < (uint)_nativeDictionary._handle->Count) + { + ref var entry = ref _nativeDictionary._handle->Entries[_index++]; + if (entry.Next >= -1) + { + _currentValue = entry.Value; + return true; + } + } + + _index = _nativeDictionary._handle->Count + 1; + _currentValue = default; + return false; + } + + /// + /// Current + /// + public TValue Current + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _currentValue; + } + } + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeDictionary.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeDictionary.cs.meta new file mode 100644 index 0000000..2764e57 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeDictionary.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 413873e8f629844b9b9d4136907a4a72 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeHashSet.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeHashSet.cs new file mode 100644 index 0000000..c886df6 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeHashSet.cs @@ -0,0 +1,550 @@ +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +#if UNITY_2021_3_OR_NEWER || GODOT +using System; +#endif + +#pragma warning disable CA2208 +#pragma warning disable CS8632 + +// ReSharper disable ALL + +namespace NativeCollections +{ + /// + /// Native hashSet + /// + /// Type + [StructLayout(LayoutKind.Sequential)] + public readonly unsafe struct NativeHashSet : IDisposable, IEquatable> where T : unmanaged, IEquatable + { + /// + /// Handle + /// + [StructLayout(LayoutKind.Sequential)] + private struct NativeHashSetHandle + { + /// + /// Buckets + /// + public int* Buckets; + + /// + /// Entries + /// + public Entry* Entries; + + /// + /// BucketsLength + /// + public int BucketsLength; + + /// + /// EntriesLength + /// + public int EntriesLength; + + /// + /// FastModMultiplier + /// + public ulong FastModMultiplier; + + /// + /// Count + /// + public int Count; + + /// + /// FreeList + /// + public int FreeList; + + /// + /// FreeCount + /// + public int FreeCount; + + /// + /// Version + /// + public int Version; + } + + /// + /// Handle + /// + private readonly NativeHashSetHandle* _handle; + + /// + /// Structure + /// + /// Capacity + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public NativeHashSet(int capacity) + { + if (capacity < 0) + throw new ArgumentOutOfRangeException(nameof(capacity), capacity, "MustBeNonNegative"); + if (capacity < 4) + capacity = 4; + _handle = (NativeHashSetHandle*)NativeMemoryAllocator.Alloc((uint)sizeof(NativeHashSetHandle)); + _handle->Count = 0; + _handle->FreeCount = 0; + _handle->Version = 0; + Initialize(capacity); + } + + /// + /// Is created + /// + public bool IsCreated => _handle != null; + + /// + /// Is empty + /// + public bool IsEmpty => _handle->Count - _handle->FreeCount == 0; + + /// + /// Count + /// + public int Count => _handle->Count - _handle->FreeCount; + + /// + /// Equals + /// + /// Other + /// Equals + public bool Equals(NativeHashSet other) => other == this; + + /// + /// Equals + /// + /// object + /// Equals + public override bool Equals(object? obj) => obj is NativeHashSet nativeHashSet && nativeHashSet == this; + + /// + /// Get hashCode + /// + /// HashCode + public override int GetHashCode() => (int)(nint)_handle; + + /// + /// To string + /// + /// String + public override string ToString() => $"NativeHashSet<{typeof(T).Name}>"; + + /// + /// Equals + /// + /// Left + /// Right + /// Equals + public static bool operator ==(NativeHashSet left, NativeHashSet right) => left._handle == right._handle; + + /// + /// Not equals + /// + /// Left + /// Right + /// Not equals + public static bool operator !=(NativeHashSet left, NativeHashSet right) => left._handle != right._handle; + + /// + /// Dispose + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Dispose() + { + if (_handle == null) + return; + NativeMemoryAllocator.Free(_handle->Buckets); + NativeMemoryAllocator.Free(_handle->Entries); + NativeMemoryAllocator.Free(_handle); + } + + /// + /// Clear + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Clear() + { + var count = _handle->Count; + if (count > 0) + { + Unsafe.InitBlockUnaligned(_handle->Buckets, 0, (uint)(_handle->BucketsLength * sizeof(int))); + _handle->Count = 0; + _handle->FreeList = -1; + _handle->FreeCount = 0; + Unsafe.InitBlockUnaligned(_handle->Entries, 0, (uint)(count * sizeof(Entry))); + } + } + + /// + /// Add + /// + /// Item + /// Added + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool Add(in T item) + { + uint collisionCount = 0; + var hashCode = item.GetHashCode(); + ref var bucket = ref GetBucketRef(hashCode); + var i = bucket - 1; + while (i >= 0) + { + ref var entry = ref _handle->Entries[i]; + if (entry.HashCode == hashCode && entry.Value.Equals(item)) + return false; + i = entry.Next; + collisionCount++; + if (collisionCount > (uint)_handle->EntriesLength) + throw new InvalidOperationException("ConcurrentOperationsNotSupported"); + } + + int index; + if (_handle->FreeCount > 0) + { + index = _handle->FreeList; + _handle->FreeCount--; + _handle->FreeList = -3 - _handle->Entries[_handle->FreeList].Next; + } + else + { + var count = _handle->Count; + if (count == _handle->EntriesLength) + { + Resize(); + bucket = ref GetBucketRef(hashCode); + } + + index = count; + _handle->Count = count + 1; + } + + ref var newEntry = ref _handle->Entries[index]; + newEntry.HashCode = hashCode; + newEntry.Next = bucket - 1; + newEntry.Value = item; + bucket = index + 1; + _handle->Version++; + return true; + } + + /// + /// Remove + /// + /// Item + /// Removed + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool Remove(in T item) + { + uint collisionCount = 0; + var last = -1; + var hashCode = item.GetHashCode(); + ref var bucket = ref GetBucketRef(hashCode); + var i = bucket - 1; + while (i >= 0) + { + ref var entry = ref _handle->Entries[i]; + if (entry.HashCode == hashCode && entry.Value.Equals(item)) + { + if (last < 0) + bucket = entry.Next + 1; + else + _handle->Entries[last].Next = entry.Next; + entry.Next = -3 - _handle->FreeList; + _handle->FreeList = i; + _handle->FreeCount++; + return true; + } + + last = i; + i = entry.Next; + collisionCount++; + if (collisionCount > (uint)_handle->EntriesLength) + throw new InvalidOperationException("ConcurrentOperationsNotSupported"); + } + + return false; + } + + /// + /// Contains + /// + /// Item + /// Contains + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool Contains(in T item) => FindItemIndex(item) >= 0; + + /// + /// Try to get the actual value + /// + /// Equal value + /// Actual value + /// Got + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool TryGetValue(in T equalValue, out T actualValue) + { + var index = FindItemIndex(equalValue); + if (index >= 0) + { + actualValue = _handle->Entries[index].Value; + return true; + } + + actualValue = default; + return false; + } + + /// + /// Ensure capacity + /// + /// Capacity + /// New capacity + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public int EnsureCapacity(int capacity) + { + if (capacity < 0) + throw new ArgumentOutOfRangeException(nameof(capacity), capacity, "MustBeNonNegative"); + var currentCapacity = _handle->EntriesLength; + if (currentCapacity >= capacity) + return currentCapacity; + var newSize = HashHelpers.GetPrime(capacity); + Resize(newSize); + return newSize; + } + + /// + /// Trim excess + /// + /// New capacity + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public int TrimExcess() + { + var capacity = _handle->Count - _handle->FreeCount; + var newSize = HashHelpers.GetPrime(capacity); + var oldEntries = _handle->Entries; + var currentCapacity = _handle->EntriesLength; + if (newSize >= currentCapacity) + return currentCapacity; + var oldCount = _handle->Count; + _handle->Version++; + NativeMemoryAllocator.Free(_handle->Buckets); + Initialize(newSize); + var newEntries = _handle->Entries; + var count = 0; + for (var i = 0; i < oldCount; ++i) + { + var hashCode = oldEntries[i].HashCode; + if (oldEntries[i].Next >= -1) + { + ref var entry = ref newEntries[count]; + entry = oldEntries[i]; + ref var bucket = ref GetBucketRef(hashCode); + entry.Next = bucket - 1; + bucket = count + 1; + count++; + } + } + + NativeMemoryAllocator.Free(oldEntries); + _handle->Count = capacity; + _handle->FreeCount = 0; + return newSize; + } + + /// + /// Initialize + /// + /// Capacity + /// New capacity + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private int Initialize(int capacity) + { + var size = HashHelpers.GetPrime(capacity); + _handle->FreeList = -1; + _handle->Buckets = (int*)NativeMemoryAllocator.AllocZeroed((uint)(size * sizeof(int))); + _handle->Entries = (Entry*)NativeMemoryAllocator.AllocZeroed((uint)(size * sizeof(Entry))); + _handle->BucketsLength = size; + _handle->EntriesLength = size; + _handle->FastModMultiplier = IntPtr.Size == 8 ? HashHelpers.GetFastModMultiplier((uint)size) : 0; + return size; + } + + /// + /// Resize + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void Resize() => Resize(HashHelpers.ExpandPrime(_handle->Count)); + + /// + /// Resize + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void Resize(int newSize) + { + var entries = (Entry*)NativeMemoryAllocator.AllocZeroed((uint)(newSize * sizeof(Entry))); + var count = _handle->Count; + Unsafe.CopyBlockUnaligned(entries, _handle->Entries, (uint)(_handle->EntriesLength * sizeof(Entry))); + var buckets = (int*)NativeMemoryAllocator.AllocZeroed((uint)(newSize * sizeof(int))); + NativeMemoryAllocator.Free(_handle->Buckets); + _handle->Buckets = buckets; + _handle->BucketsLength = newSize; + _handle->FastModMultiplier = IntPtr.Size == 8 ? HashHelpers.GetFastModMultiplier((uint)newSize) : 0; + for (var i = 0; i < count; ++i) + { + ref var entry = ref entries[i]; + if (entry.Next >= -1) + { + ref var bucket = ref GetBucketRef(entry.HashCode); + entry.Next = bucket - 1; + bucket = i + 1; + } + } + + NativeMemoryAllocator.Free(_handle->Entries); + _handle->Entries = entries; + _handle->EntriesLength = newSize; + } + + /// + /// Find item index + /// + /// Item + /// Index + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private int FindItemIndex(in T item) + { + uint collisionCount = 0; + var hashCode = item.GetHashCode(); + var i = GetBucketRef(hashCode) - 1; + while (i >= 0) + { + ref var entry = ref _handle->Entries[i]; + if (entry.HashCode == hashCode && entry.Value.Equals(item)) + return i; + i = entry.Next; + collisionCount++; + if (collisionCount > (uint)_handle->EntriesLength) + throw new InvalidOperationException("ConcurrentOperationsNotSupported"); + } + + return -1; + } + + /// + /// Get bucket ref + /// + /// HashCode + /// Bucket ref + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private ref int GetBucketRef(int hashCode) => ref IntPtr.Size == 8 ? ref _handle->Buckets[HashHelpers.FastMod((uint)hashCode, (uint)_handle->BucketsLength, _handle->FastModMultiplier)] : ref _handle->Buckets[(uint)hashCode % (uint)_handle->BucketsLength]; + + /// + /// Entry + /// + private struct Entry + { + /// + /// HashCode + /// + public int HashCode; + + /// + /// Next + /// + public int Next; + + /// + /// Value + /// + public T Value; + } + + /// + /// Empty + /// + public static NativeHashSet Empty => new(); + + /// + /// Get enumerator + /// + /// Enumerator + public Enumerator GetEnumerator() => new(this); + + /// + /// Enumerator + /// + public struct Enumerator + { + /// + /// NativeHashSet + /// + private readonly NativeHashSet _nativeHashSet; + + /// + /// Version + /// + private readonly int _version; + + /// + /// Index + /// + private int _index; + + /// + /// Current + /// + private T _current; + + /// + /// Structure + /// + /// NativeHashSet + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal Enumerator(in NativeHashSet nativeHashSet) + { + _nativeHashSet = nativeHashSet; + _version = nativeHashSet._handle->Version; + _index = 0; + _current = default; + } + + /// + /// Move next + /// + /// Moved + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool MoveNext() + { + if (_version != _nativeHashSet._handle->Version) + throw new InvalidOperationException("EnumFailedVersion"); + while ((uint)_index < (uint)_nativeHashSet._handle->Count) + { + ref var entry = ref _nativeHashSet._handle->Entries[_index++]; + if (entry.Next >= -1) + { + _current = entry.Value; + return true; + } + } + + _index = _nativeHashSet._handle->Count + 1; + _current = default; + return false; + } + + /// + /// Current + /// + public T Current + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _current; + } + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeHashSet.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeHashSet.cs.meta new file mode 100644 index 0000000..3efb902 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeHashSet.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8d7a63489e1ec43c4a04d8c8832b7510 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeList.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeList.cs new file mode 100644 index 0000000..e96dc80 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeList.cs @@ -0,0 +1,676 @@ +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +#if UNITY_2021_3_OR_NEWER || GODOT +using System; +#endif + +#pragma warning disable CA2208 +#pragma warning disable CS8632 + +// ReSharper disable ALL + +namespace NativeCollections +{ + /// + /// Native list + /// + /// Type + [StructLayout(LayoutKind.Sequential)] + public readonly unsafe struct NativeList : IDisposable, IEquatable> where T : unmanaged, IEquatable + { + /// + /// Handle + /// + [StructLayout(LayoutKind.Sequential)] + private struct NativeListHandle + { + /// + /// Array + /// + public T* Array; + + /// + /// Length + /// + public int Length; + + /// + /// Size + /// + public int Size; + + /// + /// Version + /// + public int Version; + } + + /// + /// Handle + /// + private readonly NativeListHandle* _handle; + + /// + /// Structure + /// + /// Capacity + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public NativeList(int capacity) + { + if (capacity < 0) + throw new ArgumentOutOfRangeException(nameof(capacity), capacity, "MustBeNonNegative"); + if (capacity < 4) + capacity = 4; + _handle = (NativeListHandle*)NativeMemoryAllocator.Alloc((uint)sizeof(NativeListHandle)); + _handle->Array = (T*)NativeMemoryAllocator.Alloc((uint)(capacity * sizeof(T))); + _handle->Length = capacity; + _handle->Size = 0; + _handle->Version = 0; + } + + /// + /// Is created + /// + public bool IsCreated => _handle != null; + + /// + /// Is empty + /// + public bool IsEmpty => _handle->Size == 0; + + /// + /// Get or set value + /// + /// Index + public ref T this[int index] + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => ref _handle->Array[index]; + } + + /// + /// Get or set value + /// + /// Index + public ref T this[uint index] + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => ref _handle->Array[index]; + } + + /// + /// Count + /// + public int Count => _handle->Size; + + /// + /// Capacity + /// + public int Capacity + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _handle->Length; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + set + { + if (value < _handle->Size) + throw new ArgumentOutOfRangeException(nameof(Capacity), value, "SmallCapacity"); + if (value != _handle->Length) + { + if (value > 0) + { + var newItems = (T*)NativeMemoryAllocator.Alloc((uint)(value * sizeof(T))); + if (_handle->Size > 0) + Unsafe.CopyBlockUnaligned(newItems, _handle->Array, (uint)(_handle->Size * sizeof(T))); + NativeMemoryAllocator.Free(_handle->Array); + _handle->Array = newItems; + _handle->Length = value; + } + else + { + NativeMemoryAllocator.Free(_handle->Array); + _handle->Array = (T*)NativeMemoryAllocator.Alloc(0); + _handle->Length = 0; + } + } + } + } + + /// + /// Equals + /// + /// Other + /// Equals + public bool Equals(NativeList other) => other == this; + + /// + /// Equals + /// + /// object + /// Equals + public override bool Equals(object? obj) => obj is NativeList nativeList && nativeList == this; + + /// + /// Get hashCode + /// + /// HashCode + public override int GetHashCode() => (int)(nint)_handle; + + /// + /// To string + /// + /// String + public override string ToString() => $"NativeList<{typeof(T).Name}>"; + + /// + /// As span + /// + /// Span + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator Span(NativeList nativeList) => nativeList.AsSpan(); + + /// + /// As readOnly span + /// + /// ReadOnlySpan + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator ReadOnlySpan(NativeList nativeList) => nativeList.AsReadOnlySpan(); + + /// + /// Equals + /// + /// Left + /// Right + /// Equals + public static bool operator ==(NativeList left, NativeList right) => left._handle == right._handle; + + /// + /// Not equals + /// + /// Left + /// Right + /// Not equals + public static bool operator !=(NativeList left, NativeList right) => left._handle != right._handle; + + /// + /// Dispose + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Dispose() + { + if (_handle == null) + return; + NativeMemoryAllocator.Free(_handle->Array); + NativeMemoryAllocator.Free(_handle); + } + + /// + /// As span + /// + /// Span + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Span AsSpan() => MemoryMarshal.CreateSpan(ref *_handle->Array, _handle->Length); + + /// + /// As span + /// + /// Length + /// Span + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Span AsSpan(int length) => MemoryMarshal.CreateSpan(ref *_handle->Array, length); + + /// + /// As span + /// + /// Start + /// Length + /// Span + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Span AsSpan(int start, int length) => MemoryMarshal.CreateSpan(ref *(_handle->Array + start), length); + + /// + /// As readOnly span + /// + /// ReadOnlySpan + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public ReadOnlySpan AsReadOnlySpan() => MemoryMarshal.CreateReadOnlySpan(ref *_handle->Array, _handle->Length); + + /// + /// As readOnly span + /// + /// Length + /// ReadOnlySpan + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public ReadOnlySpan AsReadOnlySpan(int length) => MemoryMarshal.CreateReadOnlySpan(ref *_handle->Array, length); + + /// + /// As readOnly span + /// + /// Start + /// Length + /// ReadOnlySpan + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public ReadOnlySpan AsReadOnlySpan(int start, int length) => MemoryMarshal.CreateReadOnlySpan(ref *(_handle->Array + start), length); + + /// + /// Clear + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Clear() + { + _handle->Version++; + _handle->Size = 0; + } + + /// + /// Add + /// + /// Item + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Add(in T item) + { + _handle->Version++; + var size = _handle->Size; + if ((uint)size < (uint)_handle->Length) + { + _handle->Size = size + 1; + _handle->Array[size] = item; + } + else + { + Grow(size + 1); + _handle->Size = size + 1; + _handle->Array[size] = item; + } + } + + /// + /// Add range + /// + /// Collection + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void AddRange(in NativeList collection) + { + var count = collection._handle->Size; + if (count > 0) + { + if (_handle->Length - _handle->Size < count) + Grow(checked(_handle->Size + count)); + Unsafe.CopyBlockUnaligned(_handle->Array + _handle->Size, collection._handle->Array, (uint)(collection._handle->Size * sizeof(T))); + _handle->Size += count; + _handle->Version++; + } + } + + /// + /// Insert + /// + /// Index + /// Item + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Insert(int index, in T item) + { + if ((uint)index > (uint)_handle->Size) + throw new ArgumentOutOfRangeException(nameof(index), index, "ListInsert"); + if (_handle->Size == _handle->Length) + Grow(_handle->Size + 1); + if (index < _handle->Size) + Unsafe.CopyBlockUnaligned(_handle->Array + (index + 1), _handle->Array + index, (uint)((_handle->Size - index) * sizeof(T))); + _handle->Array[index] = item; + _handle->Size++; + _handle->Version++; + } + + /// + /// Insert + /// + /// Index + /// Collection + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void InsertRange(int index, in NativeList collection) + { + if ((uint)index > (uint)_handle->Size) + throw new ArgumentOutOfRangeException(nameof(index), index, "IndexMustBeLessOrEqual"); + var count = collection._handle->Size; + if (count > 0) + { + if (_handle->Length - _handle->Size < count) + Grow(checked(_handle->Size + count)); + if (index < _handle->Size) + Unsafe.CopyBlockUnaligned(_handle->Array + index + count, _handle->Array + index, (uint)((_handle->Size - index) * sizeof(T))); + if (this == collection) + { + Unsafe.CopyBlockUnaligned(_handle->Array + index, _handle->Array, (uint)(index * sizeof(T))); + Unsafe.CopyBlockUnaligned(_handle->Array + index * 2, _handle->Array + index + count, (uint)((_handle->Size - index) * sizeof(T))); + } + else + { + Unsafe.CopyBlockUnaligned(_handle->Array + index, collection._handle->Array, (uint)(collection._handle->Size * sizeof(T))); + } + + _handle->Size += count; + _handle->Version++; + } + } + + /// + /// Remove + /// + /// Item + /// Removed + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool Remove(in T item) + { + var index = IndexOf(item); + if (index >= 0) + { + RemoveAt(index); + return true; + } + + return false; + } + + /// + /// Remove at + /// + /// Index + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void RemoveAt(int index) + { + if ((uint)index >= (uint)_handle->Size) + throw new ArgumentOutOfRangeException(nameof(index), index, "IndexMustBeLess"); + _handle->Size--; + if (index < _handle->Size) + Unsafe.CopyBlockUnaligned(_handle->Array + index, _handle->Array + (index + 1), (uint)((_handle->Size - index) * sizeof(T))); + _handle->Version++; + } + + /// + /// Remove range + /// + /// Index + /// Count + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void RemoveRange(int index, int count) + { + if (index < 0) + throw new ArgumentOutOfRangeException(nameof(index), index, "NeedNonNegNum"); + if (count < 0) + throw new ArgumentOutOfRangeException(nameof(count), count, "NeedNonNegNum"); + var offset = _handle->Size - index; + if (offset < count) + throw new ArgumentOutOfRangeException(offset.ToString(), "InvalidOffLen"); + if (count > 0) + { + _handle->Size -= count; + if (index < _handle->Size) + Unsafe.CopyBlockUnaligned(_handle->Array + index, _handle->Array + (index + count), (uint)((_handle->Size - index) * sizeof(T))); + _handle->Version++; + } + } + + /// + /// Reverse + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Reverse() + { + if (_handle->Size > 1) + MemoryMarshal.CreateSpan(ref *_handle->Array, _handle->Size).Reverse(); + _handle->Version++; + } + + /// + /// Reverse + /// + /// Index + /// Count + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Reverse(int index, int count) + { + if (index < 0) + throw new ArgumentOutOfRangeException(nameof(index), index, "NeedNonNegNum"); + if (count < 0) + throw new ArgumentOutOfRangeException(nameof(count), count, "NeedNonNegNum"); + var offset = _handle->Size - index; + if (offset < count) + throw new ArgumentOutOfRangeException(offset.ToString(), "InvalidOffLen"); + if (count > 1) + MemoryMarshal.CreateSpan(ref *(_handle->Array + index), count).Reverse(); + _handle->Version++; + } + + /// + /// Contains + /// + /// Item + /// Contains + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool Contains(in T item) => _handle->Size != 0 && IndexOf(item) >= 0; + + /// + /// Ensure capacity + /// + /// Capacity + /// New capacity + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public int EnsureCapacity(int capacity) + { + if (capacity < 0) + throw new ArgumentOutOfRangeException(nameof(capacity), capacity, "MustBeNonNegative"); + if (_handle->Length < capacity) + Grow(capacity); + return _handle->Length; + } + + /// + /// Trim excess + /// + /// New capacity + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public int TrimExcess() + { + var threshold = (int)(_handle->Length * 0.9); + if (_handle->Size < threshold) + Capacity = _handle->Size; + return _handle->Length; + } + + /// + /// Grow + /// + /// Capacity + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void Grow(int capacity) + { + var newCapacity = 2 * _handle->Length; + if ((uint)newCapacity > 2147483591) + newCapacity = 2147483591; + var expected = _handle->Length + 4; + newCapacity = newCapacity > expected ? newCapacity : expected; + if (newCapacity < capacity) + newCapacity = capacity; + Capacity = newCapacity; + } + + /// + /// Index of + /// + /// Item + /// Index + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public int IndexOf(in T item) => _handle->Size == 0 ? -1 : MemoryMarshal.CreateReadOnlySpan(ref *_handle->Array, _handle->Size).IndexOf(item); + + /// + /// Index of + /// + /// Item + /// Index + /// Index + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public int IndexOf(in T item, int index) + { + if (_handle->Size == 0) + return -1; + if (index < 0) + throw new ArgumentOutOfRangeException(nameof(index), index, "NeedNonNegNum"); + if (index > _handle->Size) + throw new ArgumentOutOfRangeException(nameof(index), index, "IndexMustBeLessOrEqual"); + return MemoryMarshal.CreateReadOnlySpan(ref *(_handle->Array + index), _handle->Size - index).IndexOf(item); + } + + /// + /// Index of + /// + /// Item + /// Index + /// Count + /// Index + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public int IndexOf(in T item, int index, int count) + { + if (_handle->Size == 0) + return -1; + if (index < 0) + throw new ArgumentOutOfRangeException(nameof(index), index, "NeedNonNegNum"); + if (count < 0) + throw new ArgumentOutOfRangeException(nameof(count), count, "NeedNonNegNum"); + if (index > _handle->Size) + throw new ArgumentOutOfRangeException(nameof(index), index, "IndexMustBeLessOrEqual"); + if (index > _handle->Size - count) + throw new ArgumentOutOfRangeException(nameof(count), count, "BiggerThanCollection"); + return MemoryMarshal.CreateReadOnlySpan(ref *(_handle->Array + index), count).IndexOf(item); + } + + /// + /// Last index of + /// + /// Item + /// Index + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public int LastIndexOf(in T item) => _handle->Size == 0 ? -1 : MemoryMarshal.CreateReadOnlySpan(ref *(_handle->Array + (_handle->Size - 1)), _handle->Size).LastIndexOf(item); + + /// + /// Last index of + /// + /// Item + /// Index + /// Index + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public int LastIndexOf(in T item, int index) + { + if (_handle->Size == 0) + return -1; + if (index < 0) + throw new ArgumentOutOfRangeException(nameof(index), index, "NeedNonNegNum"); + if (index >= _handle->Size) + throw new ArgumentOutOfRangeException(nameof(index), index, "IndexMustBeLess"); + return MemoryMarshal.CreateReadOnlySpan(ref *(_handle->Array + index), index + 1).LastIndexOf(item); + } + + /// + /// Last index of + /// + /// Item + /// Index + /// Count + /// Index + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public int LastIndexOf(in T item, int index, int count) + { + if (_handle->Size == 0) + return -1; + if (index < 0) + throw new ArgumentOutOfRangeException(nameof(index), index, "NeedNonNegNum"); + if (count < 0) + throw new ArgumentOutOfRangeException(nameof(count), count, "NeedNonNegNum"); + if (index >= _handle->Size) + throw new ArgumentOutOfRangeException(nameof(index), index, "BiggerThanCollection"); + if (count > index + 1) + throw new ArgumentOutOfRangeException(nameof(count), count, "BiggerThanCollection"); + return MemoryMarshal.CreateReadOnlySpan(ref *(_handle->Array + index), count).LastIndexOf(item); + } + + /// + /// Empty + /// + public static NativeList Empty => new(); + + /// + /// Get enumerator + /// + /// Enumerator + public Enumerator GetEnumerator() => new(this); + + /// + /// Enumerator + /// + public struct Enumerator + { + /// + /// NativeList + /// + private readonly NativeList _nativeList; + + /// + /// Version + /// + private readonly int _version; + + /// + /// Index + /// + private int _index; + + /// + /// Current + /// + private T _current; + + /// + /// Structure + /// + /// NativeList + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal Enumerator(in NativeList nativeList) + { + _nativeList = nativeList; + _index = 0; + _version = nativeList._handle->Version; + _current = default; + } + + /// + /// Move next + /// + /// Moved + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool MoveNext() + { + var localList = _nativeList; + if (_version == localList._handle->Version && (uint)_index < (uint)localList._handle->Size) + { + _current = localList._handle->Array[_index]; + _index++; + return true; + } + + if (_version != _nativeList._handle->Version) + throw new InvalidOperationException("EnumFailedVersion"); + _index = _nativeList._handle->Size + 1; + _current = default; + return false; + } + + /// + /// Current + /// + public T Current + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _current; + } + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeList.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeList.cs.meta new file mode 100644 index 0000000..a32b82d --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeList.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f1712d881a1474a22b9d27d2835a98c2 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeMemoryAllocator.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeMemoryAllocator.cs new file mode 100644 index 0000000..10986fb --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeMemoryAllocator.cs @@ -0,0 +1,233 @@ +#if UNITY_2021_3_OR_NEWER || GODOT +using System; +#endif + +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +#if NET7_0_OR_GREATER +using System.Runtime.Intrinsics; +#endif + +// ReSharper disable ALL + +namespace NativeCollections +{ + /// + /// Native memory allocator + /// + public static unsafe class NativeMemoryAllocator + { + /// + /// Alloc + /// + /// Byte count + /// Memory + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void* Alloc(uint byteCount) + { +#if NET6_0_OR_GREATER + return NativeMemory.Alloc(byteCount); +#else + return (void*)Marshal.AllocHGlobal((nint)byteCount); +#endif + } + + /// + /// Alloc zeroed + /// + /// Byte count + /// Memory + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void* AllocZeroed(uint byteCount) + { +#if NET6_0_OR_GREATER + return NativeMemory.AllocZeroed(byteCount, 1); +#else + var ptr = (void*)Marshal.AllocHGlobal((nint)byteCount); + Unsafe.InitBlockUnaligned(ptr, 0, byteCount); + return ptr; +#endif + } + + /// + /// Free + /// + /// Pointer + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void Free(void* ptr) + { +#if NET6_0_OR_GREATER + NativeMemory.Free(ptr); +#else + Marshal.FreeHGlobal((nint)ptr); +#endif + } + + /// + /// Copy + /// + /// Destination + /// Source + /// Byte count + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void Copy(void* destination, void* source, uint byteCount) => Unsafe.CopyBlockUnaligned(destination, source, byteCount); + + /// + /// Move + /// + /// Destination + /// Source + /// Byte count + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void Move(void* destination, void* source, uint byteCount) => Buffer.MemoryCopy(source, destination, byteCount, byteCount); + + /// + /// Set + /// + /// Start address + /// Value + /// Byte count + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void Set(void* startAddress, byte value, uint byteCount) => Unsafe.InitBlockUnaligned(startAddress, value, byteCount); + + /// + /// Compare + /// + /// Left + /// Right + /// Byte count + /// Sequences equal + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool Compare(void* left, void* right, uint byteCount) + { + ref var first = ref *(byte*)left; + ref var second = ref *(byte*)right; + nuint length = byteCount; + if (length >= (nuint)sizeof(nuint)) + { + if (!Unsafe.AreSame(ref first, ref second)) + { +#if NET7_0_OR_GREATER + if (Vector128.IsHardwareAccelerated) + { +#if NET8_0_OR_GREATER + if (Vector512.IsHardwareAccelerated && length >= (nuint)Vector512.Count) + { + nuint offset = 0; + var lengthToExamine = length - (nuint)Vector512.Count; + if (lengthToExamine != 0) + { + do + { + if (Vector512.LoadUnsafe(ref first, offset) != Vector512.LoadUnsafe(ref second, offset)) + return false; + offset += (nuint)Vector512.Count; + } while (lengthToExamine > offset); + } + + return Vector512.LoadUnsafe(ref first, lengthToExamine) == Vector512.LoadUnsafe(ref second, lengthToExamine); + } +#endif + if (Vector256.IsHardwareAccelerated && length >= (nuint)Vector256.Count) + { + nuint offset = 0; + var lengthToExamine = length - (nuint)Vector256.Count; + if (lengthToExamine != 0) + { + do + { + if (Vector256.LoadUnsafe(ref first, offset) != Vector256.LoadUnsafe(ref second, offset)) + return false; + offset += (nuint)Vector256.Count; + } while (lengthToExamine > offset); + } + + return Vector256.LoadUnsafe(ref first, lengthToExamine) == Vector256.LoadUnsafe(ref second, lengthToExamine); + } + + if (length >= (nuint)Vector128.Count) + { + nuint offset = 0; + var lengthToExamine = length - (nuint)Vector128.Count; + if (lengthToExamine != 0) + { + do + { + if (Vector128.LoadUnsafe(ref first, offset) != Vector128.LoadUnsafe(ref second, offset)) + return false; + offset += (nuint)Vector128.Count; + } while (lengthToExamine > offset); + } + + return Vector128.LoadUnsafe(ref first, lengthToExamine) == Vector128.LoadUnsafe(ref second, lengthToExamine); + } + } + + if (IntPtr.Size == 8 && Vector128.IsHardwareAccelerated) + { + var offset = length - (nuint)sizeof(nuint); + var differentBits = Unsafe.ReadUnaligned(ref first) - Unsafe.ReadUnaligned(ref second); + differentBits |= Unsafe.ReadUnaligned(ref Unsafe.AddByteOffset(ref first, offset)) - Unsafe.ReadUnaligned(ref Unsafe.AddByteOffset(ref second, offset)); + return differentBits == 0; + } + else +#endif + { + nuint offset = 0; + var lengthToExamine = length - (nuint)sizeof(nuint); + if (lengthToExamine > 0) + { + do + { +#if NET7_0_OR_GREATER + if (Unsafe.ReadUnaligned(ref Unsafe.AddByteOffset(ref first, offset)) != Unsafe.ReadUnaligned(ref Unsafe.AddByteOffset(ref second, offset))) +#else + if (Unsafe.ReadUnaligned(ref Unsafe.AddByteOffset(ref first, (nint)offset)) != Unsafe.ReadUnaligned(ref Unsafe.AddByteOffset(ref second, (nint)offset))) +#endif + return false; + offset += (nuint)sizeof(nuint); + } while (lengthToExamine > offset); + } +#if NET7_0_OR_GREATER + return Unsafe.ReadUnaligned(ref Unsafe.AddByteOffset(ref first, lengthToExamine)) == Unsafe.ReadUnaligned(ref Unsafe.AddByteOffset(ref second, lengthToExamine)); +#else + return Unsafe.ReadUnaligned(ref Unsafe.AddByteOffset(ref first, (nint)lengthToExamine)) == Unsafe.ReadUnaligned(ref Unsafe.AddByteOffset(ref second, (nint)lengthToExamine)); +#endif + } + } + + return true; + } + + if (length < sizeof(uint) || IntPtr.Size != 8) + { + uint differentBits = 0; + var offset = length & 2; + if (offset != 0) + { + differentBits = Unsafe.ReadUnaligned(ref first); + differentBits -= Unsafe.ReadUnaligned(ref second); + } + + if ((length & 1) != 0) +#if NET7_0_OR_GREATER + differentBits |= Unsafe.AddByteOffset(ref first, offset) - (uint)Unsafe.AddByteOffset(ref second, offset); +#else + differentBits |= Unsafe.AddByteOffset(ref first, (nint)offset) - (uint)Unsafe.AddByteOffset(ref second, (nint)offset); +#endif + return differentBits == 0; + } + else + { + var offset = length - sizeof(uint); + var differentBits = Unsafe.ReadUnaligned(ref first) - Unsafe.ReadUnaligned(ref second); +#if NET7_0_OR_GREATER + differentBits |= Unsafe.ReadUnaligned(ref Unsafe.AddByteOffset(ref first, offset)) - Unsafe.ReadUnaligned(ref Unsafe.AddByteOffset(ref second, offset)); +#else + differentBits |= Unsafe.ReadUnaligned(ref Unsafe.AddByteOffset(ref first, (nint)offset)) - Unsafe.ReadUnaligned(ref Unsafe.AddByteOffset(ref second, (nint)offset)); +#endif + return differentBits == 0; + } + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeMemoryAllocator.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeMemoryAllocator.cs.meta new file mode 100644 index 0000000..b33dc5e --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeMemoryAllocator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 13341ceb5e7764b089271e473be432e4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeMemoryArray.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeMemoryArray.cs new file mode 100644 index 0000000..7b1e4dc --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeMemoryArray.cs @@ -0,0 +1,329 @@ +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +#if UNITY_2021_3_OR_NEWER || GODOT +using System; +#endif + +#pragma warning disable CA2208 +#pragma warning disable CS8632 + +// ReSharper disable ALL + +namespace NativeCollections +{ + /// + /// Native memory array + /// + /// Type + [StructLayout(LayoutKind.Sequential)] + public readonly unsafe struct NativeMemoryArray : IDisposable, IEquatable> where T : unmanaged + { + /// + /// Array + /// + private readonly T* _array; + + /// + /// Length + /// + private readonly int _length; + + /// + /// Structure + /// + /// Length + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public NativeMemoryArray(int length) + { + if (length < 0) + throw new ArgumentOutOfRangeException(nameof(length), length, "MustBeNonNegative"); + _array = (T*)NativeMemoryAllocator.Alloc((uint)(length * sizeof(T))); + _length = length; + } + + /// + /// Structure + /// + /// Length + /// Zeroed + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public NativeMemoryArray(int length, bool zeroed) + { + if (length < 0) + throw new ArgumentOutOfRangeException(nameof(length), length, "MustBeNonNegative"); + _array = zeroed ? (T*)NativeMemoryAllocator.AllocZeroed((uint)(length * sizeof(T))) : (T*)NativeMemoryAllocator.Alloc((uint)(length * sizeof(T))); + _length = length; + } + + /// + /// Structure + /// + /// Array + /// Length + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public NativeMemoryArray(T* array, int length) + { + if (length < 0) + throw new ArgumentOutOfRangeException(nameof(length), length, "MustBeNonNegative"); + _array = array; + _length = length; + } + + /// + /// Is created + /// + public bool IsCreated => _array != null; + + /// + /// Is empty + /// + public bool IsEmpty => _length == 0; + + /// + /// Get reference + /// + /// Index + public T* this[int index] + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _array + index; + } + + /// + /// Get reference + /// + /// Index + public T* this[uint index] + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _array + index; + } + + /// + /// Array + /// + public T* Array => _array; + + /// + /// Length + /// + public int Length => _length; + + /// + /// Equals + /// + /// Other + /// Equals + public bool Equals(NativeMemoryArray other) => other == this; + + /// + /// Equals + /// + /// object + /// Equals + public override bool Equals(object? obj) => obj is NativeMemoryArray nativeMemoryArray && nativeMemoryArray == this; + + /// + /// Get hashCode + /// + /// HashCode + public override int GetHashCode() => (int)(nint)_array; + + /// + /// To string + /// + /// String + public override string ToString() => $"NativeMemoryArray<{typeof(T).Name}>[{_length}]"; + + /// + /// As span + /// + /// Span + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator Span(NativeMemoryArray nativeMemoryArray) => nativeMemoryArray.AsSpan(); + + /// + /// As readOnly span + /// + /// ReadOnlySpan + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator ReadOnlySpan(NativeMemoryArray nativeMemoryArray) => nativeMemoryArray.AsReadOnlySpan(); + + /// + /// As native array + /// + /// Native memory array + /// NativeArray + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator NativeArray(NativeMemoryArray nativeMemoryArray) => new(nativeMemoryArray._array, nativeMemoryArray._length); + + /// + /// As native memory array + /// + /// Native array + /// NativeMemoryArray + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator NativeMemoryArray(NativeArray nativeArray) => new(nativeArray.Array, nativeArray.Length); + + /// + /// As native array segment + /// + /// Native memory array + /// NativeArraySegment + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator NativeArraySegment(NativeMemoryArray nativeMemoryArray) => new(nativeMemoryArray._array, nativeMemoryArray._length); + + /// + /// As native memory array + /// + /// Native array segment + /// NativeMemoryArray + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator NativeMemoryArray(NativeArraySegment nativeArraySegment) => new(nativeArraySegment.Array, nativeArraySegment.Offset + nativeArraySegment.Count); + + /// + /// Equals + /// + /// Left + /// Right + /// Equals + public static bool operator ==(NativeMemoryArray left, NativeMemoryArray right) => left._length == right._length && left._array == right._array; + + /// + /// Not equals + /// + /// Left + /// Right + /// Not equals + public static bool operator !=(NativeMemoryArray left, NativeMemoryArray right) => left._length != right._length || left._array != right._array; + + /// + /// Dispose + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Dispose() + { + if (_array == null) + return; + NativeMemoryAllocator.Free(_array); + } + + /// + /// Clear + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Clear() => Unsafe.InitBlockUnaligned(_array, 0, (uint)(_length * sizeof(T))); + + /// + /// As span + /// + /// Span + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Span AsSpan() => MemoryMarshal.CreateSpan(ref *_array, _length); + + /// + /// As span + /// + /// Length + /// Span + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Span AsSpan(int length) => MemoryMarshal.CreateSpan(ref *_array, length); + + /// + /// As span + /// + /// Start + /// Length + /// Span + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Span AsSpan(int start, int length) => MemoryMarshal.CreateSpan(ref *(_array + start), length); + + /// + /// As readOnly span + /// + /// ReadOnlySpan + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public ReadOnlySpan AsReadOnlySpan() => MemoryMarshal.CreateReadOnlySpan(ref *_array, _length); + + /// + /// As readOnly span + /// + /// Length + /// ReadOnlySpan + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public ReadOnlySpan AsReadOnlySpan(int length) => MemoryMarshal.CreateReadOnlySpan(ref *_array, length); + + /// + /// As readOnly span + /// + /// Start + /// Length + /// ReadOnlySpan + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public ReadOnlySpan AsReadOnlySpan(int start, int length) => MemoryMarshal.CreateReadOnlySpan(ref *(_array + start), length); + + /// + /// Empty + /// + public static NativeMemoryArray Empty => new(); + + /// + /// Get enumerator + /// + /// Enumerator + public Enumerator GetEnumerator() => new(this); + + /// + /// Enumerator + /// + public ref struct Enumerator + { + /// + /// NativeMemoryArray + /// + private readonly NativeMemoryArray _nativeMemoryArray; + + /// + /// Index + /// + private int _index; + + /// + /// Structure + /// + /// NativeMemoryArray + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal Enumerator(NativeMemoryArray nativeMemoryArray) + { + _nativeMemoryArray = nativeMemoryArray; + _index = -1; + } + + /// + /// Move next + /// + /// Moved + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool MoveNext() + { + var index = _index + 1; + if (index < _nativeMemoryArray._length) + { + _index = index; + return true; + } + + return false; + } + + /// + /// Current + /// + public T* Current + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _nativeMemoryArray[_index]; + } + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeMemoryArray.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeMemoryArray.cs.meta new file mode 100644 index 0000000..0b10862 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeMemoryArray.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d91ae680ac25348b7baebf74f9f91122 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeMemoryBucket.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeMemoryBucket.cs new file mode 100644 index 0000000..01b8d60 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeMemoryBucket.cs @@ -0,0 +1,199 @@ +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +#if UNITY_2021_3_OR_NEWER || GODOT +using System; +#endif + +#pragma warning disable CA2208 +#pragma warning disable CS8632 + +// ReSharper disable ALL + +namespace NativeCollections +{ + /// + /// Native memory bucket + /// + [StructLayout(LayoutKind.Sequential)] + public readonly unsafe struct NativeMemoryBucket : IDisposable, IEquatable + { + /// + /// Handle + /// + [StructLayout(LayoutKind.Sequential)] + private struct NativeMemoryBucketHandle + { + /// + /// Size + /// + public int Size; + + /// + /// Length + /// + public int Length; + + /// + /// Array + /// + public void** Array; + + /// + /// Index + /// + public int Index; + + /// + /// Memory pool + /// + public NativeMemoryPool MemoryPool; + } + + /// + /// Handle + /// + private readonly NativeMemoryBucketHandle* _handle; + + /// + /// Structure + /// + /// Size + /// Length + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public NativeMemoryBucket(int size, int length) + { + if (size <= 0) + throw new ArgumentOutOfRangeException(nameof(size), size, "MustBePositive"); + if (length < 0) + throw new ArgumentOutOfRangeException(nameof(length), length, "MustBeNonNegative"); + _handle = (NativeMemoryBucketHandle*)NativeMemoryAllocator.Alloc((uint)sizeof(NativeMemoryBucketHandle)); + _handle->Size = size; + _handle->Length = length; + _handle->Array = (void**)NativeMemoryAllocator.AllocZeroed((uint)(size * sizeof(void*))); + _handle->Index = 0; + _handle->MemoryPool = new NativeMemoryPool(size, length, 0); + } + + /// + /// Is created + /// + public bool IsCreated => _handle != null; + + /// + /// Is empty + /// + public bool IsEmpty => _handle->Index == 0; + + /// + /// Is full + /// + public bool IsFull => _handle->Index == _handle->Size; + + /// + /// Size + /// + public int Size => _handle->Size; + + /// + /// Length + /// + public int Length => _handle->Length; + + /// + /// Count + /// + public int Count => _handle->Index; + + /// + /// Equals + /// + /// Other + /// Equals + public bool Equals(NativeMemoryBucket other) => other == this; + + /// + /// Equals + /// + /// object + /// Equals + public override bool Equals(object? obj) => obj is NativeMemoryBucket nativeMemoryBucket && nativeMemoryBucket == this; + + /// + /// Get hashCode + /// + /// HashCode + public override int GetHashCode() => (int)(nint)_handle; + + /// + /// To string + /// + /// String + public override string ToString() => "NativeMemoryBucket"; + + /// + /// Equals + /// + /// Left + /// Right + /// Equals + public static bool operator ==(NativeMemoryBucket left, NativeMemoryBucket right) => left._handle == right._handle; + + /// + /// Not equals + /// + /// Left + /// Right + /// Not equals + public static bool operator !=(NativeMemoryBucket left, NativeMemoryBucket right) => left._handle != right._handle; + + /// + /// Dispose + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Dispose() + { + if (_handle == null) + return; + NativeMemoryAllocator.Free(_handle->Array); + _handle->MemoryPool.Dispose(); + NativeMemoryAllocator.Free(_handle); + } + + /// + /// Rent buffer + /// + /// Buffer + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void* Rent() + { + void* buffer = null; + if (_handle->Index < _handle->Size) + { + buffer = _handle->Array[_handle->Index]; + _handle->Array[_handle->Index++] = null; + } + + if (buffer == null) + buffer = _handle->MemoryPool.Rent(); + return buffer; + } + + /// + /// Return buffer + /// + /// Pointer + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Return(void* ptr) + { + if (_handle->Index != 0) + _handle->Array[--_handle->Index] = ptr; + else + _handle->MemoryPool.Return(ptr); + } + + /// + /// Empty + /// + public static NativeMemoryBucket Empty => new(); + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeMemoryBucket.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeMemoryBucket.cs.meta new file mode 100644 index 0000000..4066561 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeMemoryBucket.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3fda080db31784f1d9266b8edc496b07 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeMemoryPool.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeMemoryPool.cs new file mode 100644 index 0000000..2c009cf --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeMemoryPool.cs @@ -0,0 +1,388 @@ +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +#if UNITY_2021_3_OR_NEWER || GODOT +using System; +#endif + +#pragma warning disable CA2208 +#pragma warning disable CS8632 + +// ReSharper disable ALL + +namespace NativeCollections +{ + /// + /// Native memory pool + /// + [StructLayout(LayoutKind.Sequential)] + public readonly unsafe struct NativeMemoryPool : IDisposable, IEquatable + { + /// + /// Handle + /// + [StructLayout(LayoutKind.Sequential)] + private struct NativeMemoryPoolHandle + { + /// + /// Slab + /// + public NativeMemorySlab* Slab; + + /// + /// Free slab + /// + public NativeMemorySlab* FreeSlab; + + /// + /// Slabs + /// + public int Slabs; + + /// + /// Free slabs + /// + public int FreeSlabs; + + /// + /// Max free slabs + /// + public int MaxFreeSlabs; + + /// + /// Size + /// + public int Size; + + /// + /// Length + /// + public int Length; + } + + /// + /// Slab + /// + [StructLayout(LayoutKind.Sequential)] + private struct NativeMemorySlab + { + /// + /// Next + /// + public NativeMemorySlab* Next; + + /// + /// Previous + /// + public NativeMemorySlab* Previous; + + /// + /// Node + /// + public NativeMemoryNode* Node; + + /// + /// Count + /// + public int Count; + } + + /// + /// Node + /// + [StructLayout(LayoutKind.Explicit)] + private struct NativeMemoryNode + { + /// + /// Slab + /// + [FieldOffset(0)] public NativeMemorySlab* Slab; + + /// + /// Next + /// + [FieldOffset(0)] public NativeMemoryNode* Next; + } + + /// + /// Handle + /// + private readonly NativeMemoryPoolHandle* _handle; + + /// + /// Structure + /// + /// Size + /// Length + /// Max free slabs + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public NativeMemoryPool(int size, int length, int maxFreeSlabs) + { + if (size <= 0) + throw new ArgumentOutOfRangeException(nameof(size), size, "MustBePositive"); + if (length < 0) + throw new ArgumentOutOfRangeException(nameof(length), length, "MustBeNonNegative"); + if (maxFreeSlabs < 0) + throw new ArgumentOutOfRangeException(nameof(maxFreeSlabs), maxFreeSlabs, "MustBeNonNegative"); + var nodeSize = sizeof(NativeMemoryNode) + length; + var array = (byte*)NativeMemoryAllocator.Alloc((uint)(sizeof(NativeMemorySlab) + size * nodeSize)); + var slab = (NativeMemorySlab*)array; + slab->Next = slab; + slab->Previous = slab; + array += sizeof(NativeMemorySlab); + NativeMemoryNode* next = null; + for (var i = size - 1; i >= 0; --i) + { + var node = (NativeMemoryNode*)(array + i * nodeSize); + node->Next = next; + next = node; + } + + slab->Node = next; + slab->Count = size; + _handle = (NativeMemoryPoolHandle*)NativeMemoryAllocator.Alloc((uint)sizeof(NativeMemoryPoolHandle)); + _handle->Slab = slab; + _handle->FreeSlab = null; + _handle->Slabs = 1; + _handle->FreeSlabs = 0; + _handle->MaxFreeSlabs = maxFreeSlabs; + _handle->Size = size; + _handle->Length = length; + } + + /// + /// Is created + /// + public bool IsCreated => _handle != null; + + /// + /// Slabs + /// + public int Slabs => _handle->Slabs; + + /// + /// Free slabs + /// + public int FreeSlabs => _handle->FreeSlabs; + + /// + /// Max free slabs + /// + public int MaxFreeSlabs => _handle->MaxFreeSlabs; + + /// + /// Size + /// + public int Size => _handle->Size; + + /// + /// Length + /// + public int Length => _handle->Length; + + /// + /// Equals + /// + /// Other + /// Equals + public bool Equals(NativeMemoryPool other) => other == this; + + /// + /// Equals + /// + /// object + /// Equals + public override bool Equals(object? obj) => obj is NativeMemoryPool nativeMemoryPool && nativeMemoryPool == this; + + /// + /// Get hashCode + /// + /// HashCode + public override int GetHashCode() => (int)(nint)_handle; + + /// + /// To string + /// + /// String + public override string ToString() => "NativeMemoryPool"; + + /// + /// Equals + /// + /// Left + /// Right + /// Equals + public static bool operator ==(NativeMemoryPool left, NativeMemoryPool right) => left._handle == right._handle; + + /// + /// Not equals + /// + /// Left + /// Right + /// Not equals + public static bool operator !=(NativeMemoryPool left, NativeMemoryPool right) => left._handle != right._handle; + + /// + /// Dispose + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Dispose() + { + if (_handle == null) + return; + var node = _handle->Slab; + while (_handle->Slabs > 0) + { + _handle->Slabs--; + var temp = node; + node = node->Next; + NativeMemoryAllocator.Free(temp); + } + + node = _handle->FreeSlab; + while (_handle->FreeSlabs > 0) + { + _handle->FreeSlabs--; + var temp = node; + node = node->Next; + NativeMemoryAllocator.Free(temp); + } + + NativeMemoryAllocator.Free(_handle); + } + + /// + /// Rent buffer + /// + /// Buffer + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void* Rent() + { + NativeMemoryNode* node; + var slab = _handle->Slab; + if (slab->Count == 0) + { + _handle->Slab = slab->Next; + slab = _handle->Slab; + if (slab->Count == 0) + { + var size = _handle->Size; + if (_handle->FreeSlabs == 0) + { + var nodeSize = sizeof(NativeMemoryNode) + _handle->Length; + var array = (byte*)NativeMemoryAllocator.Alloc((uint)(sizeof(NativeMemorySlab) + size * nodeSize)); + slab = (NativeMemorySlab*)array; + array += sizeof(NativeMemorySlab); + NativeMemoryNode* next = null; + for (var i = size - 1; i >= 0; --i) + { + node = (NativeMemoryNode*)(array + i * nodeSize); + node->Next = next; + next = node; + } + + slab->Node = next; + } + else + { + slab = _handle->FreeSlab; + _handle->FreeSlab = slab->Next; + _handle->FreeSlabs--; + } + + slab->Next = _handle->Slab; + slab->Previous = _handle->Slab->Previous; + slab->Count = size; + _handle->Slab->Previous->Next = slab; + _handle->Slab->Previous = slab; + _handle->Slab = slab; + _handle->Slabs++; + } + } + + node = slab->Node; + slab->Node = node->Next; + node->Slab = slab; + slab->Count--; + return (byte*)node + sizeof(NativeMemoryNode); + } + + /// + /// Return buffer + /// + /// Pointer + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Return(void* ptr) + { + var node = (NativeMemoryNode*)((byte*)ptr - sizeof(NativeMemoryNode)); + var slab = node->Slab; + slab->Count++; + if (slab->Count == _handle->Size && slab != _handle->Slab) + { + slab->Previous->Next = slab->Next; + slab->Next->Previous = slab->Previous; + if (_handle->FreeSlabs == _handle->MaxFreeSlabs) + { + NativeMemoryAllocator.Free(slab); + } + else + { + node->Next = slab->Node; + slab->Node = node; + slab->Next = _handle->FreeSlab; + _handle->FreeSlab = slab; + _handle->FreeSlabs++; + } + + _handle->Slabs--; + return; + } + + node->Next = slab->Node; + slab->Node = node; + } + + /// + /// Trim excess + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void TrimExcess() + { + var node = _handle->FreeSlab; + while (_handle->FreeSlabs > 0) + { + _handle->FreeSlabs--; + var temp = node; + node = node->Next; + NativeMemoryAllocator.Free(temp); + } + + _handle->FreeSlab = node; + } + + /// + /// Trim excess + /// + /// Remaining free slabs + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void TrimExcess(int capacity) + { + if (capacity < 0) + throw new ArgumentOutOfRangeException(nameof(capacity), capacity, "MustBeNonNegative"); + var node = _handle->FreeSlab; + while (_handle->FreeSlabs > capacity) + { + _handle->FreeSlabs--; + var temp = node; + node = node->Next; + NativeMemoryAllocator.Free(temp); + } + + _handle->FreeSlab = node; + } + + /// + /// Empty + /// + public static NativeMemoryPool Empty => new(); + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeMemoryPool.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeMemoryPool.cs.meta new file mode 100644 index 0000000..a606ec9 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeMemoryPool.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 837e2433d114643ffb141887b424283e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeMemoryReader.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeMemoryReader.cs new file mode 100644 index 0000000..3ca294a --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeMemoryReader.cs @@ -0,0 +1,274 @@ +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +#if UNITY_2021_3_OR_NEWER || GODOT +using System; +#endif + +#pragma warning disable CA2208 +#pragma warning disable CS8632 + +// ReSharper disable ALL + +namespace NativeCollections +{ + /// + /// Native memory reader + /// + [StructLayout(LayoutKind.Sequential)] + public unsafe ref struct NativeMemoryReader + { + /// + /// Array + /// + public readonly byte* Array; + + /// + /// Length + /// + public readonly int Length; + + /// + /// Position + /// + public int Position; + + /// + /// Structure + /// + /// Array + /// Length + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public NativeMemoryReader(byte* array, int length) + { + if (length < 0) + throw new ArgumentOutOfRangeException(nameof(length), length, "MustBeNonNegative"); + Array = array; + Length = length; + Position = 0; + } + + /// + /// Remaining + /// + public int Remaining => Length - Position; + + /// + /// Get reference + /// + /// Index + public byte* this[int index] + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => Array + index; + } + + /// + /// Get reference + /// + /// Index + public byte* this[uint index] + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => Array + index; + } + + /// + /// Equals + /// + /// Other + /// Equals + public bool Equals(NativeMemoryReader other) => other == this; + + /// + /// Equals + /// + /// object + /// Equals + public override bool Equals(object? obj) => throw new NotSupportedException("Cannot call Equals on NativeMemoryReader"); + + /// + /// Get hashCode + /// + /// HashCode + public override int GetHashCode() => HashCode.Combine((int)(nint)Array, Length, Position); + + /// + /// To string + /// + /// String + public override string ToString() => "NativeMemoryReader"; + + /// + /// Equals + /// + /// Left + /// Right + /// Equals + public static bool operator ==(NativeMemoryReader left, NativeMemoryReader right) => left.Array == right.Array && left.Length == right.Length && left.Position == right.Position; + + /// + /// Not equals + /// + /// Left + /// Right + /// Not equals + public static bool operator !=(NativeMemoryReader left, NativeMemoryReader right) => left.Array != right.Array || left.Length != right.Length || left.Position != right.Position; + + /// + /// Advance + /// + /// Count + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Advance(int count) + { + var newPosition = Position + count; + if (newPosition < 0 || newPosition > Length) + throw new ArgumentOutOfRangeException(nameof(count), "Cannot advance past the end of the buffer."); + Position = newPosition; + } + + /// + /// Try advance + /// + /// Count + /// Advanced + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool TryAdvance(int count) + { + var newPosition = Position + count; + if (newPosition < 0 || newPosition > Length) + return false; + Position = newPosition; + return true; + } + + /// + /// Read + /// + /// object + /// Type + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Read(T* obj) where T : unmanaged + { + if (Position + sizeof(T) > Length) + throw new ArgumentOutOfRangeException(nameof(T), $"Requires size is {sizeof(T)}, but buffer length is {Remaining}."); + Unsafe.CopyBlockUnaligned(obj, Array + Position, (uint)sizeof(T)); + Position += sizeof(T); + } + + /// + /// Try read + /// + /// object + /// Type + /// Read + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool TryRead(T* obj) where T : unmanaged + { + if (Position + sizeof(T) > Length) + return false; + Unsafe.CopyBlockUnaligned(obj, Array + Position, (uint)sizeof(T)); + Position += sizeof(T); + return true; + } + + /// + /// Read + /// + /// object + /// Count + /// Type + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Read(T* obj, int count) where T : unmanaged + { + count *= sizeof(T); + if (Position + count > Length) + throw new ArgumentOutOfRangeException(nameof(T), $"Requires size is {count}, but buffer length is {Remaining}."); + Unsafe.CopyBlockUnaligned(obj, Array + Position, (uint)count); + Position += count; + } + + /// + /// Try read + /// + /// object + /// Count + /// Type + /// Read + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool TryRead(T* obj, int count) where T : unmanaged + { + count *= sizeof(T); + if (Position + count > Length) + return false; + Unsafe.CopyBlockUnaligned(obj, Array + Position, (uint)count); + Position += count; + return true; + } + + /// + /// Read + /// + /// object + /// Type + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Read(ref T obj) where T : unmanaged + { + if (Position + sizeof(T) > Length) + throw new ArgumentOutOfRangeException(nameof(T), $"Requires size is {sizeof(T)}, but buffer length is {Remaining}."); + obj = Unsafe.ReadUnaligned(Array + Position); + Position += sizeof(T); + } + + /// + /// Try read + /// + /// object + /// Type + /// Read + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool TryRead(ref T obj) where T : unmanaged + { + if (Position + sizeof(T) > Length) + return false; + obj = Unsafe.ReadUnaligned(Array + Position); + Position += sizeof(T); + return true; + } + + /// + /// Read bytes + /// + /// Buffer + /// Length + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ReadBytes(byte* buffer, int length) + { + if (Position + length > Length) + throw new ArgumentOutOfRangeException(nameof(length), $"Requires size is {length}, but buffer length is {Remaining}."); + Unsafe.CopyBlockUnaligned(buffer, Array + Position, (uint)length); + Position += length; + } + + /// + /// Try read bytes + /// + /// Buffer + /// Length + /// Read + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool TryReadBytes(byte* buffer, int length) + { + if (Position + length > Length) + return false; + Unsafe.CopyBlockUnaligned(buffer, Array + Position, (uint)length); + Position += length; + return true; + } + + /// + /// Empty + /// + public static NativeMemoryReader Empty => new(); + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeMemoryReader.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeMemoryReader.cs.meta new file mode 100644 index 0000000..ba11c80 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeMemoryReader.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2c2689961a97f4777976aa6ac8bf9071 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeMemoryReaderExtensions.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeMemoryReaderExtensions.cs new file mode 100644 index 0000000..c38538e --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeMemoryReaderExtensions.cs @@ -0,0 +1,55 @@ +using System.Runtime.CompilerServices; +#if UNITY_2021_3_OR_NEWER || GODOT +using System; +#endif + +#pragma warning disable CA2208 +#pragma warning disable CS8632 + +// ReSharper disable ALL + +namespace NativeCollections +{ + /// + /// Native memory reader extensions + /// + public static unsafe class NativeMemoryReaderExtensions + { + /// + /// Read + /// + /// Reader + /// Type + /// object + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static T Read(this ref NativeMemoryReader reader) where T : unmanaged + { + if (reader.Position + sizeof(T) > reader.Length) + throw new ArgumentOutOfRangeException(nameof(T), $"Requires size is {sizeof(T)}, but buffer length is {reader.Remaining}."); + var obj = Unsafe.ReadUnaligned(reader.Array + reader.Position); + reader.Position += sizeof(T); + return obj; + } + + /// + /// Try read + /// + /// Reader + /// object + /// Type + /// Read + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool TryRead(this ref NativeMemoryReader reader, out T obj) where T : unmanaged + { + if (reader.Position + sizeof(T) > reader.Length) + { + obj = default; + return false; + } + + obj = Unsafe.ReadUnaligned(reader.Array + reader.Position); + reader.Position += sizeof(T); + return true; + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeMemoryReaderExtensions.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeMemoryReaderExtensions.cs.meta new file mode 100644 index 0000000..e4c7dd7 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeMemoryReaderExtensions.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2fdfdaa2ada744fb89338cd5acdfbf32 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeMemoryStream.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeMemoryStream.cs new file mode 100644 index 0000000..81c3ef1 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeMemoryStream.cs @@ -0,0 +1,571 @@ +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +#if UNITY_2021_3_OR_NEWER || GODOT +using System; +using System.IO; +#endif + +#pragma warning disable CA2208 +#pragma warning disable CS8632 + +// ReSharper disable ALL + +namespace NativeCollections +{ + /// + /// Native memory stream + /// + [StructLayout(LayoutKind.Sequential)] + public unsafe struct NativeMemoryStream : IDisposable, IEquatable + { + /// + /// Handle + /// + [StructLayout(LayoutKind.Sequential)] + private struct NativeMemoryStreamHandle + { + /// + /// Array + /// + public byte* Array; + + /// + /// Position + /// + public int Position; + + /// + /// Length + /// + public int Length; + + /// + /// Capacity + /// + public int Capacity; + } + + /// + /// Handle + /// + private readonly NativeMemoryStreamHandle* _handle; + + /// + /// Structure + /// + /// Capacity + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public NativeMemoryStream(int capacity) + { + if (capacity < 0) + throw new ArgumentOutOfRangeException(nameof(capacity), capacity, "MustBeNonNegative"); + if (capacity < 4) + capacity = 4; + _handle = (NativeMemoryStreamHandle*)NativeMemoryAllocator.Alloc((uint)sizeof(NativeMemoryStreamHandle)); + _handle->Array = (byte*)NativeMemoryAllocator.Alloc((uint)capacity); + _handle->Position = 0; + _handle->Length = 0; + _handle->Capacity = capacity; + } + + /// + /// Is created + /// + public bool IsCreated => _handle != null; + + /// + /// Is empty + /// + public bool IsEmpty => _handle->Length == 0; + + /// + /// Get reference + /// + /// Index + public ref byte this[int index] + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => ref _handle->Array[index]; + } + + /// + /// Get reference + /// + /// Index + public ref byte this[uint index] + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => ref _handle->Array[index]; + } + + /// + /// Can read + /// + public bool CanRead => IsCreated; + + /// + /// Can seek + /// + public bool CanSeek => IsCreated; + + /// + /// Can write + /// + public bool CanWrite => IsCreated; + + /// + /// Length + /// + public int Length + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get + { + EnsureNotClosed(); + return _handle->Length; + } + } + + /// + /// Position + /// + public int Position + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get + { + EnsureNotClosed(); + return _handle->Position; + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + set + { + if (value < 0) + throw new ArgumentOutOfRangeException(nameof(Position), value, "MustBeNonNegative"); + EnsureNotClosed(); + _handle->Position = value; + } + } + + /// + /// Capacity + /// + public int Capacity + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get + { + EnsureNotClosed(); + return _handle->Capacity; + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + set + { + EnsureNotClosed(); + if (value < _handle->Length) + throw new ArgumentOutOfRangeException(nameof(Capacity), value, "SmallCapacity"); + if (value != _handle->Capacity) + { + if (value > 0) + { + var newBuffer = (byte*)NativeMemoryAllocator.Alloc((uint)value); + if (_handle->Length > 0) + Unsafe.CopyBlockUnaligned(newBuffer, _handle->Array, (uint)_handle->Length); + NativeMemoryAllocator.Free(_handle->Array); + _handle->Array = newBuffer; + } + else + { + NativeMemoryAllocator.Free(_handle->Array); + _handle->Array = (byte*)NativeMemoryAllocator.Alloc(0); + } + + _handle->Capacity = value; + } + } + } + + /// + /// Equals + /// + /// Other + /// Equals + public bool Equals(NativeMemoryStream other) => other == this; + + /// + /// Equals + /// + /// object + /// Equals + public override bool Equals(object? obj) => obj is NativeMemoryStream nativeMemoryStream && nativeMemoryStream == this; + + /// + /// Get hashCode + /// + /// HashCode + public override int GetHashCode() => (int)(nint)_handle; + + /// + /// To string + /// + /// String + public override string ToString() => $"NativeMemoryStream<{_handle->Length}>"; + + /// + /// As span + /// + /// Span + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator Span(NativeMemoryStream nativeList) => nativeList.AsSpan(); + + /// + /// As readOnly span + /// + /// ReadOnlySpan + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator ReadOnlySpan(NativeMemoryStream nativeList) => nativeList.AsReadOnlySpan(); + + /// + /// Equals + /// + /// Left + /// Right + /// Equals + public static bool operator ==(NativeMemoryStream left, NativeMemoryStream right) => left._handle == right._handle; + + /// + /// Not equals + /// + /// Left + /// Right + /// Not equals + public static bool operator !=(NativeMemoryStream left, NativeMemoryStream right) => left._handle != right._handle; + + /// + /// Dispose + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Dispose() + { + if (_handle == null) + return; + NativeMemoryAllocator.Free(_handle->Array); + NativeMemoryAllocator.Free(_handle); + } + + /// + /// As span + /// + /// Span + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Span AsSpan() => MemoryMarshal.CreateSpan(ref *_handle->Array, _handle->Length); + + /// + /// As span + /// + /// Length + /// Span + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Span AsSpan(int length) => MemoryMarshal.CreateSpan(ref *_handle->Array, length); + + /// + /// As span + /// + /// Start + /// Length + /// Span + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Span AsSpan(int start, int length) => MemoryMarshal.CreateSpan(ref *(_handle->Array + start), length); + + /// + /// As readOnly span + /// + /// ReadOnlySpan + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public ReadOnlySpan AsReadOnlySpan() => MemoryMarshal.CreateReadOnlySpan(ref *_handle->Array, _handle->Length); + + /// + /// As readOnly span + /// + /// Length + /// ReadOnlySpan + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public ReadOnlySpan AsReadOnlySpan(int length) => MemoryMarshal.CreateReadOnlySpan(ref *_handle->Array, length); + + /// + /// As readOnly span + /// + /// Start + /// Length + /// ReadOnlySpan + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public ReadOnlySpan AsReadOnlySpan(int start, int length) => MemoryMarshal.CreateReadOnlySpan(ref *(_handle->Array + start), length); + + /// + /// Get buffer + /// + /// Buffer + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public byte* GetBuffer() => _handle->Array; + + /// + /// Seek + /// + /// Offset + /// Seek origin + /// Position + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public int Seek(int offset, SeekOrigin loc) + { + if (offset > 2147483647) + throw new ArgumentOutOfRangeException(nameof(offset), offset, "StreamLength"); + EnsureNotClosed(); + switch (loc) + { + case SeekOrigin.Begin: + { + if (offset < 0) + throw new IOException("IO_SeekBeforeBegin"); + _handle->Position = offset; + break; + } + case SeekOrigin.Current: + { + var tempPosition = unchecked(_handle->Position + offset); + if (tempPosition < 0) + throw new IOException("IO_SeekBeforeBegin"); + _handle->Position = tempPosition; + break; + } + case SeekOrigin.End: + { + var tempPosition = unchecked(_handle->Length + offset); + if (tempPosition < 0) + throw new IOException("IO_SeekBeforeBegin"); + _handle->Position = tempPosition; + break; + } + default: + throw new ArgumentException("InvalidSeekOrigin"); + } + + return _handle->Position; + } + + /// + /// Set length + /// + /// Length + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void SetLength(int length) + { + if (length < 0 || length > 2147483647) + throw new ArgumentOutOfRangeException(nameof(length), length, "StreamLength"); + EnsureNotClosed(); + var allocatedNewArray = EnsureCapacity(length); + if (!allocatedNewArray && length > _handle->Length) + Unsafe.InitBlock(_handle->Array + _handle->Length, 0, (uint)(length - _handle->Length)); + _handle->Length = length; + if (_handle->Position > length) + _handle->Position = length; + } + + /// + /// Read + /// + /// Buffer + /// Offset + /// Count + /// Bytes + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public int Read(byte* buffer, int offset, int count) + { + EnsureNotClosed(); + var n = _handle->Length - _handle->Position; + if (n > count) + n = count; + if (n <= 0) + return 0; + if (n <= 8) + { + var byteCount = n; + while (--byteCount >= 0) + buffer[offset + byteCount] = _handle->Array[_handle->Position + byteCount]; + } + else + { + Unsafe.CopyBlockUnaligned(buffer + offset, _handle->Array + _handle->Position, (uint)n); + } + + _handle->Position += n; + return n; + } + + /// + /// Read + /// + /// Buffer + /// Bytes + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public int Read(Span buffer) + { + EnsureNotClosed(); + var size = _handle->Length - _handle->Position; + var n = size < buffer.Length ? size : buffer.Length; + if (n <= 0) + return 0; + Unsafe.CopyBlockUnaligned(ref buffer[0], ref *(_handle->Array + _handle->Position), (uint)n); + _handle->Position += n; + return n; + } + + /// + /// Read + /// + /// Byte + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public int ReadByte() + { + EnsureNotClosed(); + return _handle->Position >= _handle->Length ? -1 : _handle->Array[_handle->Position++]; + } + + /// + /// Write + /// + /// Buffer + /// Offset + /// Count + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Write(byte* buffer, int offset, int count) + { + EnsureNotClosed(); + var i = _handle->Position + count; + if (i < 0) + throw new IOException("IO_StreamTooLong"); + if (i > _handle->Length) + { + var mustZero = _handle->Position > _handle->Length; + if (i > _handle->Capacity) + { + var allocatedNewArray = EnsureCapacity(i); + if (allocatedNewArray) + mustZero = false; + } + + if (mustZero) + Unsafe.InitBlock(_handle->Array + _handle->Length, 0, (uint)(i - _handle->Length)); + _handle->Length = i; + } + + if (count <= 8 && buffer != _handle->Array) + { + var byteCount = count; + while (--byteCount >= 0) + _handle->Array[_handle->Position + byteCount] = buffer[offset + byteCount]; + } + else + { + Unsafe.CopyBlockUnaligned(_handle->Array + _handle->Position, buffer + offset, (uint)count); + } + + _handle->Position = i; + } + + /// + /// Write + /// + /// Buffer + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Write(ReadOnlySpan buffer) + { + EnsureNotClosed(); + var i = _handle->Position + buffer.Length; + if (i < 0) + throw new IOException("IO_StreamTooLong"); + if (i > _handle->Length) + { + var mustZero = _handle->Position > _handle->Length; + if (i > _handle->Capacity) + { + var allocatedNewArray = EnsureCapacity(i); + if (allocatedNewArray) + mustZero = false; + } + + if (mustZero) + Unsafe.InitBlock(_handle->Array + _handle->Length, 0, (uint)(i - _handle->Length)); + _handle->Length = i; + } + + Unsafe.CopyBlockUnaligned(ref *(_handle->Array + _handle->Position), ref MemoryMarshal.GetReference(buffer), (uint)buffer.Length); + _handle->Position = i; + } + + /// + /// Write + /// + /// Byte + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void WriteByte(byte value) + { + EnsureNotClosed(); + if (_handle->Position >= _handle->Length) + { + var newLength = _handle->Position + 1; + var mustZero = _handle->Position > _handle->Length; + if (newLength >= _handle->Capacity) + { + var allocatedNewArray = EnsureCapacity(newLength); + if (allocatedNewArray) + mustZero = false; + } + + if (mustZero) + Unsafe.InitBlock(_handle->Array + _handle->Length, 0, (uint)(_handle->Position - _handle->Length)); + _handle->Length = newLength; + } + + _handle->Array[_handle->Position++] = value; + } + + /// + /// Ensure capacity + /// + /// Capacity + /// Ensured + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private bool EnsureCapacity(int capacity) + { + if (capacity < 0) + throw new IOException("IO_StreamTooLong"); + if (capacity > _handle->Capacity) + { + var newCapacity = capacity > 256 ? capacity : 256; + if (newCapacity < _handle->Capacity * 2) + newCapacity = _handle->Capacity * 2; + if ((uint)(_handle->Capacity * 2) > 2147483591) + newCapacity = capacity > 2147483591 ? capacity : 2147483591; + Capacity = newCapacity; + return true; + } + + return false; + } + + /// + /// Ensure not closed + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void EnsureNotClosed() + { + if (_handle == null) + throw new ObjectDisposedException("StreamClosed"); + } + + /// + /// Empty + /// + public static NativeMemoryStream Empty => new(); + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeMemoryStream.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeMemoryStream.cs.meta new file mode 100644 index 0000000..1045fa2 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeMemoryStream.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: bff85e1a03f9b4975812b50ae0c6f48b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeMemoryWriter.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeMemoryWriter.cs new file mode 100644 index 0000000..e5b8e20 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeMemoryWriter.cs @@ -0,0 +1,370 @@ +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +#if UNITY_2021_3_OR_NEWER || GODOT +using System; +#endif + +#pragma warning disable CA2208 +#pragma warning disable CS8632 + +// ReSharper disable ALL + +namespace NativeCollections +{ + /// + /// Native memory writer + /// + [StructLayout(LayoutKind.Sequential)] + public unsafe ref struct NativeMemoryWriter + { + /// + /// Array + /// + public readonly byte* Array; + + /// + /// Length + /// + public readonly int Length; + + /// + /// Position + /// + public int Position; + + /// + /// Structure + /// + /// Array + /// Length + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public NativeMemoryWriter(byte* array, int length) + { + if (length < 0) + throw new ArgumentOutOfRangeException(nameof(length), length, "MustBeNonNegative"); + Array = array; + Length = length; + Position = 0; + } + + /// + /// Remaining + /// + public int Remaining => Length - Position; + + /// + /// Get reference + /// + /// Index + public byte* this[int index] + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => Array + index; + } + + /// + /// Get reference + /// + /// Index + public byte* this[uint index] + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => Array + index; + } + + /// + /// Equals + /// + /// Other + /// Equals + public bool Equals(NativeMemoryWriter other) => other == this; + + /// + /// Equals + /// + /// object + /// Equals + public override bool Equals(object? obj) => throw new NotSupportedException("Cannot call Equals on NativeMemoryWriter"); + + /// + /// Get hashCode + /// + /// HashCode + public override int GetHashCode() => HashCode.Combine((int)(nint)Array, Length, Position); + + /// + /// To string + /// + /// String + public override string ToString() => "NativeMemoryWriter"; + + /// + /// Equals + /// + /// Left + /// Right + /// Equals + public static bool operator ==(NativeMemoryWriter left, NativeMemoryWriter right) => left.Array == right.Array && left.Length == right.Length && left.Position == right.Position; + + /// + /// Not equals + /// + /// Left + /// Right + /// Not equals + public static bool operator !=(NativeMemoryWriter left, NativeMemoryWriter right) => left.Array != right.Array || left.Length != right.Length || left.Position != right.Position; + + /// + /// Advance + /// + /// Count + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Advance(int count) + { + var newPosition = Position + count; + if (newPosition < 0 || newPosition > Length) + throw new ArgumentOutOfRangeException(nameof(count), "Cannot advance past the end of the buffer."); + Position = newPosition; + } + + /// + /// Try advance + /// + /// Count + /// Advanced + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool TryAdvance(int count) + { + var newPosition = Position + count; + if (newPosition < 0 || newPosition > Length) + return false; + Position = newPosition; + return true; + } + + /// + /// Write + /// + /// object + /// Type + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Write(T* obj) where T : unmanaged + { + if (Position + sizeof(T) > Length) + throw new ArgumentOutOfRangeException(nameof(T), $"Requires size is {sizeof(T)}, but buffer length is {Remaining}."); + Unsafe.CopyBlockUnaligned(Array + Position, obj, (uint)sizeof(T)); + Position += sizeof(T); + } + + /// + /// Try write + /// + /// object + /// Type + /// Wrote + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool TryWrite(T* obj) where T : unmanaged + { + if (Position + sizeof(T) > Length) + return false; + Unsafe.CopyBlockUnaligned(Array + Position, obj, (uint)sizeof(T)); + Position += sizeof(T); + return true; + } + + /// + /// Write + /// + /// object + /// Count + /// Type + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Write(T* obj, int count) where T : unmanaged + { + count *= sizeof(T); + if (Position + count > Length) + throw new ArgumentOutOfRangeException(nameof(T), $"Requires size is {count}, but buffer length is {Remaining}."); + Unsafe.CopyBlockUnaligned(Array + Position, obj, (uint)count); + Position += count; + } + + /// + /// Try write + /// + /// object + /// Count + /// Type + /// Wrote + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool TryWrite(T* obj, int count) where T : unmanaged + { + count *= sizeof(T); + if (Position + count > Length) + return false; + Unsafe.CopyBlockUnaligned(Array + Position, obj, (uint)count); + Position += count; + return true; + } + + /// + /// Write + /// + /// object + /// Type + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Write(in T obj) where T : unmanaged + { + if (Position + sizeof(T) > Length) + throw new ArgumentOutOfRangeException(nameof(T), $"Requires size is {sizeof(T)}, but buffer length is {Remaining}."); + Unsafe.WriteUnaligned(Array + Position, obj); + Position += sizeof(T); + } + + /// + /// Try write + /// + /// object + /// Type + /// Wrote + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool TryWrite(in T obj) where T : unmanaged + { + if (Position + sizeof(T) > Length) + return false; + Unsafe.WriteUnaligned(Array + Position, obj); + Position += sizeof(T); + return true; + } + + /// + /// Write bytes + /// + /// Buffer + /// Length + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void WriteBytes(byte* buffer, int length) + { + if (Position + length > Length) + throw new ArgumentOutOfRangeException(nameof(length), $"Requires size is {length}, but buffer length is {Remaining}."); + Unsafe.CopyBlockUnaligned(Array + Position, buffer, (uint)length); + Position += length; + } + + /// + /// Try write bytes + /// + /// Buffer + /// Length + /// Wrote + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool TryWriteBytes(byte* buffer, int length) + { + if (Position + length > Length) + return false; + Unsafe.CopyBlockUnaligned(Array + Position, buffer, (uint)length); + Position += length; + return true; + } + + /// + /// Clear + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Clear() => Position = 0; + + /// + /// As span + /// + /// Span + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Span AsSpan() => MemoryMarshal.CreateSpan(ref *Array, Position); + + /// + /// As span + /// + /// Length + /// Span + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Span AsSpan(int length) => MemoryMarshal.CreateSpan(ref *Array, length); + + /// + /// As span + /// + /// Start + /// Length + /// Span + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Span AsSpan(int start, int length) => MemoryMarshal.CreateSpan(ref *(Array + start), length); + + /// + /// As readOnly span + /// + /// ReadOnlySpan + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public ReadOnlySpan AsReadOnlySpan() => MemoryMarshal.CreateReadOnlySpan(ref *Array, Position); + + /// + /// As readOnly span + /// + /// Length + /// ReadOnlySpan + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public ReadOnlySpan AsReadOnlySpan(int length) => MemoryMarshal.CreateReadOnlySpan(ref *Array, length); + + /// + /// As readOnly span + /// + /// Start + /// Length + /// ReadOnlySpan + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public ReadOnlySpan AsReadOnlySpan(int start, int length) => MemoryMarshal.CreateReadOnlySpan(ref *(Array + start), length); + + /// + /// As span + /// + /// Span + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator Span(NativeMemoryWriter writer) => writer.AsSpan(); + + /// + /// As readOnly span + /// + /// ReadOnlySpan + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator ReadOnlySpan(NativeMemoryWriter writer) => writer.AsReadOnlySpan(); + + /// + /// As native memory reader + /// + /// NativeMemoryReader + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator NativeMemoryReader(NativeMemoryWriter writer) => new(writer.Array, writer.Position); + + /// + /// As native memory writer + /// + /// NativeMemoryWriter + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator NativeMemoryWriter(NativeArray writer) => new(writer.Array, writer.Length); + + /// + /// As native memory writer + /// + /// NativeMemoryWriter + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator NativeMemoryWriter(NativeMemoryArray writer) => new(writer.Array, writer.Length); + + /// + /// As native memory writer + /// + /// NativeMemoryWriter + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator NativeMemoryWriter(NativeArraySegment writer) => new(writer.Array + writer.Offset, writer.Count); + + /// + /// Empty + /// + public static NativeMemoryWriter Empty => new(); + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeMemoryWriter.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeMemoryWriter.cs.meta new file mode 100644 index 0000000..f250a69 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeMemoryWriter.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e7eda3c17c0ee481699b9ef814ec7d1b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeMonitorLock.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeMonitorLock.cs new file mode 100644 index 0000000..47bf8a5 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeMonitorLock.cs @@ -0,0 +1,210 @@ +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +#if NET7_0_OR_GREATER +#endif + +#if UNITY_2021_3_OR_NEWER || GODOT +using System; +using System.Threading; +#endif + +#pragma warning disable CA2208 +#pragma warning disable CS8604 +#pragma warning disable CS8632 + +// ReSharper disable ALL + +namespace NativeCollections +{ + /// + /// Native monitorLock + /// + [StructLayout(LayoutKind.Sequential)] + public struct NativeMonitorLock : IDisposable, IEquatable + { + /// + /// Handle + /// + private GCHandle _handle; + + /// + /// Structure + /// + /// Value + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public NativeMonitorLock(object value) => _handle = GCHandle.Alloc(value, GCHandleType.Normal); + + /// + /// Structure + /// + /// Value + /// GCHandle type + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public NativeMonitorLock(object value, GCHandleType type) => _handle = GCHandle.Alloc(value, type); + + /// + /// Is created + /// + public bool IsCreated => _handle.IsAllocated; + + /// + /// Equals + /// + /// Other + /// Equals + public bool Equals(NativeMonitorLock other) => other == this; + + /// + /// Equals + /// + /// object + /// Equals + public override bool Equals(object? obj) => obj is NativeMonitorLock nativeMonitorLock && nativeMonitorLock == this; + + /// + /// Get hashCode + /// + /// HashCode + public override int GetHashCode() => (int)(nint)_handle; + + /// + /// To string + /// + /// String + public override string ToString() => "NativeMonitorLock"; + + /// + /// Equals + /// + /// Left + /// Right + /// Equals + public static bool operator ==(NativeMonitorLock left, NativeMonitorLock right) => left._handle == right._handle; + + /// + /// Not equals + /// + /// Left + /// Right + /// Not equals + public static bool operator !=(NativeMonitorLock left, NativeMonitorLock right) => left._handle != right._handle; + + /// + /// Dispose + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Dispose() + { + if (!_handle.IsAllocated) + return; + _handle.Free(); + } + + /// + /// Enter + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Enter() => Monitor.Enter(_handle.Target); + + /// + /// Enter + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Enter(ref bool lockTaken) => Monitor.Enter(_handle.Target, ref lockTaken); + + /// + /// Enter + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool TryEnter() => Monitor.TryEnter(_handle.Target); + + /// + /// Enter + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void TryEnter(ref bool lockTaken) => Monitor.TryEnter(_handle.Target, ref lockTaken); + + /// + /// Enter + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool TryEnter(int millisecondsTimeout) => Monitor.TryEnter(_handle.Target, millisecondsTimeout); + + /// + /// Enter + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void TryEnter(int millisecondsTimeout, ref bool lockTaken) => Monitor.TryEnter(_handle.Target, millisecondsTimeout, ref lockTaken); + + /// + /// Is entered + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool IsEntered() => Monitor.IsEntered(_handle.Target); + + /// + /// Wait + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool Wait(int millisecondsTimeout) => Monitor.Wait(_handle.Target, millisecondsTimeout); + + /// + /// Pulse + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Pulse() => Monitor.Pulse(_handle.Target); + + /// + /// Pulse all + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void PulseAll() => Monitor.PulseAll(_handle.Target); + + /// + /// Try enter + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool TryEnter(TimeSpan timeout) => Monitor.TryEnter(_handle.Target, timeout); + + /// + /// Try enter + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void TryEnter(TimeSpan timeout, ref bool lockTaken) => Monitor.TryEnter(_handle.Target, timeout, ref lockTaken); + + /// + /// Wait + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool Wait(TimeSpan timeout) => Monitor.Wait(_handle.Target, timeout); + + /// + /// Wait + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool Wait() => Monitor.Wait(_handle.Target); + + /// + /// Wait + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool Wait(int millisecondsTimeout, bool exitContext) => Monitor.Wait(_handle.Target, millisecondsTimeout, exitContext); + + /// + /// Wait + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool Wait(TimeSpan timeout, bool exitContext) => Monitor.Wait(_handle.Target, timeout, exitContext); + + /// + /// Exit + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Exit() => Monitor.Exit(_handle.Target); + + /// + /// Empty + /// + public static NativeMonitorLock Empty => new(); + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeMonitorLock.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeMonitorLock.cs.meta new file mode 100644 index 0000000..804fddf --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeMonitorLock.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b4d6cec6825324e09a10f908a882f75b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativePriorityQueue.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativePriorityQueue.cs new file mode 100644 index 0000000..da6e60d --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativePriorityQueue.cs @@ -0,0 +1,618 @@ +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +#if UNITY_2021_3_OR_NEWER || GODOT +using System; +#endif + +#pragma warning disable CA2208 +#pragma warning disable CS8632 + +// ReSharper disable ALL + +namespace NativeCollections +{ + /// + /// Native priorityQueue + /// + /// Type + /// Type + [StructLayout(LayoutKind.Sequential)] + public readonly unsafe struct NativePriorityQueue : IDisposable, IEquatable> where TElement : unmanaged where TPriority : unmanaged, IComparable + { + /// + /// Handle + /// + [StructLayout(LayoutKind.Sequential)] + private struct NativePriorityQueueHandle + { + /// + /// Nodes + /// + public ValueTuple* Nodes; + + /// + /// Length + /// + public int Length; + + /// + /// Unordered items + /// + public UnorderedItemsCollection UnorderedItems; + + /// + /// Size + /// + public int Size; + + /// + /// Version + /// + public int Version; + } + + /// + /// Handle + /// + private readonly NativePriorityQueueHandle* _handle; + + /// + /// Structure + /// + /// Capacity + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public NativePriorityQueue(int capacity) + { + if (capacity < 0) + throw new ArgumentOutOfRangeException(nameof(capacity), capacity, "MustBeNonNegative"); + if (capacity < 4) + capacity = 4; + _handle = (NativePriorityQueueHandle*)NativeMemoryAllocator.Alloc((uint)sizeof(NativePriorityQueueHandle)); + _handle->Nodes = (ValueTuple*)NativeMemoryAllocator.Alloc((uint)(capacity * sizeof(ValueTuple))); + _handle->Length = capacity; + _handle->UnorderedItems = new UnorderedItemsCollection(this); + _handle->Size = 0; + _handle->Version = 0; + } + + /// + /// Is created + /// + public bool IsCreated => _handle != null; + + /// + /// Is empty + /// + public bool IsEmpty => _handle->Size == 0; + + /// + /// Get reference + /// + /// Index + public (TElement Element, TPriority Priority) this[int index] + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _handle->Nodes[index]; + } + + /// + /// Count + /// + public int Count => _handle->Size; + + /// + /// Unordered items + /// + public UnorderedItemsCollection UnorderedItems => _handle->UnorderedItems; + + /// + /// Equals + /// + /// Other + /// Equals + public bool Equals(NativePriorityQueue other) => other == this; + + /// + /// Equals + /// + /// object + /// Equals + public override bool Equals(object? obj) => obj is NativePriorityQueue nativeQueue && nativeQueue == this; + + /// + /// Get hashCode + /// + /// HashCode + public override int GetHashCode() => (int)(nint)_handle; + + /// + /// To string + /// + /// String + public override string ToString() => $"NativePriorityQueue<{typeof(TElement).Name}, {typeof(TPriority).Name}>"; + + /// + /// Equals + /// + /// Left + /// Right + /// Equals + public static bool operator ==(NativePriorityQueue left, NativePriorityQueue right) => left._handle == right._handle; + + /// + /// Not equals + /// + /// Left + /// Right + /// Not equals + public static bool operator !=(NativePriorityQueue left, NativePriorityQueue right) => left._handle != right._handle; + + /// + /// Dispose + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Dispose() + { + if (_handle == null) + return; + NativeMemoryAllocator.Free(_handle->Nodes); + NativeMemoryAllocator.Free(_handle); + } + + /// + /// Clear + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Clear() + { + _handle->Size = 0; + ++_handle->Version; + } + + /// + /// Enqueue + /// + /// Element + /// Priority + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Enqueue(in TElement element, in TPriority priority) + { + var size = _handle->Size; + ++_handle->Version; + if (_handle->Length == size) + Grow(size + 1); + _handle->Size = size + 1; + MoveUp(new ValueTuple(element, priority), size); + } + + /// + /// Try enqueue + /// + /// Element + /// Priority + /// Enqueued + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool TryEnqueue(in TElement element, in TPriority priority) + { + var size = _handle->Size; + ++_handle->Version; + if (_handle->Length != size) + { + _handle->Size = size + 1; + MoveUp(new ValueTuple(element, priority), size); + return true; + } + + return false; + } + + /// + /// Enqueue dequeue + /// + /// Element + /// Priority + /// Element + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public TElement EnqueueDequeue(in TElement element, in TPriority priority) + { + if (_handle->Size != 0) + { + var node = _handle->Nodes[0]; + if (priority.CompareTo(node.Item2) > 0) + { + MoveDown(new ValueTuple(element, priority), 0); + ++_handle->Version; + return node.Item1; + } + } + + return element; + } + + /// + /// Try enqueue dequeue + /// + /// Element + /// Priority + /// Element + /// Enqueued + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool TryEnqueueDequeue(in TElement element, in TPriority priority, out TElement result) + { + if (_handle->Size != 0) + { + var node = _handle->Nodes[0]; + if (priority.CompareTo(node.Item2) > 0) + { + MoveDown(new ValueTuple(element, priority), 0); + ++_handle->Version; + result = node.Item1; + return true; + } + } + + result = element; + return false; + } + + /// + /// Dequeue + /// + /// Item + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public TElement Dequeue() + { + if (_handle->Size == 0) + throw new InvalidOperationException("EmptyQueue"); + var element = _handle->Nodes[0].Item1; + RemoveRootNode(); + return element; + } + + /// + /// Try dequeue + /// + /// Element + /// Dequeued + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool TryDequeue(out TElement element) + { + if (_handle->Size != 0) + { + var tuple = _handle->Nodes[0]; + element = tuple.Item1; + RemoveRootNode(); + return true; + } + + element = default; + return false; + } + + /// + /// Try dequeue + /// + /// Element + /// Priority + /// Dequeued + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool TryDequeue(out TElement element, out TPriority priority) + { + if (_handle->Size != 0) + { + var tuple = _handle->Nodes[0]; + element = tuple.Item1; + priority = tuple.Item2; + RemoveRootNode(); + return true; + } + + element = default; + priority = default; + return false; + } + + /// + /// Dequeue enqueue + /// + /// Element + /// Priority + /// Element + public TElement DequeueEnqueue(in TElement element, in TPriority priority) + { + if (_handle->Size == 0) + throw new InvalidOperationException("EmptyQueue"); + var node = _handle->Nodes[0]; + if (priority.CompareTo(node.Item2) > 0) + MoveDown(new ValueTuple(element, priority), 0); + else + _handle->Nodes[0] = new ValueTuple(element, priority); + ++_handle->Version; + return node.Item1; + } + + /// + /// Try dequeue enqueue + /// + /// Element + /// Priority + /// Element + /// Dequeued + public bool TryDequeueEnqueue(in TElement element, in TPriority priority, out TElement result) + { + if (_handle->Size == 0) + { + result = default; + return false; + } + + var node = _handle->Nodes[0]; + if (priority.CompareTo(node.Item2) > 0) + MoveDown(new ValueTuple(element, priority), 0); + else + _handle->Nodes[0] = new ValueTuple(element, priority); + ++_handle->Version; + result = node.Item1; + return true; + } + + /// + /// Peek + /// + /// Item + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public TElement Peek() => _handle->Size == 0 ? throw new InvalidOperationException("EmptyQueue") : _handle->Nodes[0].Item1; + + /// + /// Try peek + /// + /// Element + /// Priority + /// Peeked + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool TryPeek(out TElement element, out TPriority priority) + { + if (_handle->Size != 0) + { + var tuple = _handle->Nodes[0]; + element = tuple.Item1; + priority = tuple.Item2; + return true; + } + + element = default; + priority = default; + return false; + } + + /// + /// Ensure capacity + /// + /// Capacity + /// New capacity + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public int EnsureCapacity(int capacity) + { + if (capacity < 0) + throw new ArgumentOutOfRangeException(nameof(capacity), capacity, "MustBeNonNegative"); + if (_handle->Length < capacity) + { + Grow(capacity); + ++_handle->Version; + } + + return _handle->Length; + } + + /// + /// Trim excess + /// + /// New capacity + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void TrimExcess() + { + if (_handle->Size >= (int)(_handle->Length * 0.9)) + return; + var nodes = (ValueTuple*)NativeMemoryAllocator.Alloc((uint)(_handle->Size * sizeof(ValueTuple))); + Unsafe.CopyBlockUnaligned(nodes, _handle->Nodes, (uint)_handle->Size); + NativeMemoryAllocator.Free(_handle->Nodes); + _handle->Nodes = nodes; + _handle->Length = _handle->Size; + ++_handle->Version; + } + + /// + /// Grow + /// + /// Capacity + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void Grow(int capacity) + { + var newCapacity = 2 * _handle->Length; + if ((uint)newCapacity > 2147483591) + newCapacity = 2147483591; + var expected = _handle->Length + 4; + newCapacity = newCapacity > expected ? newCapacity : expected; + if (newCapacity < capacity) + newCapacity = capacity; + var nodes = (ValueTuple*)NativeMemoryAllocator.Alloc((uint)(newCapacity * sizeof(ValueTuple))); + Unsafe.CopyBlockUnaligned(nodes, _handle->Nodes, (uint)_handle->Size); + NativeMemoryAllocator.Free(_handle->Nodes); + _handle->Nodes = nodes; + _handle->Length = newCapacity; + } + + /// + /// Remove root node + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void RemoveRootNode() + { + var index = --_handle->Size; + ++_handle->Version; + if (index > 0) + { + var node = _handle->Nodes[index]; + MoveDown(node, 0); + } + } + + /// + /// Move up + /// + /// Node + /// Node index + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void MoveUp(in ValueTuple node, int nodeIndex) + { + var nodes = _handle->Nodes; + int parentIndex; + for (; nodeIndex > 0; nodeIndex = parentIndex) + { + parentIndex = (nodeIndex - 1) >> 2; + var tuple = nodes[parentIndex]; + if (node.Item2.CompareTo(tuple.Item2) < 0) + nodes[nodeIndex] = tuple; + else + break; + } + + nodes[nodeIndex] = node; + } + + /// + /// Move down + /// + /// Node + /// Node index + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void MoveDown(in ValueTuple node, int nodeIndex) + { + var nodes = _handle->Nodes; + int firstChildIndex; + int first; + for (var size = _handle->Size; (firstChildIndex = (nodeIndex << 2) + 1) < size; nodeIndex = first) + { + var valueTuple = nodes[firstChildIndex]; + first = firstChildIndex; + var minSize = firstChildIndex + 4; + var second = minSize <= size ? minSize : size; + while (++firstChildIndex < second) + { + var tuple = nodes[firstChildIndex]; + if (tuple.Item2.CompareTo(valueTuple.Item2) < 0) + { + valueTuple = tuple; + first = firstChildIndex; + } + } + + if (node.Item2.CompareTo(valueTuple.Item2) > 0) + nodes[nodeIndex] = valueTuple; + else + break; + } + + nodes[nodeIndex] = node; + } + + /// + /// Empty + /// + public static NativePriorityQueue Empty => new(); + + /// + /// Unordered items collection + /// + [StructLayout(LayoutKind.Sequential)] + public readonly struct UnorderedItemsCollection + { + /// + /// NativePriorityQueue + /// + private readonly NativePriorityQueue _nativePriorityQueue; + + /// + /// Structure + /// + /// Native priorityQueue + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal UnorderedItemsCollection(NativePriorityQueue nativePriorityQueue) => _nativePriorityQueue = nativePriorityQueue; + + /// + /// Get enumerator + /// + /// Enumerator + public Enumerator GetEnumerator() => new(_nativePriorityQueue); + + /// + /// Enumerator + /// + public struct Enumerator + { + /// + /// NativePriorityQueue + /// + private readonly NativePriorityQueue _nativePriorityQueue; + + /// + /// Version + /// + private readonly int _version; + + /// + /// Index + /// + private int _index; + + /// + /// Current + /// + private ValueTuple _current; + + /// + /// Structure + /// + /// Native priorityQueue + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal Enumerator(NativePriorityQueue nativePriorityQueue) + { + _nativePriorityQueue = nativePriorityQueue; + _index = 0; + _version = nativePriorityQueue._handle->Version; + _current = default; + } + + /// + /// Move next + /// + /// Moved + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool MoveNext() + { + if (_version != _nativePriorityQueue._handle->Version) + throw new InvalidOperationException("EnumFailedVersion"); + if ((uint)_index >= (uint)_nativePriorityQueue._handle->Size) + { + _index = _nativePriorityQueue._handle->Size + 1; + _current = default; + return false; + } + + _current = _nativePriorityQueue._handle->Nodes[_index]; + ++_index; + return true; + } + + /// + /// Current + /// + public (TElement Element, TPriority Priority) Current + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _current; + } + } + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativePriorityQueue.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativePriorityQueue.cs.meta new file mode 100644 index 0000000..c435494 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativePriorityQueue.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ccbacb3413a174e6c87f2346c5423dd0 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeQueue.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeQueue.cs new file mode 100644 index 0000000..689ff66 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeQueue.cs @@ -0,0 +1,455 @@ +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +#if UNITY_2021_3_OR_NEWER || GODOT +using System; +#endif + +#pragma warning disable CA2208 +#pragma warning disable CS8632 + +// ReSharper disable ALL + +namespace NativeCollections +{ + /// + /// Native queue + /// + /// Type + [StructLayout(LayoutKind.Sequential)] + public readonly unsafe struct NativeQueue : IDisposable, IEquatable> where T : unmanaged + { + /// + /// Handle + /// + [StructLayout(LayoutKind.Sequential)] + private struct NativeQueueHandle + { + /// + /// Array + /// + public T* Array; + + /// + /// Length + /// + public int Length; + + /// + /// Head + /// + public int Head; + + /// + /// Tail + /// + public int Tail; + + /// + /// Size + /// + public int Size; + + /// + /// Version + /// + public int Version; + } + + /// + /// Handle + /// + private readonly NativeQueueHandle* _handle; + + /// + /// Structure + /// + /// Capacity + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public NativeQueue(int capacity) + { + if (capacity < 0) + throw new ArgumentOutOfRangeException(nameof(capacity), capacity, "MustBeNonNegative"); + if (capacity < 4) + capacity = 4; + _handle = (NativeQueueHandle*)NativeMemoryAllocator.Alloc((uint)sizeof(NativeQueueHandle)); + _handle->Array = (T*)NativeMemoryAllocator.Alloc((uint)(capacity * sizeof(T))); + _handle->Length = capacity; + _handle->Head = 0; + _handle->Tail = 0; + _handle->Size = 0; + _handle->Version = 0; + } + + /// + /// Is created + /// + public bool IsCreated => _handle != null; + + /// + /// Is empty + /// + public bool IsEmpty => _handle->Size == 0; + + /// + /// Get reference + /// + /// Index + public ref T this[int index] + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => ref _handle->Array[index]; + } + + /// + /// Get reference + /// + /// Index + public ref T this[uint index] + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => ref _handle->Array[index]; + } + + /// + /// Count + /// + public int Count => _handle->Size; + + /// + /// Equals + /// + /// Other + /// Equals + public bool Equals(NativeQueue other) => other == this; + + /// + /// Equals + /// + /// object + /// Equals + public override bool Equals(object? obj) => obj is NativeQueue nativeQueue && nativeQueue == this; + + /// + /// Get hashCode + /// + /// HashCode + public override int GetHashCode() => (int)(nint)_handle; + + /// + /// To string + /// + /// String + public override string ToString() => $"NativeQueue<{typeof(T).Name}>"; + + /// + /// Equals + /// + /// Left + /// Right + /// Equals + public static bool operator ==(NativeQueue left, NativeQueue right) => left._handle == right._handle; + + /// + /// Not equals + /// + /// Left + /// Right + /// Not equals + public static bool operator !=(NativeQueue left, NativeQueue right) => left._handle != right._handle; + + /// + /// Dispose + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Dispose() + { + if (_handle == null) + return; + NativeMemoryAllocator.Free(_handle->Array); + NativeMemoryAllocator.Free(_handle); + } + + /// + /// Clear + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Clear() + { + _handle->Size = 0; + _handle->Head = 0; + _handle->Tail = 0; + _handle->Version++; + } + + /// + /// Enqueue + /// + /// Item + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Enqueue(in T item) + { + if (_handle->Size == _handle->Length) + Grow(_handle->Size + 1); + _handle->Array[_handle->Tail] = item; + MoveNext(ref _handle->Tail); + _handle->Size++; + _handle->Version++; + } + + /// + /// Try enqueue + /// + /// Item + /// Enqueued + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool TryEnqueue(in T item) + { + if (_handle->Size != _handle->Length) + { + _handle->Array[_handle->Tail] = item; + MoveNext(ref _handle->Tail); + _handle->Size++; + _handle->Version++; + return true; + } + + return false; + } + + /// + /// Dequeue + /// + /// Item + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public T Dequeue() + { + if (_handle->Size == 0) + throw new InvalidOperationException("EmptyQueue"); + var removed = _handle->Array[_handle->Head]; + MoveNext(ref _handle->Head); + _handle->Size--; + _handle->Version++; + return removed; + } + + /// + /// Try dequeue + /// + /// Item + /// Dequeued + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool TryDequeue(out T result) + { + if (_handle->Size == 0) + { + result = default; + return false; + } + + result = _handle->Array[_handle->Head]; + MoveNext(ref _handle->Head); + _handle->Size--; + _handle->Version++; + return true; + } + + /// + /// Peek + /// + /// Item + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public T Peek() => _handle->Size == 0 ? throw new InvalidOperationException("EmptyQueue") : _handle->Array[_handle->Head]; + + /// + /// Try peek + /// + /// Item + /// Peeked + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool TryPeek(out T result) + { + if (_handle->Size == 0) + { + result = default; + return false; + } + + result = _handle->Array[_handle->Head]; + return true; + } + + /// + /// Ensure capacity + /// + /// Capacity + /// New capacity + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public int EnsureCapacity(int capacity) + { + if (capacity < 0) + throw new ArgumentOutOfRangeException(nameof(capacity), capacity, "MustBeNonNegative"); + if (_handle->Length < capacity) + Grow(capacity); + return _handle->Length; + } + + /// + /// Trim excess + /// + /// New capacity + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public int TrimExcess() + { + var threshold = (int)(_handle->Length * 0.9); + if (_handle->Size < threshold) + SetCapacity(_handle->Size); + return _handle->Length; + } + + /// + /// Set capacity + /// + /// Capacity + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void SetCapacity(int capacity) + { + var newArray = (T*)NativeMemoryAllocator.Alloc((uint)(capacity * sizeof(T))); + if (_handle->Size > 0) + { + if (_handle->Head < _handle->Tail) + { + Unsafe.CopyBlockUnaligned(newArray, _handle->Array + _handle->Head, (uint)(_handle->Size * sizeof(T))); + } + else + { + Unsafe.CopyBlockUnaligned(newArray, _handle->Array + _handle->Head, (uint)((_handle->Length - _handle->Head) * sizeof(T))); + Unsafe.CopyBlockUnaligned(newArray + _handle->Length - _handle->Head, _handle->Array, (uint)(_handle->Tail * sizeof(T))); + } + } + + NativeMemoryAllocator.Free(_handle->Array); + _handle->Array = newArray; + _handle->Length = capacity; + _handle->Head = 0; + _handle->Tail = _handle->Size == capacity ? 0 : _handle->Size; + _handle->Version++; + } + + /// + /// Grow + /// + /// Capacity + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void Grow(int capacity) + { + var newCapacity = 2 * _handle->Length; + if ((uint)newCapacity > 2147483591) + newCapacity = 2147483591; + var expected = _handle->Length + 4; + newCapacity = newCapacity > expected ? newCapacity : expected; + if (newCapacity < capacity) + newCapacity = capacity; + SetCapacity(newCapacity); + } + + /// + /// Move next + /// + /// Index + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void MoveNext(ref int index) + { + var tmp = index + 1; + if (tmp == _handle->Length) + tmp = 0; + index = tmp; + } + + /// + /// Empty + /// + public static NativeQueue Empty => new(); + + /// + /// Get enumerator + /// + /// Enumerator + public Enumerator GetEnumerator() => new(this); + + /// + /// Enumerator + /// + public struct Enumerator + { + /// + /// NativeQueue + /// + private readonly NativeQueue _nativeQueue; + + /// + /// Version + /// + private readonly int _version; + + /// + /// Index + /// + private int _index; + + /// + /// Current + /// + private T _currentElement; + + /// + /// Structure + /// + /// NativeQueue + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal Enumerator(in NativeQueue nativeQueue) + { + _nativeQueue = nativeQueue; + _version = nativeQueue._handle->Version; + _index = -1; + _currentElement = default; + } + + /// + /// Move next + /// + /// Moved + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool MoveNext() + { + if (_version != _nativeQueue._handle->Version) + throw new InvalidOperationException("EnumFailedVersion"); + if (_index == -2) + return false; + _index++; + if (_index == _nativeQueue._handle->Size) + { + _index = -2; + _currentElement = default; + return false; + } + + var array = _nativeQueue._handle->Array; + var capacity = (uint)_nativeQueue._handle->Length; + var arrayIndex = (uint)(_nativeQueue._handle->Head + _index); + if (arrayIndex >= capacity) + arrayIndex -= capacity; + _currentElement = array[arrayIndex]; + return true; + } + + /// + /// Current + /// + public T Current + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _index < 0 ? throw new InvalidOperationException(_index == -1 ? "EnumNotStarted" : "EnumEnded") : _currentElement; + } + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeQueue.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeQueue.cs.meta new file mode 100644 index 0000000..4d32178 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeQueue.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f7979e9a0b80b48b8b5a675b18858259 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeReference.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeReference.cs new file mode 100644 index 0000000..76ffcc9 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeReference.cs @@ -0,0 +1,149 @@ +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +#if UNITY_2021_3_OR_NEWER || GODOT +using System; +#endif + +#pragma warning disable CA2208 +#pragma warning disable CS8632 + +// ReSharper disable ALL + +namespace NativeCollections +{ + /// + /// Native reference + /// + /// Type + [StructLayout(LayoutKind.Sequential)] + public readonly unsafe struct NativeReference : IDisposable, IEquatable> where T : unmanaged + { + /// + /// Handle + /// + private readonly T* _handle; + + /// + /// Structure + /// + /// Handle + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public NativeReference(T* handle) => _handle = handle; + + /// + /// Structure + /// + /// Handle + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public NativeReference(nint handle) => _handle = (T*)handle; + + /// + /// Is created + /// + public bool IsCreated => _handle != null; + + /// + /// Handle + /// + public T* Handle + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _handle; + } + + /// + /// Value + /// + public ref T Value + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => ref *_handle; + } + + /// + /// Equals + /// + /// Other + /// Equals + public bool Equals(NativeReference other) => other == this; + + /// + /// Equals + /// + /// object + /// Equals + public override bool Equals(object? obj) => obj is NativeReference nativeReference && nativeReference == this; + + /// + /// Get hashCode + /// + /// HashCode + public override int GetHashCode() => (int)(nint)_handle; + + /// + /// To string + /// + /// String + public override string ToString() => $"NativeReference<{typeof(T).Name}>"; + + /// + /// As reference + /// + /// NativeReference + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator NativeReference(T* handle) => new(handle); + + /// + /// As handle + /// + /// Handle + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator T*(NativeReference nativeReference) => nativeReference._handle; + + /// + /// As reference + /// + /// NativeReference + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator NativeReference(nint handle) => new((T*)handle); + + /// + /// As handle + /// + /// Handle + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator nint(NativeReference nativeReference) => (nint)nativeReference._handle; + + /// + /// Equals + /// + /// Left + /// Right + /// Equals + public static bool operator ==(NativeReference left, NativeReference right) => left._handle == right._handle; + + /// + /// Not equals + /// + /// Left + /// Right + /// Not equals + public static bool operator !=(NativeReference left, NativeReference right) => left._handle != right._handle; + + /// + /// Dispose + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Dispose() + { + if (_handle == null) + return; + NativeMemoryAllocator.Free(_handle); + } + + /// + /// Empty + /// + public static NativeReference Empty => new(); + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeReference.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeReference.cs.meta new file mode 100644 index 0000000..5b669c4 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeReference.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 067f01b15247d473aa3f7a4b5a914b28 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeSortedDictionary.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeSortedDictionary.cs new file mode 100644 index 0000000..42de38c --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeSortedDictionary.cs @@ -0,0 +1,1262 @@ +#if UNITY_2021_3_OR_NEWER || GODOT +using System; +using System.Collections.Generic; +#endif +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +#if NET5_0_OR_GREATER +#endif + +#pragma warning disable CA2208 +#pragma warning disable CS8632 + +// ReSharper disable ALL + +namespace NativeCollections +{ + /// + /// Native dictionary + /// + /// Type + /// Type + [StructLayout(LayoutKind.Sequential)] + public readonly unsafe struct NativeSortedDictionary : IDisposable, IEquatable> where TKey : unmanaged, IComparable where TValue : unmanaged + { + /// + /// Handle + /// + [StructLayout(LayoutKind.Sequential)] + private struct NativeSortedDictionaryHandle + { + /// + /// Root + /// + public Node* Root; + + /// + /// Count + /// + public int Count; + + /// + /// Version + /// + public int Version; + + /// + /// Node pool + /// + public NativeMemoryPool NodePool; + + /// + /// Keys + /// + public KeyCollection Keys; + + /// + /// Values + /// + public ValueCollection Values; + } + + /// + /// Handle + /// + private readonly NativeSortedDictionaryHandle* _handle; + + /// + /// Keys + /// + public KeyCollection Keys => _handle->Keys; + + /// + /// Values + /// + public ValueCollection Values => _handle->Values; + + /// + /// Structure + /// + /// MemoryPool size + /// MemoryPool maxFreeSlabs + public NativeSortedDictionary(int size, int maxFreeSlabs) + { + var nodePool = new NativeMemoryPool(size, sizeof(Node), maxFreeSlabs); + _handle = (NativeSortedDictionaryHandle*)NativeMemoryAllocator.Alloc((uint)sizeof(NativeSortedDictionaryHandle)); + _handle->Root = null; + _handle->Count = 0; + _handle->Version = 0; + _handle->NodePool = nodePool; + _handle->Keys = new KeyCollection(this); + _handle->Values = new ValueCollection(this); + } + + /// + /// Is created + /// + public bool IsCreated => _handle != null; + + /// + /// Is empty + /// + public bool IsEmpty => _handle->Count == 0; + + /// + /// Count + /// + public int Count => _handle->Count; + + /// + /// Min + /// + public KeyValuePair? Min + { + get + { + if (_handle->Root == null) + return default; + var current = _handle->Root; + while (current->Left != null) + current = current->Left; + return new KeyValuePair(current->Key, current->Value); + } + } + + /// + /// Max + /// + public KeyValuePair? Max + { + get + { + if (_handle->Root == null) + return default; + var current = _handle->Root; + while (current->Right != null) + current = current->Right; + return new KeyValuePair(current->Key, current->Value); + } + } + + /// + /// Get or set value + /// + /// Key + public TValue this[in TKey key] + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get + { + if (!TryGetValue(key, out var value)) + throw new KeyNotFoundException(key.ToString()); + return value; + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + set + { + var node = FindNode(key); + if (node == null) + { + Add(key, value); + } + else + { + node->Value = value; + _handle->Version++; + } + } + } + + /// + /// Equals + /// + /// Other + /// Equals + public bool Equals(NativeSortedDictionary other) => other == this; + + /// + /// Equals + /// + /// object + /// Equals + public override bool Equals(object? obj) => obj is NativeSortedDictionary nativeSortedDictionary && nativeSortedDictionary == this; + + /// + /// Get hashCode + /// + /// HashCode + public override int GetHashCode() => (int)(nint)_handle; + + /// + /// To string + /// + /// String + public override string ToString() => $"NativeSortedDictionary<{typeof(TKey).Name}, {typeof(TValue).Name}>"; + + /// + /// Equals + /// + /// Left + /// Right + /// Equals + public static bool operator ==(NativeSortedDictionary left, NativeSortedDictionary right) => left._handle == right._handle; + + /// + /// Not equals + /// + /// Left + /// Right + /// Not equals + public static bool operator !=(NativeSortedDictionary left, NativeSortedDictionary right) => left._handle != right._handle; + + /// + /// Dispose + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Dispose() + { + if (_handle == null) + return; + _handle->NodePool.Dispose(); + NativeMemoryAllocator.Free(_handle); + } + + /// + /// Clear + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Clear() + { + if (_handle->Root != null) + { + var nodeStack = new NativeStack(2 * Log2(_handle->Count + 1)); + nodeStack.Push((nint)_handle->Root); + while (nodeStack.TryPop(out var node)) + { + var currentNode = (Node*)node; + if (currentNode->Left != null) + nodeStack.Push((nint)currentNode->Left); + if (currentNode->Right != null) + nodeStack.Push((nint)currentNode->Right); + _handle->NodePool.Return(currentNode); + } + + nodeStack.Dispose(); + } + + _handle->Root = null; + _handle->Count = 0; + ++_handle->Version; + } + + /// + /// Add + /// + /// Key + /// Value + /// Added + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool Add(in TKey key, in TValue value) + { + if (_handle->Root == null) + { + _handle->Root = (Node*)_handle->NodePool.Rent(); + _handle->Root->Key = key; + _handle->Root->Value = value; + _handle->Root->Left = null; + _handle->Root->Right = null; + _handle->Root->Color = NodeColor.Black; + _handle->Count = 1; + _handle->Version++; + return true; + } + + var current = _handle->Root; + Node* parent = null; + Node* grandParent = null; + Node* greatGrandParent = null; + _handle->Version++; + var order = 0; + while (current != null) + { + order = key.CompareTo(current->Key); + if (order == 0) + { + _handle->Root->ColorBlack(); + return false; + } + + if (current->Is4Node) + { + current->Split4Node(); + if (Node.IsNonNullRed(parent)) + InsertionBalance(current, parent, grandParent, greatGrandParent); + } + + greatGrandParent = grandParent; + grandParent = parent; + parent = current; + current = order < 0 ? current->Left : current->Right; + } + + var node = (Node*)_handle->NodePool.Rent(); + node->Key = key; + node->Value = value; + node->Left = null; + node->Right = null; + node->Color = NodeColor.Red; + if (order > 0) + parent->Right = node; + else + parent->Left = node; + if (parent->IsRed) + InsertionBalance(node, parent, grandParent, greatGrandParent); + _handle->Root->ColorBlack(); + ++_handle->Count; + return true; + } + + /// + /// Remove + /// + /// Key + /// Removed + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool Remove(in TKey key) + { + if (_handle->Root == null) + return false; + _handle->Version++; + var current = _handle->Root; + Node* parent = null; + Node* grandParent = null; + Node* match = null; + Node* parentOfMatch = null; + var foundMatch = false; + while (current != null) + { + if (current->Is2Node) + { + if (parent == null) + { + current->ColorRed(); + } + else + { + var sibling = parent->GetSibling(current); + if (sibling->IsRed) + { + if (parent->Right == sibling) + parent->RotateLeft(); + else + parent->RotateRight(); + parent->ColorRed(); + sibling->ColorBlack(); + ReplaceChildOrRoot(grandParent, parent, sibling); + grandParent = sibling; + if (parent == match) + parentOfMatch = sibling; + sibling = parent->GetSibling(current); + } + + if (sibling->Is2Node) + { + parent->Merge2Nodes(); + } + else + { + var newGrandParent = parent->Rotate(parent->GetRotation(current, sibling)); + newGrandParent->Color = parent->Color; + parent->ColorBlack(); + current->ColorRed(); + ReplaceChildOrRoot(grandParent, parent, newGrandParent); + if (parent == match) + parentOfMatch = newGrandParent; + } + } + } + + var order = foundMatch ? -1 : key.CompareTo(current->Key); + if (order == 0) + { + foundMatch = true; + match = current; + parentOfMatch = parent; + } + + grandParent = parent; + parent = current; + current = order < 0 ? current->Left : current->Right; + } + + if (match != null) + { + ReplaceNode(match, parentOfMatch, parent, grandParent); + --_handle->Count; + _handle->NodePool.Return(match); + } + + if (_handle->Root != null) + _handle->Root->ColorBlack(); + return foundMatch; + } + + /// + /// Remove + /// + /// Key + /// Value + /// Removed + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool Remove(in TKey key, out TValue value) + { + if (_handle->Root == null) + { + value = default; + return false; + } + + _handle->Version++; + var current = _handle->Root; + Node* parent = null; + Node* grandParent = null; + Node* match = null; + Node* parentOfMatch = null; + var foundMatch = false; + while (current != null) + { + if (current->Is2Node) + { + if (parent == null) + { + current->ColorRed(); + } + else + { + var sibling = parent->GetSibling(current); + if (sibling->IsRed) + { + if (parent->Right == sibling) + parent->RotateLeft(); + else + parent->RotateRight(); + parent->ColorRed(); + sibling->ColorBlack(); + ReplaceChildOrRoot(grandParent, parent, sibling); + grandParent = sibling; + if (parent == match) + parentOfMatch = sibling; + sibling = parent->GetSibling(current); + } + + if (sibling->Is2Node) + { + parent->Merge2Nodes(); + } + else + { + var newGrandParent = parent->Rotate(parent->GetRotation(current, sibling)); + newGrandParent->Color = parent->Color; + parent->ColorBlack(); + current->ColorRed(); + ReplaceChildOrRoot(grandParent, parent, newGrandParent); + if (parent == match) + parentOfMatch = newGrandParent; + } + } + } + + var order = foundMatch ? -1 : key.CompareTo(current->Key); + if (order == 0) + { + foundMatch = true; + match = current; + parentOfMatch = parent; + } + + grandParent = parent; + parent = current; + current = order < 0 ? current->Left : current->Right; + } + + if (match != null) + { + value = match->Value; + ReplaceNode(match, parentOfMatch, parent, grandParent); + --_handle->Count; + _handle->NodePool.Return(match); + } + else + { + value = default; + } + + if (_handle->Root != null) + _handle->Root->ColorBlack(); + return foundMatch; + } + + /// + /// Contains key + /// + /// Key + /// Contains key + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool ContainsKey(in TKey key) => FindNode(key) != null; + + /// + /// Try to get the actual value + /// + /// Key + /// Value + /// Got + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool TryGetValue(in TKey key, out TValue value) + { + var node = FindNode(key); + if (node != null) + { + value = node->Value; + return true; + } + + value = default; + return false; + } + + /// + /// Insertion balance + /// + /// Current + /// Parent + /// Grand parent + /// GreatGrand parent + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void InsertionBalance(Node* current, Node* parent, Node* grandParent, Node* greatGrandParent) + { + var parentIsOnRight = grandParent->Right == parent; + var currentIsOnRight = parent->Right == current; + Node* newChildOfGreatGrandParent; + if (parentIsOnRight == currentIsOnRight) + newChildOfGreatGrandParent = currentIsOnRight ? grandParent->RotateLeft() : grandParent->RotateRight(); + else + newChildOfGreatGrandParent = currentIsOnRight ? grandParent->RotateLeftRight() : grandParent->RotateRightLeft(); + grandParent->ColorRed(); + newChildOfGreatGrandParent->ColorBlack(); + ReplaceChildOrRoot(greatGrandParent, grandParent, newChildOfGreatGrandParent); + } + + /// + /// Replace child or root + /// + /// Parent + /// Child + /// New child + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void ReplaceChildOrRoot(Node* parent, Node* child, Node* newChild) + { + if (parent != null) + parent->ReplaceChild(child, newChild); + else + _handle->Root = newChild; + } + + /// + /// Replace node + /// + /// Match + /// Parent of match + /// Successor + /// Parent of successor + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void ReplaceNode(Node* match, Node* parentOfMatch, Node* successor, Node* parentOfSuccessor) + { + if (successor == match) + { + successor = match->Left; + } + else + { + if (successor->Right != null) + successor->Right->ColorBlack(); + if (parentOfSuccessor != match) + { + parentOfSuccessor->Left = successor->Right; + successor->Right = match->Right; + } + + successor->Left = match->Left; + } + + if (successor != null) + successor->Color = match->Color; + ReplaceChildOrRoot(parentOfMatch, match, successor); + } + + /// + /// Find node + /// + /// Key + /// Node + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private Node* FindNode(in TKey key) + { + var current = _handle->Root; + while (current != null) + { + var order = key.CompareTo(current->Key); + if (order == 0) + return current; + current = order < 0 ? current->Left : current->Right; + } + + return null; + } + + /// + /// Log2 + /// + /// Value + /// Log2 + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static int Log2(int value) => BitOperationsHelpers.Log2(value); + + /// + /// Node + /// + [StructLayout(LayoutKind.Sequential)] + private struct Node + { + /// + /// Is non null red + /// + /// Node + /// Is non null red + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool IsNonNullRed(Node* node) => node != null && node->IsRed; + + /// + /// Is null or black + /// + /// Node + /// Is null or black + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static bool IsNullOrBlack(Node* node) => node == null || node->IsBlack; + + /// + /// Key + /// + public TKey Key + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + set; + } + + /// + /// Value + /// + public TValue Value + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + set; + } + + /// + /// Left + /// + public Node* Left + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + set; + } + + /// + /// Right + /// + public Node* Right + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + set; + } + + /// + /// Color + /// + public NodeColor Color + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + set; + } + + /// + /// Is black + /// + private bool IsBlack + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => Color == NodeColor.Black; + } + + /// + /// Is red + /// + public bool IsRed + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => Color == NodeColor.Red; + } + + /// + /// Is 2 node + /// + public bool Is2Node + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => IsBlack && IsNullOrBlack(Left) && IsNullOrBlack(Right); + } + + /// + /// Is 4 node + /// + public bool Is4Node + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => IsNonNullRed(Left) && IsNonNullRed(Right); + } + + /// + /// Set color to black + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ColorBlack() => Color = NodeColor.Black; + + /// + /// Set color to red + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ColorRed() => Color = NodeColor.Red; + + /// + /// Get rotation + /// + /// Current + /// Sibling + /// Rotation + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public TreeRotation GetRotation(Node* current, Node* sibling) + { + var currentIsLeftChild = Left == current; + return IsNonNullRed(sibling->Left) ? currentIsLeftChild ? TreeRotation.RightLeft : TreeRotation.Right : currentIsLeftChild ? TreeRotation.Left : TreeRotation.LeftRight; + } + + /// + /// Get sibling + /// + /// Node + /// Sibling + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Node* GetSibling(Node* node) => node == Left ? Right : Left; + + /// + /// Split 4 node + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Split4Node() + { + ColorRed(); + Left->ColorBlack(); + Right->ColorBlack(); + } + + /// + /// Rotate + /// + /// Rotation + /// Node + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Node* Rotate(TreeRotation rotation) + { + Node* removeRed; + switch (rotation) + { + case TreeRotation.Right: + removeRed = Left->Left; + removeRed->ColorBlack(); + return RotateRight(); + case TreeRotation.Left: + removeRed = Right->Right; + removeRed->ColorBlack(); + return RotateLeft(); + case TreeRotation.RightLeft: + return RotateRightLeft(); + case TreeRotation.LeftRight: + return RotateLeftRight(); + default: + return null; + } + } + + /// + /// Rotate left + /// + /// Node + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Node* RotateLeft() + { + var child = Right; + Right = child->Left; + child->Left = (Node*)Unsafe.AsPointer(ref this); + return child; + } + + /// + /// Rotate left right + /// + /// Node + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Node* RotateLeftRight() + { + var child = Left; + var grandChild = child->Right; + Left = grandChild->Right; + grandChild->Right = (Node*)Unsafe.AsPointer(ref this); + child->Right = grandChild->Left; + grandChild->Left = child; + return grandChild; + } + + /// + /// Rotate right + /// + /// Node + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Node* RotateRight() + { + var child = Left; + Left = child->Right; + child->Right = (Node*)Unsafe.AsPointer(ref this); + return child; + } + + /// + /// Rotate right left + /// + /// Node + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Node* RotateRightLeft() + { + var child = Right; + var grandChild = child->Left; + Right = grandChild->Left; + grandChild->Left = (Node*)Unsafe.AsPointer(ref this); + child->Left = grandChild->Right; + grandChild->Right = child; + return grandChild; + } + + /// + /// Merge 2 nodes + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Merge2Nodes() + { + ColorBlack(); + Left->ColorRed(); + Right->ColorRed(); + } + + /// + /// Replace child + /// + /// Child + /// New child + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ReplaceChild(Node* child, Node* newChild) + { + if (Left == child) + Left = newChild; + else + Right = newChild; + } + } + + /// + /// Empty + /// + public static NativeSortedDictionary Empty => new(); + + /// + /// Get enumerator + /// + /// Enumerator + public Enumerator GetEnumerator() => new(this); + + /// + /// Enumerator + /// + public struct Enumerator : IDisposable + { + /// + /// NativeHashSet + /// + private readonly NativeSortedDictionary _nativeSortedDictionary; + + /// + /// Version + /// + private readonly int _version; + + /// + /// Node stack + /// + private readonly NativeStack _nodeStack; + + /// + /// Current + /// + private Node* _currentNode; + + /// + /// Current + /// + private KeyValuePair _current; + + /// + /// Structure + /// + /// NativeSortedDictionary + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal Enumerator(NativeSortedDictionary nativeSortedDictionary) + { + _nativeSortedDictionary = nativeSortedDictionary; + _version = nativeSortedDictionary._handle->Version; + _nodeStack = new NativeStack(2 * Log2(nativeSortedDictionary.Count + 1)); + _currentNode = null; + _current = default; + var node = _nativeSortedDictionary._handle->Root; + while (node != null) + { + var next = node->Left; + _nodeStack.Push((nint)node); + node = next; + } + } + + /// + /// Move next + /// + /// Moved + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool MoveNext() + { + if (_version != _nativeSortedDictionary._handle->Version) + throw new InvalidOperationException("EnumFailedVersion"); + if (!_nodeStack.TryPop(out var result)) + { + _currentNode = null; + _current = default; + return false; + } + + _currentNode = (Node*)result; + _current = new KeyValuePair(_currentNode->Key, _currentNode->Value); + var node = _currentNode->Right; + while (node != null) + { + var next = node->Left; + _nodeStack.Push((nint)node); + node = next; + } + + return true; + } + + /// + /// Current + /// + public KeyValuePair Current + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _current; + } + + /// + /// Dispose + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Dispose() => _nodeStack.Dispose(); + } + + /// + /// Key collection + /// + [StructLayout(LayoutKind.Sequential)] + public readonly struct KeyCollection + { + /// + /// NativeSortedDictionary + /// + private readonly NativeSortedDictionary _nativeSortedDictionary; + + /// + /// Structure + /// + /// NativeSortedDictionary + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal KeyCollection(NativeSortedDictionary nativeSortedDictionary) => _nativeSortedDictionary = nativeSortedDictionary; + + /// + /// Get enumerator + /// + /// Enumerator + public Enumerator GetEnumerator() => new(_nativeSortedDictionary); + + /// + /// Enumerator + /// + public struct Enumerator : IDisposable + { + /// + /// NativeHashSet + /// + private readonly NativeSortedDictionary _nativeSortedDictionary; + + /// + /// Version + /// + private readonly int _version; + + /// + /// Node stack + /// + private readonly NativeStack _nodeStack; + + /// + /// Current + /// + private Node* _currentNode; + + /// + /// Current + /// + private TKey _current; + + /// + /// Structure + /// + /// NativeSortedDictionary + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal Enumerator(NativeSortedDictionary nativeSortedDictionary) + { + _nativeSortedDictionary = nativeSortedDictionary; + _version = nativeSortedDictionary._handle->Version; + _nodeStack = new NativeStack(2 * Log2(nativeSortedDictionary.Count + 1)); + _currentNode = null; + _current = default; + var node = _nativeSortedDictionary._handle->Root; + while (node != null) + { + var next = node->Left; + _nodeStack.Push((nint)node); + node = next; + } + } + + /// + /// Move next + /// + /// Moved + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool MoveNext() + { + if (_version != _nativeSortedDictionary._handle->Version) + throw new InvalidOperationException("EnumFailedVersion"); + if (!_nodeStack.TryPop(out var result)) + { + _currentNode = null; + _current = default; + return false; + } + + _currentNode = (Node*)result; + _current = _currentNode->Key; + var node = _currentNode->Right; + while (node != null) + { + var next = node->Left; + _nodeStack.Push((nint)node); + node = next; + } + + return true; + } + + /// + /// Current + /// + public TKey Current + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _current; + } + + /// + /// Dispose + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Dispose() => _nodeStack.Dispose(); + } + } + + /// + /// Value collection + /// + [StructLayout(LayoutKind.Sequential)] + public readonly struct ValueCollection + { + /// + /// NativeSortedDictionary + /// + private readonly NativeSortedDictionary _nativeSortedDictionary; + + /// + /// Structure + /// + /// NativeSortedDictionary + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal ValueCollection(NativeSortedDictionary nativeSortedDictionary) => _nativeSortedDictionary = nativeSortedDictionary; + + /// + /// Get enumerator + /// + /// Enumerator + public Enumerator GetEnumerator() => new(_nativeSortedDictionary); + + /// + /// Enumerator + /// + public struct Enumerator : IDisposable + { + /// + /// NativeHashSet + /// + private readonly NativeSortedDictionary _nativeSortedDictionary; + + /// + /// Version + /// + private readonly int _version; + + /// + /// Node stack + /// + private readonly NativeStack _nodeStack; + + /// + /// Current + /// + private Node* _currentNode; + + /// + /// Current + /// + private TValue _current; + + /// + /// Structure + /// + /// NativeSortedDictionary + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal Enumerator(NativeSortedDictionary nativeSortedDictionary) + { + _nativeSortedDictionary = nativeSortedDictionary; + _version = nativeSortedDictionary._handle->Version; + _nodeStack = new NativeStack(2 * Log2(nativeSortedDictionary.Count + 1)); + _currentNode = null; + _current = default; + var node = _nativeSortedDictionary._handle->Root; + while (node != null) + { + var next = node->Left; + _nodeStack.Push((nint)node); + node = next; + } + } + + /// + /// Move next + /// + /// Moved + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool MoveNext() + { + if (_version != _nativeSortedDictionary._handle->Version) + throw new InvalidOperationException("EnumFailedVersion"); + if (!_nodeStack.TryPop(out var result)) + { + _currentNode = null; + _current = default; + return false; + } + + _currentNode = (Node*)result; + _current = _currentNode->Value; + var node = _currentNode->Right; + while (node != null) + { + var next = node->Left; + _nodeStack.Push((nint)node); + node = next; + } + + return true; + } + + /// + /// Current + /// + public TValue Current + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _current; + } + + /// + /// Dispose + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Dispose() => _nodeStack.Dispose(); + } + } + + /// + /// Node color + /// + private enum NodeColor : byte + { + Black, + Red + } + + /// + /// Tree rotation + /// + private enum TreeRotation : byte + { + Left, + LeftRight, + Right, + RightLeft + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeSortedDictionary.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeSortedDictionary.cs.meta new file mode 100644 index 0000000..e630072 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeSortedDictionary.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e295fbed2bc7842ba87143548bacc159 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeSortedList.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeSortedList.cs new file mode 100644 index 0000000..bb43bbf --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeSortedList.cs @@ -0,0 +1,695 @@ +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +#if UNITY_2021_3_OR_NEWER || GODOT +using System; +using System.Collections.Generic; +#endif + +#pragma warning disable CA2208 +#pragma warning disable CS8632 + +// ReSharper disable ALL + +namespace NativeCollections +{ + /// + /// Native sortedList + /// + /// Type + /// Type + [StructLayout(LayoutKind.Sequential)] + public readonly unsafe struct NativeSortedList where TKey : unmanaged, IComparable where TValue : unmanaged + { + /// + /// Handle + /// + [StructLayout(LayoutKind.Sequential)] + private struct NativeSortedListHandle + { + /// + /// Keys + /// + public TKey* Buckets; + + /// + /// Values + /// + public TValue* Entries; + + /// + /// Size + /// + public int Size; + + /// + /// Version + /// + public int Version; + + /// + /// Capacity + /// + public int Capacity; + + /// + /// Keys + /// + public KeyCollection Keys; + + /// + /// Values + /// + public ValueCollection Values; + } + + /// + /// Handle + /// + private readonly NativeSortedListHandle* _handle; + + /// + /// Keys + /// + public KeyCollection Keys => _handle->Keys; + + /// + /// Values + /// + public ValueCollection Values => _handle->Values; + + /// + /// Structure + /// + /// Capacity + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public NativeSortedList(int capacity) + { + if (capacity < 0) + throw new ArgumentOutOfRangeException(nameof(capacity), capacity, "MustBeNonNegative"); + if (capacity < 4) + capacity = 4; + _handle = (NativeSortedListHandle*)NativeMemoryAllocator.Alloc((uint)sizeof(NativeSortedListHandle)); + _handle->Buckets = (TKey*)NativeMemoryAllocator.Alloc((uint)(capacity * sizeof(TKey))); + _handle->Entries = (TValue*)NativeMemoryAllocator.Alloc((uint)(capacity * sizeof(TValue))); + _handle->Size = 0; + _handle->Version = 0; + _handle->Capacity = capacity; + _handle->Keys = new KeyCollection(this); + _handle->Values = new ValueCollection(this); + } + + /// + /// Is created + /// + public bool IsCreated => _handle != null; + + /// + /// Is empty + /// + public bool IsEmpty => _handle->Size == 0; + + /// + /// Get or set value + /// + /// Key + public TValue this[TKey key] + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get + { + var index = BinarySearch(_handle->Buckets, _handle->Size, key); + return index >= 0 ? _handle->Entries[index] : throw new KeyNotFoundException(key.ToString()); + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + set + { + var index = BinarySearch(_handle->Buckets, _handle->Size, key); + if (index >= 0) + { + _handle->Entries[index] = value; + ++_handle->Version; + } + else + { + Insert(~index, key, value); + } + } + } + + /// + /// Count + /// + public int Count => _handle->Size; + + /// + /// Capacity + /// + public int Capacity + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _handle->Capacity; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + set + { + if (value < _handle->Size) + throw new ArgumentOutOfRangeException(nameof(value), value, "SmallCapacity"); + if (value != _handle->Capacity) + { + if (value > 0) + { + var keys = (TKey*)NativeMemoryAllocator.Alloc((uint)(value * sizeof(TKey))); + var values = (TValue*)NativeMemoryAllocator.Alloc((uint)(value * sizeof(TValue))); + if (_handle->Size > 0) + { + Unsafe.CopyBlockUnaligned(keys, _handle->Buckets, (uint)(_handle->Size * sizeof(TKey))); + Unsafe.CopyBlockUnaligned(values, _handle->Entries, (uint)(_handle->Size * sizeof(TValue))); + } + + NativeMemoryAllocator.Free(_handle->Buckets); + NativeMemoryAllocator.Free(_handle->Entries); + _handle->Buckets = keys; + _handle->Entries = values; + } + else + { + NativeMemoryAllocator.Free(_handle->Buckets); + NativeMemoryAllocator.Free(_handle->Entries); + _handle->Buckets = (TKey*)NativeMemoryAllocator.Alloc(0); + _handle->Entries = (TValue*)NativeMemoryAllocator.Alloc(0); + } + + _handle->Capacity = value; + } + } + } + + /// + /// Equals + /// + /// Other + /// Equals + public bool Equals(NativeSortedList other) => other == this; + + /// + /// Equals + /// + /// object + /// Equals + public override bool Equals(object? obj) => obj is NativeSortedList nativeSortedList && nativeSortedList == this; + + /// + /// Get hashCode + /// + /// HashCode + public override int GetHashCode() => (int)(nint)_handle; + + /// + /// To string + /// + /// String + public override string ToString() => $"NativeSortedList<{typeof(TKey).Name}, {typeof(TValue).Name}>"; + + /// + /// Equals + /// + /// Left + /// Right + /// Equals + public static bool operator ==(NativeSortedList left, NativeSortedList right) => left._handle == right._handle; + + /// + /// Not equals + /// + /// Left + /// Right + /// Not equals + public static bool operator !=(NativeSortedList left, NativeSortedList right) => left._handle != right._handle; + + /// + /// Dispose + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Dispose() + { + if (_handle == null) + return; + NativeMemoryAllocator.Free(_handle->Buckets); + NativeMemoryAllocator.Free(_handle->Entries); + NativeMemoryAllocator.Free(_handle); + } + + /// + /// Clear + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Clear() + { + ++_handle->Version; + _handle->Size = 0; + } + + /// + /// Add + /// + /// Key + /// Value + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Add(in TKey key, in TValue value) + { + var num = BinarySearch(_handle->Buckets, _handle->Size, key); + if (num >= 0) + throw new ArgumentException($"AddingDuplicate, {key}", nameof(key)); + Insert(~num, key, value); + } + + /// + /// Remove + /// + /// Key + /// Removed + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool Remove(in TKey key) + { + var index = BinarySearch(_handle->Buckets, _handle->Size, key); + if (index >= 0) + { + --_handle->Size; + if (index < _handle->Size) + { + Unsafe.CopyBlockUnaligned(_handle->Buckets + index, _handle->Buckets + index + 1, (uint)((_handle->Size - index) * sizeof(TKey))); + Unsafe.CopyBlockUnaligned(_handle->Entries + index, _handle->Entries + index + 1, (uint)((_handle->Size - index) * sizeof(TValue))); + } + + ++_handle->Version; + return true; + } + + return false; + } + + /// + /// Remove + /// + /// Key + /// Value + /// Removed + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool Remove(in TKey key, out TValue value) + { + var index = BinarySearch(_handle->Buckets, _handle->Size, key); + if (index >= 0) + { + value = _handle->Entries[index]; + --_handle->Size; + if (index < _handle->Size) + { + Unsafe.CopyBlockUnaligned(_handle->Buckets + index, _handle->Buckets + index + 1, (uint)((_handle->Size - index) * sizeof(TKey))); + Unsafe.CopyBlockUnaligned(_handle->Entries + index, _handle->Entries + index + 1, (uint)((_handle->Size - index) * sizeof(TValue))); + } + + ++_handle->Version; + return true; + } + + value = default; + return false; + } + + /// + /// Contains key + /// + /// Key + /// Contains key + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool ContainsKey(in TKey key) => BinarySearch(_handle->Buckets, _handle->Size, key) >= 0; + + /// + /// Try to get the value + /// + /// Key + /// Value + /// Got + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool TryGetValue(in TKey key, out TValue value) + { + var index = BinarySearch(_handle->Buckets, _handle->Size, key); + if (index >= 0) + { + value = _handle->Entries[index]; + return true; + } + + value = default; + return false; + } + + /// + /// Ensure capacity + /// + /// Capacity + /// New capacity + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void EnsureCapacity(int capacity) + { + if (_handle->Capacity < capacity) + { + var newCapacity = 2 * _handle->Capacity; + if ((uint)newCapacity > 2147483591) + newCapacity = 2147483591; + var expected = _handle->Capacity + 4; + newCapacity = newCapacity > expected ? newCapacity : expected; + if (newCapacity < capacity) + newCapacity = capacity; + Capacity = newCapacity; + } + } + + /// + /// Trim excess + /// + /// New capacity + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public int TrimExcess() + { + var threshold = (int)(_handle->Capacity * 0.9); + if (_handle->Size < threshold) + Capacity = _handle->Size; + return _handle->Capacity; + } + + /// + /// Insert + /// + /// Index + /// Key + /// Value + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void Insert(int index, in TKey key, in TValue value) + { + if (_handle->Size == _handle->Capacity) + EnsureCapacity(_handle->Size + 1); + if (index < _handle->Size) + { + Unsafe.CopyBlockUnaligned(_handle->Buckets + index + 1, _handle->Buckets + index, (uint)((_handle->Size - index) * sizeof(TKey))); + Unsafe.CopyBlockUnaligned(_handle->Entries + index + 1, _handle->Entries + index, (uint)((_handle->Size - index) * sizeof(TValue))); + } + + _handle->Buckets[index] = key; + _handle->Entries[index] = value; + ++_handle->Size; + ++_handle->Version; + } + + /// + /// Binary search + /// + /// Start + /// Length + /// Comparable + /// Index + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static int BinarySearch(TKey* start, int length, in TKey comparable) + { + var low = 0; + var high = length - 1; + while (low <= high) + { + var i = (int)(((uint)high + (uint)low) >> 1); + var c = comparable.CompareTo(*(start + i)); + if (c == 0) + return i; + if (c > 0) + low = i + 1; + else + high = i - 1; + } + + return ~low; + } + + /// + /// Empty + /// + public static NativeSortedList Empty => new(); + + /// + /// Get enumerator + /// + /// Enumerator + public Enumerator GetEnumerator() => new(this); + + /// + /// Enumerator + /// + public struct Enumerator + { + /// + /// NativeSortedList + /// + private readonly NativeSortedList _nativeSortedList; + + /// + /// Current + /// + private KeyValuePair _current; + + /// + /// Index + /// + private int _index; + + /// + /// Version + /// + private readonly int _version; + + /// + /// Structure + /// + /// NativeSortedList + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal Enumerator(NativeSortedList nativeSortedList) + { + _nativeSortedList = nativeSortedList; + _current = default; + _index = 0; + _version = _nativeSortedList._handle->Version; + } + + /// + /// Move next + /// + /// Moved + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool MoveNext() + { + if (_version != _nativeSortedList._handle->Version) + throw new InvalidOperationException("EnumFailedVersion"); + if ((uint)_index < (uint)_nativeSortedList._handle->Size) + { + _current = new KeyValuePair(_nativeSortedList._handle->Buckets[_index], _nativeSortedList._handle->Entries[_index]); + ++_index; + return true; + } + + _index = _nativeSortedList._handle->Size + 1; + return false; + } + + /// + /// Current + /// + public KeyValuePair Current + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _current; + } + } + + /// + /// Key collection + /// + [StructLayout(LayoutKind.Sequential)] + public readonly struct KeyCollection + { + /// + /// NativeSortedList + /// + private readonly NativeSortedList _nativeSortedList; + + /// + /// Structure + /// + /// NativeSortedList + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal KeyCollection(NativeSortedList nativeSortedList) => _nativeSortedList = nativeSortedList; + + /// + /// Get enumerator + /// + /// Enumerator + public Enumerator GetEnumerator() => new(_nativeSortedList); + + /// + /// Enumerator + /// + public struct Enumerator + { + /// + /// NativeSortedList + /// + private readonly NativeSortedList _nativeSortedList; + + /// + /// Current + /// + private TKey _current; + + /// + /// Index + /// + private int _index; + + /// + /// Version + /// + private readonly int _version; + + /// + /// Structure + /// + /// NativeSortedList + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal Enumerator(NativeSortedList nativeSortedList) + { + _nativeSortedList = nativeSortedList; + _current = default; + _index = 0; + _version = _nativeSortedList._handle->Version; + } + + /// + /// Move next + /// + /// Moved + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool MoveNext() + { + if (_version != _nativeSortedList._handle->Version) + throw new InvalidOperationException("EnumFailedVersion"); + if ((uint)_index < (uint)_nativeSortedList._handle->Size) + { + _current = _nativeSortedList._handle->Buckets[_index]; + ++_index; + return true; + } + + _index = _nativeSortedList._handle->Size + 1; + return false; + } + + /// + /// Current + /// + public TKey Current + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _current; + } + } + } + + /// + /// Value collection + /// + [StructLayout(LayoutKind.Sequential)] + public readonly struct ValueCollection + { + /// + /// NativeSortedList + /// + private readonly NativeSortedList _nativeSortedList; + + /// + /// Structure + /// + /// NativeSortedList + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal ValueCollection(NativeSortedList nativeSortedList) => _nativeSortedList = nativeSortedList; + + /// + /// Get enumerator + /// + /// Enumerator + public Enumerator GetEnumerator() => new(_nativeSortedList); + + /// + /// Enumerator + /// + public struct Enumerator + { + /// + /// NativeSortedList + /// + private readonly NativeSortedList _nativeSortedList; + + /// + /// Current + /// + private TValue _current; + + /// + /// Index + /// + private int _index; + + /// + /// Version + /// + private readonly int _version; + + /// + /// Structure + /// + /// NativeSortedList + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal Enumerator(NativeSortedList nativeSortedList) + { + _nativeSortedList = nativeSortedList; + _current = default; + _index = 0; + _version = _nativeSortedList._handle->Version; + } + + /// + /// Move next + /// + /// Moved + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool MoveNext() + { + if (_version != _nativeSortedList._handle->Version) + throw new InvalidOperationException("EnumFailedVersion"); + if ((uint)_index < (uint)_nativeSortedList._handle->Size) + { + _current = _nativeSortedList._handle->Entries[_index]; + ++_index; + return true; + } + + _index = _nativeSortedList._handle->Size + 1; + return false; + } + + /// + /// Current + /// + public TValue Current + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _current; + } + } + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeSortedList.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeSortedList.cs.meta new file mode 100644 index 0000000..dc022ff --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeSortedList.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d099ab61a6bc1402d9b93681aa02480b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeSortedSet.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeSortedSet.cs new file mode 100644 index 0000000..f339276 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeSortedSet.cs @@ -0,0 +1,973 @@ +#if UNITY_2021_3_OR_NEWER || GODOT +using System; +#endif +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +#if NET5_0_OR_GREATER +#endif + +#pragma warning disable CA2208 +#pragma warning disable CS8632 + +// ReSharper disable ALL + +namespace NativeCollections +{ + /// + /// Native sortedSet + /// + /// Type + [StructLayout(LayoutKind.Sequential)] + public readonly unsafe struct NativeSortedSet : IDisposable, IEquatable> where T : unmanaged, IComparable + { + /// + /// Handle + /// + [StructLayout(LayoutKind.Sequential)] + private struct NativeSortedSetHandle + { + /// + /// Root + /// + public Node* Root; + + /// + /// Count + /// + public int Count; + + /// + /// Version + /// + public int Version; + + /// + /// Node pool + /// + public NativeMemoryPool NodePool; + } + + /// + /// Handle + /// + private readonly NativeSortedSetHandle* _handle; + + /// + /// Structure + /// + /// MemoryPool size + /// MemoryPool maxFreeSlabs + public NativeSortedSet(int size, int maxFreeSlabs) + { + var nodePool = new NativeMemoryPool(size, sizeof(Node), maxFreeSlabs); + _handle = (NativeSortedSetHandle*)NativeMemoryAllocator.Alloc((uint)sizeof(NativeSortedSetHandle)); + _handle->Root = null; + _handle->Count = 0; + _handle->Version = 0; + _handle->NodePool = nodePool; + } + + /// + /// Is created + /// + public bool IsCreated => _handle != null; + + /// + /// Is empty + /// + public bool IsEmpty => _handle->Count == 0; + + /// + /// Count + /// + public int Count => _handle->Count; + + /// + /// Min + /// + public T? Min + { + get + { + if (_handle->Root == null) + return default; + var current = _handle->Root; + while (current->Left != null) + current = current->Left; + return current->Item; + } + } + + /// + /// Max + /// + public T? Max + { + get + { + if (_handle->Root == null) + return default; + var current = _handle->Root; + while (current->Right != null) + current = current->Right; + return current->Item; + } + } + + /// + /// Equals + /// + /// Other + /// Equals + public bool Equals(NativeSortedSet other) => other == this; + + /// + /// Equals + /// + /// object + /// Equals + public override bool Equals(object? obj) => obj is NativeSortedSet nativeSortedSet && nativeSortedSet == this; + + /// + /// Get hashCode + /// + /// HashCode + public override int GetHashCode() => (int)(nint)_handle; + + /// + /// To string + /// + /// String + public override string ToString() => $"NativeSortedSet<{typeof(T).Name}>"; + + /// + /// Equals + /// + /// Left + /// Right + /// Equals + public static bool operator ==(NativeSortedSet left, NativeSortedSet right) => left._handle == right._handle; + + /// + /// Not equals + /// + /// Left + /// Right + /// Not equals + public static bool operator !=(NativeSortedSet left, NativeSortedSet right) => left._handle != right._handle; + + /// + /// Dispose + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Dispose() + { + if (_handle == null) + return; + _handle->NodePool.Dispose(); + NativeMemoryAllocator.Free(_handle); + } + + /// + /// Clear + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Clear() + { + if (_handle->Root != null) + { + var nodeStack = new NativeStack(2 * Log2(_handle->Count + 1)); + nodeStack.Push((nint)_handle->Root); + while (nodeStack.TryPop(out var node)) + { + var currentNode = (Node*)node; + if (currentNode->Left != null) + nodeStack.Push((nint)currentNode->Left); + if (currentNode->Right != null) + nodeStack.Push((nint)currentNode->Right); + _handle->NodePool.Return(currentNode); + } + + nodeStack.Dispose(); + } + + _handle->Root = null; + _handle->Count = 0; + ++_handle->Version; + } + + /// + /// Add + /// + /// Item + /// Added + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool Add(in T item) + { + if (_handle->Root == null) + { + _handle->Root = (Node*)_handle->NodePool.Rent(); + _handle->Root->Item = item; + _handle->Root->Left = null; + _handle->Root->Right = null; + _handle->Root->Color = NodeColor.Black; + _handle->Count = 1; + _handle->Version++; + return true; + } + + var current = _handle->Root; + Node* parent = null; + Node* grandParent = null; + Node* greatGrandParent = null; + _handle->Version++; + var order = 0; + while (current != null) + { + order = item.CompareTo(current->Item); + if (order == 0) + { + _handle->Root->ColorBlack(); + return false; + } + + if (current->Is4Node) + { + current->Split4Node(); + if (Node.IsNonNullRed(parent)) + InsertionBalance(current, parent, grandParent, greatGrandParent); + } + + greatGrandParent = grandParent; + grandParent = parent; + parent = current; + current = order < 0 ? current->Left : current->Right; + } + + var node = (Node*)_handle->NodePool.Rent(); + node->Item = item; + node->Left = null; + node->Right = null; + node->Color = NodeColor.Red; + if (order > 0) + parent->Right = node; + else + parent->Left = node; + if (parent->IsRed) + InsertionBalance(node, parent, grandParent, greatGrandParent); + _handle->Root->ColorBlack(); + ++_handle->Count; + return true; + } + + /// + /// Add + /// + /// Equal value + /// Actual value + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Add(in T equalValue, in T actualValue) + { + var node = FindNode(equalValue); + if (node == null) + { + Add(actualValue); + } + else + { + node->Item = actualValue; + _handle->Version++; + } + } + + /// + /// Remove + /// + /// Item + /// Removed + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool Remove(in T item) + { + if (_handle->Root == null) + return false; + _handle->Version++; + var current = _handle->Root; + Node* parent = null; + Node* grandParent = null; + Node* match = null; + Node* parentOfMatch = null; + var foundMatch = false; + while (current != null) + { + if (current->Is2Node) + { + if (parent == null) + { + current->ColorRed(); + } + else + { + var sibling = parent->GetSibling(current); + if (sibling->IsRed) + { + if (parent->Right == sibling) + parent->RotateLeft(); + else + parent->RotateRight(); + parent->ColorRed(); + sibling->ColorBlack(); + ReplaceChildOrRoot(grandParent, parent, sibling); + grandParent = sibling; + if (parent == match) + parentOfMatch = sibling; + sibling = parent->GetSibling(current); + } + + if (sibling->Is2Node) + { + parent->Merge2Nodes(); + } + else + { + var newGrandParent = parent->Rotate(parent->GetRotation(current, sibling)); + newGrandParent->Color = parent->Color; + parent->ColorBlack(); + current->ColorRed(); + ReplaceChildOrRoot(grandParent, parent, newGrandParent); + if (parent == match) + parentOfMatch = newGrandParent; + } + } + } + + var order = foundMatch ? -1 : item.CompareTo(current->Item); + if (order == 0) + { + foundMatch = true; + match = current; + parentOfMatch = parent; + } + + grandParent = parent; + parent = current; + current = order < 0 ? current->Left : current->Right; + } + + if (match != null) + { + ReplaceNode(match, parentOfMatch, parent, grandParent); + --_handle->Count; + _handle->NodePool.Return(match); + } + + if (_handle->Root != null) + _handle->Root->ColorBlack(); + return foundMatch; + } + + /// + /// Remove + /// + /// Equal value + /// Actual value + /// Removed + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool Remove(in T equalValue, out T actualValue) + { + if (_handle->Root == null) + { + actualValue = default; + return false; + } + + _handle->Version++; + var current = _handle->Root; + Node* parent = null; + Node* grandParent = null; + Node* match = null; + Node* parentOfMatch = null; + var foundMatch = false; + while (current != null) + { + if (current->Is2Node) + { + if (parent == null) + { + current->ColorRed(); + } + else + { + var sibling = parent->GetSibling(current); + if (sibling->IsRed) + { + if (parent->Right == sibling) + parent->RotateLeft(); + else + parent->RotateRight(); + parent->ColorRed(); + sibling->ColorBlack(); + ReplaceChildOrRoot(grandParent, parent, sibling); + grandParent = sibling; + if (parent == match) + parentOfMatch = sibling; + sibling = parent->GetSibling(current); + } + + if (sibling->Is2Node) + { + parent->Merge2Nodes(); + } + else + { + var newGrandParent = parent->Rotate(parent->GetRotation(current, sibling)); + newGrandParent->Color = parent->Color; + parent->ColorBlack(); + current->ColorRed(); + ReplaceChildOrRoot(grandParent, parent, newGrandParent); + if (parent == match) + parentOfMatch = newGrandParent; + } + } + } + + var order = foundMatch ? -1 : equalValue.CompareTo(current->Item); + if (order == 0) + { + foundMatch = true; + match = current; + parentOfMatch = parent; + } + + grandParent = parent; + parent = current; + current = order < 0 ? current->Left : current->Right; + } + + if (match != null) + { + actualValue = match->Item; + ReplaceNode(match, parentOfMatch, parent, grandParent); + --_handle->Count; + _handle->NodePool.Return(match); + } + else + { + actualValue = default; + } + + if (_handle->Root != null) + _handle->Root->ColorBlack(); + return foundMatch; + } + + /// + /// Contains + /// + /// Item + /// Contains + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool Contains(in T item) => FindNode(item) != null; + + /// + /// Try to get the actual value + /// + /// Equal value + /// Actual value + /// Got + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool TryGetValue(in T equalValue, out T actualValue) + { + var node = FindNode(equalValue); + if (node != null) + { + actualValue = node->Item; + return true; + } + + actualValue = default; + return false; + } + + /// + /// Insertion balance + /// + /// Current + /// Parent + /// Grand parent + /// GreatGrand parent + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void InsertionBalance(Node* current, Node* parent, Node* grandParent, Node* greatGrandParent) + { + var parentIsOnRight = grandParent->Right == parent; + var currentIsOnRight = parent->Right == current; + Node* newChildOfGreatGrandParent; + if (parentIsOnRight == currentIsOnRight) + newChildOfGreatGrandParent = currentIsOnRight ? grandParent->RotateLeft() : grandParent->RotateRight(); + else + newChildOfGreatGrandParent = currentIsOnRight ? grandParent->RotateLeftRight() : grandParent->RotateRightLeft(); + grandParent->ColorRed(); + newChildOfGreatGrandParent->ColorBlack(); + ReplaceChildOrRoot(greatGrandParent, grandParent, newChildOfGreatGrandParent); + } + + /// + /// Replace child or root + /// + /// Parent + /// Child + /// New child + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void ReplaceChildOrRoot(Node* parent, Node* child, Node* newChild) + { + if (parent != null) + parent->ReplaceChild(child, newChild); + else + _handle->Root = newChild; + } + + /// + /// Replace node + /// + /// Match + /// Parent of match + /// Successor + /// Parent of successor + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void ReplaceNode(Node* match, Node* parentOfMatch, Node* successor, Node* parentOfSuccessor) + { + if (successor == match) + { + successor = match->Left; + } + else + { + if (successor->Right != null) + successor->Right->ColorBlack(); + if (parentOfSuccessor != match) + { + parentOfSuccessor->Left = successor->Right; + successor->Right = match->Right; + } + + successor->Left = match->Left; + } + + if (successor != null) + successor->Color = match->Color; + ReplaceChildOrRoot(parentOfMatch, match, successor); + } + + /// + /// Find node + /// + /// Item + /// Node + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private Node* FindNode(in T item) + { + var current = _handle->Root; + while (current != null) + { + var order = item.CompareTo(current->Item); + if (order == 0) + return current; + current = order < 0 ? current->Left : current->Right; + } + + return null; + } + + /// + /// Log2 + /// + /// Value + /// Log2 + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static int Log2(int value) => BitOperationsHelpers.Log2(value); + + /// + /// Node + /// + [StructLayout(LayoutKind.Sequential)] + private struct Node + { + /// + /// Is non null red + /// + /// Node + /// Is non null red + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool IsNonNullRed(Node* node) => node != null && node->IsRed; + + /// + /// Is null or black + /// + /// Node + /// Is null or black + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static bool IsNullOrBlack(Node* node) => node == null || node->IsBlack; + + /// + /// Item + /// + public T Item + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + set; + } + + /// + /// Left + /// + public Node* Left + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + set; + } + + /// + /// Right + /// + public Node* Right + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + set; + } + + /// + /// Color + /// + public NodeColor Color + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + set; + } + + /// + /// Is black + /// + private bool IsBlack + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => Color == NodeColor.Black; + } + + /// + /// Is red + /// + public bool IsRed + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => Color == NodeColor.Red; + } + + /// + /// Is 2 node + /// + public bool Is2Node + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => IsBlack && IsNullOrBlack(Left) && IsNullOrBlack(Right); + } + + /// + /// Is 4 node + /// + public bool Is4Node + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => IsNonNullRed(Left) && IsNonNullRed(Right); + } + + /// + /// Set color to black + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ColorBlack() => Color = NodeColor.Black; + + /// + /// Set color to red + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ColorRed() => Color = NodeColor.Red; + + /// + /// Get rotation + /// + /// Current + /// Sibling + /// Rotation + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public TreeRotation GetRotation(Node* current, Node* sibling) + { + var currentIsLeftChild = Left == current; + return IsNonNullRed(sibling->Left) ? currentIsLeftChild ? TreeRotation.RightLeft : TreeRotation.Right : currentIsLeftChild ? TreeRotation.Left : TreeRotation.LeftRight; + } + + /// + /// Get sibling + /// + /// Node + /// Sibling + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Node* GetSibling(Node* node) => node == Left ? Right : Left; + + /// + /// Split 4 node + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Split4Node() + { + ColorRed(); + Left->ColorBlack(); + Right->ColorBlack(); + } + + /// + /// Rotate + /// + /// Rotation + /// Node + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Node* Rotate(TreeRotation rotation) + { + Node* removeRed; + switch (rotation) + { + case TreeRotation.Right: + removeRed = Left->Left; + removeRed->ColorBlack(); + return RotateRight(); + case TreeRotation.Left: + removeRed = Right->Right; + removeRed->ColorBlack(); + return RotateLeft(); + case TreeRotation.RightLeft: + return RotateRightLeft(); + case TreeRotation.LeftRight: + return RotateLeftRight(); + default: + return null; + } + } + + /// + /// Rotate left + /// + /// Node + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Node* RotateLeft() + { + var child = Right; + Right = child->Left; + child->Left = (Node*)Unsafe.AsPointer(ref this); + return child; + } + + /// + /// Rotate left right + /// + /// Node + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Node* RotateLeftRight() + { + var child = Left; + var grandChild = child->Right; + Left = grandChild->Right; + grandChild->Right = (Node*)Unsafe.AsPointer(ref this); + child->Right = grandChild->Left; + grandChild->Left = child; + return grandChild; + } + + /// + /// Rotate right + /// + /// Node + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Node* RotateRight() + { + var child = Left; + Left = child->Right; + child->Right = (Node*)Unsafe.AsPointer(ref this); + return child; + } + + /// + /// Rotate right left + /// + /// Node + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Node* RotateRightLeft() + { + var child = Right; + var grandChild = child->Left; + Right = grandChild->Left; + grandChild->Left = (Node*)Unsafe.AsPointer(ref this); + child->Left = grandChild->Right; + grandChild->Right = child; + return grandChild; + } + + /// + /// Merge 2 nodes + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Merge2Nodes() + { + ColorBlack(); + Left->ColorRed(); + Right->ColorRed(); + } + + /// + /// Replace child + /// + /// Child + /// New child + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void ReplaceChild(Node* child, Node* newChild) + { + if (Left == child) + Left = newChild; + else + Right = newChild; + } + } + + /// + /// Empty + /// + public static NativeSortedSet Empty => new(); + + /// + /// Get enumerator + /// + /// Enumerator + public Enumerator GetEnumerator() => new(this); + + /// + /// Enumerator + /// + public struct Enumerator : IDisposable + { + /// + /// NativeHashSet + /// + private readonly NativeSortedSet _nativeSortedSet; + + /// + /// Version + /// + private readonly int _version; + + /// + /// Node stack + /// + private readonly NativeStack _nodeStack; + + /// + /// Current + /// + private Node* _currentNode; + + /// + /// Current + /// + private T _current; + + /// + /// Structure + /// + /// NativeSortedSet + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal Enumerator(NativeSortedSet nativeSortedSet) + { + _nativeSortedSet = nativeSortedSet; + _version = nativeSortedSet._handle->Version; + _nodeStack = new NativeStack(2 * Log2(nativeSortedSet.Count + 1)); + _currentNode = null; + _current = default; + var node = _nativeSortedSet._handle->Root; + while (node != null) + { + var next = node->Left; + _nodeStack.Push((nint)node); + node = next; + } + } + + /// + /// Move next + /// + /// Moved + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool MoveNext() + { + if (_version != _nativeSortedSet._handle->Version) + throw new InvalidOperationException("EnumFailedVersion"); + if (!_nodeStack.TryPop(out var result)) + { + _currentNode = null; + _current = default; + return false; + } + + _currentNode = (Node*)result; + _current = _currentNode->Item; + var node = _currentNode->Right; + while (node != null) + { + var next = node->Left; + _nodeStack.Push((nint)node); + node = next; + } + + return true; + } + + /// + /// Current + /// + public T Current + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _current; + } + + /// + /// Dispose + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Dispose() => _nodeStack.Dispose(); + } + + /// + /// Node color + /// + private enum NodeColor : byte + { + Black, + Red + } + + /// + /// Tree rotation + /// + private enum TreeRotation : byte + { + Left, + LeftRight, + Right, + RightLeft + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeSortedSet.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeSortedSet.cs.meta new file mode 100644 index 0000000..6ced484 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeSortedSet.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d0caa62cbe6fc40269cb9da947e76599 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeStack.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeStack.cs new file mode 100644 index 0000000..5a295a2 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeStack.cs @@ -0,0 +1,425 @@ +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +#if UNITY_2021_3_OR_NEWER || GODOT +using System; +#endif + +#pragma warning disable CA2208 +#pragma warning disable CS8632 + +// ReSharper disable ALL + +namespace NativeCollections +{ + /// + /// Native stack + /// + /// Type + [StructLayout(LayoutKind.Sequential)] + public readonly unsafe struct NativeStack : IDisposable, IEquatable> where T : unmanaged + { + /// + /// Handle + /// + [StructLayout(LayoutKind.Sequential)] + private struct NativeStackHandle + { + /// + /// Array + /// + public T* Array; + + /// + /// Length + /// + public int Length; + + /// + /// Size + /// + public int Size; + + /// + /// Version + /// + public int Version; + } + + /// + /// Handle + /// + private readonly NativeStackHandle* _handle; + + /// + /// Structure + /// + /// Capacity + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public NativeStack(int capacity) + { + if (capacity < 0) + throw new ArgumentOutOfRangeException(nameof(capacity), capacity, "MustBeNonNegative"); + if (capacity < 4) + capacity = 4; + _handle = (NativeStackHandle*)NativeMemoryAllocator.Alloc((uint)sizeof(NativeStackHandle)); + _handle->Array = (T*)NativeMemoryAllocator.Alloc((uint)(capacity * sizeof(T))); + _handle->Length = capacity; + _handle->Size = 0; + _handle->Version = 0; + } + + /// + /// Is created + /// + public bool IsCreated => _handle != null; + + /// + /// Is empty + /// + public bool IsEmpty => _handle->Size == 0; + + /// + /// Get reference + /// + /// Index + public ref T this[int index] + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => ref _handle->Array[index]; + } + + /// + /// Get reference + /// + /// Index + public ref T this[uint index] + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => ref _handle->Array[index]; + } + + /// + /// Count + /// + public int Count => _handle->Size; + + /// + /// Equals + /// + /// Other + /// Equals + public bool Equals(NativeStack other) => other == this; + + /// + /// Equals + /// + /// object + /// Equals + public override bool Equals(object? obj) => obj is NativeStack nativeStack && nativeStack == this; + + /// + /// Get hashCode + /// + /// HashCode + public override int GetHashCode() => (int)(nint)_handle; + + /// + /// To string + /// + /// String + public override string ToString() => $"NativeStack<{typeof(T).Name}>"; + + /// + /// Equals + /// + /// Left + /// Right + /// Equals + public static bool operator ==(NativeStack left, NativeStack right) => left._handle == right._handle; + + /// + /// Not equals + /// + /// Left + /// Right + /// Not equals + public static bool operator !=(NativeStack left, NativeStack right) => left._handle != right._handle; + + /// + /// Dispose + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Dispose() + { + if (_handle == null) + return; + NativeMemoryAllocator.Free(_handle->Array); + NativeMemoryAllocator.Free(_handle); + } + + /// + /// Clear + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Clear() + { + _handle->Size = 0; + _handle->Version++; + } + + /// + /// Push + /// + /// Item + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Push(in T item) + { + var size = _handle->Size; + if ((uint)size < (uint)_handle->Length) + { + _handle->Array[size] = item; + _handle->Version++; + _handle->Size = size + 1; + } + else + { + Grow(_handle->Size + 1); + _handle->Array[_handle->Size] = item; + _handle->Version++; + _handle->Size++; + } + } + + /// + /// Try push + /// + /// Item + /// Pushed + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool TryPush(in T item) + { + var size = _handle->Size; + if ((uint)size < (uint)_handle->Length) + { + _handle->Array[size] = item; + _handle->Version++; + _handle->Size = size + 1; + return true; + } + + return false; + } + + /// + /// Pop + /// + /// Item + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public T Pop() + { + var size = _handle->Size - 1; + if ((uint)size >= (uint)_handle->Length) + throw new InvalidOperationException("EmptyStack"); + _handle->Version++; + _handle->Size = size; + var item = _handle->Array[size]; + return item; + } + + /// + /// Try pop + /// + /// Item + /// Popped + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool TryPop(out T result) + { + var size = _handle->Size - 1; + if ((uint)size >= (uint)_handle->Length) + { + result = default; + return false; + } + + _handle->Version++; + _handle->Size = size; + result = _handle->Array[size]; + return true; + } + + /// + /// Peek + /// + /// Item + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public T Peek() + { + var size = _handle->Size - 1; + return (uint)size >= (uint)_handle->Length ? throw new InvalidOperationException("EmptyStack") : _handle->Array[size]; + } + + /// + /// Try peek + /// + /// Item + /// Peeked + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool TryPeek(out T result) + { + var size = _handle->Size - 1; + if ((uint)size >= (uint)_handle->Length) + { + result = default; + return false; + } + + result = _handle->Array[size]; + return true; + } + + /// + /// Ensure capacity + /// + /// Capacity + /// New capacity + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public int EnsureCapacity(int capacity) + { + if (capacity < 0) + throw new ArgumentOutOfRangeException(nameof(capacity), capacity, "MustBeNonNegative"); + if (_handle->Length < capacity) + Grow(capacity); + return _handle->Length; + } + + /// + /// Trim excess + /// + /// New capacity + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public int TrimExcess() + { + var threshold = (int)(_handle->Length * 0.9); + if (_handle->Size < threshold) + SetCapacity(_handle->Size); + return _handle->Length; + } + + /// + /// Set capacity + /// + /// Capacity + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void SetCapacity(int capacity) + { + var newArray = (T*)NativeMemoryAllocator.Alloc((uint)(capacity * sizeof(T))); + if (_handle->Size > 0) + Unsafe.CopyBlockUnaligned(newArray, _handle->Array, (uint)(_handle->Length * sizeof(T))); + NativeMemoryAllocator.Free(_handle->Array); + _handle->Array = newArray; + _handle->Length = capacity; + } + + /// + /// Grow + /// + /// Capacity + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void Grow(int capacity) + { + var newCapacity = 2 * _handle->Length; + if ((uint)newCapacity > 2147483591) + newCapacity = 2147483591; + var expected = _handle->Length + 4; + newCapacity = newCapacity > expected ? newCapacity : expected; + if (newCapacity < capacity) + newCapacity = capacity; + SetCapacity(newCapacity); + } + + /// + /// Empty + /// + public static NativeStack Empty => new(); + + /// + /// Get enumerator + /// + /// Enumerator + public Enumerator GetEnumerator() => new(this); + + /// + /// Enumerator + /// + public struct Enumerator + { + /// + /// NativeStack + /// + private readonly NativeStack _nativeStack; + + /// + /// Version + /// + private readonly int _version; + + /// + /// Index + /// + private int _index; + + /// + /// Current element + /// + private T _currentElement; + + /// + /// Structure + /// + /// NativeStack + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal Enumerator(in NativeStack nativeStack) + { + _nativeStack = nativeStack; + _version = nativeStack._handle->Version; + _index = -2; + _currentElement = default; + } + + /// + /// Move next + /// + /// Moved + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool MoveNext() + { + if (_version != _nativeStack._handle->Version) + throw new InvalidOperationException("EnumFailedVersion"); + bool returned; + if (_index == -2) + { + _index = _nativeStack._handle->Size - 1; + returned = _index >= 0; + if (returned) + _currentElement = _nativeStack._handle->Array[_index]; + return returned; + } + + if (_index == -1) + return false; + returned = --_index >= 0; + _currentElement = returned ? _nativeStack._handle->Array[_index] : default; + return returned; + } + + /// + /// Current + /// + public T Current + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _index < 0 ? throw new InvalidOperationException(_index == -1 ? "EnumNotStarted" : "EnumEnded") : _currentElement; + } + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeStack.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeStack.cs.meta new file mode 100644 index 0000000..084a941 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/NativeCollections/NativeStack.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e743287c1428842cb84bffacf9ffcc39 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/README.md b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/README.md new file mode 100644 index 0000000..c3b41cf --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/README.md @@ -0,0 +1,3 @@ +# NativeCollections + +This project is a pure C# native collections for (Unity/Godot/.NET) \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/README.md.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/README.md.meta new file mode 100644 index 0000000..becb406 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/NativeCollections/README.md.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: b01660bc17b1a4f60bdf2a71837899c6 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/PriorityQueue.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/PriorityQueue.meta new file mode 100644 index 0000000..b926d22 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/PriorityQueue.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 2af7e2648850348b591adabb5ba44532 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/PriorityQueue/PriorityQueueGenerics.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/PriorityQueue/PriorityQueueGenerics.cs new file mode 100644 index 0000000..2ef6704 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/PriorityQueue/PriorityQueueGenerics.cs @@ -0,0 +1,121 @@ +// ReSharper disable SwapViaDeconstruction +// ReSharper disable UseIndexFromEndExpression +// ReSharper disable ConvertToPrimaryConstructor +using System; +using System.Collections.Generic; +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member + +#pragma warning disable CS8601 // Possible null reference assignment. +namespace Fantasy.DataStructure.PriorityQueue +{ + /// + /// 优先队列 + /// + /// 节点数据 + /// 排序的类型、 + public sealed class PriorityQueue where TPriority : IComparable + { + private readonly List> _heap; + + public PriorityQueue(int initialCapacity = 16) + { + _heap = new List>(initialCapacity); + } + + public int Count => _heap.Count; + + public void Enqueue(TElement element, TPriority priority) + { + _heap.Add(new PriorityQueueItem(element, priority)); + HeapifyUp(_heap.Count - 1); + } + + public TElement Dequeue() + { + if (_heap.Count == 0) + { + throw new InvalidOperationException("The queue is empty."); + } + + var item = _heap[0]; + _heap[0] = _heap[_heap.Count - 1]; + _heap.RemoveAt(_heap.Count - 1); + HeapifyDown(0); + return item.Element; + } + + public bool TryDequeue(out TElement element) + { + if (_heap.Count == 0) + { + element = default(TElement); + return false; + } + + element = Dequeue(); + return true; + } + + public TElement Peek() + { + if (_heap.Count == 0) + { + throw new InvalidOperationException("The queue is empty."); + } + return _heap[0].Element; + } + + // ReSharper disable once IdentifierTypo + private void HeapifyUp(int index) + { + while (index > 0) + { + var parentIndex = (index - 1) / 2; + if (_heap[index].Priority.CompareTo(_heap[parentIndex].Priority) >= 0) + { + break; + } + Swap(index, parentIndex); + index = parentIndex; + } + } + + // ReSharper disable once IdentifierTypo + private void HeapifyDown(int index) + { + var lastIndex = _heap.Count - 1; + while (true) + { + var smallestIndex = index; + var leftChildIndex = 2 * index + 1; + var rightChildIndex = 2 * index + 2; + + if (leftChildIndex <= lastIndex && _heap[leftChildIndex].Priority.CompareTo(_heap[smallestIndex].Priority) < 0) + { + smallestIndex = leftChildIndex; + } + + if (rightChildIndex <= lastIndex && _heap[rightChildIndex].Priority.CompareTo(_heap[smallestIndex].Priority) < 0) + { + smallestIndex = rightChildIndex; + } + + if (smallestIndex == index) + { + break; + } + + Swap(index, smallestIndex); + index = smallestIndex; + } + } + + private void Swap(int index1, int index2) + { + var temp = _heap[index1]; + _heap[index1] = _heap[index2]; + _heap[index2] = temp; + } + } +} + diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/PriorityQueue/PriorityQueueGenerics.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/PriorityQueue/PriorityQueueGenerics.cs.meta new file mode 100644 index 0000000..cd9ba0b --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/PriorityQueue/PriorityQueueGenerics.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d0fb73a1acb1843ad86127be8503ed92 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/PriorityQueue/PriorityQueueItem.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/PriorityQueue/PriorityQueueItem.cs new file mode 100644 index 0000000..5b020b2 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/PriorityQueue/PriorityQueueItem.cs @@ -0,0 +1,30 @@ +// ReSharper disable ConvertToPrimaryConstructor +// ReSharper disable SwapViaDeconstruction +// ReSharper disable InconsistentNaming +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member +namespace Fantasy.DataStructure.PriorityQueue +{ + public struct PriorityQueueItemUint + { + public T Element { get; set; } + public uint Priority { get; set; } + + public PriorityQueueItemUint(T element, uint priority) + { + Element = element; + Priority = priority; + } + } + + public struct PriorityQueueItem + { + public T Element { get; } + public T1 Priority { get; } + + public PriorityQueueItem(T element, T1 priority) + { + Element = element; + Priority = priority; + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/PriorityQueue/PriorityQueueItem.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/PriorityQueue/PriorityQueueItem.cs.meta new file mode 100644 index 0000000..17b47a5 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/PriorityQueue/PriorityQueueItem.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 79c4ab0531d874383b52d8b7082cf3a8 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/PriorityQueue/PriorityQueueSimple.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/PriorityQueue/PriorityQueueSimple.cs new file mode 100644 index 0000000..63a4418 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/PriorityQueue/PriorityQueueSimple.cs @@ -0,0 +1,116 @@ +// ReSharper disable SwapViaDeconstruction +// ReSharper disable UseIndexFromEndExpression +// ReSharper disable ConvertToPrimaryConstructor +using System; +using System.Collections.Generic; +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member +#pragma warning disable CS8601 // Possible null reference assignment. +namespace Fantasy.DataStructure.PriorityQueue +{ + public sealed class PriorityQueue where T : IComparable + { + private readonly List _heap; + + public PriorityQueue(int initialCapacity = 16) + { + _heap = new List(initialCapacity); + } + + public int Count => _heap.Count; + + public void Enqueue(T item) + { + _heap.Add(item); + HeapifyUp(_heap.Count - 1); + } + + public T Dequeue() + { + if (_heap.Count == 0) + { + throw new InvalidOperationException("The queue is empty."); + } + + var item = _heap[0]; + var heapCount = _heap.Count - 1; + _heap[0] = _heap[heapCount]; + _heap.RemoveAt(heapCount); + HeapifyDown(0); + return item; + } + + public bool TryDequeue(out T item) + { + if (_heap.Count == 0) + { + item = default(T); + return false; + } + + item = Dequeue(); + return true; + } + + public T Peek() + { + if (_heap.Count == 0) + { + throw new InvalidOperationException("The queue is empty."); + } + return _heap[0]; + } + + // ReSharper disable once IdentifierTypo + private void HeapifyUp(int index) + { + while (index > 0) + { + var parentIndex = (index - 1) / 2; + if (_heap[index].CompareTo(_heap[parentIndex]) >= 0) + { + break; + } + Swap(index, parentIndex); + index = parentIndex; + } + } + + // ReSharper disable once IdentifierTypo + private void HeapifyDown(int index) + { + var lastIndex = _heap.Count - 1; + while (true) + { + var smallestIndex = index; + var leftChildIndex = 2 * index + 1; + var rightChildIndex = 2 * index + 2; + + if (leftChildIndex <= lastIndex && _heap[leftChildIndex].CompareTo(_heap[smallestIndex]) < 0) + { + smallestIndex = leftChildIndex; + } + + if (rightChildIndex <= lastIndex && _heap[rightChildIndex].CompareTo(_heap[smallestIndex]) < 0) + { + smallestIndex = rightChildIndex; + } + + if (smallestIndex == index) + { + break; + } + + Swap(index, smallestIndex); + index = smallestIndex; + } + } + + private void Swap(int index1, int index2) + { + var temp = _heap[index1]; + _heap[index1] = _heap[index2]; + _heap[index2] = temp; + } + } +} + diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/PriorityQueue/PriorityQueueSimple.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/PriorityQueue/PriorityQueueSimple.cs.meta new file mode 100644 index 0000000..0cc767a --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/PriorityQueue/PriorityQueueSimple.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6c604a0410d104d68a5d1718a570e5c0 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/SkipTable.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/SkipTable.meta new file mode 100644 index 0000000..2361a4c --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/SkipTable.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 68c20f8b3fb7f461f9b2f22aa39b4c2e +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/SkipTable/SkipTable.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/SkipTable/SkipTable.cs new file mode 100644 index 0000000..acbc2c1 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/SkipTable/SkipTable.cs @@ -0,0 +1,190 @@ + +#pragma warning disable CS8602 // Dereference of a possibly null reference. +#pragma warning disable CS8601 // Possible null reference assignment. +#pragma warning disable CS8604 // Possible null reference argument. +#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. +#pragma warning disable CS8600 // Converting null literal or possible null value to non-nullable type. +namespace Fantasy.DataStructure.SkipTable +{ + /// + /// 跳表数据结构(升序版) + /// + /// 跳表中存储的值的类型。 + public class SkipTable : SkipTableBase + { + /// + /// 创建一个新的跳表实例。 + /// + /// 跳表的最大层数。 + public SkipTable(int maxLayer = 8) : base(maxLayer) { } + + /// + /// 向跳表中添加一个新节点。 + /// + /// 节点的主排序键。 + /// 节点的副排序键。 + /// 节点的唯一键。 + /// 要添加的值。 + public override void Add(long sortKey, long viceKey, long key, TValue value) + { + var rLevel = 1; + + while (rLevel <= MaxLayer && Random.Next(3) == 0) + { + ++rLevel; + } + + SkipTableNode cur = TopHeader, last = null; + + for (var layer = MaxLayer; layer >= 1; --layer) + { + // 节点有next节点,且 (next主键 < 插入主键) 或 (next主键 == 插入主键 且 next副键 < 插入副键) + while (cur.Right != null && ((cur.Right.SortKey < sortKey) || + (cur.Right.SortKey == sortKey && cur.Right.ViceKey < viceKey))) + { + cur = cur.Right; + } + + if (layer <= rLevel) + { + var currentRight = cur.Right; + + // 在当前层插入新节点 + cur.Right = new SkipTableNode(sortKey, viceKey, key, value, layer == 1 ? cur.Index + 1 : 0, cur, cur.Right, null); + + if (currentRight != null) + { + currentRight.Left = cur.Right; + } + + if (last != null) + { + last.Down = cur.Right; + } + + if (layer == 1) + { + // 更新索引信息 + cur.Right.Index = cur.Index + 1; + Node.Add(key, cur.Right); + + SkipTableNode v = cur.Right.Right; + + while (v != null) + { + v.Index++; + v = v.Right; + } + } + + last = cur.Right; + } + + cur = cur.Down; + } + } + + /// + /// 从跳表中移除一个节点。 + /// + /// 节点的主排序键。 + /// 节点的副排序键。 + /// 节点的唯一键。 + /// 被移除的节点的值。 + /// 如果成功移除节点,则为 true;否则为 false。 + public override bool Remove(long sortKey, long viceKey, long key, out TValue value) + { + value = default; + var seen = false; + var cur = TopHeader; + + for (var layer = MaxLayer; layer >= 1; --layer) + { + // 先按照主键查找 再 按副键查找 + while (cur.Right != null && cur.Right.SortKey < sortKey && cur.Right.Key != key) cur = cur.Right; + while (cur.Right != null && (cur.Right.SortKey == sortKey && cur.Right.ViceKey <= viceKey) && + cur.Right.Key != key) cur = cur.Right; + + var isFind = false; + var currentCur = cur; + SkipTableNode removeCur = null; + // 如果当前不是要删除的节点、但主键和副键都一样、需要特殊处理下。 + if (cur.Right != null && cur.Right.Key == key) + { + isFind = true; + removeCur = cur.Right; + currentCur = cur; + } + else + { + // 先向左查找下 + var currentNode = cur.Left; + while (currentNode != null && currentNode.SortKey == sortKey && currentNode.ViceKey == viceKey) + { + if (currentNode.Key == key) + { + isFind = true; + removeCur = currentNode; + currentCur = currentNode.Left; + break; + } + + currentNode = currentNode.Left; + } + + // 再向右查找下 + if (!isFind) + { + currentNode = cur.Right; + while (currentNode != null && currentNode.SortKey == sortKey && currentNode.ViceKey == viceKey) + { + if (currentNode.Key == key) + { + isFind = true; + removeCur = currentNode; + currentCur = currentNode.Left; + break; + } + + currentNode = currentNode.Right; + } + } + } + + if (isFind && currentCur != null) + { + value = removeCur.Value; + currentCur.Right = removeCur.Right; + + if (removeCur.Right != null) + { + removeCur.Right.Left = currentCur; + removeCur.Right = null; + } + + removeCur.Left = null; + removeCur.Down = null; + removeCur.Value = default; + + if (layer == 1) + { + var tempCur = currentCur.Right; + while (tempCur != null) + { + tempCur.Index--; + tempCur = tempCur.Right; + } + + Node.Remove(removeCur.Key); + } + + seen = true; + } + + cur = cur.Down; + } + + return seen; + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/SkipTable/SkipTable.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/SkipTable/SkipTable.cs.meta new file mode 100644 index 0000000..ebd23fe --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/SkipTable/SkipTable.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 45fbcdc219ef843aaa31594eb4e76a5b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/SkipTable/SkipTableBase.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/SkipTable/SkipTableBase.cs new file mode 100644 index 0000000..82783e8 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/SkipTable/SkipTableBase.cs @@ -0,0 +1,282 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Fantasy.DataStructure.Collection; + +#pragma warning disable CS8601 +#pragma warning disable CS8603 +#pragma warning disable CS8625 +#pragma warning disable CS8604 + +namespace Fantasy.DataStructure.SkipTable +{ + /// + /// 抽象的跳表基类,提供跳表的基本功能和操作。 + /// + /// 跳表中存储的值的类型。 + public abstract class SkipTableBase : IEnumerable> + { + /// + /// 跳表的最大层数 + /// + public readonly int MaxLayer; + /// + /// 跳表的顶部头节点 + /// + public readonly SkipTableNode TopHeader; + /// + /// 跳表的底部头节点 + /// + public SkipTableNode BottomHeader; + /// + /// 跳表中节点的数量,使用了 Node 字典的计数 + /// + public int Count => Node.Count; + /// + /// 用于生成随机数的随机数生成器 + /// + protected readonly Random Random = new Random(); + /// + /// 存储跳表节点的字典 + /// + protected readonly Dictionary> Node = new(); + /// + /// 用于辅助反向查找的栈 + /// + protected readonly Stack> AntiFindStack = new Stack>(); + + /// + /// 初始化一个新的跳表实例。 + /// + /// 跳表的最大层数,默认为 8。 + protected SkipTableBase(int maxLayer = 8) + { + MaxLayer = maxLayer; + var cur = TopHeader = new SkipTableNode(long.MinValue, 0, 0, default, 0, null, null, null); + + for (var layer = MaxLayer - 1; layer >= 1; --layer) + { + cur.Down = new SkipTableNode(long.MinValue, 0, 0, default, 0, null, null, null); + cur = cur.Down; + } + + BottomHeader = cur; + } + + /// + /// 获取指定键的节点的值,若不存在则返回默认值。 + /// + /// 要查找的键。 + public TValue this[long key] => !TryGetValueByKey(key, out TValue value) ? default : value; + + /// + /// 获取指定键的节点在跳表中的排名。 + /// + /// 要查找的键。 + /// 节点的排名。 + public int GetRanking(long key) + { + if (!Node.TryGetValue(key, out var node)) + { + return 0; + } + + return node.Index; + } + + /// + /// 获取指定键的反向排名,即在比该键更大的节点中的排名。 + /// + /// 要查找的键。 + /// 反向排名。 + public int GetAntiRanking(long key) + { + var ranking = GetRanking(key); + + if (ranking == 0) + { + return 0; + } + + return Count + 1 - ranking; + } + + /// + /// 尝试通过键获取节点的值。 + /// + /// 要查找的键。 + /// 获取到的节点的值,如果键不存在则为默认值。 + /// 是否成功获取节点的值。 + public bool TryGetValueByKey(long key, out TValue value) + { + if (!Node.TryGetValue(key, out var node)) + { + value = default; + return false; + } + + value = node.Value; + return true; + } + + /// + /// 尝试通过键获取节点。 + /// + /// 要查找的键。 + /// 获取到的节点,如果键不存在则为 null。 + /// 是否成功获取节点。 + public bool TryGetNodeByKey(long key, out SkipTableNode node) + { + if (Node.TryGetValue(key, out node)) + { + return true; + } + + return false; + } + + /// + /// 在跳表中查找节点,返回从起始位置到结束位置的节点列表。 + /// + /// 起始位置的排名。 + /// 结束位置的排名。 + /// 用于存储节点列表的 实例。 + public void Find(int start, int end, ListPool> list) + { + var cur = BottomHeader; + var count = end - start; + + for (var i = 0; i < start; i++) + { + cur = cur.Right; + } + + for (var i = 0; i <= count; i++) + { + if (cur == null) + { + break; + } + + list.Add(cur); + cur = cur.Right; + } + } + + /// + /// 在跳表中进行反向查找节点,返回从结束位置到起始位置的节点列表。 + /// + /// 结束位置的排名。 + /// 起始位置的排名。 + /// 用于存储节点列表的 实例。 + public void AntiFind(int start, int end, ListPool> list) + { + var cur = BottomHeader; + start = Count + 1 - start; + end = start - end; + + for (var i = 0; i < start; i++) + { + cur = cur.Right; + + if (cur == null) + { + break; + } + + if (i < end) + { + continue; + } + + AntiFindStack.Push(cur); + } + + while (AntiFindStack.TryPop(out var node)) + { + list.Add(node); + } + } + + /// + /// 获取跳表中最后一个节点的值。 + /// + /// 最后一个节点的值。 + public TValue GetLastValue() + { + var cur = TopHeader; + + while (cur.Right != null || cur.Down != null) + { + while (cur.Right != null) + { + cur = cur.Right; + } + + if (cur.Down != null) + { + cur = cur.Down; + } + } + + return cur.Value; + } + + /// + /// 移除跳表中指定键的节点。 + /// + /// 要移除的节点的键。 + /// 移除是否成功。 + public bool Remove(long key) + { + if (!Node.TryGetValue(key, out var node)) + { + return false; + } + + return Remove(node.SortKey, node.ViceKey, key, out _); + } + + /// + /// 向跳表中添加节点。 + /// + /// 节点的排序键。 + /// 节点的副键。 + /// 节点的键。 + /// 节点的值。 + public abstract void Add(long sortKey, long viceKey, long key, TValue value); + + /// + /// 从跳表中移除指定键的节点。 + /// + /// 节点的排序键。 + /// 节点的副键。 + /// 节点的键。 + /// 被移除的节点的值。 + /// 移除是否成功。 + public abstract bool Remove(long sortKey, long viceKey, long key, out TValue value); + + /// + /// 返回一个枚举器,用于遍历跳表中的节点。 + /// + /// 一个可用于遍历跳表节点的枚举器。 + public IEnumerator> GetEnumerator() + { + var cur = BottomHeader.Right; + while (cur != null) + { + yield return cur; + cur = cur.Right; + } + } + + /// + /// 返回一个非泛型枚举器,用于遍历跳表中的节点。 + /// + /// 一个非泛型枚举器,可用于遍历跳表节点。 + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/SkipTable/SkipTableBase.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/SkipTable/SkipTableBase.cs.meta new file mode 100644 index 0000000..500fa2d --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/SkipTable/SkipTableBase.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3c70c703e84d842b9b488dd0798290d3 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/SkipTable/SkipTableDesc.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/SkipTable/SkipTableDesc.cs new file mode 100644 index 0000000..63daa16 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/SkipTable/SkipTableDesc.cs @@ -0,0 +1,188 @@ + +#pragma warning disable CS8600 // Converting null literal or possible null value to non-nullable type. +#pragma warning disable CS8604 // Possible null reference argument. +#pragma warning disable CS8602 // Dereference of a possibly null reference. +#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. +#pragma warning disable CS8601 // Possible null reference assignment. +namespace Fantasy.DataStructure.SkipTable +{ + /// + /// 跳表降序版,用于存储降序排列的数据。 + /// + /// 存储的值的类型。 + public class SkipTableDesc : SkipTableBase + { + /// + /// 初始化跳表降序版的新实例。 + /// + /// 跳表的最大层数,默认为 8。 + public SkipTableDesc(int maxLayer = 8) : base(maxLayer) { } + + /// + /// 向跳表中添加一个节点,根据降序规则进行插入。 + /// + /// 排序主键。 + /// 副键。 + /// 键。 + /// 值。 + public override void Add(long sortKey, long viceKey, long key, TValue value) + { + var rLevel = 1; + + while (rLevel <= MaxLayer && Random.Next(3) == 0) + { + ++rLevel; + } + + SkipTableNode cur = TopHeader, last = null; + + for (var layer = MaxLayer; layer >= 1; --layer) + { + // 节点有next节点,且 (next主键 > 插入主键) 或 (next主键 == 插入主键 且 next副键 > 插入副键) + while (cur.Right != null && ((cur.Right.SortKey > sortKey) || + (cur.Right.SortKey == sortKey && cur.Right.ViceKey > viceKey))) + { + cur = cur.Right; + } + + if (layer <= rLevel) + { + var currentRight = cur.Right; + cur.Right = new SkipTableNode(sortKey, viceKey, key, value, + layer == 1 ? cur.Index + 1 : 0, cur, cur.Right, null); + + if (currentRight != null) + { + currentRight.Left = cur.Right; + } + + if (last != null) + { + last.Down = cur.Right; + } + + if (layer == 1) + { + cur.Right.Index = cur.Index + 1; + Node.Add(key, cur.Right); + + SkipTableNode v = cur.Right.Right; + + while (v != null) + { + v.Index++; + v = v.Right; + } + } + + last = cur.Right; + } + + cur = cur.Down; + } + } + + /// + /// 从跳表中移除一个节点,根据降序规则进行移除。 + /// + /// 排序主键。 + /// 副键。 + /// 键。 + /// 移除的节点值。 + /// 如果成功移除节点,则返回 true,否则返回 false。 + public override bool Remove(long sortKey, long viceKey, long key, out TValue value) + { + value = default; + var seen = false; + var cur = TopHeader; + + for (var layer = MaxLayer; layer >= 1; --layer) + { + // 先按照主键查找 再 按副键查找 + while (cur.Right != null && cur.Right.SortKey > sortKey && cur.Right.Key != key) cur = cur.Right; + while (cur.Right != null && (cur.Right.SortKey == sortKey && cur.Right.ViceKey >= viceKey) && + cur.Right.Key != key) cur = cur.Right; + + var isFind = false; + var currentCur = cur; + SkipTableNode removeCur = null; + // 如果当前不是要删除的节点、但主键和副键都一样、需要特殊处理下。 + if (cur.Right != null && cur.Right.Key == key) + { + isFind = true; + removeCur = cur.Right; + currentCur = cur; + } + else + { + // 先向左查找下 + var currentNode = cur.Left; + while (currentNode != null && currentNode.SortKey == sortKey && currentNode.ViceKey == viceKey) + { + if (currentNode.Key == key) + { + isFind = true; + removeCur = currentNode; + currentCur = currentNode.Left; + break; + } + + currentNode = currentNode.Left; + } + + // 再向右查找下 + if (!isFind) + { + currentNode = cur.Right; + while (currentNode != null && currentNode.SortKey == sortKey && currentNode.ViceKey == viceKey) + { + if (currentNode.Key == key) + { + isFind = true; + removeCur = currentNode; + currentCur = currentNode.Left; + break; + } + + currentNode = currentNode.Right; + } + } + } + + if (isFind && currentCur != null) + { + value = removeCur.Value; + currentCur.Right = removeCur.Right; + + if (removeCur.Right != null) + { + removeCur.Right.Left = currentCur; + removeCur.Right = null; + } + + removeCur.Left = null; + removeCur.Down = null; + removeCur.Value = default; + + if (layer == 1) + { + var tempCur = currentCur.Right; + while (tempCur != null) + { + tempCur.Index--; + tempCur = tempCur.Right; + } + + Node.Remove(removeCur.Key); + } + + seen = true; + } + + cur = cur.Down; + } + + return seen; + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/SkipTable/SkipTableDesc.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/SkipTable/SkipTableDesc.cs.meta new file mode 100644 index 0000000..7a58880 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/SkipTable/SkipTableDesc.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ae15364981a674c59a2e20d2b99f097b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/SkipTable/SkipTableNode.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/SkipTable/SkipTableNode.cs new file mode 100644 index 0000000..8a1a144 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/SkipTable/SkipTableNode.cs @@ -0,0 +1,68 @@ +namespace Fantasy.DataStructure.SkipTable +{ + /// + /// 跳跃表节点。 + /// + /// 节点的值的类型。 + public class SkipTableNode + { + /// + /// 节点在跳跃表中的索引。 + /// + public int Index; + /// + /// 节点的主键。 + /// + public long Key; + /// + /// 节点的排序键。 + /// + public long SortKey; + /// + /// 节点的副键。 + /// + public long ViceKey; + /// + /// 节点存储的值。 + /// + public TValue Value; + /// + /// 指向左侧节点的引用。 + /// + public SkipTableNode Left; + /// + /// 指向右侧节点的引用。 + /// + public SkipTableNode Right; + /// + /// 指向下一层节点的引用。 + /// + public SkipTableNode Down; + + /// + /// 初始化跳跃表节点的新实例。 + /// + /// 节点的排序键。 + /// 节点的副键。 + /// 节点的主键。 + /// 节点存储的值。 + /// 节点在跳跃表中的索引。 + /// 指向左侧节点的引用。 + /// 指向右侧节点的引用。 + /// 指向下一层节点的引用。 + public SkipTableNode(long sortKey, long viceKey, long key, TValue value, int index, + SkipTableNode l, + SkipTableNode r, + SkipTableNode d) + { + Left = l; + Right = r; + Down = d; + Value = value; + Key = key; + Index = index; + SortKey = sortKey; + ViceKey = viceKey; + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/SkipTable/SkipTableNode.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/SkipTable/SkipTableNode.cs.meta new file mode 100644 index 0000000..c3154ea --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/DataStructure/SkipTable/SkipTableNode.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9384bd7a2a46f401ea6de3461b5aa36b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas.meta new file mode 100644 index 0000000..9f74120 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 27462e8175ff84272b8b14c7b2ffb00c +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Component.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Component.meta new file mode 100644 index 0000000..01ffb2b --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Component.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e39207f0f9770415093af2f27fd7e988 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Component/CoroutineLock.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Component/CoroutineLock.meta new file mode 100644 index 0000000..779e6f2 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Component/CoroutineLock.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: db6a6392f9f6e4a2fbedb6ba3df377e8 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Component/CoroutineLock/CoroutineLock.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Component/CoroutineLock/CoroutineLock.cs new file mode 100644 index 0000000..a95d8f3 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Component/CoroutineLock/CoroutineLock.cs @@ -0,0 +1,140 @@ +using System; +using System.Collections.Generic; +using Fantasy.Pool; + +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. +#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. +namespace Fantasy.Async +{ + /// + /// 协程锁专用的对象池 + /// + public sealed class CoroutineLockPool : PoolCore + { + /// + /// 协程锁专用的对象池的构造函数 + /// + public CoroutineLockPool() : base(2000) { } + } + + /// + /// 协程锁 + /// + public sealed class CoroutineLock : IPool, IDisposable + { + private Scene _scene; + private CoroutineLockComponent _coroutineLockComponent; + private readonly Dictionary _queue = new Dictionary(); + /// + /// 表示是否是对象池中创建的 + /// + private bool _isPool; + /// + /// 协程锁的类型 + /// + public long CoroutineLockType { get; private set; } + + internal void Initialize(CoroutineLockComponent coroutineLockComponent, ref long coroutineLockType) + { + _scene = coroutineLockComponent.Scene; + CoroutineLockType = coroutineLockType; + _coroutineLockComponent = coroutineLockComponent; + } + /// + /// 销毁协程锁,如果调用了该方法,所有使用当前协程锁等待的逻辑会按照顺序释放锁。 + /// + public void Dispose() + { + foreach (var (_, coroutineLockQueue) in _queue) + { + while (TryCoroutineLockQueueDequeue(coroutineLockQueue)) { } + } + + _queue.Clear(); + _scene = null; + CoroutineLockType = 0; + _coroutineLockComponent = null; + } + /// + /// 等待上一个任务完成 + /// + /// 需要等待的Id + /// 用于查询协程锁的标记,可不传入,只有在超时的时候排查是哪个锁超时时使用 + /// 等待多久会超时,当到达设定的时候会把当前锁给按照超时处理 + /// + public async FTask Wait(long coroutineLockQueueKey, string tag = null, int timeOut = 30000) + { + var waitCoroutineLock = _coroutineLockComponent.WaitCoroutineLockPool.Rent(this, ref coroutineLockQueueKey, tag, timeOut); + + if (!_queue.TryGetValue(coroutineLockQueueKey, out var queue)) + { + queue = _coroutineLockComponent.CoroutineLockQueuePool.Rent(); + _queue.Add(coroutineLockQueueKey, queue); + return waitCoroutineLock; + } + + queue.Enqueue(waitCoroutineLock); + return await waitCoroutineLock.Tcs; + } + /// + /// 按照先入先出的顺序,释放最早的一个协程锁 + /// + /// + public void Release(long coroutineLockQueueKey) + { + if (!_queue.TryGetValue(coroutineLockQueueKey, out var coroutineLockQueue)) + { + return; + } + + if (!TryCoroutineLockQueueDequeue(coroutineLockQueue)) + { + _queue.Remove(coroutineLockQueueKey); + } + } + + private bool TryCoroutineLockQueueDequeue(CoroutineLockQueue coroutineLockQueue) + { + if (!coroutineLockQueue.TryDequeue(out var waitCoroutineLock)) + { + _coroutineLockComponent.CoroutineLockQueuePool.Return(coroutineLockQueue); + return false; + } + + if (waitCoroutineLock.TimerId != 0) + { + _scene.TimerComponent.Net.Remove(waitCoroutineLock.TimerId); + } + + try + { + // 放到下一帧执行,如果不这样会导致逻辑的顺序不正常。 + _scene.ThreadSynchronizationContext.Post(waitCoroutineLock.SetResult); + } + catch (Exception e) + { + Log.Error($"Error in disposing CoroutineLock: {e}"); + } + + return true; + } + + /// + /// 获取一个值,该值指示当前实例是否为对象池中的实例。 + /// + /// + public bool IsPool() + { + return _isPool; + } + + /// + /// 设置一个值,该值指示当前实例是否为对象池中的实例。 + /// + /// + public void SetIsPool(bool isPool) + { + _isPool = isPool; + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Component/CoroutineLock/CoroutineLock.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Component/CoroutineLock/CoroutineLock.cs.meta new file mode 100644 index 0000000..d67163d --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Component/CoroutineLock/CoroutineLock.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e2fe8fb8f49ad4565b47c840fb690d1f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Component/CoroutineLock/CoroutineLockComponent.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Component/CoroutineLock/CoroutineLockComponent.cs new file mode 100644 index 0000000..4644274 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Component/CoroutineLock/CoroutineLockComponent.cs @@ -0,0 +1,100 @@ +using System.Collections.Generic; +using Fantasy.Entitas; + +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. +#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. + +namespace Fantasy.Async +{ + /// + /// 协程锁组件 + /// + public class CoroutineLockComponent : Entity + { + private long _lockId; + private CoroutineLockPool _coroutineLockPool; + internal WaitCoroutineLockPool WaitCoroutineLockPool { get; private set; } + internal CoroutineLockQueuePool CoroutineLockQueuePool { get; private set; } + private readonly Dictionary _coroutineLocks = new Dictionary(); + internal CoroutineLockComponent Initialize() + { + _coroutineLockPool = new CoroutineLockPool(); + CoroutineLockQueuePool = new CoroutineLockQueuePool(); + WaitCoroutineLockPool = new WaitCoroutineLockPool(this); + return this; + } + + internal long LockId => ++_lockId; + +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member + public override void Dispose() +#pragma warning restore CS1591 // Missing XML comment for publicly visible type or member + { + if (IsDisposed) + { + return; + } + + _lockId = 0; + base.Dispose(); + } + + /// + /// 创建一个新的协程锁 + /// 使用这个方法创建的协程锁,需要手动释放管理CoroutineLock。 + /// 不会再CoroutineLockComponent理进行管理。 + /// + /// + /// + public CoroutineLock Create(long coroutineLockType) + { + var coroutineLock = _coroutineLockPool.Rent(); + coroutineLock.Initialize(this, ref coroutineLockType); + return coroutineLock; + } + + /// + /// 请求一个协程锁。 + /// 使用这个方法创建的协程锁,会自动释放CoroutineLockQueueType。 + /// + /// 锁类型 + /// 锁队列Id + /// 当某些锁超时,需要一个标记来方便排查问题,正常的情况下这个默认为null就可以。 + /// 设置锁的超时时间,让超过设置的时间会触发超时,保证锁不会因为某一个锁一直不解锁导致卡住的问题。 + /// + /// 返回的WaitCoroutineLock通过Dispose来解除这个锁、建议用using来保住这个锁。 + /// 也可以返回的WaitCoroutineLock通过CoroutineLockComponent.UnLock来解除这个锁。 + /// + public FTask Wait(long coroutineLockType, long coroutineLockQueueKey, string tag = null, int time = 30000) + { + if (!_coroutineLocks.TryGetValue(coroutineLockType, out var coroutineLock)) + { + coroutineLock = _coroutineLockPool.Rent(); + coroutineLock.Initialize(this, ref coroutineLockType); + _coroutineLocks.Add(coroutineLockType, coroutineLock); + } + + return coroutineLock.Wait(coroutineLockQueueKey, tag, time); + } + + /// + /// 解除一个协程锁。 + /// + /// + /// + public void Release(int coroutineLockType, long coroutineLockQueueKey) + { + if (IsDisposed) + { + return; + } + + if (!_coroutineLocks.TryGetValue(coroutineLockType, out var coroutineLock)) + { + return; + } + + coroutineLock.Release(coroutineLockQueueKey); + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Component/CoroutineLock/CoroutineLockComponent.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Component/CoroutineLock/CoroutineLockComponent.cs.meta new file mode 100644 index 0000000..c4a03b1 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Component/CoroutineLock/CoroutineLockComponent.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8abfde11ad4d344eda0bf16b249a0dae +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Component/CoroutineLock/CoroutineLockQueue.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Component/CoroutineLock/CoroutineLockQueue.cs new file mode 100644 index 0000000..2948aca --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Component/CoroutineLock/CoroutineLockQueue.cs @@ -0,0 +1,35 @@ +// ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract +using System.Collections.Generic; +using Fantasy.Pool; + +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. +#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. +namespace Fantasy.Async +{ + internal sealed class CoroutineLockQueuePool : PoolCore + { + public CoroutineLockQueuePool() : base(2000) { } + } + + internal sealed class CoroutineLockQueue : Queue, IPool + { + private bool _isPool; + /// + /// 获取一个值,该值指示当前实例是否为对象池中的实例。 + /// + /// + public bool IsPool() + { + return _isPool; + } + + /// + /// 设置一个值,该值指示当前实例是否为对象池中的实例。 + /// + /// + public void SetIsPool(bool isPool) + { + _isPool = isPool; + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Component/CoroutineLock/CoroutineLockQueue.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Component/CoroutineLock/CoroutineLockQueue.cs.meta new file mode 100644 index 0000000..1e55b8c --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Component/CoroutineLock/CoroutineLockQueue.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c1a15c49a7b7b488c8aac3d7720d506e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Component/CoroutineLock/WaitCoroutineLock.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Component/CoroutineLock/WaitCoroutineLock.cs new file mode 100644 index 0000000..28d04d4 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Component/CoroutineLock/WaitCoroutineLock.cs @@ -0,0 +1,146 @@ +using System; +using Fantasy.Event; +using Fantasy.Pool; + +#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. +namespace Fantasy.Async +{ + internal sealed class WaitCoroutineLockPool : PoolCore + { + private readonly Scene _scene; + private readonly CoroutineLockComponent _coroutineLockComponent; + + public WaitCoroutineLockPool(CoroutineLockComponent coroutineLockComponent) : base(2000) + { + _scene = coroutineLockComponent.Scene; + _coroutineLockComponent = coroutineLockComponent; + } + + public WaitCoroutineLock Rent(CoroutineLock coroutineLock, ref long coroutineLockQueueKey, string tag = null, int timeOut = 30000) + { + var timerId = 0L; + var lockId = _coroutineLockComponent.LockId; + var waitCoroutineLock = _coroutineLockComponent.WaitCoroutineLockPool.Rent(); + + if (timeOut > 0) + { + timerId = _scene.TimerComponent.Net.OnceTimer(timeOut, new CoroutineLockTimeout(ref lockId, waitCoroutineLock)); + } + + waitCoroutineLock.Initialize(coroutineLock, this, ref coroutineLockQueueKey, ref timerId, ref lockId, tag); + return waitCoroutineLock; + } + } + + internal struct CoroutineLockTimeout + { + public readonly long LockId; + public readonly WaitCoroutineLock WaitCoroutineLock; + + public CoroutineLockTimeout(ref long lockId, WaitCoroutineLock waitCoroutineLock) + { + LockId = lockId; + WaitCoroutineLock = waitCoroutineLock; + } + } + + internal sealed class OnCoroutineLockTimeout : EventSystem + { + protected override void Handler(CoroutineLockTimeout self) + { + var selfWaitCoroutineLock = self.WaitCoroutineLock; + + if (self.LockId != selfWaitCoroutineLock.LockId) + { + return; + } + + Log.Error($"coroutine lock timeout CoroutineLockQueueType:{selfWaitCoroutineLock.CoroutineLock.CoroutineLockType} Key:{selfWaitCoroutineLock.CoroutineLockQueueKey} Tag:{selfWaitCoroutineLock.Tag}"); + } + } + + /// + /// 一个协程锁的实例,用户可以用过这个手动释放锁 + /// + public sealed class WaitCoroutineLock : IPool, IDisposable + { + private bool _isPool; + internal string Tag { get; private set; } + internal long LockId { get; private set; } + internal long TimerId { get; private set; } + internal long CoroutineLockQueueKey { get; private set; } + internal CoroutineLock CoroutineLock { get; private set; } + + private bool _isSetResult; + private FTask _tcs; + private WaitCoroutineLockPool _waitCoroutineLockPool; + internal void Initialize(CoroutineLock coroutineLock, WaitCoroutineLockPool waitCoroutineLockPool, ref long coroutineLockQueueKey, ref long timerId, ref long lockId, string tag) + { + Tag = tag; + LockId = lockId; + TimerId = timerId; + CoroutineLock = coroutineLock; + CoroutineLockQueueKey = coroutineLockQueueKey; + _waitCoroutineLockPool = waitCoroutineLockPool; + } + /// + /// 释放协程锁 + /// + public void Dispose() + { + if (LockId == 0) + { + Log.Error("WaitCoroutineLock is already disposed"); + return; + } + + CoroutineLock.Release(CoroutineLockQueueKey); + + _tcs = null; + Tag = null; + LockId = 0; + TimerId = 0; + _isSetResult = false; + CoroutineLockQueueKey = 0; + _waitCoroutineLockPool.Return(this); + CoroutineLock = null; + _waitCoroutineLockPool = null; + } + + internal FTask Tcs + { + get { return _tcs ??= FTask.Create(); } + } + + internal void SetResult() + { + if (_isSetResult) + { + Log.Error("WaitCoroutineLock is already SetResult"); + return; + } + + _isSetResult = true; + Tcs.SetResult(this); + } + + /// + /// 获取一个值,该值指示当前实例是否为对象池中的实例。 + /// + /// + public bool IsPool() + { + return _isPool; + } + + /// + /// 设置一个值,该值指示当前实例是否为对象池中的实例。 + /// + /// + public void SetIsPool(bool isPool) + { + _isPool = isPool; + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Component/CoroutineLock/WaitCoroutineLock.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Component/CoroutineLock/WaitCoroutineLock.cs.meta new file mode 100644 index 0000000..9aa7508 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Component/CoroutineLock/WaitCoroutineLock.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c6d5307f677ba48f891c12ac183a0128 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Component/EntityComponent.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Component/EntityComponent.cs new file mode 100644 index 0000000..aa92314 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Component/EntityComponent.cs @@ -0,0 +1,399 @@ +// ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using Fantasy.Assembly; +using Fantasy.Async; +using Fantasy.DataStructure.Collection; +using Fantasy.Entitas; +using Fantasy.Entitas.Interface; +using Fantasy.Helper; + +#pragma warning disable CS8604 // Possible null reference argument. +#pragma warning disable CS8600 // Converting null literal or possible null value to non-nullable type. +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member +namespace Fantasy.Entitas +{ + internal sealed class UpdateQueueInfo + { + public bool IsStop; + public readonly Type Type; + public readonly long RunTimeId; + + public UpdateQueueInfo(Type type, long runTimeId) + { + Type = type; + IsStop = false; + RunTimeId = runTimeId; + } + } + + internal sealed class FrameUpdateQueueInfo + { + public readonly Type Type; + public readonly long RunTimeId; + + public FrameUpdateQueueInfo(Type type, long runTimeId) + { + Type = type; + RunTimeId = runTimeId; + } + } + + /// + /// Entity管理组件 + /// + public sealed class EntityComponent : Entity, ISceneUpdate, IAssembly + { + private readonly OneToManyList _assemblyList = new(); + private readonly OneToManyList _assemblyHashCodes = new(); + + private readonly Dictionary _awakeSystems = new(); + private readonly Dictionary _updateSystems = new(); + private readonly Dictionary _destroySystems = new(); + private readonly Dictionary _deserializeSystems = new(); + private readonly Dictionary _frameUpdateSystem = new(); + + private readonly Dictionary _hashCodes = new Dictionary(); + private readonly Queue _updateQueue = new Queue(); + private readonly Queue _frameUpdateQueue = new Queue(); + private readonly Dictionary _updateQueueDic = new Dictionary(); + + internal async FTask Initialize() + { + await AssemblySystem.Register(this); + return this; + } + + #region Assembly + + public FTask Load(long assemblyIdentity) + { + var task = FTask.Create(false); + Scene.ThreadSynchronizationContext.Post(() => + { + LoadInner(assemblyIdentity); + task.SetResult(); + }); + return task; + } + + public FTask ReLoad(long assemblyIdentity) + { + var task = FTask.Create(false); + Scene.ThreadSynchronizationContext.Post(() => + { + OnUnLoadInner(assemblyIdentity); + LoadInner(assemblyIdentity); + task.SetResult(); + }); + + return task; + } + + public FTask OnUnLoad(long assemblyIdentity) + { + var task = FTask.Create(false); + Scene.ThreadSynchronizationContext.Post(() => + { + OnUnLoadInner(assemblyIdentity); + task.SetResult(); + }); + return task; + } + + private void LoadInner(long assemblyIdentity) + { + foreach (var entityType in AssemblySystem.ForEach(assemblyIdentity, typeof(IEntity))) + { + _hashCodes.Add(entityType, HashCodeHelper.ComputeHash64(entityType.FullName)); + _assemblyHashCodes.Add(assemblyIdentity, entityType); + } + + foreach (var entitiesSystemType in AssemblySystem.ForEach(assemblyIdentity, typeof(IEntitiesSystem))) + { + Type entitiesType = null; + var entity = Activator.CreateInstance(entitiesSystemType); + + switch (entity) + { + case IAwakeSystem iAwakeSystem: + { + entitiesType = iAwakeSystem.EntitiesType(); + _awakeSystems.Add(entitiesType, iAwakeSystem); + break; + } + case IDestroySystem iDestroySystem: + { + entitiesType = iDestroySystem.EntitiesType(); + _destroySystems.Add(entitiesType, iDestroySystem); + break; + } + case IDeserializeSystem iDeserializeSystem: + { + entitiesType = iDeserializeSystem.EntitiesType(); + _deserializeSystems.Add(entitiesType, iDeserializeSystem); + break; + } + case IUpdateSystem iUpdateSystem: + { + entitiesType = iUpdateSystem.EntitiesType(); + _updateSystems.Add(entitiesType, iUpdateSystem); + break; + } + case IFrameUpdateSystem iFrameUpdateSystem: + { + entitiesType = iFrameUpdateSystem.EntitiesType(); + _frameUpdateSystem.Add(entitiesType, iFrameUpdateSystem); + break; + } + default: + { + Log.Error($"IEntitiesSystem not support type {entitiesSystemType}"); + return; + } + } + + _assemblyList.Add(assemblyIdentity, entitiesType); + } + } + + private void OnUnLoadInner(long assemblyIdentity) + { + if (_assemblyHashCodes.TryGetValue(assemblyIdentity, out var entityType)) + { + foreach (var type in entityType) + { + _hashCodes.Remove(type); + } + + _assemblyHashCodes.RemoveByKey(assemblyIdentity); + } + + if (_assemblyList.TryGetValue(assemblyIdentity, out var assembly)) + { + foreach (var type in assembly) + { + _awakeSystems.Remove(type); + _updateSystems.Remove(type); + _destroySystems.Remove(type); + _deserializeSystems.Remove(type); + _frameUpdateSystem.Remove(type); + } + + _assemblyList.RemoveByKey(assemblyIdentity); + } + } + + #endregion + + #region Event + + /// + /// 触发实体的唤醒方法 + /// + /// 实体对象 + public void Awake(Entity entity) + { + if (!_awakeSystems.TryGetValue(entity.Type, out var awakeSystem)) + { + return; + } + + try + { + awakeSystem.Invoke(entity); + } + catch (Exception e) + { + Log.Error($"{entity.Type.FullName} Error {e}"); + } + } + + /// + /// 触发实体的销毁方法 + /// + /// 实体对象 + public void Destroy(Entity entity) + { + if (!_destroySystems.TryGetValue(entity.Type, out var system)) + { + return; + } + + try + { + system.Invoke(entity); + } + catch (Exception e) + { + Log.Error($"{entity.Type.FullName} Destroy Error {e}"); + } + } + + /// + /// 触发实体的反序列化方法 + /// + /// 实体对象 + public void Deserialize(Entity entity) + { + if (!_deserializeSystems.TryGetValue(entity.Type, out var system)) + { + return; + } + + try + { + system.Invoke(entity); + } + catch (Exception e) + { + Log.Error($"{entity.Type.FullName} Deserialize Error {e}"); + } + } + + #endregion + + #region Update + + /// + /// 将实体加入更新队列,准备进行更新 + /// + /// 实体对象 + public void StartUpdate(Entity entity) + { + var type = entity.Type; + var entityRuntimeId = entity.RuntimeId; + + if (_updateSystems.ContainsKey(type)) + { + var updateQueueInfo = new UpdateQueueInfo(type, entityRuntimeId); + _updateQueue.Enqueue(updateQueueInfo); + _updateQueueDic.Add(entityRuntimeId, updateQueueInfo); + } + + if (_frameUpdateSystem.ContainsKey(type)) + { + _frameUpdateQueue.Enqueue(new FrameUpdateQueueInfo(type, entityRuntimeId)); + } + } + + /// + /// 停止实体进行更新 + /// + /// 实体对象 + public void StopUpdate(Entity entity) + { + if (!_updateQueueDic.Remove(entity.RuntimeId, out var updateQueueInfo)) + { + return; + } + + updateQueueInfo.IsStop = true; + } + + /// + /// 执行实体系统的更新逻辑 + /// + public void Update() + { + var updateQueueCount = _updateQueue.Count; + + while (updateQueueCount-- > 0) + { + var updateQueueStruct = _updateQueue.Dequeue(); + + if (updateQueueStruct.IsStop) + { + continue; + } + + if (!_updateSystems.TryGetValue(updateQueueStruct.Type, out var updateSystem)) + { + continue; + } + + var entity = Scene.GetEntity(updateQueueStruct.RunTimeId); + + if (entity == null || entity.IsDisposed) + { + _updateQueueDic.Remove(updateQueueStruct.RunTimeId); + continue; + } + + _updateQueue.Enqueue(updateQueueStruct); + + try + { + updateSystem.Invoke(entity); + } + catch (Exception e) + { + Log.Error($"{updateQueueStruct.Type.FullName} Update Error {e}"); + } + } + } + + /// + /// 执行实体系统的帧更新逻辑 + /// + public void FrameUpdate() + { + var count = _frameUpdateQueue.Count; + + while (count-- > 0) + { + var frameUpdateQueueStruct = _frameUpdateQueue.Dequeue(); + + if (!_frameUpdateSystem.TryGetValue(frameUpdateQueueStruct.Type, out var frameUpdateSystem)) + { + continue; + } + + var entity = Scene.GetEntity(frameUpdateQueueStruct.RunTimeId); + + if (entity == null || entity.IsDisposed) + { + continue; + } + + _frameUpdateQueue.Enqueue(frameUpdateQueueStruct); + + try + { + frameUpdateSystem.Invoke(entity); + } + catch (Exception e) + { + Log.Error($"{frameUpdateQueueStruct.Type.FullName} FrameUpdate Error {e}"); + } + } + } + + #endregion + + public long GetHashCode(Type type) + { + return _hashCodes[type]; + } + + /// + /// 释放实体系统管理器资源 + /// + public override void Dispose() + { + _updateQueue.Clear(); + _frameUpdateQueue.Clear(); + + _assemblyList.Clear(); + _awakeSystems.Clear(); + _updateSystems.Clear(); + _destroySystems.Clear(); + _deserializeSystems.Clear(); + _frameUpdateSystem.Clear(); + + AssemblySystem.UnRegister(this); + base.Dispose(); + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Component/EntityComponent.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Component/EntityComponent.cs.meta new file mode 100644 index 0000000..a838498 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Component/EntityComponent.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 41c0ffdbeaaf84d848105eb341414c4a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Component/EventComponent.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Component/EventComponent.meta new file mode 100644 index 0000000..e453554 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Component/EventComponent.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 5ff190d313de0433bb5c6cad4f116d1a +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Component/EventComponent/EventComponent.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Component/EventComponent/EventComponent.cs new file mode 100644 index 0000000..d2213f7 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Component/EventComponent/EventComponent.cs @@ -0,0 +1,252 @@ +using System; +using System.Reflection; +using Fantasy.Assembly; +using Fantasy.Async; +using Fantasy.DataStructure.Collection; +using Fantasy.Entitas; + +// ReSharper disable PossibleMultipleEnumeration +#pragma warning disable CS8600 // Converting null literal or possible null value to non-nullable type. +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member +// ReSharper disable MethodOverloadWithOptionalParameter + +namespace Fantasy.Event +{ + internal sealed class EventCache + { + public readonly Type EnventType; + public readonly object Obj; + public EventCache(Type enventType, object obj) + { + EnventType = enventType; + Obj = obj; + } + } + + public sealed class EventComponent : Entity, IAssembly + { + private readonly OneToManyList _events = new(); + private readonly OneToManyList _asyncEvents = new(); + private readonly OneToManyList _assemblyEvents = new(); + private readonly OneToManyList _assemblyAsyncEvents = new(); + + internal async FTask Initialize() + { + await AssemblySystem.Register(this); + return this; + } + + #region Assembly + + public async FTask Load(long assemblyIdentity) + { + var tcs = FTask.Create(false); + Scene.ThreadSynchronizationContext.Post(() => + { + LoadInner(assemblyIdentity); + tcs.SetResult(); + }); + await tcs; + } + + public async FTask ReLoad(long assemblyIdentity) + { + var tcs = FTask.Create(false); + Scene.ThreadSynchronizationContext.Post(() => + { + OnUnLoadInner(assemblyIdentity); + LoadInner(assemblyIdentity); + tcs.SetResult(); + }); + await tcs; + } + + public async FTask OnUnLoad(long assemblyIdentity) + { + var tcs = FTask.Create(false); + Scene.ThreadSynchronizationContext.Post(() => + { + OnUnLoadInner(assemblyIdentity); + tcs.SetResult(); + }); + await tcs; + } + + private void LoadInner(long assemblyIdentity) + { + foreach (var type in AssemblySystem.ForEach(assemblyIdentity, typeof(IEvent))) + { + var @event = (IEvent)Activator.CreateInstance(type); + + if (@event == null) + { + continue; + } + + var eventType = @event.EventType(); + _events.Add(eventType, @event); + _assemblyEvents.Add(assemblyIdentity, new EventCache(eventType, @event)); + } + + foreach (var type in AssemblySystem.ForEach(assemblyIdentity, typeof(IAsyncEvent))) + { + var @event = (IAsyncEvent)Activator.CreateInstance(type); + + if (@event == null) + { + continue; + } + + var eventType = @event.EventType(); + _asyncEvents.Add(eventType, @event); + _assemblyAsyncEvents.Add(assemblyIdentity, new EventCache(eventType, @event)); + } + } + + private void OnUnLoadInner(long assemblyIdentity) + { + if (_assemblyEvents.TryGetValue(assemblyIdentity, out var events)) + { + foreach (var @event in events) + { + _events.RemoveValue(@event.EnventType, (IEvent)@event.Obj); + } + + _assemblyEvents.RemoveByKey(assemblyIdentity); + } + + if (_assemblyAsyncEvents.TryGetValue(assemblyIdentity, out var asyncEvents)) + { + foreach (var @event in asyncEvents) + { + _asyncEvents.RemoveValue(@event.EnventType, (IAsyncEvent)@event.Obj); + } + + _assemblyAsyncEvents.RemoveByKey(assemblyIdentity); + } + } + + #endregion + + #region Publish + + /// + /// 发布一个值类型的事件数据。 + /// + /// 事件数据类型(值类型)。 + /// 事件数据实例。 + public void Publish(TEventData eventData) where TEventData : struct + { + if (!_events.TryGetValue(typeof(TEventData), out var list)) + { + return; + } + + foreach (var @event in list) + { + try + { + @event.Invoke(eventData); + } + catch (Exception e) + { + Log.Error(e); + } + } + } + + /// + /// 发布一个继承自 Entity 的事件数据。 + /// + /// 事件数据类型(继承自 Entity)。 + /// 事件数据实例。 + /// 是否释放事件数据。 + public void Publish(TEventData eventData, bool isDisposed = true) where TEventData : Entity + { + if (!_events.TryGetValue(typeof(TEventData), out var list)) + { + return; + } + + foreach (var @event in list) + { + try + { + @event.Invoke(eventData); + } + catch (Exception e) + { + Log.Error(e); + } + } + + if (isDisposed) + { + eventData.Dispose(); + } + } + + /// + /// 异步发布一个值类型的事件数据。 + /// + /// 事件数据类型(值类型)。 + /// 事件数据实例。 + /// 表示异步操作的任务。 + public async FTask PublishAsync(TEventData eventData) where TEventData : struct + { + if (!_asyncEvents.TryGetValue(typeof(TEventData), out var list)) + { + return; + } + + using var tasks = ListPool.Create(); + + foreach (var @event in list) + { + tasks.Add(@event.InvokeAsync(eventData)); + } + + await FTask.WaitAll(tasks); + } + + /// + /// 异步发布一个继承自 Entity 的事件数据。 + /// + /// 事件数据类型(继承自 Entity)。 + /// 事件数据实例。 + /// 是否释放事件数据。 + /// 表示异步操作的任务。 + public async FTask PublishAsync(TEventData eventData, bool isDisposed = true) where TEventData : Entity + { + if (!_asyncEvents.TryGetValue(eventData.GetType(), out var list)) + { + return; + } + + using var tasks = ListPool.Create(); + + foreach (var @event in list) + { + tasks.Add(@event.InvokeAsync(eventData)); + } + + await FTask.WaitAll(tasks); + + if (isDisposed) + { + eventData.Dispose(); + } + } + + #endregion + + public override void Dispose() + { + _events.Clear(); + _asyncEvents.Clear(); + _assemblyEvents.Clear(); + _assemblyAsyncEvents.Clear(); + base.Dispose(); + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Component/EventComponent/EventComponent.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Component/EventComponent/EventComponent.cs.meta new file mode 100644 index 0000000..ac84806 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Component/EventComponent/EventComponent.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: bc6c3f6b01eb14a35934175e36eeb544 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Component/EventComponent/Interface.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Component/EventComponent/Interface.meta new file mode 100644 index 0000000..af3d4b8 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Component/EventComponent/Interface.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 10dcbb383d66a4915b44d6f20331a7bf +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Component/EventComponent/Interface/IEvent.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Component/EventComponent/Interface/IEvent.cs new file mode 100644 index 0000000..5314995 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Component/EventComponent/Interface/IEvent.cs @@ -0,0 +1,112 @@ +using System; +using Fantasy.Async; + +namespace Fantasy.Event +{ + /// + /// 事件的接口 + /// + public interface IEvent + { + /// + /// 用于指定事件的Type + /// + /// + Type EventType(); + /// + /// 时间内部使用的入口 + /// + /// + void Invoke(object self); + } + + /// + /// 异步事件的接口 + /// + public interface IAsyncEvent + { + /// + /// + /// + /// + Type EventType(); + /// + /// + /// + /// + FTask InvokeAsync(object self); + } + + /// + /// 事件的抽象类,要使用事件必须要继承这个抽象接口。 + /// + /// 要监听的事件泛型类型 + public abstract class EventSystem : IEvent + { + private readonly Type _selfType = typeof(T); + /// + /// + /// + /// + public Type EventType() + { + return _selfType; + } + /// + /// 事件调用的方法,要在这个方法里编写事件发生的逻辑 + /// + /// + protected abstract void Handler(T self); + /// + /// + /// + /// + public void Invoke(object self) + { + try + { + Handler((T) self); + } + catch (Exception e) + { + Log.Error($"{_selfType.Name} Error {e}"); + } + } + } + /// + /// 异步事件的抽象类,要使用事件必须要继承这个抽象接口。 + /// + /// 要监听的事件泛型类型 + public abstract class AsyncEventSystem : IAsyncEvent + { + private readonly Type _selfType = typeof(T); + /// + /// + /// + /// + public Type EventType() + { + return _selfType; + } + /// + /// 事件调用的方法,要在这个方法里编写事件发生的逻辑 + /// + /// + protected abstract FTask Handler(T self); + /// + /// + /// + /// + public async FTask InvokeAsync(object self) + { + try + { + await Handler((T) self); + } + catch (Exception e) + { + Log.Error($"{_selfType.Name} Error {e}"); + } + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Component/EventComponent/Interface/IEvent.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Component/EventComponent/Interface/IEvent.cs.meta new file mode 100644 index 0000000..5811d14 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Component/EventComponent/Interface/IEvent.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1e46ad748051f4277a8f660fa842b19d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Component/MessagePoolComponent.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Component/MessagePoolComponent.cs new file mode 100644 index 0000000..f1ddb23 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Component/MessagePoolComponent.cs @@ -0,0 +1,139 @@ +// ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract + +using System; +using System.Collections.Generic; +using System.Runtime.CompilerServices; +using Fantasy.DataStructure.Collection; +using Fantasy.Entitas; +using Fantasy.Pool; +using Fantasy.Serialize; + +namespace Fantasy.Entitas +{ + /// + /// 消息的对象池组件 + /// + public sealed class MessagePoolComponent : Entity + { + private int _poolCount; + private const int MaxCapacity = ushort.MaxValue; + private readonly OneToManyQueue _poolQueue = new OneToManyQueue(); + private readonly Dictionary> _typeCheckCache = new Dictionary>(); + /// + /// 销毁组件 + /// + public override void Dispose() + { + _poolCount = 0; + _poolQueue.Clear(); + _typeCheckCache.Clear(); + base.Dispose(); + } + /// + /// 从对象池里获取一个消息,如果没有就创建一个新的 + /// + /// 消息的泛型类型 + /// + public T Rent() where T : AMessage, new() + { + if (!_poolQueue.TryDequeue(typeof(T), out var queue)) + { + var instance = new T(); + instance.SetScene(Scene); + instance.SetIsPool(true); + return instance; + } + + queue.SetIsPool(true); + _poolCount--; + return (T)queue; + } + + /// + /// + /// + /// 消息的类型 + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public AMessage Rent(Type type) + { + if (!_poolQueue.TryDequeue(type, out var queue)) + { + if (!_typeCheckCache.TryGetValue(type, out var createInstance)) + { + if (!typeof(AMessage).IsAssignableFrom(type)) + { + throw new NotSupportedException($"{this.GetType().FullName} Type:{type.FullName} must inherit from IPool"); + } + else + { + createInstance = CreateInstance.CreateMessage(type); + _typeCheckCache[type] = createInstance; + } + } + + var instance = createInstance(); + instance.SetScene(Scene); + instance.SetIsPool(true); + return instance; + } + + queue.SetIsPool(true); + _poolCount--; + return queue; + } + /// + /// 返还一个消息到对象池中 + /// + /// + public void Return(AMessage obj) + { + if (obj == null) + { + return; + } + + if (!obj.IsPool()) + { + return; + } + + if (_poolCount >= MaxCapacity) + { + return; + } + + _poolCount++; + obj.SetIsPool(false); + _poolQueue.Enqueue(obj.GetType(), obj); + } + + /// + /// + /// + /// 返还的消息 + /// 返还的消息泛型类型 + public void Return(T obj) where T : AMessage + { + if (obj == null) + { + return; + } + + if (!obj.IsPool()) + { + return; + } + + if (_poolCount >= MaxCapacity) + { + return; + } + + _poolCount++; + obj.SetIsPool(false); + _poolQueue.Enqueue(typeof(T), obj); + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Component/MessagePoolComponent.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Component/MessagePoolComponent.cs.meta new file mode 100644 index 0000000..a2ded96 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Component/MessagePoolComponent.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b4db4a3115fd64377b5b89f2bdc001a1 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Component/SingleCollectionComponent.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Component/SingleCollectionComponent.meta new file mode 100644 index 0000000..d84b4bb --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Component/SingleCollectionComponent.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 3e4a6422ca1a44689a82bd9c788c8310 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Component/SingleCollectionComponent/SingleCollectionComponent.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Component/SingleCollectionComponent/SingleCollectionComponent.cs new file mode 100644 index 0000000..9ecfdd2 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Component/SingleCollectionComponent/SingleCollectionComponent.cs @@ -0,0 +1,167 @@ +// ReSharper disable SuspiciousTypeConversion.Global + +using Fantasy.Assembly; +using Fantasy.Async; +using Fantasy.DataStructure.Collection; +using Fantasy.Entitas; +using Fantasy.Entitas.Interface; +using Fantasy.Helper; + +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member +#pragma warning disable CS8604 // Possible null reference argument. +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. +#if FANTASY_NET +namespace Fantasy.SingleCollection +{ + /// + /// 用于处理Entity下的实体进行数据库分表存储的组件 + /// + public sealed class SingleCollectionComponent : Entity, IAssembly + { + private CoroutineLock _coroutineLock; + private readonly OneToManyHashSet _collection = new OneToManyHashSet(); + + private readonly OneToManyList _assemblyCollections = + new OneToManyList(); + + private sealed class SingleCollectionInfo(Type rootType, string collectionName) + { + public readonly Type RootType = rootType; + public readonly string CollectionName = collectionName; + } + + internal async FTask Initialize() + { + var coroutineLockType = HashCodeHelper.ComputeHash64(GetType().FullName); + _coroutineLock = Scene.CoroutineLockComponent.Create(coroutineLockType); + await AssemblySystem.Register(this); + return this; + } + + #region Assembly + + public async FTask Load(long assemblyIdentity) + { + var tcs = FTask.Create(false); + Scene.ThreadSynchronizationContext.Post(() => + { + LoadInner(assemblyIdentity); + tcs.SetResult(); + }); + await tcs; + } + + public async FTask ReLoad(long assemblyIdentity) + { + var tcs = FTask.Create(false); + Scene.ThreadSynchronizationContext.Post(() => + { + OnUnLoadInner(assemblyIdentity); + LoadInner(assemblyIdentity); + tcs.SetResult(); + }); + await tcs; + } + + public async FTask OnUnLoad(long assemblyIdentity) + { + var tcs = FTask.Create(false); + Scene.ThreadSynchronizationContext.Post(() => + { + OnUnLoadInner(assemblyIdentity); + tcs.SetResult(); + }); + await tcs; + } + + private void LoadInner(long assemblyIdentity) + { + foreach (var type in AssemblySystem.ForEach(assemblyIdentity, typeof(ISupportedSingleCollection))) + { + var customAttributes = type.GetCustomAttributes(typeof(SingleCollectionAttribute), false); + if (customAttributes.Length == 0) + { + Log.Error( + $"type {type.FullName} Implemented the interface of ISingleCollection, requiring the implementation of SingleCollectionAttribute"); + continue; + } + + var singleCollectionAttribute = (SingleCollectionAttribute)customAttributes[0]; + var rootType = singleCollectionAttribute.RootType; + var collectionName = singleCollectionAttribute.CollectionName; + _collection.Add(rootType, collectionName); + _assemblyCollections.Add(assemblyIdentity, new SingleCollectionInfo(rootType, collectionName)); + } + } + + private void OnUnLoadInner(long assemblyIdentity) + { + if (!_assemblyCollections.TryGetValue(assemblyIdentity, out var types)) + { + return; + } + + foreach (var singleCollectionInfo in types) + { + _collection.RemoveValue(singleCollectionInfo.RootType, singleCollectionInfo.CollectionName); + } + + _assemblyCollections.RemoveByKey(assemblyIdentity); + } + + #endregion + + #region Collections + + /// + /// 通过数据库获取某一个实体类型下所有的分表数据到当前实体下,并且会自动建立父子关系。 + /// + /// 实体实例 + /// 实体泛型类型 + public async FTask GetCollections(T entity) where T : Entity, ISingleCollectionRoot + { + if (!_collection.TryGetValue(typeof(T), out var collections)) + { + return; + } + + var worldDateBase = Scene.World.DataBase; + + using (await _coroutineLock.Wait(entity.Id)) + { + foreach (var collectionName in collections) + { + var singleCollection = await worldDateBase.QueryNotLock(entity.Id, true, collectionName); + entity.AddComponent(singleCollection); + } + } + } + + /// + /// 存储当前实体下支持分表的组件到数据中,包括存储实体本身。 + /// + /// 实体实例 + /// 实体泛型类型 + public async FTask SaveCollections(T entity) where T : Entity, ISingleCollectionRoot + { + using var collections = ListPool.Create(); + + foreach (var treeEntity in entity.ForEachSingleCollection) + { + if (treeEntity is not ISupportedSingleCollection) + { + continue; + } + + collections.Add(treeEntity); + } + + collections.Add(entity); + await entity.Scene.World.DataBase.Save(entity.Id, collections); + } + + #endregion + } +} + +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Component/SingleCollectionComponent/SingleCollectionComponent.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Component/SingleCollectionComponent/SingleCollectionComponent.cs.meta new file mode 100644 index 0000000..00f78d3 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Component/SingleCollectionComponent/SingleCollectionComponent.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 41291147b69444a6cb19ba948b421d2c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Component/TimerComponent.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Component/TimerComponent.meta new file mode 100644 index 0000000..e990774 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Component/TimerComponent.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: de3b132dd12a0427face9541cc1ba095 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Component/TimerComponent/Interface.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Component/TimerComponent/Interface.meta new file mode 100644 index 0000000..58c8617 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Component/TimerComponent/Interface.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 20842cefeece84173bf625c41a94ef63 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Component/TimerComponent/Interface/TimerHandler.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Component/TimerComponent/Interface/TimerHandler.cs new file mode 100644 index 0000000..9e1f4c9 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Component/TimerComponent/Interface/TimerHandler.cs @@ -0,0 +1,10 @@ +using Fantasy.Event; + +namespace Fantasy.Timer +{ + /// + /// 计时器抽象类,提供了一个基础框架,用于创建处理计时器事件的具体类。 + /// + /// 事件的类型参数 + public abstract class TimerHandler : EventSystem { } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Component/TimerComponent/Interface/TimerHandler.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Component/TimerComponent/Interface/TimerHandler.cs.meta new file mode 100644 index 0000000..cab3f9c --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Component/TimerComponent/Interface/TimerHandler.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0bb411c4d246b43aba54eb60b7654492 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Component/TimerComponent/TimeWheel.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Component/TimerComponent/TimeWheel.meta new file mode 100644 index 0000000..8799bb8 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Component/TimerComponent/TimeWheel.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: c29f20c4c348c4a2892df1702f14a9e8 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Component/TimerComponent/TimeWheel/ScheduledTask.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Component/TimerComponent/TimeWheel/ScheduledTask.cs new file mode 100644 index 0000000..d644386 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Component/TimerComponent/TimeWheel/ScheduledTask.cs @@ -0,0 +1,49 @@ +// #pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. +// #pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. +// namespace Fantasy +// { +// public sealed class ScheduledTaskPool : PoolCore +// { +// public ScheduledTaskPool() : base(2000) { } +// +// public ScheduledTask Rent(Action action, ref int rounds, ref int finalSlot) +// { +// var scheduledTask = Rent(); +// scheduledTask.Rounds = rounds; +// scheduledTask.Action = action; +// scheduledTask.FinalSlot = finalSlot; +// return scheduledTask; +// } +// +// public override void Return(ScheduledTask item) +// { +// base.Return(item); +// item.Dispose(); +// } +// } +// +// public sealed class ScheduledTask : IPool, IDisposable +// { +// public int Rounds; +// public int FinalSlot; +// public Action Action; +// public LinkedListNode Node; +// +// public bool IsPool { get; set; } +// public ScheduledTask() { } +// public ScheduledTask(Action action, ref int rounds, ref int finalSlot) +// { +// Action = action; +// Rounds = rounds; +// FinalSlot = finalSlot; +// } +// +// public void Dispose() +// { +// Rounds = 0; +// FinalSlot = 0; +// Action = null; +// Node = null; +// } +// } +// } \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Component/TimerComponent/TimeWheel/ScheduledTask.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Component/TimerComponent/TimeWheel/ScheduledTask.cs.meta new file mode 100644 index 0000000..4a73d85 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Component/TimerComponent/TimeWheel/ScheduledTask.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d711c8e49efac42c9bde8a1ff993b6f0 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Component/TimerComponent/TimeWheel/TimeWheel.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Component/TimerComponent/TimeWheel/TimeWheel.cs new file mode 100644 index 0000000..58916b1 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Component/TimerComponent/TimeWheel/TimeWheel.cs @@ -0,0 +1,134 @@ +// using System.Runtime.CompilerServices; +// // ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract +// #pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. +// +// namespace Fantasy +// { +// public sealed class TimeWheel +// { +// private int _currentIndex; +// private ScheduledTaskPool _scheduledTaskPool; +// +// private readonly Scene _scene; +// private readonly int _wheelSize; +// private readonly int _tickDuration; +// private readonly TimeWheel _upperLevelWheel; +// private readonly LinkedList[] _wheel; +// private readonly Queue _tasksToReschedule = new Queue(); +// private readonly Dictionary _taskDictionary = new Dictionary(); +// +// public TimeWheel(TimerComponent timerComponent, int wheelSize, int tickDuration, TimeWheel upperLevelWheel = null) +// { +// _scene = timerComponent.Scene; +// _wheelSize = wheelSize; +// _tickDuration = tickDuration; +// _upperLevelWheel = upperLevelWheel; +// _scheduledTaskPool = timerComponent.ScheduledTaskPool; +// _wheel = new LinkedList[_wheelSize]; +// for (var i = 0; i < wheelSize; i++) +// { +// _wheel[i] = new LinkedList(); +// } +// } +// +// public long Schedule(Action action, int delay) +// { +// var ticks = delay / _tickDuration; +// var futureIndex = ticks + _currentIndex; +// var rounds = futureIndex / _wheelSize; +// var slot = futureIndex % _wheelSize; +// +// if (slot == 0) +// { +// slot = _wheelSize - 1; +// rounds--; +// } +// else +// { +// slot--; +// } +// +// var taskId = _scene.RuntimeIdFactory.Create; +// var task = _scheduledTaskPool.Rent(action, ref rounds, ref slot); +// task.Node = _wheel[slot].AddLast(task); +// _taskDictionary.Add(taskId, task); +// Console.WriteLine($"Schedule rounds:{rounds} slot:{slot} _currentIndex:{_currentIndex}"); +// return taskId; +// } +// +// public bool Remove(int taskId) +// { +// if (!_taskDictionary.TryGetValue(taskId, out var task)) +// { +// return false; +// } +// +// _taskDictionary.Remove(taskId); +// _wheel[task.FinalSlot].Remove(task.Node); +// _scheduledTaskPool.Return(task); +// Console.WriteLine("找到已经删除了任务"); +// return true; +// } +// +// public void Tick(object? state) +// { +// var currentWheel = _wheel[_currentIndex]; +// +// if (currentWheel.Count == 0) +// { +// AdvanceIndex(); +// return; +// } +// +// var currentNode = currentWheel.First; +// +// while (currentNode != null) +// { +// var nextNode = currentNode.Next; +// var task = currentNode.Value; +// +// if (task.Rounds <= 0 && task.FinalSlot == _currentIndex) +// { +// try +// { +// task.Action.Invoke(); +// } +// catch (Exception ex) +// { +// Log.Error($"Exception during task execution: {ex.Message}"); +// } +// } +// else +// { +// task.Rounds--; +// _tasksToReschedule.Enqueue(task); +// } +// +// currentWheel.Remove(currentNode); +// currentNode = nextNode; +// } +// +// RescheduleTasks(); +// AdvanceIndex(); +// } +// +// [MethodImpl(MethodImplOptions.AggressiveInlining)] +// private void AdvanceIndex() +// { +// _currentIndex = (_currentIndex + 1) % _wheelSize; +// if (_currentIndex == 0 && _upperLevelWheel != null) +// { +// _upperLevelWheel.Tick(null); +// } +// } +// +// [MethodImpl(MethodImplOptions.AggressiveInlining)] +// private void RescheduleTasks() +// { +// while (_tasksToReschedule.TryDequeue(out var task)) +// { +// _wheel[task.FinalSlot].AddLast(task); +// } +// } +// } +// } \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Component/TimerComponent/TimeWheel/TimeWheel.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Component/TimerComponent/TimeWheel/TimeWheel.cs.meta new file mode 100644 index 0000000..bc71944 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Component/TimerComponent/TimeWheel/TimeWheel.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 362cc9ecb907d45129e4fdff9ef87039 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Component/TimerComponent/TimerAction.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Component/TimerComponent/TimerAction.cs new file mode 100644 index 0000000..2a836ab --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Component/TimerComponent/TimerAction.cs @@ -0,0 +1,27 @@ +using System; +using System.Runtime.InteropServices; + +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member +#pragma warning disable CS8625 +#pragma warning disable CS8618 + +namespace Fantasy.Timer +{ + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct TimerAction + { + public long TimerId; + public long StartTime; + public long TriggerTime; + public readonly object Callback; + public readonly TimerType TimerType; + public TimerAction(long timerId, TimerType timerType, long startTime, long triggerTime, object callback) + { + TimerId = timerId; + Callback = callback; + TimerType = timerType; + StartTime = startTime; + TriggerTime = triggerTime; + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Component/TimerComponent/TimerAction.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Component/TimerComponent/TimerAction.cs.meta new file mode 100644 index 0000000..6da3670 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Component/TimerComponent/TimerAction.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 5c875fd82f74f430c963315b79f7a9a7 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Component/TimerComponent/TimerComponent.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Component/TimerComponent/TimerComponent.cs new file mode 100644 index 0000000..ffa7864 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Component/TimerComponent/TimerComponent.cs @@ -0,0 +1,52 @@ +// ReSharper disable ForCanBeConvertedToForeach + +using Fantasy.Entitas; +using Fantasy.Entitas.Interface; + +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. +#if FANTASY_UNITY +using UnityEngine; +#endif +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member +namespace Fantasy.Timer +{ + public sealed class TimerComponentUpdateSystem : UpdateSystem + { + protected override void Update(TimerComponent self) + { + self.Update(); + } + } + + /// + /// 时间调度组件 + /// + public sealed class TimerComponent : Entity + { + /// + /// 使用系统时间创建的计时器核心。 + /// + public TimerSchedulerNet Net { get; private set; } +#if FANTASY_UNITY + /// + /// 使用 Unity 时间创建的计时器核心。 + /// + public TimerSchedulerNetUnity Unity { get; private set; } +#endif + internal TimerComponent Initialize() + { + Net = new TimerSchedulerNet(Scene); +#if FANTASY_UNITY + Unity = new TimerSchedulerNetUnity(Scene); +#endif + return this; + } + public void Update() + { + Net.Update(); +#if FANTASY_UNITY + Unity.Update(); +#endif + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Component/TimerComponent/TimerComponent.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Component/TimerComponent/TimerComponent.cs.meta new file mode 100644 index 0000000..32b5101 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Component/TimerComponent/TimerComponent.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4b33402f4024349359a173ef6aa46abf +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Component/TimerComponent/TimerScheduler.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Component/TimerComponent/TimerScheduler.meta new file mode 100644 index 0000000..d4294c1 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Component/TimerComponent/TimerScheduler.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 74544bc3e0a9a4cc2af251a9a2a871c1 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Component/TimerComponent/TimerScheduler/TimerSchedulerNet.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Component/TimerComponent/TimerScheduler/TimerSchedulerNet.cs new file mode 100644 index 0000000..26581f8 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Component/TimerComponent/TimerScheduler/TimerSchedulerNet.cs @@ -0,0 +1,390 @@ +using System; +using System.Collections.Generic; +using Fantasy.Async; +using Fantasy.DataStructure.Collection; +using Fantasy.Helper; +// ReSharper disable UnusedParameter.Global + +#pragma warning disable CS8602 // Dereference of a possibly null reference. +#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. + +namespace Fantasy.Timer +{ + /// + /// 基于系统事件的任务调度系统 + /// + public sealed class TimerSchedulerNet + { + private readonly Scene _scene; + private long _idGenerator; + private long _minTime; // 最小时间 + private readonly Queue _timeOutTime = new Queue(); + private readonly Queue _timeOutTimerIds = new Queue(); + private readonly Dictionary _timerActions = new Dictionary(); + private readonly SortedOneToManyList _timeId = new(); // 时间与计时器ID的有序一对多列表 + private long GetId => ++_idGenerator; + /// + /// 构造函数 + /// + /// 当前的Scene + public TimerSchedulerNet(Scene scene) + { + _scene = scene; + } + + private long Now() + { + return TimeHelper.Now; + } + + /// + /// 驱动方法,只有调用这个方法任务系统才会正常运转。 + /// + public void Update() + { + if (_timeId.Count == 0) + { + return; + } + + var currentTime = Now(); + + if (currentTime < _minTime) + { + return; + } + + // 遍历时间ID列表,查找超时的计时器任务 + foreach (var (key, _) in _timeId) + { + if (key > currentTime) + { + _minTime = key; + break; + } + + _timeOutTime.Enqueue(key); + } + + // 处理超时的计时器任务 + while (_timeOutTime.TryDequeue(out var time)) + { + var timerIds = _timeId[time]; + for (var i = 0; i < timerIds.Count; ++i) + { + _timeOutTimerIds.Enqueue(timerIds[i]); + } + + _timeId.Remove(time); + // _timeId.RemoveKey(time); + } + + if (_timeId.Count == 0) + { + _minTime = long.MaxValue; + } + + // 执行超时的计时器任务的回调操作 + while (_timeOutTimerIds.TryDequeue(out var timerId)) + { + if (!_timerActions.Remove(timerId, out var timerAction)) + { + continue; + } + + // 根据计时器类型执行不同的操作 + switch (timerAction.TimerType) + { + case TimerType.OnceWaitTimer: + { + var tcs = (FTask)timerAction.Callback; + tcs.SetResult(true); + break; + } + case TimerType.OnceTimer: + { + if (timerAction.Callback is not Action action) + { + Log.Error($"timerAction {timerAction.ToJson()}"); + break; + } + + action(); + break; + } + case TimerType.RepeatedTimer: + { + if (timerAction.Callback is not Action action) + { + Log.Error($"timerAction {timerAction.ToJson()}"); + break; + } + + timerAction.StartTime = Now(); + AddTimer(ref timerAction); + action(); + break; + } + } + } + } + + private void AddTimer(ref TimerAction timer) + { + var tillTime = timer.StartTime + timer.TriggerTime; + _timeId.Add(tillTime, timer.TimerId); + _timerActions.Add(timer.TimerId, timer); + + if (tillTime < _minTime) + { + _minTime = tillTime; + } + } + + /// + /// 异步等待指定时间。 + /// + /// 等待的时间长度。 + /// 取消令牌。 + /// 等待是否成功。 + public async FTask WaitAsync(long time, FCancellationToken cancellationToken = null) + { + if (time <= 0) + { + return true; + } + + var now = Now(); + var timerId = GetId; + var tcs = FTask.Create(); + var timerAction = new TimerAction(timerId, TimerType.OnceWaitTimer, now, time, tcs); + + void CancelActionVoid() + { + if (Remove(timerId)) + { + tcs.SetResult(false); + } + } + + bool result; + + try + { + cancellationToken?.Add(CancelActionVoid); + AddTimer(ref timerAction); + result = await tcs; + } + finally + { + cancellationToken?.Remove(CancelActionVoid); + } + + return result; + } + + /// + /// 异步等待直到指定时间。 + /// + /// 等待的目标时间。 + /// 取消令牌。 + /// 等待是否成功。 + public async FTask WaitTillAsync(long tillTime, FCancellationToken cancellationToken = null) + { + var now = Now(); + + if (now >= tillTime) + { + return true; + } + + var timerId = GetId; + var tcs = FTask.Create(); + var timerAction = new TimerAction(timerId, TimerType.OnceWaitTimer, now, tillTime - now, tcs); + + void CancelActionVoid() + { + if (Remove(timerId)) + { + tcs.SetResult(false); + } + } + + bool result; + + try + { + cancellationToken?.Add(CancelActionVoid); + AddTimer(ref timerAction); + result = await tcs; + } + finally + { + cancellationToken?.Remove(CancelActionVoid); + } + + return result; + } + + /// + /// 异步等待一帧时间。 + /// + /// 等待是否成功。 + public async FTask WaitFrameAsync() + { +#if FANTASY_NET + await WaitAsync(100); +#else + await WaitAsync(1); +#endif + } + + /// + /// 创建一个只执行一次的计时器,直到指定时间 + /// + /// 计时器执行的目标时间。 + /// 计时器回调方法。 + /// + public long OnceTimer(long time, Action action) + { + var now = Now(); + var timerId = GetId; + var timerAction = new TimerAction(timerId, TimerType.OnceTimer, now, time, action); + AddTimer(ref timerAction); + return timerId; + } + + /// + /// 创建一个只执行一次的计时器,直到指定时间。 + /// + /// 计时器执行的目标时间。 + /// 计时器回调方法。 + /// 计时器的 ID。 + public long OnceTillTimer(long tillTime, Action action) + { + var now = Now(); + + if (tillTime < now) + { + Log.Error($"new once time too small tillTime:{tillTime} Now:{now}"); + } + + var timerId = GetId; + var timerAction = new TimerAction(timerId, TimerType.OnceTimer, now, tillTime - now, action); + AddTimer(ref timerAction); + return timerId; + } + + /// + /// 创建一个只执行一次的计时器,用于发布指定类型的事件。 + /// + /// 事件类型。 + /// 计时器执行的延迟时间。 + /// 事件处理器类型。 + /// 计时器的 ID。 + public long OnceTimer(long time, T timerHandlerType) where T : struct + { + void OnceTimerVoid() + { + _scene.EventComponent.Publish(timerHandlerType); + } + + return OnceTimer(time, OnceTimerVoid); + } + + /// + /// 创建一个只执行一次的计时器,直到指定时间,用于发布指定类型的事件。 + /// + /// 事件类型。 + /// 计时器执行的目标时间。 + /// 事件处理器类型。 + /// 计时器的 ID。 + public long OnceTillTimer(long tillTime, T timerHandlerType) where T : struct + { + void OnceTillTimerVoid() + { + _scene.EventComponent.Publish(timerHandlerType); + } + + return OnceTillTimer(tillTime, OnceTillTimerVoid); + } + + /// + /// 创建一个帧任务 + /// + /// + /// + public long FrameTimer(Action action) + { +#if FANTASY_NET + return RepeatedTimerInner(100, action); +#else + return RepeatedTimerInner(0, action); +#endif + } + + /// + /// 创建一个重复执行的计时器。 + /// + /// 计时器重复间隔的时间。 + /// 计时器回调方法。 + /// 计时器的 ID。 + public long RepeatedTimer(long time, Action action) + { + if (time < 0) + { + Log.Error($"time too small: {time}"); + return 0; + } + + return RepeatedTimerInner(time, action); + } + + /// + /// 创建一个重复执行的计时器,用于发布指定类型的事件。 + /// + /// 事件类型。 + /// 计时器重复间隔的时间。 + /// 事件处理器类型。 + /// 计时器的 ID。 + public long RepeatedTimer(long time, T timerHandlerType) where T : struct + { + void RepeatedTimerVoid() + { + _scene.EventComponent.Publish(timerHandlerType); + } + + return RepeatedTimer(time, RepeatedTimerVoid); + } + + private long RepeatedTimerInner(long time, Action action) + { + var now = Now(); + var timerId = GetId; + var timerAction = new TimerAction(timerId, TimerType.RepeatedTimer, now, time, action); + AddTimer(ref timerAction); + return timerId; + } + + /// + /// 移除指定 ID 的计时器。 + /// + /// + /// + public bool Remove(ref long timerId) + { + var id = timerId; + timerId = 0; + return Remove(id); + } + + /// + /// 移除指定 ID 的计时器。 + /// + /// 计时器的 ID。 + public bool Remove(long timerId) + { + return timerId != 0 && _timerActions.Remove(timerId, out _); + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Component/TimerComponent/TimerScheduler/TimerSchedulerNet.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Component/TimerComponent/TimerScheduler/TimerSchedulerNet.cs.meta new file mode 100644 index 0000000..c9f6027 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Component/TimerComponent/TimerScheduler/TimerSchedulerNet.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: af9a02de83dce4c088f786cf6cf6bdd7 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Component/TimerComponent/TimerScheduler/TimerSchedulerNetUnity.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Component/TimerComponent/TimerScheduler/TimerSchedulerNetUnity.cs new file mode 100644 index 0000000..f00bfe4 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Component/TimerComponent/TimerScheduler/TimerSchedulerNetUnity.cs @@ -0,0 +1,372 @@ +#if FANTASY_UNITY +using System; +using System.Collections.Generic; +using Fantasy.Async; +using Fantasy.DataStructure.Collection; +using Fantasy.Helper; +using UnityEngine; +namespace Fantasy.Timer +{ + public sealed class TimerSchedulerNetUnity + { + private readonly Scene _scene; + private long _idGenerator; + private long _minTime; // 最小时间 + private readonly Queue _timeOutTime = new Queue(); + private readonly Queue _timeOutTimerIds = new Queue(); + private readonly Dictionary _timerActions = new Dictionary(); + private readonly SortedOneToManyList _timeId = new(); // 时间与计时器ID的有序一对多列表 + private long GetId => ++_idGenerator; + public TimerSchedulerNetUnity(Scene scene) + { + _scene = scene; + } + + private long Now() + { + return (long)(Time.time * 1000); + } + + public void Update() + { + if (_timeId.Count == 0) + { + return; + } + + var currentTime = Now(); + + if (currentTime < _minTime) + { + return; + } + + // 遍历时间ID列表,查找超时的计时器任务 + foreach (var (key, _) in _timeId) + { + if (key > currentTime) + { + _minTime = key; + break; + } + + _timeOutTime.Enqueue(key); + } + + // 处理超时的计时器任务 + while (_timeOutTime.TryDequeue(out var time)) + { + var timerIds = _timeId[time]; + for (var i = 0; i < timerIds.Count; ++i) + { + _timeOutTimerIds.Enqueue(timerIds[i]); + } + + _timeId.Remove(time); + // _timeId.RemoveKey(time); + } + + if (_timeId.Count == 0) + { + _minTime = long.MaxValue; + } + + // 执行超时的计时器任务的回调操作 + while (_timeOutTimerIds.TryDequeue(out var timerId)) + { + if (!_timerActions.Remove(timerId, out var timerAction)) + { + continue; + } + + // 根据计时器类型执行不同的操作 + switch (timerAction.TimerType) + { + case TimerType.OnceWaitTimer: + { + var tcs = (FTask)timerAction.Callback; + tcs.SetResult(true); + break; + } + case TimerType.OnceTimer: + { + if (timerAction.Callback is not Action action) + { + Log.Error($"timerAction {timerAction.ToJson()}"); + break; + } + + action(); + break; + } + case TimerType.RepeatedTimer: + { + if (timerAction.Callback is not Action action) + { + Log.Error($"timerAction {timerAction.ToJson()}"); + break; + } + + timerAction.StartTime = Now(); + AddTimer(ref timerAction); + action(); + break; + } + } + } + } + + private void AddTimer(ref TimerAction timer) + { + var tillTime = timer.StartTime + timer.TriggerTime; + _timeId.Add(tillTime, timer.TimerId); + _timerActions.Add(timer.TimerId, timer); + + if (tillTime < _minTime) + { + _minTime = tillTime; + } + } + + /// + /// 异步等待指定时间。 + /// + /// 等待的时间长度。 + /// 可选的取消令牌。 + /// 等待是否成功。 + public async FTask WaitAsync(long time, FCancellationToken cancellationToken = null) + { + if (time <= 0) + { + return true; + } + + var now = Now(); + var timerId = GetId; + var tcs = FTask.Create(); + var timerAction = new TimerAction(timerId, TimerType.OnceWaitTimer, now, time, tcs); + + + void CancelActionVoid() + { + if (Remove(timerId)) + { + tcs.SetResult(false); + } + } + + bool result; + + try + { + cancellationToken?.Add(CancelActionVoid); + AddTimer(ref timerAction); + result =await tcs; + } + finally + { + cancellationToken?.Remove(CancelActionVoid); + } + + return result; + } + + /// + /// 异步等待直到指定时间。 + /// + /// 等待的目标时间。 + /// 可选的取消令牌。 + /// 等待是否成功。 + public async FTask WaitTillAsync(long tillTime, FCancellationToken cancellationToken = null) + { + var now = Now(); + + if (now >= tillTime) + { + return true; + } + + var timerId = GetId; + var tcs = FTask.Create(); + var timerAction = new TimerAction(timerId, TimerType.OnceWaitTimer, now, tillTime - now, tcs); + + void CancelActionVoid() + { + if (Remove(timerId)) + { + tcs.SetResult(false); + } + } + + bool result; + + try + { + cancellationToken?.Add(CancelActionVoid); + AddTimer(ref timerAction); + result = await tcs; + } + finally + { + cancellationToken?.Remove(CancelActionVoid); + } + + return result; + } + + /// + /// 异步等待一帧时间。 + /// + /// 等待是否成功。 + public async FTask WaitFrameAsync(FCancellationToken cancellationToken = null) + { + await WaitAsync(1, cancellationToken); + } + + /// + /// 创建一个只执行一次的计时器,直到指定时间 + /// + /// 计时器执行的目标时间。 + /// 计时器回调方法。 + /// + public long OnceTimer(long time, Action action) + { + var now = Now(); + var timerId = GetId; + var timerAction = new TimerAction(timerId, TimerType.OnceTimer, now, time, action); + AddTimer(ref timerAction); + return timerId; + } + + /// + /// 创建一个只执行一次的计时器,直到指定时间。 + /// + /// 计时器执行的目标时间。 + /// 计时器回调方法。 + /// 计时器的 ID。 + public long OnceTillTimer(long tillTime, Action action) + { + var now = Now(); + + if (tillTime < now) + { + Log.Error($"new once time too small tillTime:{tillTime} Now:{now}"); + } + + var timerId = GetId; + var timerAction = new TimerAction(timerId, TimerType.OnceTimer, now, tillTime - now, action); + AddTimer(ref timerAction); + return timerId; + } + + /// + /// 创建一个只执行一次的计时器,用于发布指定类型的事件。 + /// + /// 事件类型。 + /// 计时器执行的延迟时间。 + /// 事件处理器类型。 + /// 计时器的 ID。 + public long OnceTimer(long time, T timerHandlerType) where T : struct + { + void OnceTimerVoid() + { + _scene.EventComponent.Publish(timerHandlerType); + } + + return OnceTimer(time, OnceTimerVoid); + } + + /// + /// 创建一个只执行一次的计时器,直到指定时间,用于发布指定类型的事件。 + /// + /// 事件类型。 + /// 计时器执行的目标时间。 + /// 事件处理器类型。 + /// 计时器的 ID。 + public long OnceTillTimer(long tillTime, T timerHandlerType) where T : struct + { + void OnceTillTimerVoid() + { + _scene.EventComponent.Publish(timerHandlerType); + } + + return OnceTillTimer(tillTime, OnceTillTimerVoid); + } + + /// + /// 创建一个帧任务 + /// + /// + /// + public long FrameTimer(Action action) + { + return RepeatedTimerInner(1, action); + } + + /// + /// 创建一个重复执行的计时器。 + /// + /// 计时器重复间隔的时间。 + /// 计时器回调方法。 + /// 计时器的 ID。 + public long RepeatedTimer(long time, Action action) + { + if (time < 0) + { + Log.Error($"time too small: {time}"); + return 0; + } + + return RepeatedTimerInner(time, action); + } + + /// + /// 创建一个重复执行的计时器,用于发布指定类型的事件。 + /// + /// 事件类型。 + /// 计时器重复间隔的时间。 + /// 事件处理器类型。 + /// 计时器的 ID。 + public long RepeatedTimer(long time, T timerHandlerType) where T : struct + { + void RepeatedTimerVoid() + { + _scene.EventComponent.Publish(timerHandlerType); + } + + return RepeatedTimer(time, RepeatedTimerVoid); + } + + private long RepeatedTimerInner(long time, Action action) + { + var now = Now(); + var timerId = GetId; + var timerAction = new TimerAction(timerId, TimerType.RepeatedTimer, now, time, action); + AddTimer(ref timerAction); + return timerId; + } + + /// + /// 移除指定 ID 的计时器。 + /// + /// + /// + public bool Remove(ref long timerId) + { + var id = timerId; + timerId = 0; + return Remove(id); + } + + /// + /// 移除指定 ID 的计时器。 + /// + /// 计时器的 ID。 + public bool Remove(long timerId) + { + return timerId != 0 && _timerActions.Remove(timerId, out _); + } + } +} +#endif + diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Component/TimerComponent/TimerScheduler/TimerSchedulerNetUnity.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Component/TimerComponent/TimerScheduler/TimerSchedulerNetUnity.cs.meta new file mode 100644 index 0000000..a5e2539 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Component/TimerComponent/TimerScheduler/TimerSchedulerNetUnity.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3d14712dd51d84d7eb7e8998013d28ce +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Component/TimerComponent/TimerType.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Component/TimerComponent/TimerType.cs new file mode 100644 index 0000000..6f16f80 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Component/TimerComponent/TimerType.cs @@ -0,0 +1,25 @@ +namespace Fantasy.Timer +{ + /// + /// 枚举对象TimerType + /// + public enum TimerType + { + /// + /// None + /// + None, + /// + /// 一次等待定时器 + /// + OnceWaitTimer, + /// + /// 一次性定时器 + /// + OnceTimer, + /// + /// 重复定时器 + /// + RepeatedTimer + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Component/TimerComponent/TimerType.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Component/TimerComponent/TimerType.cs.meta new file mode 100644 index 0000000..b098572 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Component/TimerComponent/TimerType.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b1b471e1861ac4718a57e94ba520588e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Entity.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Entity.cs new file mode 100644 index 0000000..0dc46b9 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Entity.cs @@ -0,0 +1,1047 @@ +using System; +using System.Collections.Generic; +using System.Runtime.Serialization; +using Fantasy.Entitas.Interface; +using Fantasy.Pool; +using MongoDB.Bson.Serialization.Attributes; +using Newtonsoft.Json; +using ProtoBuf; + +// ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract +// ReSharper disable MergeIntoPattern +// ReSharper disable SuspiciousTypeConversion.Global +// ReSharper disable NullCoalescingConditionIsAlwaysNotNullAccordingToAPIContract +// ReSharper disable CheckNamespace +#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. +#pragma warning disable CS8603 // Possible null reference return. +#pragma warning disable CS8602 // Dereference of a possibly null reference. +#pragma warning disable CS8600 // Converting null literal or possible null value to non-nullable type. +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. + +namespace Fantasy.Entitas +{ + /// + /// 用来表示一个Entity + /// + public interface IEntity : IDisposable, IPool { } + + /// + /// Entity的抽象类,任何Entity必须继承这个接口才可以使用 + /// + public abstract partial class Entity : IEntity + { + #region Members + + /// + /// 获取一个值,表示实体是否支持对象池。 + /// + [BsonIgnore] + [JsonIgnore] + [ProtoIgnore] + [IgnoreDataMember] + private bool _isPool; + /// + /// 实体的Id + /// + [BsonId] + [BsonElement] + [BsonIgnoreIfDefault] + [BsonDefaultValue(0L)] + public long Id { get; protected set; } + /// + /// 实体的RunTimeId,其他系统可以通过这个Id发送Route消息,这个Id也可以理解为RouteId + /// + [BsonIgnore] + [IgnoreDataMember] + [ProtoIgnore] + public long RuntimeId { get; protected set; } + /// + /// 当前实体是否已经被销毁 + /// + [BsonIgnore] + [JsonIgnore] + [IgnoreDataMember] + [ProtoIgnore] + public bool IsDisposed => RuntimeId == 0; + /// + /// 当前实体所归属的Scene + /// + [BsonIgnore] + [JsonIgnore] + [IgnoreDataMember] + [ProtoIgnore] + public Scene Scene { get; protected set; } + /// + /// 实体的父实体 + /// + [BsonIgnore] + [JsonIgnore] + [IgnoreDataMember] + [ProtoIgnore] + public Entity Parent { get; protected set; } + /// + /// 实体的真实Type + /// + [BsonIgnore] + [JsonIgnore] + [IgnoreDataMember] + [ProtoIgnore] + public Type Type { get; protected set; } +#if FANTASY_NET + [BsonElement("t")] [BsonIgnoreIfNull] private EntityList _treeDb; + [BsonElement("m")] [BsonIgnoreIfNull] private EntityList _multiDb; +#endif + [BsonIgnore] [IgnoreDataMember] [ProtoIgnore] private EntitySortedDictionary _tree; + [BsonIgnore] [IgnoreDataMember] [ProtoIgnore] private EntitySortedDictionary _multi; + + /// + /// 获得父Entity + /// + /// 父实体的泛型类型 + /// + public T GetParent() where T : Entity, new() + { + return Parent as T; + } + + #endregion + + #region Create + + /// + /// 创建一个实体 + /// + /// 所属的Scene + /// 实体的Type + /// 是否从对象池创建,如果选择的是,销毁的时候同样会进入对象池 + /// 是否执行实体事件 + /// + public static Entity Create(Scene scene, Type type, bool isPool, bool isRunEvent) + { + return Create(scene, type, scene.EntityIdFactory.Create, isPool, isRunEvent); + } + + /// + /// 创建一个实体 + /// + /// 所属的Scene + /// 实体的Type + /// 指定实体的Id + /// 是否从对象池创建,如果选择的是,销毁的时候同样会进入对象池 + /// 是否执行实体事件 + /// + public static Entity Create(Scene scene, Type type, long id, bool isPool, bool isRunEvent) + { + if (!typeof(Entity).IsAssignableFrom(type)) + { + throw new NotSupportedException($"{type.FullName} Type:{type.FullName} must inherit from Entity"); + } + + Entity entity = null; + + if (isPool) + { + entity = (Entity)scene.EntityPool.Rent(type); + } + else + { + if (!scene.TypeInstance.TryGetValue(type, out var createInstance)) + { + createInstance = CreateInstance.CreateIPool(type); + scene.TypeInstance[type] = createInstance; + } + + entity = (Entity)createInstance(); + } + + entity.Scene = scene; + entity.Type = type; + entity.SetIsPool(isPool); + entity.Id = id; + entity.RuntimeId = scene.RuntimeIdFactory.Create; + scene.AddEntity(entity); + + if (isRunEvent) + { + scene.EntityComponent.Awake(entity); + scene.EntityComponent.StartUpdate(entity); + } + + return entity; + } + + /// + /// 创建一个实体 + /// + /// 所属的Scene + /// 是否从对象池创建,如果选择的是,销毁的时候同样会进入对象池 + /// 是否执行实体事件 + /// 要创建的实体泛型类型 + /// + public static T Create(Scene scene, bool isPool, bool isRunEvent) where T : Entity, new() + { + return Create(scene, scene.EntityIdFactory.Create, isPool, isRunEvent); + } + + /// + /// 创建一个实体 + /// + /// 所属的Scene + /// 指定实体的Id + /// 是否从对象池创建,如果选择的是,销毁的时候同样会进入对象池 + /// 是否执行实体事件 + /// 要创建的实体泛型类型 + /// + public static T Create(Scene scene, long id, bool isPool, bool isRunEvent) where T : Entity, new() + { + var entity = isPool ? scene.EntityPool.Rent() : new T(); + entity.Scene = scene; + entity.Type = typeof(T); + entity.SetIsPool(isPool); + entity.Id = id; + entity.RuntimeId = scene.RuntimeIdFactory.Create; + scene.AddEntity(entity); + + if (isRunEvent) + { + scene.EntityComponent.Awake(entity); + scene.EntityComponent.StartUpdate(entity); + } + + return entity; + } + + #endregion + + #region AddComponent + + /// + /// 添加一个组件到当前实体上 + /// + /// 是否从对象池里创建 + /// 要添加组件的泛型类型 + /// 返回添加到实体上组件的实例 + public T AddComponent(bool isPool = true) where T : Entity, new() + { + var id = SupportedMultiEntityChecker.IsSupported ? Scene.EntityIdFactory.Create : Id; + var entity = Create(Scene, id, isPool, false); + AddComponent(entity); + Scene.EntityComponent.Awake(entity); + Scene.EntityComponent.StartUpdate(entity); + return entity; + } + + /// + /// 添加一个组件到当前实体上 + /// + /// 要添加组件的Id + /// 是否从对象池里创建 + /// 要添加组件的泛型类型 + /// 返回添加到实体上组件的实例 + public T AddComponent(long id, bool isPool = true) where T : Entity, new() + { + var entity = Create(Scene, id, isPool, false); + AddComponent(entity); + Scene.EntityComponent.Awake(entity); + Scene.EntityComponent.StartUpdate(entity); + return entity; + } + + /// + /// 添加一个组件到当前实体上 + /// + /// 要添加的实体实例 + public void AddComponent(Entity component) + { + if (this == component) + { + Log.Error("Cannot add oneself to one's own components"); + return; + } + + if (component.IsDisposed) + { + Log.Error($"component is Disposed {component.Type.FullName}"); + return; + } + + var type = component.Type; + component.Parent?.RemoveComponent(component, false); + + if (component is ISupportedMultiEntity) + { + _multi ??= Scene.EntitySortedDictionaryPool.Rent(); + _multi.Add(component.Id, component); +#if FANTASY_NET + if (component is ISupportedDataBase) + { + _multiDb ??= Scene.EntityListPool.Rent(); + _multiDb.Add(component); + } +#endif + } + else + { +#if FANTASY_NET + if (component is ISupportedSingleCollection && component.Id != Id) + { + Log.Error($"component type :{type.FullName} for implementing ISupportedSingleCollection, it is required that the Id must be the same as the parent"); + } +#endif + var typeHashCode = Scene.EntityComponent.GetHashCode(type);; + + if (_tree == null) + { + _tree = Scene.EntitySortedDictionaryPool.Rent(); + } + else if (_tree.ContainsKey(typeHashCode)) + { + Log.Error($"type:{type.FullName} If you want to add multiple components of the same type, please implement IMultiEntity"); + return; + } + + _tree.Add(typeHashCode, component); +#if FANTASY_NET + if (component is ISupportedDataBase) + { + _treeDb ??= Scene.EntityListPool.Rent(); + _treeDb.Add(component); + } +#endif + } + + component.Parent = this; + component.Scene = Scene; + } + + /// + /// 添加一个组件到当前实体上 + /// + /// 要添加的实体实例 + /// 要添加组件的泛型类型 + public void AddComponent(T component) where T : Entity + { + var type = typeof(T); + + if (type == typeof(Entity)) + { + Log.Error("Cannot add a generic Entity type as a component. Specify a more specific type."); + return; + } + + if (this == component) + { + Log.Error("Cannot add oneself to one's own components"); + return; + } + + if (component.IsDisposed) + { + Log.Error($"component is Disposed {type.FullName}"); + return; + } + + component.Parent?.RemoveComponent(component, false); + + if (SupportedMultiEntityChecker.IsSupported) + { + _multi ??= Scene.EntitySortedDictionaryPool.Rent(); + _multi.Add(component.Id, component); +#if FANTASY_NET + if (SupportedDataBaseChecker.IsSupported) + { + _multiDb ??= Scene.EntityListPool.Rent(); + _multiDb.Add(component); + } +#endif + } + else + { +#if FANTASY_NET + if (SupportedSingleCollectionChecker.IsSupported && component.Id != Id) + { + Log.Error($"component type :{type.FullName} for implementing ISupportedSingleCollection, it is required that the Id must be the same as the parent"); + } +#endif + var typeHashCode = Scene.EntityComponent.GetHashCode(type); + + if (_tree == null) + { + _tree = Scene.EntitySortedDictionaryPool.Rent(); + } + else if (_tree.ContainsKey(typeHashCode)) + { + Log.Error($"type:{type.FullName} If you want to add multiple components of the same type, please implement IMultiEntity"); + return; + } + + _tree.Add(typeHashCode, component); +#if FANTASY_NET + if (SupportedDataBaseChecker.IsSupported) + { + _treeDb ??= Scene.EntityListPool.Rent(); + _treeDb.Add(component); + } +#endif + } + + component.Parent = this; + component.Scene = Scene; + } + + /// + /// 添加一个组件到当前实体上 + /// + /// 组件的类型 + /// 是否在对象池创建 + /// + public Entity AddComponent(Type type, bool isPool = true) + { + var id = typeof(ISupportedMultiEntity).IsAssignableFrom(type) ? Scene.EntityIdFactory.Create : Id; + var entity = Entity.Create(Scene, type, id, isPool, false); + AddComponent(entity); + Scene.EntityComponent.Awake(entity); + Scene.EntityComponent.StartUpdate(entity); + return entity; + } + + #endregion + + #region HasComponent + + /// + /// 当前实体上是否有指定类型的组件 + /// + /// + /// + public bool HasComponent() where T : Entity, new() + { + return HasComponent(typeof(T)); + } + + /// + /// 当前实体上是否有指定类型的组件 + /// + /// + /// + public bool HasComponent(Type type) + { + if (_tree == null) + { + return false; + } + + return _tree.ContainsKey(Scene.EntityComponent.GetHashCode(type)); + } + + /// + /// 当前实体上是否有指定类型的组件 + /// + /// + /// + /// + public bool HasComponent(long id) where T : Entity, ISupportedMultiEntity, new() + { + if (_multi == null) + { + return false; + } + + return _multi.ContainsKey(id); + } + + #endregion + + #region GetComponent + + /// + /// 当前实体上查找一个字实体 + /// + /// 要查找实体泛型类型 + /// 查找的实体实例 + public T GetComponent() where T : Entity, new() + { + if (_tree == null) + { + return null; + } + + var typeHashCode = Scene.EntityComponent.GetHashCode(typeof(T)); + return _tree.TryGetValue(typeHashCode, out var component) ? (T)component : null; + } + + /// + /// 当前实体上查找一个字实体 + /// + /// 要查找实体类型 + /// 查找的实体实例 + public Entity GetComponent(Type type) + { + if (_tree == null) + { + return null; + } + + var typeHashCode = Scene.EntityComponent.GetHashCode(type); + return _tree.TryGetValue(typeHashCode, out var component) ? component : null; + } + + /// + /// 当前实体上查找一个字实体 + /// + /// 要查找实体的Id + /// 要查找实体泛型类型 + /// 查找的实体实例 + public T GetComponent(long id) where T : Entity, ISupportedMultiEntity, new() + { + if (_multi == null) + { + return default; + } + + return _multi.TryGetValue(id, out var entity) ? (T)entity : default; + } + + /// + /// 当前实体上查找一个字实体,如果没有就创建一个新的并添加到当前实体上 + /// + /// 是否从对象池创建 + /// 要查找或添加实体泛型类型 + /// 查找的实体实例 + public T GetOrAddComponent(bool isPool = true) where T : Entity, new() + { + return GetComponent() ?? AddComponent(isPool); + } + + #endregion + + #region RemoveComponent + + /// + /// 当前实体下删除一个实体 + /// + /// 是否执行删除实体的Dispose方法 + /// 实体的泛型类型 + /// + public void RemoveComponent(bool isDispose = true) where T : Entity, new() + { + if (SupportedMultiEntityChecker.IsSupported) + { + throw new NotSupportedException($"{typeof(T).FullName} message:Cannot delete components that implement the ISupportedMultiEntity interface"); + } + + if (_tree == null) + { + return; + } + + var type = typeof(T); + var typeHashCode = Scene.EntityComponent.GetHashCode(type); + if (!_tree.TryGetValue(typeHashCode, out var component)) + { + return; + } +#if FANTASY_NET + if (_treeDb != null && SupportedDataBaseChecker.IsSupported) + { + _treeDb.Remove(component); + + if (_treeDb.Count == 0) + { + Scene.EntityListPool.Return(_treeDb); + _treeDb = null; + } + } +#endif + _tree.Remove(typeHashCode); + + if (_tree.Count == 0) + { + Scene.EntitySortedDictionaryPool.Return(_tree); + _tree = null; + } + + if (isDispose) + { + component.Dispose(); + } + } + + /// + /// 当前实体下删除一个实体 + /// + /// 要删除的实体Id + /// 是否执行删除实体的Dispose方法 + /// 实体的泛型类型 + public void RemoveComponent(long id, bool isDispose = true) where T : Entity, ISupportedMultiEntity, new() + { + if (_multi == null) + { + return; + } + + if (!_multi.TryGetValue(id, out var component)) + { + return; + } +#if FANTASY_NET + if (SupportedDataBaseChecker.IsSupported) + { + _multiDb.Remove(component); + if (_multiDb.Count == 0) + { + Scene.EntityListPool.Return(_multiDb); + _multiDb = null; + } + } +#endif + _multi.Remove(component.Id); + if (_multi.Count == 0) + { + Scene.EntitySortedDictionaryPool.Return(_multi); + _multi = null; + } + + if (isDispose) + { + component.Dispose(); + } + } + + /// + /// 当前实体下删除一个实体 + /// + /// 要删除的实体实例 + /// 是否执行删除实体的Dispose方法 + public void RemoveComponent(Entity component, bool isDispose = true) + { + if (this == component) + { + return; + } + + if (component is ISupportedMultiEntity) + { + if (_multi != null) + { + if (!_multi.ContainsKey(component.Id)) + { + return; + } +#if FANTASY_NET + if (component is ISupportedDataBase) + { + _multiDb.Remove(component); + if (_multiDb.Count == 0) + { + Scene.EntityListPool.Return(_multiDb); + _multiDb = null; + } + } +#endif + _multi.Remove(component.Id); + if (_multi.Count == 0) + { + Scene.EntitySortedDictionaryPool.Return(_multi); + _multi = null; + } + } + } + else if (_tree != null) + { + var typeHashCode = Scene.EntityComponent.GetHashCode(component.Type); + if (!_tree.ContainsKey(typeHashCode)) + { + return; + } +#if FANTASY_NET + if (_treeDb != null && component is ISupportedDataBase) + { + _treeDb.Remove(component); + + if (_treeDb.Count == 0) + { + Scene.EntityListPool.Return(_treeDb); + _treeDb = null; + } + } +#endif + _tree.Remove(typeHashCode); + + if (_tree.Count == 0) + { + Scene.EntitySortedDictionaryPool.Return(_tree); + _tree = null; + } + } + + if (isDispose) + { + component.Dispose(); + } + } + + /// + /// 当前实体下删除一个实体 + /// + /// 要删除的实体实例 + /// 是否执行删除实体的Dispose方法 + /// 实体的泛型类型 + public void RemoveComponent(T component, bool isDispose = true) where T : Entity + { + if (this == component) + { + return; + } + + if (typeof(T) == typeof(Entity)) + { + Log.Error("Cannot remove a generic Entity type as a component. Specify a more specific type."); + return; + } + + if (SupportedMultiEntityChecker.IsSupported) + { + if (_multi != null) + { + if (!_multi.ContainsKey(component.Id)) + { + return; + } +#if FANTASY_NET + if (SupportedDataBaseChecker.IsSupported) + { + _multiDb.Remove(component); + if (_multiDb.Count == 0) + { + Scene.EntityListPool.Return(_multiDb); + _multiDb = null; + } + } +#endif + _multi.Remove(component.Id); + if (_multi.Count == 0) + { + Scene.EntitySortedDictionaryPool.Return(_multi); + _multi = null; + } + } + } + else if (_tree != null) + { + var typeHashCode = Scene.EntityComponent.GetHashCode(typeof(T)); + if (!_tree.ContainsKey(typeHashCode)) + { + return; + } +#if FANTASY_NET + if (_treeDb != null && SupportedDataBaseChecker.IsSupported) + { + _treeDb.Remove(component); + + if (_treeDb.Count == 0) + { + Scene.EntityListPool.Return(_treeDb); + _treeDb = null; + } + } +#endif + _tree.Remove(typeHashCode); + + if (_tree.Count == 0) + { + Scene.EntitySortedDictionaryPool.Return(_tree); + _tree = null; + } + } + + if (isDispose) + { + component.Dispose(); + } + } + + #endregion + + #region Deserialize + + /// + /// 反序列化当前实体,因为在数据库加载过来的或通过协议传送过来的实体并没有跟当前Scene做关联。 + /// 所以必须要执行一下这个反序列化的方法才可以使用。 + /// + /// Scene + /// 是否是重新生成实体的Id,如果是数据库加载过来的一般是不需要的 + public void Deserialize(Scene scene, bool resetId = false) + { + if (RuntimeId != 0) + { + return; + } + + try + { + Scene = scene; + Type ??= GetType(); + RuntimeId = Scene.RuntimeIdFactory.Create; + if (resetId) + { + Id = RuntimeId; + } +#if FANTASY_NET + if (_treeDb != null && _treeDb.Count > 0) + { + _tree = Scene.EntitySortedDictionaryPool.Rent(); + foreach (var entity in _treeDb) + { + entity.Parent = this; + entity.Type = entity.GetType(); + var typeHashCode = Scene.EntityComponent.GetHashCode(entity.Type); + _tree.Add(typeHashCode, entity); + entity.Deserialize(scene, resetId); + } + } + + if (_multiDb != null && _multiDb.Count > 0) + { + _multi = Scene.EntitySortedDictionaryPool.Rent(); + foreach (var entity in _multiDb) + { + entity.Parent = this; + entity.Deserialize(scene, resetId); + _multi.Add(entity.Id, entity); + } + } +#endif + scene.AddEntity(this); + scene.EntityComponent.Deserialize(this); + } + catch (Exception e) + { + if (RuntimeId != 0) + { + scene.RemoveEntity(RuntimeId); + } + + Log.Error(e); + } + } + + #endregion + + #region ForEach +#if FANTASY_NET + /// + /// 查询当前实体下支持数据库分表存储实体 + /// + [BsonIgnore] + [JsonIgnore] + [IgnoreDataMember] + [ProtoIgnore] + public IEnumerable ForEachSingleCollection + { + get + { + foreach (var (_, treeEntity) in _tree) + { + if (treeEntity is not ISupportedSingleCollection) + { + continue; + } + + yield return treeEntity; + } + } + } + /// + /// 查询当前实体下支持传送实体 + /// + [BsonIgnore] + [JsonIgnore] + [IgnoreDataMember] + [ProtoIgnore] + public IEnumerable ForEachTransfer + { + get + { + if (_tree != null) + { + foreach (var (_, treeEntity) in _tree) + { + if (treeEntity is ISupportedTransfer) + { + yield return treeEntity; + } + } + } + + if (_multiDb != null) + { + foreach (var treeEntity in _multiDb) + { + if (treeEntity is not ISupportedTransfer) + { + continue; + } + + yield return treeEntity; + } + } + } + } +#endif + /// + /// 查询当前实体下的实现了ISupportedMultiEntity接口的实体 + /// + [BsonIgnore] + [JsonIgnore] + [IgnoreDataMember] + [ProtoIgnore] + public IEnumerable ForEachMultiEntity + { + get + { + if (_multi == null) + { + yield break; + } + + foreach (var (_, supportedMultiEntity) in _multi) + { + yield return supportedMultiEntity; + } + } + } + /// + /// 查找当前实体下的所有实体,不包括实现ISupportedMultiEntity接口的实体 + /// + [BsonIgnore] + [JsonIgnore] + [IgnoreDataMember] + [ProtoIgnore] + public IEnumerable ForEachEntity + { + get + { + if (_tree == null) + { + yield break; + } + + foreach (var (_, entity) in _tree) + { + yield return entity; + } + } + } + #endregion + + #region Dispose + + /// + /// 销毁当前实体,销毁后会自动销毁当前实体下的所有实体。 + /// + public virtual void Dispose() + { + if (IsDisposed) + { + return; + } + + var scene = Scene; + var runTimeId = RuntimeId; + RuntimeId = 0; + + if (_tree != null) + { + foreach (var (_, entity) in _tree) + { + entity.Dispose(); + } + + _tree.Clear(); + scene.EntitySortedDictionaryPool.Return(_tree); + _tree = null; + } + + if (_multi != null) + { + foreach (var (_, entity) in _multi) + { + entity.Dispose(); + } + + _multi.Clear(); + scene.EntitySortedDictionaryPool.Return(_multi); + _multi = null; + } +#if FANTASY_NET + if (_treeDb != null) + { + foreach (var entity in _treeDb) + { + entity.Dispose(); + } + + _treeDb.Clear(); + scene.EntityListPool.Return(_treeDb); + _treeDb = null; + } + + if (_multiDb != null) + { + foreach (var entity in _multiDb) + { + entity.Dispose(); + } + + _multiDb.Clear(); + scene.EntityListPool.Return(_multiDb); + _multiDb = null; + } +#endif + scene.EntityComponent.Destroy(this); + + if (Parent != null && Parent != this && !Parent.IsDisposed) + { + Parent.RemoveComponent(this, false); + Parent = null; + } + + Id = 0; + Scene = null; + Parent = null; + scene.RemoveEntity(runTimeId); + + if (IsPool()) + { + scene.EntityPool.Return(Type, this); + } + + Type = null; + } + + #endregion + + #region Pool + + /// + /// 获取一个值,该值指示当前实例是否为对象池中的实例。 + /// + /// + public bool IsPool() + { + return _isPool; + } + + /// + /// 设置一个值,该值指示当前实例是否为对象池中的实例。 + /// + /// + public void SetIsPool(bool isPool) + { + _isPool = isPool; + } + + #endregion + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Entity.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Entity.cs.meta new file mode 100644 index 0000000..4b46a48 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Entity.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0a47c9eec9972439e88417f2f4b18482 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/EntityPool.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/EntityPool.cs new file mode 100644 index 0000000..9a6441c --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/EntityPool.cs @@ -0,0 +1,66 @@ +using System.Collections.Generic; +using Fantasy.Pool; + +#pragma warning disable CS8714 // The type cannot be used as type parameter in the generic type or method. Nullability of type argument doesn't match 'notnull' constraint. + +namespace Fantasy.Entitas +{ + internal sealed class EntityPool : PoolCore + { + public EntityPool() : base(4096) { } + } + + internal sealed class EntityList : List, IPool where T : Entity + { + private bool _isPool; + /// + /// 获取一个值,该值指示当前实例是否为对象池中的实例。 + /// + /// + public bool IsPool() + { + return _isPool; + } + + /// + /// 设置一个值,该值指示当前实例是否为对象池中的实例。 + /// + /// + public void SetIsPool(bool isPool) + { + _isPool = isPool; + } + } + + internal sealed class EntityListPool : PoolCore> where T : Entity + { + public EntityListPool() : base(4096) { } + } + + internal sealed class EntitySortedDictionary : SortedDictionary, IPool where TN : Entity + { + private bool _isPool; + /// + /// 获取一个值,该值指示当前实例是否为对象池中的实例。 + /// + /// + public bool IsPool() + { + return _isPool; + } + + /// + /// 设置一个值,该值指示当前实例是否为对象池中的实例。 + /// + /// + public void SetIsPool(bool isPool) + { + _isPool = isPool; + } + } + + internal sealed class EntitySortedDictionaryPool : PoolCore> where TN : Entity + { + public EntitySortedDictionaryPool() : base(4096) { } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/EntityPool.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/EntityPool.cs.meta new file mode 100644 index 0000000..6bc9fac --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/EntityPool.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f30a1dcea6418429889f3e2216a883c6 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/EntityReference.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/EntityReference.cs new file mode 100644 index 0000000..dd1a3fd --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/EntityReference.cs @@ -0,0 +1,59 @@ +// ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. +#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. +#pragma warning disable CS8603 // Possible null reference return. +namespace Fantasy.Entitas +{ + /// + /// 实体引用检查组件 + /// + /// + public struct EntityReference where T : Entity + { + private T _entity; + private readonly long _runTimeId; + + private EntityReference(T t) + { + if (t == null) + { + _entity = null; + _runTimeId = 0; + return; + } + + _entity = t; + _runTimeId = t.RuntimeId; + } + + /// + /// 将一个实体转换为EntityReference + /// + /// 实体泛型类型 + /// 返回一个EntityReference + public static implicit operator EntityReference(T t) + { + return new EntityReference(t); + } + + /// + /// 将一个EntityReference转换为实体 + /// + /// 实体泛型类型 + /// 当实体已经被销毁过会返回null + public static implicit operator T(EntityReference v) + { + if (v._entity == null) + { + return null; + } + + if (v._entity.RuntimeId != v._runTimeId) + { + v._entity = null; + } + + return v._entity; + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/EntityReference.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/EntityReference.cs.meta new file mode 100644 index 0000000..8e9553f --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/EntityReference.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: aba2430182a244c3393abe66830172b9 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Interface.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Interface.meta new file mode 100644 index 0000000..291e641 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Interface.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 9b2fb651801ec40d1a0565114e0059d6 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Interface/Supported.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Interface/Supported.meta new file mode 100644 index 0000000..b20488c --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Interface/Supported.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 9255f085833224805bf13e026b755fd2 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Interface/Supported/ISingleCollectionRoot.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Interface/Supported/ISingleCollectionRoot.cs new file mode 100644 index 0000000..84de7a4 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Interface/Supported/ISingleCollectionRoot.cs @@ -0,0 +1,17 @@ +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member +namespace Fantasy.Entitas.Interface +{ + /// + /// Entity保存到数据库的时候会根据子组件设置分离存储特性分表存储在不同的集合表中 + /// + public interface ISingleCollectionRoot { } + public static class SingleCollectionRootChecker where T : Entity + { + public static bool IsSupported { get; } + + static SingleCollectionRootChecker() + { + IsSupported = typeof(ISingleCollectionRoot).IsAssignableFrom(typeof(T)); + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Interface/Supported/ISingleCollectionRoot.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Interface/Supported/ISingleCollectionRoot.cs.meta new file mode 100644 index 0000000..94cbb13 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Interface/Supported/ISingleCollectionRoot.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 57298dd8265554d6087d79ef5a6e89cc +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Interface/Supported/ISupportedDataBase.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Interface/Supported/ISupportedDataBase.cs new file mode 100644 index 0000000..f505241 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Interface/Supported/ISupportedDataBase.cs @@ -0,0 +1,19 @@ +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member +namespace Fantasy.Entitas.Interface +{ + /// + /// Entity支持数据库 + /// + // ReSharper disable once InconsistentNaming + public interface ISupportedDataBase { } + + public static class SupportedDataBaseChecker where T : Entity + { + public static bool IsSupported { get; } + + static SupportedDataBaseChecker() + { + IsSupported = typeof(ISupportedDataBase).IsAssignableFrom(typeof(T)); + } + } +} diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Interface/Supported/ISupportedDataBase.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Interface/Supported/ISupportedDataBase.cs.meta new file mode 100644 index 0000000..4b72ec6 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Interface/Supported/ISupportedDataBase.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ae64989e8b146443e99c66290b20a3c8 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Interface/Supported/ISupportedMultiEntity.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Interface/Supported/ISupportedMultiEntity.cs new file mode 100644 index 0000000..ee6aeb7 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Interface/Supported/ISupportedMultiEntity.cs @@ -0,0 +1,20 @@ +using System; +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member + +namespace Fantasy.Entitas.Interface +{ + /// + /// 支持再一个组件里添加多个同类型组件 + /// + public interface ISupportedMultiEntity : IDisposable { } + + public static class SupportedMultiEntityChecker where T : Entity + { + public static bool IsSupported { get; } + + static SupportedMultiEntityChecker() + { + IsSupported = typeof(ISupportedMultiEntity).IsAssignableFrom(typeof(T)); + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Interface/Supported/ISupportedMultiEntity.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Interface/Supported/ISupportedMultiEntity.cs.meta new file mode 100644 index 0000000..4096fe8 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Interface/Supported/ISupportedMultiEntity.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 36105e7ed5c974fdabf37eead97ef95c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Interface/Supported/ISupportedSingleCollection.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Interface/Supported/ISupportedSingleCollection.cs new file mode 100644 index 0000000..302e697 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Interface/Supported/ISupportedSingleCollection.cs @@ -0,0 +1,47 @@ +using System; +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member +namespace Fantasy.Entitas.Interface +{ + // Entity是单一集合、保存到数据库的时候不会跟随父组件保存在一个集合里、会单独保存在一个集合里 + // 需要配合SingleCollectionAttribute一起使用、如在Entity类头部定义SingleCollectionAttribute(typeOf(Unit)) + // SingleCollectionAttribute用来定义这个Entity是属于哪个Entity的子集 + /// + /// 定义实体支持单一集合存储的接口。当实体需要单独存储在一个集合中,并且在保存到数据库时不会与父组件一起保存在同一个集合中时,应实现此接口。 + /// + public interface ISupportedSingleCollection { } + public static class SupportedSingleCollectionChecker where T : Entity + { + public static bool IsSupported { get; } + + static SupportedSingleCollectionChecker() + { + IsSupported = typeof(ISupportedSingleCollection).IsAssignableFrom(typeof(T)); + } + } + /// + /// 表示用于指定实体的单一集合存储属性。此属性用于配合 接口使用, + /// 用于定义实体属于哪个父实体的子集合,以及在数据库中使用的集合名称。 + /// + [AttributeUsage(AttributeTargets.Class, Inherited = true, AllowMultiple = false)] + public class SingleCollectionAttribute : Attribute + { + /// + /// 获取父实体的类型,指示此实体是属于哪个父实体的子集合。 + /// + public readonly Type RootType; + /// + /// 获取在数据库中使用的集合名称。 + /// + public readonly string CollectionName; + /// + /// 初始化 类的新实例,指定父实体类型和集合名称。 + /// + /// 父实体的类型。 + /// 在数据库中使用的集合名称。 + public SingleCollectionAttribute(Type rootType, string collectionName) + { + RootType = rootType; + CollectionName = collectionName; + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Interface/Supported/ISupportedSingleCollection.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Interface/Supported/ISupportedSingleCollection.cs.meta new file mode 100644 index 0000000..dc89d3b --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Interface/Supported/ISupportedSingleCollection.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: afd453d04ac254206a9bb83664a888a0 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Interface/Supported/ISupportedTransfer.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Interface/Supported/ISupportedTransfer.cs new file mode 100644 index 0000000..a3ae4a9 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Interface/Supported/ISupportedTransfer.cs @@ -0,0 +1,19 @@ +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member +#if FANTASY_NET +namespace Fantasy.Entitas.Interface +{ + /// + /// Entity支持传送 + /// + public interface ISupportedTransfer { } + public static class SupportedTransferChecker where T : Entity + { + public static bool IsSupported { get; } + + static SupportedTransferChecker() + { + IsSupported = typeof(ISupportedTransfer).IsAssignableFrom(typeof(T)); + } + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Interface/Supported/ISupportedTransfer.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Interface/Supported/ISupportedTransfer.cs.meta new file mode 100644 index 0000000..8f1493c --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Interface/Supported/ISupportedTransfer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a127a7c6e345a42e3860b804457f0fe5 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Interface/System.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Interface/System.meta new file mode 100644 index 0000000..01495d4 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Interface/System.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 275ef1a555d6f41cbb322011303dd57c +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Interface/System/IAwakeSystem.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Interface/System/IAwakeSystem.cs new file mode 100644 index 0000000..f651701 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Interface/System/IAwakeSystem.cs @@ -0,0 +1,32 @@ +using System; +using Fantasy.Async; + +namespace Fantasy.Entitas.Interface +{ + internal interface IAwakeSystem : IEntitiesSystem { } + /// + /// 实体的Awake事件的抽象接口 + /// + /// 实体的泛型类型 + public abstract class AwakeSystem : IAwakeSystem where T : Entity + { + /// + /// 实体的类型 + /// + /// + public Type EntitiesType() => typeof(T); + /// + /// 事件的抽象方法,需要自己实现这个方法 + /// + /// 触发事件的实体实例 + protected abstract void Awake(T self); + /// + /// 框架内部调用的触发Awake的方法。 + /// + /// 触发事件的实体实例 + public void Invoke(Entity self) + { + Awake((T) self); + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Interface/System/IAwakeSystem.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Interface/System/IAwakeSystem.cs.meta new file mode 100644 index 0000000..782be94 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Interface/System/IAwakeSystem.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: fe2caf80007df454bb76729547780d28 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Interface/System/IDeserializeSystem.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Interface/System/IDeserializeSystem.cs new file mode 100644 index 0000000..9c38ab6 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Interface/System/IDeserializeSystem.cs @@ -0,0 +1,32 @@ +using System; +using Fantasy.Async; + +namespace Fantasy.Entitas.Interface +{ + internal interface IDeserializeSystem : IEntitiesSystem { } + /// + /// 实体的反序列化事件的抽象接口 + /// + /// 实体的泛型数据 + public abstract class DeserializeSystem : IDeserializeSystem where T : Entity + { + /// + /// 实体的类型 + /// + /// + public Type EntitiesType() => typeof(T); + /// + /// 事件的抽象方法,需要自己实现这个方法 + /// + /// 触发事件的实体实例 + protected abstract void Deserialize(T self); + /// + /// 框架内部调用的触发Deserialize的方法 + /// + /// 触发事件的实体实例 + public void Invoke(Entity self) + { + Deserialize((T) self); + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Interface/System/IDeserializeSystem.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Interface/System/IDeserializeSystem.cs.meta new file mode 100644 index 0000000..b2b90be --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Interface/System/IDeserializeSystem.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f9d2fff74aed249e8aa0acbb122614c2 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Interface/System/IDestroySystem.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Interface/System/IDestroySystem.cs new file mode 100644 index 0000000..531ebbe --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Interface/System/IDestroySystem.cs @@ -0,0 +1,32 @@ +using System; +using Fantasy.Async; + +namespace Fantasy.Entitas.Interface +{ + internal interface IDestroySystem : IEntitiesSystem { } + /// + /// 实体销毁事件的抽象接口 + /// + /// + public abstract class DestroySystem : IDestroySystem where T : Entity + { + /// + /// 实体的类型 + /// + /// + public Type EntitiesType() => typeof(T); + /// + /// 事件的抽象方法,需要自己实现这个方法 + /// + /// 触发事件的实体实例 + protected abstract void Destroy(T self); + /// + /// 框架内部调用的触发Destroy的方法 + /// + /// + public void Invoke(Entity self) + { + Destroy((T) self); + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Interface/System/IDestroySystem.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Interface/System/IDestroySystem.cs.meta new file mode 100644 index 0000000..f46b2c4 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Interface/System/IDestroySystem.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 899a57e15b99948c7bcaef5b76cae97c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Interface/System/IEntitiesSystem.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Interface/System/IEntitiesSystem.cs new file mode 100644 index 0000000..555d21a --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Interface/System/IEntitiesSystem.cs @@ -0,0 +1,22 @@ +using System; +using Fantasy.Async; + +namespace Fantasy.Entitas.Interface +{ + /// + /// ECS事件系统的核心接口,任何事件都是要继承这个接口 + /// + public interface IEntitiesSystem + { + /// + /// 实体的类型 + /// + /// + Type EntitiesType(); + /// + /// 框架内部调用的触发事件方法 + /// + /// + void Invoke(Entity entity); + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Interface/System/IEntitiesSystem.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Interface/System/IEntitiesSystem.cs.meta new file mode 100644 index 0000000..d5370f1 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Interface/System/IEntitiesSystem.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 287ae5e33ccda4c28946371bcad4755b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Interface/System/IFrameUpdateSystem.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Interface/System/IFrameUpdateSystem.cs new file mode 100644 index 0000000..c50061b --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Interface/System/IFrameUpdateSystem.cs @@ -0,0 +1,31 @@ +using System; + +namespace Fantasy.Entitas.Interface +{ + internal interface IFrameUpdateSystem : IEntitiesSystem { } + /// + /// 帧更新时间的抽象接口 + /// + /// + public abstract class FrameUpdateSystem : IFrameUpdateSystem where T : Entity + { + /// + /// 实体的类型 + /// + /// + public Type EntitiesType() => typeof(T); + /// + /// 事件的抽象方法,需要自己实现这个方法 + /// + /// 触发事件的实体实例 + protected abstract void FrameUpdate(T self); + /// + /// 框架内部调用的触发FrameUpdate的方法 + /// + /// + public void Invoke(Entity self) + { + FrameUpdate((T) self); + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Interface/System/IFrameUpdateSystem.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Interface/System/IFrameUpdateSystem.cs.meta new file mode 100644 index 0000000..866ab9a --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Interface/System/IFrameUpdateSystem.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b785fffadcd8c4461b1f1fcf397728b9 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Interface/System/IUpdateSystem.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Interface/System/IUpdateSystem.cs new file mode 100644 index 0000000..4b34ac8 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Interface/System/IUpdateSystem.cs @@ -0,0 +1,31 @@ +using System; + +namespace Fantasy.Entitas.Interface +{ + internal interface IUpdateSystem : IEntitiesSystem { } + /// + /// Update事件的抽象接口 + /// + /// + public abstract class UpdateSystem : IUpdateSystem where T : Entity + { + /// + /// 实体的类型 + /// + /// + public Type EntitiesType() => typeof(T); + /// + /// 事件的抽象方法,需要自己实现这个方法 + /// + /// 触发事件的实体实例 + protected abstract void Update(T self); + /// + /// 框架内部调用的触发Update的方法 + /// + /// 触发事件的实体实例 + public void Invoke(Entity self) + { + Update((T) self); + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Interface/System/IUpdateSystem.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Interface/System/IUpdateSystem.cs.meta new file mode 100644 index 0000000..a78de3d --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Entitas/Interface/System/IUpdateSystem.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a40db65b7285747ffad3a0346966406c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/FTask.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/FTask.meta new file mode 100644 index 0000000..0d3ce15 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/FTask.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 7cbdb29429eef4863afcac2d65fb563a +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/FTask/Builder.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/FTask/Builder.meta new file mode 100644 index 0000000..f6bbcfa --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/FTask/Builder.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 8882af7b2bcd247b79a45e5a7f166996 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/FTask/Builder/AsyncFTaskCompletedMethodBuilder.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/FTask/Builder/AsyncFTaskCompletedMethodBuilder.cs new file mode 100644 index 0000000..60b0d08 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/FTask/Builder/AsyncFTaskCompletedMethodBuilder.cs @@ -0,0 +1,52 @@ +using System; +using System.Diagnostics; +using System.Runtime.CompilerServices; +using System.Runtime.ExceptionServices; +using System.Runtime.InteropServices; +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member + +namespace Fantasy.Async +{ + [StructLayout(LayoutKind.Auto)] + public struct AsyncFTaskCompletedMethodBuilder + { + public FTaskCompleted Task => default; + + [DebuggerHidden] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static AsyncFTaskCompletedMethodBuilder Create() + { + return new AsyncFTaskCompletedMethodBuilder(); + } + [DebuggerHidden] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Start(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine + { + stateMachine.MoveNext(); + } + [DebuggerHidden] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void SetException(Exception exception) + { + ExceptionDispatchInfo.Capture(exception).Throw(); + } + [DebuggerHidden] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void SetResult() { } + [DebuggerHidden] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void AwaitOnCompleted(ref TAwaiter awaiter, ref TStateMachine stateMachine) where TAwaiter : INotifyCompletion where TStateMachine : IAsyncStateMachine + { + awaiter.OnCompleted(stateMachine.MoveNext); + } + [DebuggerHidden] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void AwaitUnsafeOnCompleted(ref TAwaiter awaiter, ref TStateMachine stateMachine) where TAwaiter : ICriticalNotifyCompletion where TStateMachine : IAsyncStateMachine + { + awaiter.UnsafeOnCompleted(stateMachine.MoveNext); + } + [DebuggerHidden] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void SetStateMachine(IAsyncStateMachine stateMachine) { } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/FTask/Builder/AsyncFTaskCompletedMethodBuilder.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/FTask/Builder/AsyncFTaskCompletedMethodBuilder.cs.meta new file mode 100644 index 0000000..85f4821 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/FTask/Builder/AsyncFTaskCompletedMethodBuilder.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8444248debce04e9c82848c9649bf183 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/FTask/Builder/AsyncFTaskMethodBuilder.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/FTask/Builder/AsyncFTaskMethodBuilder.cs new file mode 100644 index 0000000..6c072cd --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/FTask/Builder/AsyncFTaskMethodBuilder.cs @@ -0,0 +1,140 @@ +using System; +using System.Collections.Concurrent; +using System.Diagnostics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +// ReSharper disable MemberCanBePrivate.Global +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member +#pragma warning disable CS8604 // Possible null reference argument. + +namespace Fantasy.Async +{ + [StructLayout(LayoutKind.Auto)] + public readonly struct AsyncFTaskMethodBuilder + { + public FTask Task + { + [DebuggerHidden] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get; + } + + [DebuggerHidden] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static AsyncFTaskMethodBuilder Create() + { + return new AsyncFTaskMethodBuilder(FTask.Create()); + } + + public AsyncFTaskMethodBuilder(FTask fTask) + { + Task = fTask; + } + + [DebuggerHidden] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Start(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine + { + stateMachine.MoveNext(); + } + + [DebuggerHidden] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void SetResult() + { + Task.SetResult(); + } + + [DebuggerHidden] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void SetException(Exception exception) + { + Task.SetException(exception); + } + + [DebuggerHidden] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void AwaitOnCompleted(ref TAwaiter awaiter, ref TStateMachine stateMachine) where TAwaiter : INotifyCompletion where TStateMachine : IAsyncStateMachine + { + // 通常在异步方法中遇到 await 关键字时调用,并且需要将执行恢复到调用 await 之前的同步上下文。 + awaiter.OnCompleted(stateMachine.MoveNext); + } + + [DebuggerHidden] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void AwaitUnsafeOnCompleted(ref TAwaiter awaiter, ref TStateMachine stateMachine) where TAwaiter : ICriticalNotifyCompletion where TStateMachine : IAsyncStateMachine + { + // 通常在你不需要恢复到原始同步上下文时调用,这意味着你不关心在什么线程上恢复执行。 + awaiter.UnsafeOnCompleted(stateMachine.MoveNext); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void SetStateMachine(IAsyncStateMachine stateMachine) + { + // 用于设置和保存异步方法的状态机实例。 + // 编译器在生成异步方法时要求其存在。 + // 编译器生成的代码已经足够处理状态机的管理,所以这里没有什么特殊要求所以保持空实现。 + } + } + + [StructLayout(LayoutKind.Auto)] + public readonly struct AsyncFTaskMethodBuilder + { + public FTask Task + { + [DebuggerHidden] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get; + } + + [DebuggerHidden] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static AsyncFTaskMethodBuilder Create() + { + return new AsyncFTaskMethodBuilder(FTask.Create()); + } + + public AsyncFTaskMethodBuilder(FTask fTask) + { + Task = fTask; + } + + [DebuggerHidden] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Start(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine + { + stateMachine.MoveNext(); + } + + [DebuggerHidden] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void SetResult(T value) + { + Task.SetResult(value); + } + + [DebuggerHidden] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void SetException(Exception exception) + { + Task.SetException(exception); + } + + [DebuggerHidden] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void AwaitOnCompleted(ref TAwaiter awaiter, ref TStateMachine stateMachine) where TAwaiter : INotifyCompletion where TStateMachine : IAsyncStateMachine + { + awaiter.OnCompleted(stateMachine.MoveNext); + } + + [DebuggerHidden] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void AwaitUnsafeOnCompleted(ref TAwaiter awaiter, ref TStateMachine stateMachine) where TAwaiter : ICriticalNotifyCompletion where TStateMachine : IAsyncStateMachine + { + awaiter.UnsafeOnCompleted(stateMachine.MoveNext); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void SetStateMachine(IAsyncStateMachine stateMachine) { } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/FTask/Builder/AsyncFTaskMethodBuilder.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/FTask/Builder/AsyncFTaskMethodBuilder.cs.meta new file mode 100644 index 0000000..787ab12 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/FTask/Builder/AsyncFTaskMethodBuilder.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: fd60976f4009a44fd9171c750809cbf1 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/FTask/Builder/AsyncFVoidMethodBuilder.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/FTask/Builder/AsyncFVoidMethodBuilder.cs new file mode 100644 index 0000000..b9f7bc0 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/FTask/Builder/AsyncFVoidMethodBuilder.cs @@ -0,0 +1,62 @@ +using System; +using System.Diagnostics; +using System.Runtime.CompilerServices; +using System.Runtime.ExceptionServices; +using System.Runtime.InteropServices; +#pragma warning disable CS8603 // Possible null reference return. + +namespace Fantasy.Async +{ + [StructLayout(LayoutKind.Auto)] + internal struct AsyncFVoidMethodBuilder + { + public FVoid Task + { + [DebuggerHidden] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => default; + } + + [DebuggerHidden] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static AsyncFVoidMethodBuilder Create() + { + return default; + } + + [DebuggerHidden] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Start(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine + { + stateMachine.MoveNext(); + } + + [DebuggerHidden] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void SetResult() { } + + [DebuggerHidden] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void SetException(Exception exception) + { + ExceptionDispatchInfo.Capture(exception).Throw(); + } + + [DebuggerHidden] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void AwaitOnCompleted(ref TAwaiter awaiter, ref TStateMachine stateMachine) where TAwaiter : INotifyCompletion where TStateMachine : IAsyncStateMachine + { + awaiter.OnCompleted(stateMachine.MoveNext); + } + + [DebuggerHidden] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void AwaitUnsafeOnCompleted(ref TAwaiter awaiter, ref TStateMachine stateMachine) where TAwaiter : ICriticalNotifyCompletion where TStateMachine : IAsyncStateMachine + { + awaiter.UnsafeOnCompleted(stateMachine.MoveNext); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void SetStateMachine(IAsyncStateMachine stateMachine) { } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/FTask/Builder/AsyncFVoidMethodBuilder.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/FTask/Builder/AsyncFVoidMethodBuilder.cs.meta new file mode 100644 index 0000000..ac64174 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/FTask/Builder/AsyncFVoidMethodBuilder.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 79d8b6cd8361948c8a19fe4722544c53 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/FTask/FCancellationToken.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/FTask/FCancellationToken.meta new file mode 100644 index 0000000..62a795f --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/FTask/FCancellationToken.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ed149491fa2ce43ef9ed42f42d24a71e +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/FTask/FCancellationToken/FCancellationToken.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/FTask/FCancellationToken/FCancellationToken.cs new file mode 100644 index 0000000..90913e3 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/FTask/FCancellationToken/FCancellationToken.cs @@ -0,0 +1,121 @@ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; + +namespace Fantasy.Async +{ + /// + /// 用于FTask取消的CancellationToken + /// + public sealed class FCancellationToken : IDisposable + { + private bool _isDispose; + private bool _isCancel; + private readonly HashSet _actions = new HashSet(); + /// + /// 当前CancellationToken是否已经取消过了 + /// + public bool IsCancel => _isDispose || _isCancel; + /// + /// 添加一个取消要执行的Action + /// + /// + public void Add(Action action) + { + if (_isDispose) + { + return; + } + + _actions.Add(action); + } + /// + /// 移除一个取消要执行的Action + /// + /// + public void Remove(Action action) + { + if (_isDispose) + { + return; + } + + _actions.Remove(action); + } + /// + /// 取消CancellationToken + /// + public void Cancel() + { + if (IsCancel) + { + return; + } + + _isCancel = true; + + foreach (var action in _actions) + { + try + { + action.Invoke(); + } + catch (Exception e) + { + Console.WriteLine(e); + } + } + + _actions.Clear(); + } + /// + /// 销毁掉CancellationToken,会执行Cancel方法。 + /// + public void Dispose() + { + if (_isDispose) + { + return; + } + + if (!IsCancel) + { + Cancel(); + _isCancel = true; + } + + _isDispose = true; + + if (Caches.Count > 2000) + { + return; + } + + Caches.Enqueue(this); + } + + #region Static + + private static readonly ConcurrentQueue Caches = new ConcurrentQueue(); + + /// + /// 获取一个新的CancellationToken + /// + public static FCancellationToken ToKen + { + get + { + if (!Caches.TryDequeue(out var fCancellationToken)) + { + fCancellationToken = new FCancellationToken(); + } + + fCancellationToken._isCancel = false; + fCancellationToken._isDispose = false; + return fCancellationToken; + } + } + + #endregion + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/FTask/FCancellationToken/FCancellationToken.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/FTask/FCancellationToken/FCancellationToken.cs.meta new file mode 100644 index 0000000..a22ae5f --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/FTask/FCancellationToken/FCancellationToken.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 44bc4f64d35cb4ead9af1b57d36250d5 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/FTask/FTask.Extension.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/FTask/FTask.Extension.meta new file mode 100644 index 0000000..1bf7170 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/FTask/FTask.Extension.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 8cb2da0c1fd8f4b66912dd23ae2c0b62 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/FTask/FTask.Extension/FTask.Factory.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/FTask/FTask.Extension/FTask.Factory.cs new file mode 100644 index 0000000..80c7fc8 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/FTask/FTask.Extension/FTask.Factory.cs @@ -0,0 +1,115 @@ +#if !FANTASY_WEBGL +using System.Collections.Concurrent; +#endif +using System.Collections.Generic; +using System.Diagnostics; +using System.Runtime.CompilerServices; +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. +#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. + +namespace Fantasy.Async +{ + /// + /// 一个异步任务 + /// + public partial class FTask + { + private bool _isPool; +#if FANTASY_WEBGL + private static readonly Queue Caches = new Queue(); +#else + private static readonly ConcurrentQueue Caches = new ConcurrentQueue(); +#endif + /// + /// 创建一个空的任务 + /// + public static FTaskCompleted CompletedTask => new FTaskCompleted(); + + private FTask() { } + + /// + /// 创建一个任务 + /// + /// 是否从对象池中创建 + /// + [DebuggerHidden] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static FTask Create(bool isPool = true) + { + if (!isPool) + { + return new FTask(); + } + + if (!Caches.TryDequeue(out var fTask)) + { + fTask = new FTask(); + } + + fTask._isPool = true; + return fTask; + } + + private void Return() + { + if (!_isPool || Caches.Count > 2000) + { + return; + } + + _callBack = null; + _status = STaskStatus.Pending; + Caches.Enqueue(this); + } + } + + /// + /// 一个异步任务 + /// + /// 任务的泛型类型 + public partial class FTask + { + private bool _isPool; +#if FANTASY_WEBGL + private static readonly Queue> Caches = new Queue>(); +#else + private static readonly ConcurrentQueue> Caches = new ConcurrentQueue>(); +#endif + /// + /// 创建一个任务 + /// + /// 是否从对象池中创建 + /// + [DebuggerHidden] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static FTask Create(bool isPool = true) + { + if (!isPool) + { + return new FTask(); + } + + if (!Caches.TryDequeue(out var fTask)) + { + fTask = new FTask(); + } + + fTask._isPool = true; + return fTask; + } + + private FTask() { } + + private void Return() + { + if (!_isPool || Caches.Count > 2000) + { + return; + } + + _callBack = null; + _status = STaskStatus.Pending; + Caches.Enqueue(this); + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/FTask/FTask.Extension/FTask.Factory.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/FTask/FTask.Extension/FTask.Factory.cs.meta new file mode 100644 index 0000000..817d814 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/FTask/FTask.Extension/FTask.Factory.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 206d4fc3ee71b4059a08781f251ceb46 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/FTask/FTask.Extension/FTask.Tools.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/FTask/FTask.Extension/FTask.Tools.cs new file mode 100644 index 0000000..a42edec --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/FTask/FTask.Extension/FTask.Tools.cs @@ -0,0 +1,345 @@ +// ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract + +using System; +using System.Collections.Generic; +#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. +namespace Fantasy.Async +{ + public partial class FTask + { + #region NetTimer + + /// + /// 异步等待指定时间 + /// + /// + /// + /// + /// + public static FTask Wait(Scene scene, long time, FCancellationToken cancellationToken = null) + { + return scene.TimerComponent.Net.WaitAsync(time, cancellationToken); + } + + /// + /// 异步等待直到指定时间 + /// + /// + /// + /// + /// + public static FTask WaitTill(Scene scene, long time, FCancellationToken cancellationToken = null) + { + return scene.TimerComponent.Net.WaitTillAsync(time, cancellationToken); + } + + /// + /// 异步等待一帧时间 + /// + /// + /// + public static FTask WaitFrame(Scene scene) + { + return scene.TimerComponent.Net.WaitFrameAsync(); + } + + /// + /// 创建一个只执行一次的计时器,直到指定时间 + /// + /// + /// + /// + /// + public static long OnceTimer(Scene scene, long time, Action action) + { + return scene.TimerComponent.Net.OnceTimer(time, action); + } + + /// + /// 创建一个只执行一次的计时器,直到指定时间。 + /// + /// + /// + /// + /// + public static long OnceTillTimer(Scene scene, long time, Action action) + { + return scene.TimerComponent.Net.OnceTillTimer(time, action); + } + + /// + /// 创建一个只执行一次的计时器,用于发布指定类型的事件。 + /// + /// + /// + /// + /// + /// + public static long OnceTimer(Scene scene, long time, T timerHandlerType) where T : struct + { + return scene.TimerComponent.Net.OnceTimer(time, timerHandlerType); + } + + /// + /// 创建一个只执行一次的计时器,直到指定时间,用于发布指定类型的事件。 + /// + /// + /// + /// + /// + /// + public static long OnceTillTimer(Scene scene, long tillTime, T timerHandlerType) where T : struct + { + return scene.TimerComponent.Net.OnceTillTimer(tillTime, timerHandlerType); + } + + /// + /// 创建一个重复执行的计时器。 + /// + /// + /// + /// + /// + public static long RepeatedTimer(Scene scene, long time, Action action) + { + return scene.TimerComponent.Net.RepeatedTimer(time, action); + } + + /// + /// 创建一个重复执行的计时器,用于发布指定类型的事件。 + /// + /// + /// + /// + /// + /// + public static long RepeatedTimer(Scene scene, long time, T timerHandlerType) where T : struct + { + return scene.TimerComponent.Net.RepeatedTimer(time, timerHandlerType); + } + + /// + /// 移除指定 ID 的计时器。 + /// + /// + /// + /// + public static bool RemoveTimer(Scene scene, ref long timerId) + { + return scene.TimerComponent.Net.Remove(ref timerId); + } + + #endregion + + #region Unity + +#if FANTASY_UNITY + /// + /// 异步等待指定时间。(使用Unity的Time时间) + /// + /// + /// + /// + /// + public static FTask UnityWait(Scene scene, long time, FCancellationToken cancellationToken = null) + { + return scene.TimerComponent.Unity.WaitAsync(time, cancellationToken); + } + + /// + /// 异步等待直到指定时间。(使用Unity的Time时间) + /// + /// + /// + /// + /// + public static FTask UnityWaitTill(Scene scene, long time, FCancellationToken cancellationToken = null) + { + return scene.TimerComponent.Unity.WaitTillAsync(time, cancellationToken); + } + + /// + /// 异步等待一帧时间。(使用Unity的Time时间) + /// + /// + /// + public static FTask UnityWaitFrame(Scene scene) + { + return scene.TimerComponent.Unity.WaitFrameAsync(); + } + + /// + /// 创建一个只执行一次的计时器,直到指定时间。(使用Unity的Time时间) + /// + /// + /// + /// + /// + public static long UnityOnceTimer(Scene scene, long time, Action action) + { + return scene.TimerComponent.Unity.OnceTimer(time, action); + } + + /// + /// 创建一个只执行一次的计时器,直到指定时间。(使用Unity的Time时间) + /// + /// + /// + /// + /// + public static long UnityOnceTillTimer(Scene scene, long time, Action action) + { + return scene.TimerComponent.Unity.OnceTillTimer(time, action); + } + + /// + /// 创建一个只执行一次的计时器,用于发布指定类型的事件。(使用Unity的Time时间) + /// + /// + /// + /// + /// + /// + public static long UnityOnceTimer(Scene scene, long time, T timerHandlerType) where T : struct + { + return scene.TimerComponent.Unity.OnceTimer(time, timerHandlerType); + } + + /// + /// 创建一个只执行一次的计时器,直到指定时间,用于发布指定类型的事件。(使用Unity的Time时间) + /// + /// + /// + /// + /// + /// + public static long UnityOnceTillTimer(Scene scene, long tillTime, T timerHandlerType) where T : struct + { + return scene.TimerComponent.Unity.OnceTillTimer(tillTime, timerHandlerType); + } + + /// + /// 创建一个重复执行的计时器。(使用Unity的Time时间) + /// + /// + /// + /// + /// + public static long UnityRepeatedTimer(Scene scene, long time, Action action) + { + return scene.TimerComponent.Unity.RepeatedTimer(time, action); + } + + /// + /// 创建一个重复执行的计时器,用于发布指定类型的事件。(使用Unity的Time时间) + /// + /// + /// + /// + /// + /// + public static long UnityRepeatedTimer(Scene scene, long time, T timerHandlerType) where T : struct + { + return scene.TimerComponent.Unity.RepeatedTimer(time, timerHandlerType); + } + + /// + /// 移除指定 ID 的计时器。(使用Unity的Time时间) + /// + /// + /// + /// + public static bool UnityRemoveTimer(Scene scene, ref long timerId) + { + return scene.TimerComponent.Unity.Remove(ref timerId); + } +#endif + + #endregion + + /// + /// 创建并运行一个异步任务 + /// + /// + /// + public static FTask Run(Func factory) + { + return factory(); + } + + /// + /// 创建并运行一个带有结果的异步任务 + /// + /// + /// + /// + public static FTask Run(Func> factory) + { + return factory(); + } + + /// + /// 等待所有任务完成 + /// + /// + public static async FTask WaitAll(List tasks) + { + if (tasks.Count <= 0) + { + return; + } + + var count = tasks.Count; + var sTaskCompletionSource = Create(); + + foreach (var task in tasks) + { + RunSTask(task).Coroutine(); + } + + await sTaskCompletionSource; + + async FVoid RunSTask(FTask task) + { + await task; + count--; + if (count <= 0) + { + sTaskCompletionSource.SetResult(); + } + } + } + /// + /// 等待其中一个任务完成 + /// + /// + public static async FTask WaitAny(List tasks) + { + if (tasks.Count <= 0) + { + return; + } + + var count = 1; + var sTaskCompletionSource = Create(); + + foreach (var task in tasks) + { + RunSTask(task).Coroutine(); + } + + await sTaskCompletionSource; + + async FVoid RunSTask(FTask task) + { + await task; + count--; + if (count == 0) + { + sTaskCompletionSource.SetResult(); + } + } + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/FTask/FTask.Extension/FTask.Tools.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/FTask/FTask.Extension/FTask.Tools.cs.meta new file mode 100644 index 0000000..b256f43 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/FTask/FTask.Extension/FTask.Tools.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 049fb897477f44b90ab54db418990e90 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/FTask/Task.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/FTask/Task.meta new file mode 100644 index 0000000..50a79bc --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/FTask/Task.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b49f1eac772b94ed68a9b19184d4ce80 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/FTask/Task/FTask.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/FTask/Task/FTask.cs new file mode 100644 index 0000000..ce925f2 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/FTask/Task/FTask.cs @@ -0,0 +1,263 @@ +using System; +using System.Diagnostics; +using System.Runtime.CompilerServices; +using System.Runtime.ExceptionServices; +// ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract +// ReSharper disable ConditionalAccessQualifierIsNonNullableAccordingToAPIContract +// ReSharper disable CheckNamespace +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member +#pragma warning disable CS8602 // Dereference of a possibly null reference. +#pragma warning disable CS8603 // Possible null reference return. +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. +#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. + +namespace Fantasy.Async +{ + public enum STaskStatus : byte + { + Pending = 0, // The operation has not yet completed. + Succeeded = 1, // The operation completed successfully. + Faulted = 2 // The operation completed with an error. + } + + [AsyncMethodBuilder(typeof(AsyncFTaskMethodBuilder))] + public sealed partial class FTask : ICriticalNotifyCompletion + { + private Action _callBack; + private ExceptionDispatchInfo _exception; + private STaskStatus _status = STaskStatus.Pending; + public bool IsCompleted + { + [DebuggerHidden] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _status != STaskStatus.Pending; + } + + [DebuggerHidden] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public FTask GetAwaiter() => this; + + [DebuggerHidden] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private async FVoid InnerCoroutine() + { + await this; + } + + [DebuggerHidden] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Coroutine() + { + InnerCoroutine().Coroutine(); + } + + [DebuggerHidden] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void GetResult() + { + switch (_status) + { + case STaskStatus.Succeeded: + { + Return(); + return; + } + case STaskStatus.Faulted: + { + Return(); + + if (_exception == null) + { + return; + } + + var exception = _exception; + _exception = null; + exception.Throw(); + return; + } + default: + { + throw new NotSupportedException("Direct call to getResult is not allowed"); + } + } + } + + [DebuggerHidden] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void SetResult() + { + if (_status != STaskStatus.Pending) + { + throw new InvalidOperationException("The task has been completed"); + } + + _status = STaskStatus.Succeeded; + + if (_callBack == null) + { + return; + } + + var callBack = _callBack; + _callBack = null; + callBack.Invoke(); + } + + [DebuggerHidden] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void OnCompleted(Action action) + { + UnsafeOnCompleted(action); + } + + [DebuggerHidden] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void UnsafeOnCompleted(Action action) + { + if (_status != STaskStatus.Pending) + { + action?.Invoke(); + return; + } + + _callBack = action; + } + + [DebuggerHidden] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void SetException(Exception exception) + { + if (_status != STaskStatus.Pending) + { + throw new InvalidOperationException("The task has been completed"); + } + + _status = STaskStatus.Faulted; + _exception = ExceptionDispatchInfo.Capture(exception); + _callBack?.Invoke(); + } + } + + [AsyncMethodBuilder(typeof(AsyncFTaskMethodBuilder<>))] + public sealed partial class FTask : ICriticalNotifyCompletion + { + private T _value; + private Action _callBack; + private ExceptionDispatchInfo _exception; + private STaskStatus _status = STaskStatus.Pending; + public bool IsCompleted + { + [DebuggerHidden] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _status != STaskStatus.Pending; + } + + [DebuggerHidden] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public FTask GetAwaiter() => this; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + [DebuggerHidden] + private async FVoid InnerCoroutine() + { + await this; + } + + [DebuggerHidden] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Coroutine() + { + InnerCoroutine().Coroutine(); + } + + [DebuggerHidden] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public T GetResult() + { + switch (_status) + { + case STaskStatus.Succeeded: + { + var value = _value; + Return(); + return value; + } + case STaskStatus.Faulted: + { + Return(); + + if (_exception == null) + { + return default; + } + + var exception = _exception; + _exception = null; + exception.Throw(); + return default; + } + default: + { + throw new NotSupportedException("Direct call to getResult is not allowed"); + } + } + } + + [DebuggerHidden] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void SetResult(T value) + { + if (_status != STaskStatus.Pending) + { + throw new InvalidOperationException("The task has been completed"); + } + + _value = value; + _status = STaskStatus.Succeeded; + + if (_callBack == null) + { + return; + } + + var callBack = _callBack; + _callBack = null; + callBack.Invoke(); + } + + [DebuggerHidden] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void OnCompleted(Action action) + { + UnsafeOnCompleted(action); + } + + [DebuggerHidden] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void UnsafeOnCompleted(Action action) + { + if (_status != STaskStatus.Pending) + { + action?.Invoke(); + return; + } + + _callBack = action; + } + + [DebuggerHidden] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void SetException(Exception exception) + { + if (_status != STaskStatus.Pending) + { + throw new InvalidOperationException("The task has been completed"); + } + + _status = STaskStatus.Faulted; + _exception = ExceptionDispatchInfo.Capture(exception); + _callBack?.Invoke(); + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/FTask/Task/FTask.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/FTask/Task/FTask.cs.meta new file mode 100644 index 0000000..f9de66a --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/FTask/Task/FTask.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8e8d0072a6c1c45a4982529ab0d6385d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/FTask/Task/FTaskCompleted.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/FTask/Task/FTaskCompleted.cs new file mode 100644 index 0000000..48b9e36 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/FTask/Task/FTaskCompleted.cs @@ -0,0 +1,31 @@ +using System; +using System.Diagnostics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member + +namespace Fantasy.Async +{ + [StructLayout(LayoutKind.Auto)] + [AsyncMethodBuilder(typeof(AsyncFTaskCompletedMethodBuilder))] + public struct FTaskCompleted : ICriticalNotifyCompletion + { + [DebuggerHidden] + public bool IsCompleted => true; + [DebuggerHidden] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public FTaskCompleted GetAwaiter() + { + return this; + } + [DebuggerHidden] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void GetResult() { } + [DebuggerHidden] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void OnCompleted(Action continuation) { } + [DebuggerHidden] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void UnsafeOnCompleted(Action continuation) { } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/FTask/Task/FTaskCompleted.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/FTask/Task/FTaskCompleted.cs.meta new file mode 100644 index 0000000..f8f4f0b --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/FTask/Task/FTaskCompleted.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7d28012d411e14000ab2ecf1c0fb5b4d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/FTask/Task/FVoid.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/FTask/Task/FVoid.cs new file mode 100644 index 0000000..f10ca7c --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/FTask/Task/FVoid.cs @@ -0,0 +1,29 @@ +using System; +using System.Diagnostics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace Fantasy.Async +{ + [StructLayout(LayoutKind.Auto)] + [AsyncMethodBuilder(typeof(AsyncFVoidMethodBuilder))] + internal struct FVoid : ICriticalNotifyCompletion + { + public bool IsCompleted + { + [DebuggerHidden] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => true; + } + [DebuggerHidden] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Coroutine() { } + [DebuggerHidden] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void OnCompleted(Action continuation) { } + + [DebuggerHidden] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void UnsafeOnCompleted(Action continuation) { } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/FTask/Task/FVoid.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/FTask/Task/FVoid.cs.meta new file mode 100644 index 0000000..d8444c1 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/FTask/Task/FVoid.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b065583f9d663494e973c49cf75623b5 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper.meta new file mode 100644 index 0000000..c54fa75 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: cc72684821a1e4f3082e9b1b1c7cdba2 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/ByteHelper.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/ByteHelper.cs new file mode 100644 index 0000000..9d3d6e0 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/ByteHelper.cs @@ -0,0 +1,388 @@ +using System; +using System.Buffers; +using System.IO; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Text; +using Fantasy.Async; + +namespace Fantasy.Helper +{ + /// + /// 提供字节操作辅助方法的静态类。 + /// + public static class ByteHelper + { + private static readonly string[] Suffix = { "Byte", "KB", "MB", "GB", "TB" }; + + /// + /// 从指定的文件流中读取一个 64 位整数。 + /// + public static long ReadInt64(FileStream stream) + { + var buffer = new byte[8]; +#if FANTASY_NET + stream.ReadExactly(buffer, 0, 8); +#else + stream.Read(buffer, 0, 8); +#endif + return BitConverter.ToInt64(buffer, 0); + } + + /// + /// 从指定的文件流中读取一个 32 位整数。 + /// + public static int ReadInt32(FileStream stream) + { + var buffer = new byte[4]; +#if FANTASY_NET + stream.ReadExactly(buffer, 0, 4); +#else + stream.Read(buffer, 0, 4); +#endif + return BitConverter.ToInt32(buffer, 0); + } + + /// + /// 从指定的内存流中读取一个 64 位整数。 + /// + public static long ReadInt64(MemoryStream stream) + { + var buffer = new byte[8]; +#if FANTASY_NET + stream.ReadExactly(buffer, 0, 8); +#else + stream.Read(buffer, 0, 8); +#endif + return BitConverter.ToInt64(buffer, 0); + } + + /// + /// 从指定的内存流中读取一个 32 位整数。 + /// + public static int ReadInt32(MemoryStream stream) + { + var buffer = new byte[4]; +#if FANTASY_NET + stream.ReadExactly(buffer, 0, 4); +#else + stream.Read(buffer, 0, 4); +#endif + return BitConverter.ToInt32(buffer, 0); + } + + /// + /// 将字节转换为十六进制字符串表示。 + /// + public static string ToHex(this byte b) + { + return b.ToString("X2"); + } + + /// + /// 将字节数组转换为十六进制字符串表示。 + /// + public static string ToHex(this byte[] bytes) + { + var stringBuilder = new StringBuilder(); + foreach (var b in bytes) + { + stringBuilder.Append(b.ToString("X2")); + } + + return stringBuilder.ToString(); + } + + /// + /// 将字节数组按指定格式转换为十六进制字符串表示。 + /// + public static string ToHex(this byte[] bytes, string format) + { + var stringBuilder = new StringBuilder(); + foreach (var b in bytes) + { + stringBuilder.Append(b.ToString(format)); + } + + return stringBuilder.ToString(); + } + + /// + /// 将字节数组的指定范围按十六进制格式转换为字符串表示。 + /// + public static string ToHex(this byte[] bytes, int offset, int count) + { + var stringBuilder = new StringBuilder(); + for (var i = offset; i < offset + count; ++i) + { + stringBuilder.Append(bytes[i].ToString("X2")); + } + + return stringBuilder.ToString(); + } + + /// + /// 将字节数组转换为默认编码的字符串表示。 + /// + public static string ToStr(this byte[] bytes) + { + return Encoding.Default.GetString(bytes); + } + + /// + /// 将字节数组的指定范围按默认编码转换为字符串表示。 + /// + public static string ToStr(this byte[] bytes, int index, int count) + { + return Encoding.Default.GetString(bytes, index, count); + } + + /// + /// 将字节数组转换为 UTF-8 编码的字符串表示。 + /// + public static string Utf8ToStr(this byte[] bytes) + { + return Encoding.UTF8.GetString(bytes); + } + + /// + /// 将字节数组的指定范围按 UTF-8 编码转换为字符串表示。 + /// + public static string Utf8ToStr(this byte[] bytes, int index, int count) + { + return Encoding.UTF8.GetString(bytes, index, count); + } + + /// + /// 将无符号整数写入字节数组的指定偏移位置。 + /// + public static void WriteTo(this byte[] bytes, int offset, uint num) + { + bytes[offset] = (byte)(num & 0xff); + bytes[offset + 1] = (byte)((num & 0xff00) >> 8); + bytes[offset + 2] = (byte)((num & 0xff0000) >> 16); + bytes[offset + 3] = (byte)((num & 0xff000000) >> 24); + } + + /// + /// 将有符号整数写入字节数组的指定偏移位置。 + /// + public static void WriteTo(this byte[] bytes, int offset, int num) + { + bytes[offset] = (byte)(num & 0xff); + bytes[offset + 1] = (byte)((num & 0xff00) >> 8); + bytes[offset + 2] = (byte)((num & 0xff0000) >> 16); + bytes[offset + 3] = (byte)((num & 0xff000000) >> 24); + } + + /// + /// 将字节写入字节数组的指定偏移位置。 + /// + public static void WriteTo(this byte[] bytes, int offset, byte num) + { + bytes[offset] = num; + } + + /// + /// 将有符号短整数写入字节数组的指定偏移位置。 + /// + public static void WriteTo(this byte[] bytes, int offset, short num) + { + bytes[offset] = (byte)(num & 0xff); + bytes[offset + 1] = (byte)((num & 0xff00) >> 8); + } + + /// + /// 将无符号短整数写入字节数组的指定偏移位置。 + /// + public static void WriteTo(this byte[] bytes, int offset, ushort num) + { + bytes[offset] = (byte)(num & 0xff); + bytes[offset + 1] = (byte)((num & 0xff00) >> 8); + } + + /// + /// 将字节数转换为可读的速度表示。 + /// + /// 字节数 + /// 可读的速度表示 + public static string ToReadableSpeed(this long byteCount) + { + var i = 0; + double dblSByte = byteCount; + if (byteCount <= 1024) + { + return $"{dblSByte:0.##}{Suffix[i]}"; + } + + for (i = 0; byteCount / 1024 > 0; i++, byteCount /= 1024) + { + dblSByte = byteCount / 1024.0; + } + + return $"{dblSByte:0.##}{Suffix[i]}"; + } + + /// + /// 将字节数转换为可读的速度表示。 + /// + /// 字节数 + /// 可读的速度表示 + public static string ToReadableSpeed(this ulong byteCount) + { + var i = 0; + double dblSByte = byteCount; + + if (byteCount <= 1024) + { + return $"{dblSByte:0.##}{Suffix[i]}"; + } + + for (i = 0; byteCount / 1024 > 0; i++, byteCount /= 1024) + { + dblSByte = byteCount / 1024.0; + } + + return $"{dblSByte:0.##}{Suffix[i]}"; + } + + /// + /// 合并两个字节数组。 + /// + /// 第一个字节数组 + /// 第二个字节数组 + /// 合并后的字节数组 + public static byte[] MergeBytes(byte[] bytes, byte[] otherBytes) + { + var result = new byte[bytes.Length + otherBytes.Length]; + bytes.CopyTo(result, 0); + otherBytes.CopyTo(result, bytes.Length); + return result; + } + + /// + /// 根据int值获取字节数组。 + /// + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void GetBytes(this int value, byte[] buffer) + { + if (buffer.Length < 4) + { + throw new ArgumentException("Buffer too small."); + } + +#if FANTASY_NET || FANTASY_CONSOLE + MemoryMarshal.Write(buffer.AsSpan(), in value); +#endif +#if FANTASY_UNITY + MemoryMarshal.Write(buffer.AsSpan(), ref value); +#endif + } + + /// + /// 根据int值获取字节数组。 + /// + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void WriteBytes(this MemoryStream memoryStream, int value) + { + using var memoryOwner = MemoryPool.Shared.Rent(4); + var memorySpan = memoryOwner.Memory.Span; +#if FANTASY_NET + MemoryMarshal.Write(memorySpan, in value); +#endif +#if FANTASY_UNITY + MemoryMarshal.Write(memorySpan, ref value); +#endif + memoryStream.Write(memorySpan); + } + + /// + /// 根据uint值获取字节数组。 + /// + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void GetBytes(ref this uint value, byte[] buffer) + { + if (buffer.Length < 4) + { + throw new ArgumentException("Buffer too small."); + } + +#if FANTASY_NET + MemoryMarshal.Write(buffer.AsSpan(), in value); +#endif +#if FANTASY_UNITY + MemoryMarshal.Write(buffer.AsSpan(), ref value); +#endif + } + + /// + /// 根据uint值获取字节数组。 + /// + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void WriteBytes(this MemoryStream memoryStream, uint value) + { + using var memoryOwner = MemoryPool.Shared.Rent(4); + var memorySpan = memoryOwner.Memory.Span; +#if FANTASY_NET + MemoryMarshal.Write(memorySpan, in value); +#endif +#if FANTASY_UNITY + MemoryMarshal.Write(memorySpan, ref value); +#endif + memoryStream.Write(memorySpan); + } + + /// + /// 根据int值获取字节数组。 + /// + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void GetBytes(this long value, byte[] buffer) + { + if (buffer.Length < 8) + { + throw new ArgumentException("Buffer too small."); + } +#if FANTASY_NET + MemoryMarshal.Write(buffer.AsSpan(), in value); +#endif +#if FANTASY_UNITY + MemoryMarshal.Write(buffer.AsSpan(), ref value); +#endif + } + + /// + /// 根据uint值获取字节数组。 + /// + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void WriteBytes(this MemoryStream memoryStream, long value) + { + using var memoryOwner = MemoryPool.Shared.Rent(8); + var memorySpan = memoryOwner.Memory.Span; +#if FANTASY_NET + MemoryMarshal.Write(memorySpan, in value); +#endif +#if FANTASY_UNITY + MemoryMarshal.Write(memorySpan, ref value); +#endif + memoryStream.Write(memorySpan); + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/ByteHelper.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/ByteHelper.cs.meta new file mode 100644 index 0000000..53c8998 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/ByteHelper.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3d992f9fd88d64d9085ab2945d98c3d3 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/Download.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/Download.meta new file mode 100644 index 0000000..21f991f --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/Download.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 287852db62f5047f2a0400646628e51d +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/Download/ADownload.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/Download/ADownload.cs new file mode 100644 index 0000000..4846d51 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/Download/ADownload.cs @@ -0,0 +1,50 @@ +#if FANTASY_UNITY +using System; +using Fantasy.Async; +using UnityEngine.Networking; + +namespace Fantasy.Unity.Download +{ + public abstract class AUnityDownload : IDisposable + { + private long _timeId; + private ulong _totalDownloadedBytes; + private Download _download; + protected UnityWebRequest UnityWebRequest; + private FCancellationToken _cancellationToken; + private Scene Scene; + + protected AUnityDownload(Scene scene,Download download) + { + Scene = scene; + _download = download; + _download.Tasks.Add(this); + } + + protected UnityWebRequestAsyncOperation Start(UnityWebRequest unityWebRequest, bool monitor) + { + UnityWebRequest = unityWebRequest; + _timeId = Scene.TimerComponent.Unity.RepeatedTimer(33, Update); + return UnityWebRequest.SendWebRequest(); + } + + private void Update() + { + var downloadSpeed = UnityWebRequest.downloadedBytes - _totalDownloadedBytes; + _download.DownloadSpeed += downloadSpeed; + _download.TotalDownloadedBytes += downloadSpeed; + _totalDownloadedBytes = UnityWebRequest.downloadedBytes; + } + + public virtual void Dispose() + { + Update(); + _totalDownloadedBytes = 0; + UnityWebRequest?.Dispose(); + _download.Tasks.Remove(this); + Scene.TimerComponent.Unity.Remove(ref _timeId); + _download = null; + } + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/Download/ADownload.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/Download/ADownload.cs.meta new file mode 100644 index 0000000..70e1e3c --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/Download/ADownload.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: c5743903d34d474a818b5c2bafa31459 +timeCreated: 1726021902 \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/Download/Download.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/Download/Download.cs new file mode 100644 index 0000000..a53a42a --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/Download/Download.cs @@ -0,0 +1,72 @@ +#if FANTASY_UNITY +using System.Collections.Generic; +using System.Linq; +using Fantasy.Async; +using UnityEngine; + +namespace Fantasy.Unity.Download +{ + public sealed class Download + { + public Scene Scene; + public ulong DownloadSpeed; + public ulong TotalDownloadedBytes; + public readonly HashSet Tasks = new(); + + public static Download Create(Scene scene) => new Download(scene); + + private Download(Scene scene) + { + Scene = scene; + } + + public void Clear() + { + DownloadSpeed = 0; + TotalDownloadedBytes = 0; + + if (Tasks.Count <= 0) + { + return; + } + + foreach (var aUnityDownload in Tasks.ToArray()) + { + aUnityDownload.Dispose(); + } + + Tasks.Clear(); + } + + public FTask DownloadAssetBundle(string url, bool monitor = false, FCancellationToken cancellationToken = null) + { + return new DownloadAssetBundle(Scene, this).StartDownload(url, monitor, cancellationToken); + } + + public FTask DownloadAudioClip(string url, AudioType audioType, bool monitor = false, FCancellationToken cancellationToken = null) + { + return new DownloadAudioClip(Scene, this).StartDownload(url, audioType, monitor, cancellationToken); + } + + public FTask DownloadSprite(string url, bool monitor = false, FCancellationToken cancellationToken = null) + { + return new DownloadSprite(Scene, this).StartDownload(url, monitor, cancellationToken); + } + + public FTask DownloadTexture(string url, bool monitor = false, FCancellationToken cancellationToken = null) + { + return new DownloadTexture(Scene, this).StartDownload(url, monitor, cancellationToken); + } + + public FTask DownloadText(string url, bool monitor = false, FCancellationToken cancellationToken = null) + { + return new DownloadText(Scene, this).StartDownload(url, monitor, cancellationToken); + } + + public FTask DownloadByte(string url, bool monitor = false, FCancellationToken cancellationToken = null) + { + return new DownloadByte(Scene, this).StartDownload(url, monitor, cancellationToken); + } + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/Download/Download.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/Download/Download.cs.meta new file mode 100644 index 0000000..41e84be --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/Download/Download.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 5715816370e84842aaab799c9776a5e4 +timeCreated: 1726023436 \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/Download/DownloadAssetBundle.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/Download/DownloadAssetBundle.cs new file mode 100644 index 0000000..9d8f5a4 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/Download/DownloadAssetBundle.cs @@ -0,0 +1,54 @@ +#if FANTASY_UNITY +using System; +using Fantasy.Async; +using UnityEngine; +using UnityEngine.Networking; + +namespace Fantasy.Unity.Download +{ + public sealed class DownloadAssetBundle : AUnityDownload + { + public DownloadAssetBundle(Scene scene, Download download) : base(scene, download) + { + } + + public FTask StartDownload(string url, bool monitor, FCancellationToken cancellationToken = null) + { + var task = FTask.Create(false); + var unityWebRequestAsyncOperation = Start(UnityWebRequestAssetBundle.GetAssetBundle(Uri.EscapeUriString(url)), monitor); + + if (cancellationToken != null) + { + cancellationToken.Add(() => + { + Dispose(); + task.SetResult(null); + }); + } + + unityWebRequestAsyncOperation.completed += operation => + { + try + { + if (UnityWebRequest.result == UnityWebRequest.Result.Success) + { + var assetBundle = DownloadHandlerAssetBundle.GetContent(UnityWebRequest); + task.SetResult(assetBundle); + } + else + { + Log.Error(UnityWebRequest.error); + task.SetResult(null); + } + } + finally + { + Dispose(); + } + }; + + return task; + } + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/Download/DownloadAssetBundle.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/Download/DownloadAssetBundle.cs.meta new file mode 100644 index 0000000..c6bf29a --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/Download/DownloadAssetBundle.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 07cbb9a010ed4fe1b90919f81847b9ea +timeCreated: 1726023471 \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/Download/DownloadAudioClip.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/Download/DownloadAudioClip.cs new file mode 100644 index 0000000..29b3dc5 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/Download/DownloadAudioClip.cs @@ -0,0 +1,54 @@ +#if FANTASY_UNITY +using System; +using Fantasy.Async; +using UnityEngine; +using UnityEngine.Networking; + +namespace Fantasy.Unity.Download +{ + public sealed class DownloadAudioClip : AUnityDownload + { + public DownloadAudioClip(Scene scene, Download download) : base(scene, download) + { + } + + public FTask StartDownload(string url, AudioType audioType, bool monitor, FCancellationToken cancellationToken = null) + { + var task = FTask.Create(false); + var unityWebRequestAsyncOperation = Start(UnityWebRequestMultimedia.GetAudioClip(Uri.EscapeUriString(url), audioType), monitor); + + if (cancellationToken != null) + { + cancellationToken.Add(() => + { + Dispose(); + task.SetResult(null); + }); + } + + unityWebRequestAsyncOperation.completed += operation => + { + try + { + if (UnityWebRequest.result == UnityWebRequest.Result.Success) + { + var audioClip = DownloadHandlerAudioClip.GetContent(UnityWebRequest); + task.SetResult(audioClip); + } + else + { + Log.Error(UnityWebRequest.error); + task.SetResult(null); + } + } + finally + { + Dispose(); + } + }; + + return task; + } + } +} +#endif diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/Download/DownloadAudioClip.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/Download/DownloadAudioClip.cs.meta new file mode 100644 index 0000000..6440f22 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/Download/DownloadAudioClip.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 66d3739ec33845148534e6ecaf134b73 +timeCreated: 1726023476 \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/Download/DownloadByte.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/Download/DownloadByte.cs new file mode 100644 index 0000000..6c934d9 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/Download/DownloadByte.cs @@ -0,0 +1,52 @@ +#if FANTASY_UNITY +using Fantasy.Async; +using UnityEngine.Networking; + +namespace Fantasy.Unity.Download +{ + public sealed class DownloadByte : AUnityDownload + { + public DownloadByte(Scene scene, Download download) : base(scene, download) + { + } + + public FTask StartDownload(string url, bool monitor, FCancellationToken cancellationToken = null) + { + var task = FTask.Create(false); + var unityWebRequestAsyncOperation = Start(UnityWebRequest.Get(url), monitor); + + if (cancellationToken != null) + { + cancellationToken.Add(() => + { + Dispose(); + task.SetResult(null); + }); + } + + unityWebRequestAsyncOperation.completed += operation => + { + try + { + if (UnityWebRequest.result == UnityWebRequest.Result.Success) + { + var bytes = UnityWebRequest.downloadHandler.data; + task.SetResult(bytes); + } + else + { + Log.Error(UnityWebRequest.error); + task.SetResult(null); + } + } + finally + { + Dispose(); + } + }; + + return task; + } + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/Download/DownloadByte.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/Download/DownloadByte.cs.meta new file mode 100644 index 0000000..0aa0487 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/Download/DownloadByte.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: ae87f3ea9f4e4c9ebabedf45b0bb83b1 +timeCreated: 1726023481 \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/Download/DownloadSprite.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/Download/DownloadSprite.cs new file mode 100644 index 0000000..802a967 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/Download/DownloadSprite.cs @@ -0,0 +1,55 @@ +#if FANTASY_UNITY +using System; +using Fantasy.Async; +using UnityEngine; +using UnityEngine.Networking; + +namespace Fantasy.Unity.Download +{ + public sealed class DownloadSprite : AUnityDownload + { + public DownloadSprite(Scene scene, Download download) : base(scene, download) + { + } + + public FTask StartDownload(string url, bool monitor, FCancellationToken cancellationToken = null) + { + var task = FTask.Create(false); + var unityWebRequestAsyncOperation = Start(UnityWebRequestTexture.GetTexture(Uri.EscapeUriString(url)), monitor); + + if (cancellationToken != null) + { + cancellationToken.Add(() => + { + Dispose(); + task.SetResult(null); + }); + } + + unityWebRequestAsyncOperation.completed += operation => + { + try + { + if (UnityWebRequest.result == UnityWebRequest.Result.Success) + { + var texture = DownloadHandlerTexture.GetContent(UnityWebRequest); + var sprite = Sprite.Create(texture, new Rect(0, 0, texture.width, texture.height), Vector2.one * 5, 1f); + task.SetResult(sprite); + } + else + { + Log.Error(UnityWebRequest.error); + task.SetResult(null); + } + } + finally + { + Dispose(); + } + }; + + return task; + } + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/Download/DownloadSprite.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/Download/DownloadSprite.cs.meta new file mode 100644 index 0000000..354e3e3 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/Download/DownloadSprite.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 0c2a0f442e974169b7d8b7a5878fe0e6 +timeCreated: 1726023487 \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/Download/DownloadText.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/Download/DownloadText.cs new file mode 100644 index 0000000..50d8329 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/Download/DownloadText.cs @@ -0,0 +1,52 @@ +#if FANTASY_UNITY +using Fantasy.Async; +using UnityEngine.Networking; + +namespace Fantasy.Unity.Download +{ + public sealed class DownloadText : AUnityDownload + { + public DownloadText(Scene scene, Download download) : base(scene, download) + { + } + + public FTask StartDownload(string url, bool monitor, FCancellationToken cancellationToken = null) + { + var task = FTask.Create(false); + var unityWebRequestAsyncOperation = Start(UnityWebRequest.Get(url), monitor); + + if (cancellationToken != null) + { + cancellationToken.Add(() => + { + Dispose(); + task.SetResult(null); + }); + } + + unityWebRequestAsyncOperation.completed += operation => + { + try + { + if (UnityWebRequest.result == UnityWebRequest.Result.Success) + { + var text = UnityWebRequest.downloadHandler.text; + task.SetResult(text); + } + else + { + Log.Error(UnityWebRequest.error); + task.SetResult(null); + } + } + finally + { + Dispose(); + } + }; + + return task; + } + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/Download/DownloadText.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/Download/DownloadText.cs.meta new file mode 100644 index 0000000..35892a9 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/Download/DownloadText.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 4284aafa8572453cb75920d2d58e9c50 +timeCreated: 1726023491 \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/Download/DownloadTexture.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/Download/DownloadTexture.cs new file mode 100644 index 0000000..f66533d --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/Download/DownloadTexture.cs @@ -0,0 +1,54 @@ +#if FANTASY_UNITY +using System; +using Fantasy.Async; +using UnityEngine; +using UnityEngine.Networking; + +namespace Fantasy.Unity.Download +{ + public sealed class DownloadTexture : AUnityDownload + { + public DownloadTexture(Scene scene, Download download) : base(scene, download) + { + } + + public FTask StartDownload(string url, bool monitor, FCancellationToken cancellationToken = null) + { + var task = FTask.Create(false); + var unityWebRequestAsyncOperation = Start(UnityWebRequestTexture.GetTexture(Uri.EscapeUriString(url)), monitor); + + if (cancellationToken != null) + { + cancellationToken.Add(() => + { + Dispose(); + task.SetResult(null); + }); + } + + unityWebRequestAsyncOperation.completed += operation => + { + try + { + if (UnityWebRequest.result == UnityWebRequest.Result.Success) + { + var texture = DownloadHandlerTexture.GetContent(UnityWebRequest); + task.SetResult(texture); + } + else + { + Log.Error(UnityWebRequest.error); + task.SetResult(null); + } + } + finally + { + Dispose(); + } + }; + + return task; + } + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/Download/DownloadTexture.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/Download/DownloadTexture.cs.meta new file mode 100644 index 0000000..7b48ea6 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/Download/DownloadTexture.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 5eaa6023378844ebb51e4b80425d8a4e +timeCreated: 1726023496 \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/EncryptHelper.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/EncryptHelper.cs new file mode 100644 index 0000000..be950bc --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/EncryptHelper.cs @@ -0,0 +1,63 @@ +using System.IO; +using System.Security.Cryptography; +using System.Text; + +namespace Fantasy.Helper +{ + /// + /// 提供计算 MD5 散列值的辅助方法。 + /// + public static partial class EncryptHelper + { + private static readonly SHA256 Sha256Hash = SHA256.Create(); + + /// + /// 计算指定字节数组的Sha256。 + /// + /// + /// + public static byte[] ComputeSha256Hash(byte[] bytes) + { +#if FANTASY_UNITY + using var sha256Hash = SHA256.Create(); + return sha256Hash.ComputeHash(bytes); +#else + return SHA256.HashData(bytes); +#endif + } + + /// + /// 计算指定文件的 MD5 散列值。 + /// + /// 要计算散列值的文件路径。 + /// 表示文件的 MD5 散列值的字符串。 + public static string FileMD5(string filePath) + { + using var file = new FileStream(filePath, FileMode.Open); + return FileMD5(file); + } + + /// + /// 计算给定文件流的 MD5 散列值。 + /// + /// 要计算散列值的文件流。 + /// 表示文件流的 MD5 散列值的字符串。 + public static string FileMD5(FileStream fileStream) + { + var md5 = MD5.Create(); + return md5.ComputeHash(fileStream).ToHex("x2"); + } + + /// + /// 计算给定字节数组的 MD5 散列值。 + /// + /// 要计算散列值的字节数组。 + /// 表示字节数组的 MD5 散列值的字符串。 + public static string BytesMD5(byte[] bytes) + { + var md5 = MD5.Create(); + bytes = md5.ComputeHash(bytes); + return bytes.ToHex("x2"); + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/EncryptHelper.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/EncryptHelper.cs.meta new file mode 100644 index 0000000..5dc15c4 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/EncryptHelper.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2c09f5dc7247c4396b293e9c91b42361 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/FileHelper.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/FileHelper.cs new file mode 100644 index 0000000..058db82 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/FileHelper.cs @@ -0,0 +1,175 @@ +using System.Collections.Generic; +using System.IO; +using System.Text; +using System.Threading.Tasks; + +namespace Fantasy.Helper +{ + /// + /// 文件操作助手类,提供了各种文件操作方法。 + /// + public static partial class FileHelper + { + /// + /// 获取相对路径的完整路径。 + /// + /// 相对路径。 + /// 完整路径。 + public static string GetFullPath(string relativePath) + { + return Path.GetFullPath(Path.Combine(Directory.GetCurrentDirectory(), relativePath)); + } + + /// + /// 获取相对路径的的文本信息。 + /// + /// + /// + public static async Task GetTextByRelativePath(string relativePath) + { + var fullPath = GetFullPath(relativePath); + return await File.ReadAllTextAsync(fullPath, Encoding.UTF8); + } + + /// + /// 获取绝对路径的的文本信息。 + /// + /// + /// + public static async Task GetText(string fullPath) + { + return await File.ReadAllTextAsync(fullPath, Encoding.UTF8); + } + + /// + /// 根据文件夹路径创建文件夹,如果文件夹不存在会自动创建文件夹。 + /// + /// + public static void CreateDirectory(string directoryPath) + { + if (directoryPath.LastIndexOf('/') != directoryPath.Length - 1) + { + directoryPath += "/"; + } + + var directoriesByFilePath = GetDirectoriesByFilePath(directoryPath); + + foreach (var dir in directoriesByFilePath) + { + if (Directory.Exists(dir)) + { + continue; + } + + Directory.CreateDirectory(dir); + } + } + + /// + /// 将文件复制到目标路径,如果目标目录不存在会自动创建目录。 + /// + /// 源文件路径。 + /// 目标文件路径。 + /// 是否覆盖已存在的目标文件。 + public static void Copy(string sourceFile, string destinationFile, bool overwrite) + { + CreateDirectory(destinationFile); + File.Copy(sourceFile, destinationFile, overwrite); + } + + /// + /// 获取文件路径内的所有文件夹路径。 + /// + /// 文件路径。 + /// 文件夹路径列表。 + public static IEnumerable GetDirectoriesByFilePath(string filePath) + { + var dir = ""; + var fileDirectories = filePath.Split('/'); + + for (var i = 0; i < fileDirectories.Length - 1; i++) + { + dir = $"{dir}{fileDirectories[i]}/"; + yield return dir; + } + + if (fileDirectories.Length == 1) + { + yield return filePath; + } + } + + /// + /// 将文件夹内的所有内容复制到目标位置。 + /// + /// 源文件夹路径。 + /// 目标文件夹路径。 + /// 是否覆盖已存在的文件。 + public static void CopyDirectory(string sourceDirectory, string destinationDirectory, bool overwrite) + { + // 创建目标文件夹 + + if (!Directory.Exists(destinationDirectory)) + { + Directory.CreateDirectory(destinationDirectory); + } + + // 获取当前文件夹中的所有文件 + + var files = Directory.GetFiles(sourceDirectory); + + // 拷贝文件到目标文件夹 + + foreach (var file in files) + { + var fileName = Path.GetFileName(file); + var destinationPath = Path.Combine(destinationDirectory, fileName); + File.Copy(file, destinationPath, overwrite); + } + + // 获取源文件夹中的所有子文件夹 + + var directories = Directory.GetDirectories(sourceDirectory); + + // 递归方式拷贝文件夹 + + foreach (var directory in directories) + { + var directoryName = Path.GetFileName(directory); + var destinationPath = Path.Combine(destinationDirectory, directoryName); + CopyDirectory(directory, destinationPath, overwrite); + } + } + + /// + /// 获取目录下的所有文件 + /// + /// 文件夹路径。 + /// 需要查找的文件通配符 + /// 查找的类型 + /// + public static string[] GetDirectoryFile(string folderPath, string searchPattern, SearchOption searchOption) + { + return Directory.GetFiles(folderPath, searchPattern, searchOption); + } + + /// + /// 清空文件夹内的所有文件。 + /// + /// 文件夹路径。 + public static void ClearDirectoryFile(string folderPath) + { + if (!Directory.Exists(folderPath)) + { + return; + } + + var files = Directory.GetFiles(folderPath); + + foreach (var file in files) + { + File.Delete(file); + } + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/FileHelper.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/FileHelper.cs.meta new file mode 100644 index 0000000..c341e6b --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/FileHelper.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: cb7aa7f0698f4409da7f0cdb32e8d8ea +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/HashCodeHelper.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/HashCodeHelper.cs new file mode 100644 index 0000000..42be4e4 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/HashCodeHelper.cs @@ -0,0 +1,129 @@ +using System.Security.Cryptography; +using System.Text; +// ReSharper disable InconsistentNaming + +namespace Fantasy.Helper +{ + /// + /// HashCode算法帮助类 + /// + public static partial class HashCodeHelper + { + private static readonly SHA256 Sha256Hash = SHA256.Create(); + + /// + /// 使用bkdr算法生成一个long的值 + /// + /// + /// + public static unsafe long GetBKDRHashCode(string str) + { + ulong hash = 0; + // 如果要修改这个种子、建议选择一个质数来做种子 + const uint seed = 13131; // 31 131 1313 13131 131313 etc.. + fixed (char* p = str) + { + for (var i = 0; i < str.Length; i++) + { + var c = p[i]; + var high = (byte)(c >> 8); + var low = (byte)(c & byte.MaxValue); + hash = hash * seed + high; + hash = hash * seed + low; + } + } + return (long)hash; + } + + /// + /// 使用MurmurHash3算法生成一个uint的值 + /// + /// + /// + public static unsafe uint MurmurHash3(string str) + { + const uint seed = 0xc58f1a7b; + uint hash = seed; + uint c1 = 0xcc9e2d51; + uint c2 = 0x1b873593; + + fixed (char* p = str) + { + var current = p; + + for (var i = 0; i < str.Length; i++) + { + var k1 = (uint)(*current); + k1 *= c1; + k1 = (k1 << 15) | (k1 >> (32 - 15)); + k1 *= c2; + + hash ^= k1; + hash = (hash << 13) | (hash >> (32 - 13)); + hash = hash * 5 + 0xe6546b64; + + current++; + } + } + + hash ^= (uint)str.Length; + hash ^= hash >> 16; + hash *= 0x85ebca6b; + hash ^= hash >> 13; + hash *= 0xc2b2ae35; + hash ^= hash >> 16; + return hash; + } + + /// + /// 使用MurmurHash3算法生成一个long的值 + /// + /// + /// + public static unsafe long ComputeHash64(string str) + { + const ulong seed = 0xc58f1a7bc58f1a7bUL; // 64-bit seed + var hash = seed; + var c1 = 0x87c37b91114253d5UL; + var c2 = 0x4cf5ad432745937fUL; + + fixed (char* p = str) + { + var current = p; + + for (var i = 0; i < str.Length; i++) + { + var k1 = (ulong)(*current); + k1 *= c1; + k1 = (k1 << 31) | (k1 >> (64 - 31)); + k1 *= c2; + + hash ^= k1; + hash = (hash << 27) | (hash >> (64 - 27)); + hash = hash * 5 + 0x52dce729; + + current++; + } + } + + hash ^= (ulong)str.Length; + hash ^= hash >> 33; + hash *= 0xff51afd7ed558ccdUL; + hash ^= hash >> 33; + hash *= 0xc4ceb9fe1a85ec53UL; + hash ^= hash >> 33; + return (long)hash; + } + + /// + /// 根据字符串计算一个Hash值 + /// + /// + /// + public static int ComputeSha256HashAsInt(string rawData) + { + var bytes = Sha256Hash.ComputeHash(Encoding.UTF8.GetBytes(rawData)); + return (bytes[0] << 24) | (bytes[1] << 16) | (bytes[2] << 8) | bytes[3]; + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/HashCodeHelper.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/HashCodeHelper.cs.meta new file mode 100644 index 0000000..406fe87 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/HashCodeHelper.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6ec2f7d0b1e3d4605bc7224099e156a4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/HttpClient.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/HttpClient.meta new file mode 100644 index 0000000..fe15834 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/HttpClient.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 724626f87e31e4ac4a3098336100c034 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/HttpClient/HttpClientHelper.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/HttpClient/HttpClientHelper.cs new file mode 100644 index 0000000..3954a8c --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/HttpClient/HttpClientHelper.cs @@ -0,0 +1,144 @@ +#if !FANTASY_WEBGL +using System; +using System.Net; +using System.Net.Http; +using System.Net.Http.Headers; +using System.Text; +using Fantasy.Async; +using Fantasy.Helper; +using Fantasy.Pool; +#pragma warning disable CS8603 // Possible null reference return. + +namespace Fantasy.Http +{ + /// + /// HTTP帮助类 + /// + public static partial class HttpClientHelper + { + private static readonly HttpClient Client = new HttpClient(new HttpClientHandler + { + ServerCertificateCustomValidationCallback = (sender, cert, chain, sslPolicyErrors) => true + }); + + /// + /// 用Post方式请求string数据 + /// + /// + /// + /// + /// + public static async FTask CallNotDeserializeByPost(string url, HttpContent content) + { + var response = await Client.PostAsync(url, content); + + if (response.StatusCode != HttpStatusCode.OK) + { + throw new Exception($"Unable to connect to server url {(object)url} HttpStatusCode:{(object)response.StatusCode}"); + } + + return await response.Content.ReadAsStringAsync(); + } + + /// + /// 用Get方式请求string数据 + /// + /// + /// + /// + public static async FTask CallNotDeserializeByGet(string url) + { + var response = await Client.GetAsync(url); + + if (response.StatusCode != HttpStatusCode.OK) + { + throw new Exception($"Unable to connect to server url {(object)url} HttpStatusCode:{(object)response.StatusCode}"); + } + + return await response.Content.ReadAsStringAsync(); + } + + /// + /// 用Post方式请求JSON数据,并自动把JSON转换为对象。 + /// + /// + /// + /// + /// + public static async FTask CallByPost(string url, HttpContent content) + { + return await Deserialize(url, await Client.PostAsync(url, content)); + } + + /// + /// 用Post方式请求JSON数据,并自动把JSON转换为对象。 + /// + /// + /// + /// + /// + public static async FTask CallByPost(string url, HttpMethod method) + { + return await Deserialize(url, await Client.SendAsync(new HttpRequestMessage(method, url))); + } + + /// + /// 用Get方式请求JSON数据,并自动把JSON转换为对象。 + /// + /// + /// + /// + public static async FTask CallByGet(string url) + { + return await Deserialize(url, await Client.GetAsync(url)); + } + + /// + /// 用Post方式请求JSON数据,并自动把JSON转换为对象。 + /// + /// + /// + /// + /// + /// + /// + /// + /// + public static async FTask Call(string url, int id, AuthenticationHeaderValue authentication, string method, params object[] @params) where TRequest : class, IJsonRpcRequest, new() + { + var request = Pool.Rent(); + using var httpClientPool = HttpClientPool.Create(); + var client = httpClientPool.Client; + client.DefaultRequestHeaders.Authorization = authentication; + + try + { + request.Init(method, id, @params); + var content = new StringContent(request.ToJson(), Encoding.UTF8, "application/json"); + var response = await Deserialize(url, await client.PostAsync(url, content)); + return response; + } + catch (Exception e) + { + Log.Error(e); + } + finally + { + Pool.Return(request); + } + + return default; + } + + private static async FTask Deserialize(string url, HttpResponseMessage response) + { + if (response.StatusCode != HttpStatusCode.OK) + { + throw new Exception($"Unable to connect to server url {(object)url} HttpStatusCode:{(object)response.StatusCode}"); + } + + return (await response.Content.ReadAsStringAsync()).Deserialize(); + } + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/HttpClient/HttpClientHelper.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/HttpClient/HttpClientHelper.cs.meta new file mode 100644 index 0000000..70e3bd5 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/HttpClient/HttpClientHelper.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: f8005f3a1a1945a2929442f82832e765 +timeCreated: 1726023741 \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/HttpClient/HttpClientPool.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/HttpClient/HttpClientPool.cs new file mode 100644 index 0000000..de421ff --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/HttpClient/HttpClientPool.cs @@ -0,0 +1,44 @@ +#if !FANTASY_WEBGL +using System; +using System.Collections.Generic; +using System.Net.Http; +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. + +namespace Fantasy.Http +{ + internal class HttpClientPool : IDisposable + { + private bool IsDispose { get; set; } + public HttpClient Client { get; private set; } + private static readonly Queue Pools = new Queue(); + private static readonly HttpClientHandler ClientHandler = new HttpClientHandler + { + ServerCertificateCustomValidationCallback = (sender, cert, chain, sslPolicyErrors) => true + }; + + public static HttpClientPool Create() + { + if (Pools.TryDequeue(out var httpClientPool)) + { + httpClientPool.IsDispose = false; + return httpClientPool; + } + + httpClientPool = new HttpClientPool(); + httpClientPool.Client = new HttpClient(ClientHandler); + return httpClientPool; + } + + public void Dispose() + { + if (IsDispose) + { + return; + } + + IsDispose = true; + Pools.Enqueue(this); + } + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/HttpClient/HttpClientPool.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/HttpClient/HttpClientPool.cs.meta new file mode 100644 index 0000000..a1ac3bf --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/HttpClient/HttpClientPool.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: a78c441357d244d5ba490a13c89e1c50 +timeCreated: 1726023895 \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/HttpClient/IJsonRpcRequest.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/HttpClient/IJsonRpcRequest.cs new file mode 100644 index 0000000..ae756c5 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/HttpClient/IJsonRpcRequest.cs @@ -0,0 +1,20 @@ +using Fantasy.Pool; + +#if !FANTASY_WEBGL +namespace Fantasy.Http +{ + /// + /// 一个JsonRPC的接口 + /// + public interface IJsonRpcRequest : IPool + { + /// + /// 用于初始化这个Json对象 + /// + /// + /// + /// + void Init(string method, int id, params object[] @params); + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/HttpClient/IJsonRpcRequest.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/HttpClient/IJsonRpcRequest.cs.meta new file mode 100644 index 0000000..9e01783 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/HttpClient/IJsonRpcRequest.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 72a03580c619417b9f8f92d99938e371 +timeCreated: 1726023900 \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/JsonHelper.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/JsonHelper.cs new file mode 100644 index 0000000..2b10fab --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/JsonHelper.cs @@ -0,0 +1,57 @@ +using System; +using Newtonsoft.Json; +#pragma warning disable CS8603 + +namespace Fantasy.Helper +{ + /// + /// 提供操作 JSON 数据的辅助方法。 + /// + public static partial class JsonHelper + { + /// + /// 将对象序列化为 JSON 字符串。 + /// + /// 要序列化的对象类型。 + /// 要序列化的对象。 + /// 表示序列化对象的 JSON 字符串。 + public static string ToJson(this T t) + { + return JsonConvert.SerializeObject(t); + } + + /// + /// 反序列化 JSON 字符串为指定类型的对象。 + /// + /// 要反序列化的 JSON 字符串。 + /// 目标对象的类型。 + /// 是否使用反射进行反序列化(默认为 true)。 + /// 反序列化后的对象。 + public static object Deserialize(this string json, Type type, bool reflection = true) + { + return JsonConvert.DeserializeObject(json, type); + } + + /// + /// 反序列化 JSON 字符串为指定类型的对象。 + /// + /// 目标对象的类型。 + /// 要反序列化的 JSON 字符串。 + /// 反序列化后的对象。 + public static T Deserialize(this string json) + { + return JsonConvert.DeserializeObject(json); + } + + /// + /// 克隆对象,通过将对象序列化为 JSON,然后再进行反序列化。 + /// + /// 要克隆的对象类型。 + /// 要克隆的对象。 + /// 克隆后的对象。 + public static T Clone(T t) + { + return t.ToJson().Deserialize(); + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/JsonHelper.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/JsonHelper.cs.meta new file mode 100644 index 0000000..0459592 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/JsonHelper.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 5f25483965eb6459583e1d328adc8f05 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/NetworkHelper.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/NetworkHelper.cs new file mode 100644 index 0000000..6a35a61 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/NetworkHelper.cs @@ -0,0 +1,443 @@ +#if !FANTASY_WEBGL +using System; +using System.Collections.Generic; +using System.Net; +using System.Net.NetworkInformation; +using System.Net.Sockets; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +#pragma warning disable CS8603 // Possible null reference return. + +// ReSharper disable InconsistentNaming + +namespace Fantasy.Helper +{ + /// + /// 提供网络操作相关的帮助方法。 + /// + public static partial class NetworkHelper + { + /// + /// 根据字符串获取一个IPEndPoint + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static IPEndPoint GetIPEndPoint(string address) + { + try + { + var addressSplit = address.Split(':'); + if (addressSplit.Length != 2) + { + throw new FormatException("Invalid format"); + } + + var ipString = addressSplit[0]; + var portString = addressSplit[1]; + + if (!IPAddress.TryParse(ipString, out var ipAddress)) + { + throw new FormatException("Invalid IP address"); + } + + if (!int.TryParse(portString, out var port) || port < 0 || port > 65535) + { + throw new FormatException("Invalid port number"); + } + + return new IPEndPoint(ipAddress, port); + } + catch (Exception e) + { + Log.Error($"Error parsing IP and Port:{e.Message}"); + return null; + } + } + + /// + /// 克隆一个IPEndPoint + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static IPEndPoint Clone(this EndPoint endPoint) + { + var ip = (IPEndPoint)endPoint; + return new IPEndPoint(ip.Address, ip.Port); + } + + /// + /// 比较两个IPEndPoint是否相等 + /// + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool IPEndPointEquals(this EndPoint endPoint, IPEndPoint ipEndPoint) + { + var ip = (IPEndPoint)endPoint; + return ip.Address.Equals(ipEndPoint.Address) && ip.Port == ipEndPoint.Port; + } + + /// + /// 比较两个IPEndPoint是否相等 + /// + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool IPEndPointEquals(this IPEndPoint endPoint, IPEndPoint ipEndPoint) + { + return endPoint.Address.Equals(ipEndPoint.Address) && endPoint.Port == ipEndPoint.Port; + } + +#if !FANTASY_WEBGL + /// + /// 将SocketAddress写入到Byte[]中 + /// + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe void SocketAddressToByte(this SocketAddress socketAddress, byte[] buffer, int offset) + { + if (socketAddress == null) + { + throw new ArgumentNullException(nameof(socketAddress), "The SocketAddress cannot be null."); + } + + if (buffer == null) + { + throw new ArgumentNullException(nameof(buffer), "The buffer cannot be null."); + } + + if (buffer.Length < socketAddress.Size + offset + 8) + { + throw new ArgumentException("The buffer length is insufficient. It must be at least the size of the SocketAddress plus 8 bytes.", nameof(buffer)); + } + + fixed (byte* pBuffer = buffer) + { + var pOffsetBuffer = pBuffer + offset; + var addressFamilyValue = (int)socketAddress.Family; + var socketAddressSizeValue = socketAddress.Size; + Buffer.MemoryCopy(&addressFamilyValue, pOffsetBuffer, buffer.Length - offset, sizeof(int)); + Buffer.MemoryCopy(&socketAddressSizeValue, pOffsetBuffer + 4, buffer.Length - offset -4, sizeof(int)); + for (var i = 0; i < socketAddress.Size - 2; i++) + { + pOffsetBuffer[8 + i] = socketAddress[i + 2]; + } + } + } + + /// + /// 将byre[]转换为SocketAddress + /// + /// + /// + /// + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe int ByteToSocketAddress(byte[] buffer, int offset, out SocketAddress socketAddress) + { + if (buffer == null) + { + throw new ArgumentNullException(nameof(buffer), "The buffer cannot be null."); + } + + if (buffer.Length < 8) + { + throw new ArgumentException("Buffer length is insufficient. It must be at least 8 bytes.", nameof(buffer)); + } + + try + { + fixed (byte* pBuffer = buffer) + { + var pOffsetBuffer = pBuffer + offset; + var addressFamily = (AddressFamily)Marshal.ReadInt32((IntPtr)pOffsetBuffer); + var socketAddressSize = Marshal.ReadInt32((IntPtr)(pOffsetBuffer + 4)); + + if (buffer.Length < offset + 8 + socketAddressSize) + { + throw new ArgumentException("Buffer length is insufficient for the given SocketAddress size.", nameof(buffer)); + } + + socketAddress = new SocketAddress(addressFamily, socketAddressSize); + + for (var i = 0; i < socketAddressSize - 2; i++) + { + socketAddress[i + 2] = *(pOffsetBuffer + 8 + i); + } + + return 8 + offset + socketAddressSize; + } + } + catch (ArgumentNullException ex) + { + throw new InvalidOperationException("An argument provided to the method is null.", ex); + } + catch (ArgumentException ex) + { + throw new InvalidOperationException("An argument provided to the method is invalid.", ex); + } + catch (Exception ex) + { + throw new InvalidOperationException("An unexpected error occurred while processing the buffer.", ex); + } + } + + /// + /// 将ReadOnlyMemory转换为SocketAddress + /// + /// + /// + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe int ByteToSocketAddress(ReadOnlyMemory buffer, int offset, out SocketAddress socketAddress) + { + if (buffer.Length < 8) + { + throw new ArgumentException("Buffer length is insufficient. It must be at least 8 bytes.", nameof(buffer)); + } + + try + { + fixed (byte* pBuffer = buffer.Span) + { + var pOffsetBuffer = pBuffer + offset; + var addressFamily = (AddressFamily)Marshal.ReadInt32((IntPtr)pOffsetBuffer); + var socketAddressSize = Marshal.ReadInt32((IntPtr)(pOffsetBuffer + 4)); + + if (buffer.Length < offset + 8 + socketAddressSize) + { + throw new ArgumentException("Buffer length is insufficient for the given SocketAddress size.", nameof(buffer)); + } + + socketAddress = new SocketAddress(addressFamily, socketAddressSize); + + for (var i = 0; i < socketAddressSize - 2; i++) + { + socketAddress[i + 2] = *(pOffsetBuffer + 8 + i); + } + + return 8 + offset + socketAddressSize; + } + } + catch (ArgumentNullException ex) + { + throw new InvalidOperationException("An argument provided to the method is null.", ex); + } + catch (ArgumentException ex) + { + throw new InvalidOperationException("An argument provided to the method is invalid.", ex); + } + catch (Exception ex) + { + throw new InvalidOperationException("An unexpected error occurred while processing the buffer.", ex); + } + } + + /// + /// 根据SocketAddress获得IPEndPoint + /// + /// + /// + /// + public static unsafe IPEndPoint GetIPEndPoint(this SocketAddress socketAddress) + { + switch (socketAddress.Family) + { + case AddressFamily.InterNetwork: + { + var ipBytes = new byte[4]; + for (var i = 0; i < 4; i++) + { + ipBytes[i] = socketAddress[4 + i]; + } + var port = (socketAddress[2] << 8) + socketAddress[3]; + var ip = new IPAddress(ipBytes); + return new IPEndPoint(ip, port); + } + case AddressFamily.InterNetworkV6: + { + var ipBytes = new byte[16]; + Span socketAddressSpan = stackalloc byte[28]; + + for (var i = 0; i < 28; i++) + { + socketAddressSpan[i] = socketAddress[i]; + } + + fixed (byte* pSocketAddress = socketAddressSpan) + { + for (var i = 0; i < 16; i++) + { + ipBytes[i] = *(pSocketAddress + 8 + i); + } + + var port = (*(pSocketAddress + 2) << 8) + *(pSocketAddress + 3); + var scopeId = Marshal.ReadInt64((IntPtr)(pSocketAddress + 24)); + var ip = new IPAddress(ipBytes, scopeId); + return new IPEndPoint(ip, port); + } + } + default: + { + throw new NotSupportedException("Address family not supported."); + } + } + } +#endif + /// + /// 获取本机所有网络适配器的IP地址。 + /// + /// IP地址数组。 + public static string[] GetAddressIPs() + { + var list = new List(); + foreach (var networkInterface in NetworkInterface.GetAllNetworkInterfaces()) + { + // 仅考虑以太网类型的网络适配器 + if (networkInterface.NetworkInterfaceType != NetworkInterfaceType.Ethernet) + { + continue; + } + + foreach (var add in networkInterface.GetIPProperties().UnicastAddresses) + { + list.Add(add.Address.ToString()); + } + } + + return list.ToArray(); + } + + /// + /// 将主机名和端口号转换为 实例。 + /// + /// 主机名。 + /// 端口号。 + /// 实例。 + public static IPEndPoint ToIPEndPoint(string host, int port) + { + return new IPEndPoint(IPAddress.Parse(host), port); + } + + /// + /// 将地址字符串转换为 实例。 + /// + /// 地址字符串,格式为 "主机名:端口号"。 + /// 实例。 + public static IPEndPoint ToIPEndPoint(string address) + { + var index = address.LastIndexOf(':'); + var host = address.Substring(0, index); + var p = address.Substring(index + 1); + var port = int.Parse(p); + return ToIPEndPoint(host, port); + } + + /// + /// 将 实例转换为字符串表示形式。 + /// + /// 实例。 + /// 表示 的字符串。 + public static string IPEndPointToStr(this IPEndPoint self) + { + return $"{self.Address}:{self.Port}"; + } + + /// + /// 针对 Windows 平台设置UDP连接重置选项。 + /// + /// 要设置选项的 实例。 + public static void SetSioUdpConnReset(this Socket socket) + { + if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + return; + } + + /* + 目前这个问题只有Windows下才会出现。 + 服务器端在发送数据时捕获到了一个异常, + 这个异常导致原因应该是远程客户端的UDP监听已停止导致数据发送出错。 + 按理说UDP是无连接的,报这个异常是不合理的 + 这个异常让整UDP的服务监听也停止了。 + 这样就因为一个客户端的数据发送无法到达而导致了服务挂了,所有客户端都无法与服务器通信了 + 想详细了解看下https://blog.csdn.net/sunzhen6251/article/details/124168805*/ + const uint IOC_IN = 0x80000000; + const uint IOC_VENDOR = 0x18000000; + const int SIO_UDP_CONNRESET = unchecked((int) (IOC_IN | IOC_VENDOR | 12)); + + socket.IOControl(SIO_UDP_CONNRESET, new[] {Convert.ToByte(false)}, null); + } + + /// + /// 将 Socket 缓冲区大小设置为操作系统限制。 + /// + /// 要设置缓冲区大小的 Socket。 + public static void SetSocketBufferToOsLimit(this Socket socket) + { + socket.SetReceiveBufferToOSLimit(); + socket.SetSendBufferToOSLimit(); + } + + /// + /// 将 Socket 接收缓冲区大小设置为操作系统限制。 + /// 尝试增加接收缓冲区大小的次数 = 默认 + 最大增加 100 MB。 + /// + /// 要设置接收缓冲区大小的 Socket。 + /// 每次增加的步长大小。 + /// 尝试增加缓冲区大小的次数。 + public static void SetReceiveBufferToOSLimit(this Socket socket, int stepSize = 1024, int attempts = 100_000) + { + // setting a too large size throws a socket exception. + // so let's keep increasing until we encounter it. + for (int i = 0; i < attempts; ++i) + { + // increase in 1 KB steps + try + { + socket.ReceiveBufferSize += stepSize; + } + catch (SocketException) + { + break; + } + } + } + + /// + /// 将 Socket 发送缓冲区大小设置为操作系统限制。 + /// 尝试增加发送缓冲区大小的次数 = 默认 + 最大增加 100 MB。 + /// + /// 要设置发送缓冲区大小的 Socket。 + /// 每次增加的步长大小。 + /// 尝试增加缓冲区大小的次数。 + public static void SetSendBufferToOSLimit(this Socket socket, int stepSize = 1024, int attempts = 100_000) + { + // setting a too large size throws a socket exception. + // so let's keep increasing until we encounter it. + for (var i = 0; i < attempts; ++i) + { + // increase in 1 KB steps + try + { + socket.SendBufferSize += stepSize; + } + catch (SocketException) + { + break; + } + } + } + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/NetworkHelper.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/NetworkHelper.cs.meta new file mode 100644 index 0000000..7e3f70c --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/NetworkHelper.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f35b5f3e69dae431982e69500c1c97c6 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/RandomHelper.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/RandomHelper.cs new file mode 100644 index 0000000..a91b360 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/RandomHelper.cs @@ -0,0 +1,293 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Numerics; + +namespace Fantasy.Helper +{ + /// + /// 随机数操作助手类,提供各种随机数生成和操作方法。 + /// + public static partial class RandomHelper + { + private static readonly Random Random = new Random(); + private static readonly byte[] Byte8 = new byte[8]; + private static readonly byte[] Byte2 = new byte[2]; + + /// + /// 生成一个随机的无符号 64 位整数。 + /// + /// 无符号 64 位整数。 + public static ulong RandUInt64() + { + Random.NextBytes(Byte8); + return BitConverter.ToUInt64(Byte8, 0); + } + + /// + /// 生成一个随机的 64 位整数。 + /// + /// 64 位整数。 + public static long RandInt64() + { + Random.NextBytes(Byte8); + return BitConverter.ToInt64(Byte8, 0); + } + + /// + /// 生成一个随机的无符号 32 位整数。 + /// + /// 无符号 32 位整数。 + public static uint RandUInt32() + { + return (uint) Random.Next(); + } + + /// + /// 生成一个随机的无符号 16 位整数。 + /// + /// 无符号 16 位整数。 + public static ushort RandUInt16() + { + Random.NextBytes(Byte2); + return BitConverter.ToUInt16(Byte2, 0); + } + + /// + /// 在指定范围内生成一个随机整数(包含下限,不包含上限)。 + /// + /// 下限。 + /// 上限。 + /// 生成的随机整数。 + public static int RandomNumber(int lower, int upper) + { + return Random.Next(lower, upper); + } + + /// + /// 生成一个随机的布尔值。 + /// + /// 随机的布尔值。 + public static bool RandomBool() + { + return Random.Next(2) == 0; + } + + /// + /// 从数组中随机选择一个元素。 + /// + /// 数组元素的类型。 + /// 要选择的数组。 + /// 随机选择的数组元素。 + public static T RandomArray(this T[] array) + { + return array[RandomNumber(0, array.Count())]; + } + + /// + /// 从列表中随机选择一个元素。 + /// + /// 列表元素的类型。 + /// 要选择的列表。 + /// 随机选择的列表元素。 + public static T RandomArray(this List array) + { + return array[RandomNumber(0, array.Count())]; + } + + /// + /// 打乱列表中元素的顺序。 + /// + /// 列表元素的类型。 + /// 要打乱顺序的列表。 + public static void BreakRank(List arr) + { + if (arr == null || arr.Count < 2) + { + return; + } + + for (var i = 0; i < arr.Count / 2; i++) + { + var index = Random.Next(0, arr.Count); + (arr[index], arr[arr.Count - index - 1]) = (arr[arr.Count - index - 1], arr[index]); + } + } + + /// + /// 生成一个介于 0 和 1 之间的随机单精度浮点数。 + /// + /// 随机单精度浮点数。 + public static float RandFloat01() + { + var value = Random.NextDouble(); + return (float) value; + } + + private static int Rand(int n) + { + var rd = new Random(); + // 注意,返回值是左闭右开,所以maxValue要加1 + return rd.Next(1, n + 1); + } + + /// + /// 根据权重随机选择一个索引。 + /// + /// 权重数组,每个元素表示相应索引的权重。 + /// 随机选择的索引值。 + public static int RandomByWeight(int[] weights) + { + var sum = weights.Sum(); + var numberRand = Rand(sum); + var sumTemp = 0; + for (var i = 0; i < weights.Length; i++) + { + sumTemp += weights[i]; + if (numberRand <= sumTemp) + { + return i; + } + } + + return -1; + } + + /// + /// 根据固定概率随机选择一个索引,即某个数值上限内随机多少次。 + /// + /// 概率数组,每个元素表示相应索引的概率。 + /// 随机选择的索引值。 + public static int RandomByFixedProbability(int[] args) + { + var argCount = args.Length; + var sum = args.Sum(); + var random = Random.NextDouble() * sum; + while (sum > random) + { + sum -= args[argCount - 1]; + argCount--; + } + + return argCount; + } + + /// + /// 返回随机数。 + /// + /// 是否包含负数。 + /// 返回一个随机的单精度浮点数。 + public static float NextFloat(bool containNegative = false) + { + float f; + var buffer = new byte[4]; + if (containNegative) + { + do + { + Random.NextBytes(buffer); + f = BitConverter.ToSingle(buffer, 0); + } while ((f >= float.MinValue && f < float.MaxValue) == false); + + return f; + } + + do + { + Random.NextBytes(buffer); + f = BitConverter.ToSingle(buffer, 0); + } while ((f >= 0 && f < float.MaxValue) == false); + + return f; + } + + /// + /// 返回一个小于所指定最大值的非负随机数。 + /// + /// 要生成的随机数的上限(随机数不能取该上限值)。 maxValue 必须大于或等于零。 + /// 大于等于零且小于 maxValue 的单精度浮点数,即:返回值的范围通常包括零但不包括 maxValue。 不过,如果 maxValue 等于零,则返回 maxValue。 + public static float NextFloat(float maxValue) + { + if (maxValue.Equals(0)) + { + return maxValue; + } + + if (maxValue < 0) + { + throw new ArgumentOutOfRangeException("“maxValue”必须大于 0。", "maxValue"); + } + + float f; + var buffer = new byte[4]; + + do + { + Random.NextBytes(buffer); + f = BitConverter.ToSingle(buffer, 0); + } while ((f >= 0 && f < maxValue) == false); + + return f; + } + + /// + /// 返回一个指定范围内的随机数。 + /// + /// 返回的随机数的下界(随机数可取该下界值)。 + /// 返回的随机数的上界(随机数不能取该上界值)。 maxValue 必须大于或等于 minValue。 + /// 一个大于等于 minValue 且小于 maxValue 的单精度浮点数,即:返回的值范围包括 minValue 但不包括 maxValue。 如果 minValue 等于 maxValue,则返回 minValue。 + public static float NextFloat(float minValue, float maxValue) + { + if (minValue.Equals(maxValue)) + { + return minValue; + } + + if (minValue > maxValue) + { + throw new ArgumentOutOfRangeException("“minValue”不能大于 maxValue。", "minValue"); + } + + float f; + var buffer = new byte[4]; + + do + { + Random.NextBytes(buffer); + f = BitConverter.ToSingle(buffer, 0); + } while ((f >= minValue && f < maxValue) == false); + + return f; + } + + /// + /// 在指定的矩形区域内随机生成一个二维向量位置。 + /// + /// X轴最小值。 + /// X轴最大值。 + /// Y轴最小值。 + /// Y轴最大值。 + /// 随机生成的二维向量位置。 + public static Vector2 NextVector2(float minX, float maxX, float minY, float maxY) + { + return new Vector2(NextFloat(minX, maxX), NextFloat(minY, maxY)); + } + + /// + /// 生成指定长度的随机数字代码。 + /// + /// 数字代码的长度。 + /// 生成的随机数字代码。 + public static string RandomNumberCode(int len = 6) + { + int num = 0; + for (int i = 0; i < len; i++) + { + int number = RandomNumber(0, 10); + num = num * 10 + number; + } + + return num.ToString(); + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/RandomHelper.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/RandomHelper.cs.meta new file mode 100644 index 0000000..bc0e9e4 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/RandomHelper.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 5ca1a2a2ac7a7472ab9c07166a4e471a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/SocketHelper.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/SocketHelper.cs new file mode 100644 index 0000000..15027c5 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/SocketHelper.cs @@ -0,0 +1,74 @@ +#if !FANTASY_WEBGL +using System.Net; +using System.Net.Sockets; +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member +namespace Fantasy.Helper +{ + /// + /// Socket帮助类 + /// + public static partial class SocketHelper + { + // always pass the same IPEndPointNonAlloc instead of allocating a new + // one each time. + // + // use IPEndPointNonAlloc.temp to get the latest SocketAdddress written + // by ReceiveFrom_Internal! + // + // IMPORTANT: .temp will be overwritten in next call! + // hash or manually copy it if you need to store it, e.g. + // when adding a new connection. + public static int ReceiveFrom_NonAlloc( + this Socket socket, + byte[] buffer, + int offset, + int size, + SocketFlags socketFlags, + EndPoint remoteEndPoint) + { + // call ReceiveFrom with IPEndPointNonAlloc. + // need to wrap this in ReceiveFrom_NonAlloc because it's not + // obvious that IPEndPointNonAlloc.Create does NOT create a new + // IPEndPoint. it saves the result in IPEndPointNonAlloc.temp! +#if FANTASY_UNITY + EndPoint casted = remoteEndPoint; + return socket.ReceiveFrom(buffer, offset, size, socketFlags, ref casted); +#else + return socket.ReceiveFrom(buffer, offset, size, socketFlags, ref remoteEndPoint); +#endif + } + + // same as above, different parameters + public static int ReceiveFrom_NonAlloc(this Socket socket, byte[] buffer, ref EndPoint remoteEndPoint) + { +#if UNITY + EndPoint casted = remoteEndPoint; + return socket.ReceiveFrom(buffer, ref casted); +#else + return socket.ReceiveFrom(buffer, ref remoteEndPoint); +#endif + + } + + // SendTo allocates too: + // https://github.com/mono/mono/blob/f74eed4b09790a0929889ad7fc2cf96c9b6e3757/mcs/class/System/System.Net.Sockets/Socket.cs#L2240 + // -> the allocation is in EndPoint.Serialize() + // NOTE: technically this function isn't necessary. + // could just pass IPEndPointNonAlloc. + // still good for strong typing. + //public static int SendTo_NonAlloc( + // this Socket socket, + // byte[] buffer, + // int offset, + // int size, + // SocketFlags socketFlags, + // IPEndPointNonAlloc remoteEndPoint) + //{ + // EndPoint casted = remoteEndPoint; + // return socket.SendTo(buffer, offset, size, socketFlags, casted); + //} + } +} +#endif + + diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/SocketHelper.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/SocketHelper.cs.meta new file mode 100644 index 0000000..d0fad2d --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/SocketHelper.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 54d75f1a06d9144e482ec46a67f2cfeb +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/TimeHelper.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/TimeHelper.cs new file mode 100644 index 0000000..ec6ff4d --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/TimeHelper.cs @@ -0,0 +1,78 @@ +using System; +#if FANTASY_UNITY +using UnityEngine; +#endif + +namespace Fantasy.Helper +{ + /// + /// 提供与时间相关的帮助方法。 + /// + public static partial class TimeHelper + { + /// + /// 一小时的毫秒值。 + /// + public const long Hour = 3600000; + /// + /// 一分钟的毫秒值。 + /// + public const long Minute = 60000; + /// + /// 一天的毫秒值。 + /// + public const long OneDay = 86400000; + // 1970年1月1日的Ticks + private const long Epoch = 621355968000000000L; + private static readonly DateTime Dt1970 = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); + /// + /// 获取当前时间的毫秒数,从1970年1月1日开始计算。 + /// + public static long Now => (DateTime.UtcNow.Ticks - Epoch) / 10000; +#if FANTASY_UNITY || FANTASY_CONSOLE + /// + /// 与服务器时间的偏差。 + /// + public static long TimeDiff; + /// + /// 获取当前服务器时间的毫秒数,加上与服务器时间的偏差。 + /// + public static long ServerNow => Now + TimeDiff; +#if FANTASY_UNITY + /// + /// 获取当前Unity运行的总时间的毫秒数。 + /// + public static long UnityNow => (long) (Time.time * 1000); +#endif +#endif + /// + /// 将日期时间转换为毫秒数,从1970年1月1日开始计算。 + /// + /// 要转换的日期时间。 + /// 转换后的毫秒数。 + public static long Transition(this DateTime d) + { + return (d.Ticks - Epoch) / 10000; + } + + /// + /// 将毫秒数转换为日期时间。 + /// + /// 要转换的毫秒数。 + /// 转换后的日期时间。 + public static DateTime Transition(this long timeStamp) + { + return Dt1970.AddTicks(timeStamp); + } + + /// + /// 将毫秒数转换为本地时间的日期时间。 + /// + /// 要转换的毫秒数。 + /// 转换后的本地时间的日期时间。 + public static DateTime TransitionLocal(this long timeStamp) + { + return Dt1970.AddTicks(timeStamp).ToLocalTime(); + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/TimeHelper.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/TimeHelper.cs.meta new file mode 100644 index 0000000..3a8d962 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/TimeHelper.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3937c5cea56304a79b138c980c91b79b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/UnityWebRequest.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/UnityWebRequest.meta new file mode 100644 index 0000000..c5d6e4e --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/UnityWebRequest.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 1d9aa49407518439ebc2527068436501 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/UnityWebRequest/UnityWebRequestHelper.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/UnityWebRequest/UnityWebRequestHelper.cs new file mode 100644 index 0000000..dbc0334 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/UnityWebRequest/UnityWebRequestHelper.cs @@ -0,0 +1,244 @@ +#if FANTASY_UNITY +using System; +using Fantasy.Async; +using UnityEngine; +using UnityEngine.Networking; + +namespace Fantasy.Unity +{ + /// + /// UnityWebRequest的帮助类 + /// + public static class UnityWebRequestHelper + { + /// + /// 获取一个文本 + /// + /// + /// + /// + public static FTask GetText(string url, FCancellationToken cancellationToken = null) + { + var task = FTask.Create(false); + var unityWebRequest = UnityWebRequest.Get(url); + var unityWebRequestAsyncOperation = unityWebRequest.SendWebRequest(); + + if (cancellationToken != null) + { + cancellationToken.Add(() => + { + unityWebRequest.Abort(); + task.SetResult(null); + }); + } + + unityWebRequestAsyncOperation.completed += operation => + { + if (unityWebRequest.result == UnityWebRequest.Result.Success) + { + var text = unityWebRequest.downloadHandler.text; + task.SetResult(text); + } + else + { + Log.Error(unityWebRequest.error); + task.SetResult(null); + } + }; + + return task; + } + + /// + /// 获取一个Sprite + /// + /// + /// + /// + public static FTask GetSprite(string url, FCancellationToken cancellationToken = null) + { + var task = FTask.Create(false); + var unityWebRequest = UnityWebRequestTexture.GetTexture(Uri.EscapeUriString(url)); + var unityWebRequestAsyncOperation = unityWebRequest.SendWebRequest(); + + if (cancellationToken != null) + { + cancellationToken.Add(() => + { + unityWebRequest.Abort(); + task.SetResult(null); + }); + } + + unityWebRequestAsyncOperation.completed += operation => + { + if (unityWebRequest.result == UnityWebRequest.Result.Success) + { + var texture = DownloadHandlerTexture.GetContent(unityWebRequest); + var sprite = Sprite.Create(texture, new Rect(0, 0, texture.width, texture.height), Vector2.one * 5, 1f); + task.SetResult(sprite); + } + else + { + Log.Error(unityWebRequest.error); + task.SetResult(null); + } + }; + + return task; + } + + /// + /// 获取一个Texture + /// + /// + /// + /// + public static FTask GetTexture(string url, FCancellationToken cancellationToken = null) + { + var task = FTask.Create(false); + var unityWebRequest = UnityWebRequestTexture.GetTexture(Uri.EscapeUriString(url)); + var unityWebRequestAsyncOperation = unityWebRequest.SendWebRequest(); + + if (cancellationToken != null) + { + cancellationToken.Add(() => + { + unityWebRequest.Abort(); + task.SetResult(null); + }); + } + + unityWebRequestAsyncOperation.completed += operation => + { + if (unityWebRequest.result == UnityWebRequest.Result.Success) + { + var texture = DownloadHandlerTexture.GetContent(unityWebRequest); + task.SetResult(texture); + } + else + { + Log.Error(unityWebRequest.error); + task.SetResult(null); + } + }; + + return task; + } + + /// + /// 获取Bytes + /// + /// + /// + /// + public static FTask GetBytes(string url, FCancellationToken cancellationToken = null) + { + var task = FTask.Create(false); + var unityWebRequest = UnityWebRequest.Get(url); + var unityWebRequestAsyncOperation = unityWebRequest.SendWebRequest(); + + if (cancellationToken != null) + { + cancellationToken.Add(() => + { + unityWebRequest.Abort(); + task.SetResult(null); + }); + } + + unityWebRequestAsyncOperation.completed += operation => + { + if (unityWebRequest.result == UnityWebRequest.Result.Success) + { + var bytes = unityWebRequest.downloadHandler.data; + task.SetResult(bytes); + } + else + { + Log.Error(unityWebRequest.error); + task.SetResult(null); + } + }; + + return task; + } + + /// + /// 获取AssetBundle + /// + /// + /// + /// + public static FTask GetAssetBundle(string url, FCancellationToken cancellationToken = null) + { + var task = FTask.Create(false); + var unityWebRequest = UnityWebRequestAssetBundle.GetAssetBundle(Uri.EscapeUriString(url)); + var unityWebRequestAsyncOperation = unityWebRequest.SendWebRequest(); + + if (cancellationToken != null) + { + cancellationToken.Add(() => + { + unityWebRequest.Abort(); + task.SetResult(null); + }); + } + + unityWebRequestAsyncOperation.completed += operation => + { + if (unityWebRequest.result == UnityWebRequest.Result.Success) + { + var assetBundle = DownloadHandlerAssetBundle.GetContent(unityWebRequest); + task.SetResult(assetBundle); + return; + } + + Log.Error(unityWebRequest.error); + task.SetResult(null); + }; + + return task; + } + + /// + /// 获取AudioClip + /// + /// + /// + /// + /// + public static FTask GetAudioClip(string url, AudioType audioType, FCancellationToken cancellationToken = null) + { + var task = FTask.Create(false); + var unityWebRequest = UnityWebRequestMultimedia.GetAudioClip(Uri.EscapeUriString(url), audioType); + var unityWebRequestAsyncOperation = unityWebRequest.SendWebRequest(); + + if (cancellationToken != null) + { + cancellationToken.Add(() => + { + unityWebRequest.Abort(); + task.SetResult(null); + }); + } + + unityWebRequestAsyncOperation.completed += operation => + { + if (unityWebRequest.result == UnityWebRequest.Result.Success) + { + var audioClip = DownloadHandlerAudioClip.GetContent(unityWebRequest); + task.SetResult(audioClip); + } + else + { + Log.Error(unityWebRequest.error); + task.SetResult(null); + } + }; + + return task; + } + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/UnityWebRequest/UnityWebRequestHelper.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/UnityWebRequest/UnityWebRequestHelper.cs.meta new file mode 100644 index 0000000..53b7c3c --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/UnityWebRequest/UnityWebRequestHelper.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 4a679bf05117455388666f6d8cc35d7d +timeCreated: 1726022012 \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/WebSocketHelper.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/WebSocketHelper.cs new file mode 100644 index 0000000..822db06 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/WebSocketHelper.cs @@ -0,0 +1,38 @@ +using System; +using System.Runtime.CompilerServices; + +namespace Fantasy.Helper +{ + /// + /// WebSocket帮助类 + /// + public static partial class WebSocketHelper + { + /// + /// 根据字符串获取WebSocket的连接地址 + /// + /// 目标服务器地址格式为:127.0.0.1:2000 + /// 目标服务器是否为加密连接也就是https + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static string GetWebSocketAddress(string address, bool isHttps) + { + var addressSplit = address.Split(':'); + if (addressSplit.Length != 2) + { + throw new FormatException("Invalid format"); + } + + var ipString = addressSplit[0]; + var portString = addressSplit[1]; + + if (!int.TryParse(portString, out var port) || port < 0 || port > 65535) + { + throw new FormatException("Invalid port number"); + } + + return isHttps ? $"wss://{ipString}:{portString}" : $"ws://{ipString}:{portString}"; + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/WebSocketHelper.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/WebSocketHelper.cs.meta new file mode 100644 index 0000000..66d58c1 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/WebSocketHelper.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 43d82d55edae640d69ed83a832d4dd3e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/WinPeriod.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/WinPeriod.cs new file mode 100644 index 0000000..a1a5aca --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/WinPeriod.cs @@ -0,0 +1,24 @@ +using System.Runtime.InteropServices; + +namespace Fantasy.Helper +{ + /// + /// 精度设置 + /// + public static partial class WinPeriod + { + // 一般默认的精度不止1毫秒(不同操作系统有所不同),需要调用timeBeginPeriod与timeEndPeriod来设置精度 + [DllImport("winmm")] + private static extern void timeBeginPeriod(int t); + /// + /// 针对Windows平台设置精度 + /// + public static void Initialize() + { + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + timeBeginPeriod(1); + } + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/WinPeriod.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/WinPeriod.cs.meta new file mode 100644 index 0000000..5cfeef0 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Helper/WinPeriod.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 20f6f771c52ad42f0a0e74df662f45cc +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/IdFactory.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/IdFactory.meta new file mode 100644 index 0000000..e70ab4f --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/IdFactory.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ded441da24c074aeca67d4b36b990070 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/IdFactory/Default.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/IdFactory/Default.meta new file mode 100644 index 0000000..9e886ae --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/IdFactory/Default.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 589e4893c03744665b44c3159497bfc5 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/IdFactory/Default/EntityIdStruct.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/IdFactory/Default/EntityIdStruct.cs new file mode 100644 index 0000000..2eb393b --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/IdFactory/Default/EntityIdStruct.cs @@ -0,0 +1,136 @@ +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using Fantasy.Helper; + +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member + +namespace Fantasy.IdFactory +{ + /// + /// 表示一个唯一实体的ID。 + /// + [StructLayout(LayoutKind.Sequential, Pack = 1)] + internal struct EntityIdStruct + { + // EntityId:39 + 16 + 18 = 64 + // +-------------------+-----------------------------+------------------------------------+ + // | time(30) 最大34年 | SceneId(16) 最多65535个Scene | sequence(18) 每秒每个进程能生产262143个 + // +-------------------+-----------------------------+------------------------------------+ + public uint Time { get; set; } + public uint SceneId { get; set; } + public uint Sequence { get; set; } + + public const uint MaskSequence = 0x3FFFF; + public const uint MaskSceneId = 0xFFFF; + public const uint MaskTime = 0x3FFFFFFF; + + /// + /// WorldEntityIdStruct(如果超过下面参数的设定该ID会失效)。 + /// + /// time不能超过1073741823 + /// sceneId不能超过65535 + /// sequence不能超过262143 + public EntityIdStruct(uint time, uint sceneId, uint sequence) + { + // 因为都是在配置表里拿到参数、所以这个不做边界判定、能节省一点点性能。 + Time = time; + SceneId = sceneId; + Sequence = sequence; + } + + public static implicit operator long(EntityIdStruct entityIdStruct) + { + ulong result = 0; + result |= entityIdStruct.Sequence; + result |= (ulong)entityIdStruct.SceneId << 18; + result |= (ulong)entityIdStruct.Time << 34; + return (long)result; + } + + public static implicit operator EntityIdStruct(long entityId) + { + var result = (ulong) entityId; + var entityIdStruct = new EntityIdStruct + { + Sequence = (uint)(result & MaskSequence) + }; + result >>= 18; + entityIdStruct.SceneId = (uint)(result & MaskSceneId); + result >>= 16; + entityIdStruct.Time = (uint)(result & MaskTime); + return entityIdStruct; + } + } + + public sealed class EntityIdFactory : IEntityIdFactory + { + private readonly ushort _sceneId; + + private uint _lastTime; + private uint _lastSequence; + private static readonly long Epoch1970 = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).Ticks / 10000; + private static readonly long EpochThisYear = new DateTime(DateTime.Now.Year, 1, 1, 0, 0, 0, DateTimeKind.Utc).Ticks / 10000 - Epoch1970; + + private EntityIdFactory() { } + + public EntityIdFactory(uint sceneId) + { + switch (sceneId) + { + case > 65535: + { + throw new NotSupportedException($"sceneId:{sceneId} cannot be greater than 255255"); + } + default: + { + _sceneId = (ushort)sceneId; + break; + } + } + } + + public long Create + { + get + { + var time = (uint)((TimeHelper.Now - EpochThisYear) / 1000); + + if (time > _lastTime) + { + _lastTime = time; + _lastSequence = 0; + } + else if (++_lastSequence > EntityIdStruct.MaskSequence - 1) + { + _lastTime++; + _lastSequence = 0; + } + + return new EntityIdStruct(time, _sceneId, _lastSequence); + } + } + } + + public sealed class EntityIdFactoryTool : IIdFactoryTool + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public uint GetTime(ref long entityId) + { + var result = (ulong)entityId >> 34; + return (uint)(result & EntityIdStruct.MaskTime); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public uint GetSceneId(ref long entityId) + { + var result = (ulong)entityId >> 18; + return (uint)(result & EntityIdStruct.MaskSceneId); + } + + public byte GetWorldId(ref long entityId) + { + throw new NotImplementedException(); + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/IdFactory/Default/EntityIdStruct.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/IdFactory/Default/EntityIdStruct.cs.meta new file mode 100644 index 0000000..1a583a5 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/IdFactory/Default/EntityIdStruct.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7c41b57a384fe4af6ba68c292e5d913f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/IdFactory/Default/RuntimeIdStruct.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/IdFactory/Default/RuntimeIdStruct.cs new file mode 100644 index 0000000..a5d5e10 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/IdFactory/Default/RuntimeIdStruct.cs @@ -0,0 +1,137 @@ +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using Fantasy.Helper; +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member + +namespace Fantasy.IdFactory +{ + /// + /// 表示一个运行时的ID。 + /// + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct RuntimeIdStruct + { + // RuntimeId:23 + 8 + 8 + 25 = 64 + // +-------------------+-----------------------------+--------------------------------------+ + // | time(23) 最大60天 | SceneId(16) 最多65535个Scene | sequence(25) 每秒每个进程能生产33554431个 + // +-------------------+-----------------------------+--------------------------------------+ + public uint Time { get; private set; } + public uint SceneId { get; private set; } + public uint Sequence { get; private set; } + + public const uint MaskSequence = 0x1FFFFFF; + public const uint MaskSceneId = 0xFFFF; + public const uint MaskTime = 0x7FFFFF; + + /// + /// RuntimeIdStruct(如果超过下面参数的设定该ID会失效)。 + /// + /// time不能超过8388607 + /// sceneId不能超过65535 + /// sequence不能超过33554431 + public RuntimeIdStruct(uint time, uint sceneId, uint sequence) + { + // 因为都是在配置表里拿到参数、所以这个不做边界判定、能节省一点点性能。 + Time = time; + SceneId = sceneId; + Sequence = sequence; + } + + public static implicit operator long(RuntimeIdStruct runtimeIdStruct) + { + ulong result = runtimeIdStruct.Sequence; + result |= (ulong)runtimeIdStruct.SceneId << 25; + result |= (ulong)runtimeIdStruct.Time << 41; + return (long)result; + } + + public static implicit operator RuntimeIdStruct(long runtimeId) + { + var result = (ulong)runtimeId; + var runtimeIdStruct = new RuntimeIdStruct + { + Sequence = (uint)(result & MaskSequence) + }; + result >>= 25; + runtimeIdStruct.SceneId = (byte)(result & MaskSceneId); + result >>= 16; + runtimeIdStruct.Time = (uint)(result & MaskTime); + return runtimeIdStruct; + } + } + + public sealed class RuntimeIdFactory : IRuntimeIdFactory + { + private readonly uint _sceneId; + + private uint _lastTime; + private uint _lastSequence; + private readonly long _epochNow; + private readonly long _epoch1970 = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).Ticks / 10000; + + private RuntimeIdFactory() { } + + public RuntimeIdFactory(uint sceneId) : this(TimeHelper.Now, sceneId) { } + + public RuntimeIdFactory(long epochNow, uint sceneId) + { + switch (sceneId) + { + case > 65535: + { + throw new NotSupportedException($"sceneId:{sceneId} cannot be greater than 255255"); + } + default: + { + _sceneId = (ushort)sceneId; + _epochNow = epochNow - _epoch1970; + break; + } + } + } + + public long Create + { + get + { + var time = (uint)((TimeHelper.Now - _epochNow) / 1000); + + if (time > _lastTime) + { + _lastTime = time; + _lastSequence = 0; + } + else if (++_lastSequence > RuntimeIdStruct.MaskSequence - 1) + { + _lastTime++; + _lastSequence = 0; + } + + return new RuntimeIdStruct(time, _sceneId, _lastSequence); + } + } + } + + public sealed class RuntimeIdFactoryTool : IIdFactoryTool + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public uint GetTime(ref long runtimeId) + { + var result = (ulong)runtimeId >> 41; + return (uint)(result & RuntimeIdStruct.MaskTime); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public uint GetSceneId(ref long runtimeId) + { + var result = (ulong)runtimeId >> 25; + return (uint)(result & RuntimeIdStruct.MaskSceneId); + } + + public byte GetWorldId(ref long entityId) + { + throw new NotImplementedException(); + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/IdFactory/Default/RuntimeIdStruct.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/IdFactory/Default/RuntimeIdStruct.cs.meta new file mode 100644 index 0000000..65bb018 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/IdFactory/Default/RuntimeIdStruct.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7beff4714d321419ab54719d2f084edc +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/IdFactory/IdFactoryHelper.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/IdFactory/IdFactoryHelper.cs new file mode 100644 index 0000000..4251d53 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/IdFactory/IdFactoryHelper.cs @@ -0,0 +1,132 @@ +using System; +using System.Runtime.CompilerServices; +using Fantasy.Helper; +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring as nullable. + +namespace Fantasy.IdFactory +{ + /// + /// Id生成器帮助类 + /// + public static class IdFactoryHelper + { + private static IdFactoryType _idFactoryType = IdFactoryType.World; + + /// + /// EntityId工具 + /// + public static IIdFactoryTool EntityIdTool { get; private set; } = new WorldEntityIdFactoryTool(); + + /// + /// RuntimeId工具 + /// + public static IIdFactoryTool RuntimeIdTool { get; private set; } = new WorldRuntimeIdFactoryTool(); + + /// + /// 初始化 + /// + /// + public static void Initialize(IdFactoryType idFactoryType) + { + _idFactoryType = idFactoryType; + + switch (_idFactoryType) + { + case IdFactoryType.Default: + { + EntityIdTool = new EntityIdFactoryTool(); + RuntimeIdTool = new RuntimeIdFactoryTool(); + return; + } + case IdFactoryType.World: + { + EntityIdTool = new WorldEntityIdFactoryTool(); + RuntimeIdTool = new WorldRuntimeIdFactoryTool(); + return; + } + } + } + + internal static IEntityIdFactory EntityIdFactory(uint sceneId, byte worldId) + { + switch (_idFactoryType) + { + case IdFactoryType.Default: + { + return new EntityIdFactory(sceneId); + } + case IdFactoryType.World: + { + return new WorldEntityIdFactory(sceneId, worldId); + } + default: + { + throw new NotSupportedException($"IdFactoryType {_idFactoryType} is not supported."); + } + } + } + + internal static IRuntimeIdFactory RuntimeIdFactory(long epochNow, uint sceneId, byte worldId) + { + switch (_idFactoryType) + { + case IdFactoryType.Default: + { + return new RuntimeIdFactory(sceneId); + } + case IdFactoryType.World: + { + if (epochNow == 0) + { + epochNow = TimeHelper.Now; + } + + return new WorldRuntimeIdFactory(epochNow, sceneId, worldId); + } + default: + { + throw new NotSupportedException($"IdFactoryType {_idFactoryType} is not supported."); + } + } + } + + internal static long EntityId(uint time, uint sceneId, byte wordId, uint sequence) + { + switch (_idFactoryType) + { + case IdFactoryType.Default: + { + return new EntityIdStruct(time, sceneId, sequence); + } + case IdFactoryType.World: + { + return new WorldEntityIdStruct(time, sceneId, wordId, sequence); + } + default: + { + throw new NotSupportedException($"IdFactoryType {_idFactoryType} is not supported."); + } + } + } + + internal static long RuntimeId(uint time, uint sceneId, byte wordId, uint sequence) + { + switch (_idFactoryType) + { + case IdFactoryType.Default: + { + return new RuntimeIdStruct(time, sceneId, sequence); + } + case IdFactoryType.World: + { + return new WorldRuntimeIdStruct(time, sceneId, wordId, sequence); + } + default: + { + throw new NotSupportedException($"IdFactoryType {_idFactoryType} is not supported."); + } + } + } + } +} + diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/IdFactory/IdFactoryHelper.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/IdFactory/IdFactoryHelper.cs.meta new file mode 100644 index 0000000..09dfc6c --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/IdFactory/IdFactoryHelper.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 473af6a8da63d4275b47b1010f32eaf2 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/IdFactory/IdFactoryType.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/IdFactory/IdFactoryType.cs new file mode 100644 index 0000000..d465b5b --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/IdFactory/IdFactoryType.cs @@ -0,0 +1,23 @@ +namespace Fantasy.IdFactory +{ + /// + /// ID生成器规则 + /// + public enum IdFactoryType + { + /// + /// 空。 + /// + None = 0, + /// + /// 默认生成器 + /// Scene最大为65535个。 + /// + Default = 1, + /// + /// ID中包含World,使用这种方式可以不用管理合区的ID重复的问题。 + /// 但Scene的数量也会限制到255个。 + /// + World = 2 + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/IdFactory/IdFactoryType.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/IdFactory/IdFactoryType.cs.meta new file mode 100644 index 0000000..5a107b9 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/IdFactory/IdFactoryType.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d12eb30419c7546ca9b4729e0bc45a36 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/IdFactory/Interface.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/IdFactory/Interface.meta new file mode 100644 index 0000000..41aedbb --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/IdFactory/Interface.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b846d5724675746918a518042f24e956 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/IdFactory/Interface/IIdFactory.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/IdFactory/Interface/IIdFactory.cs new file mode 100644 index 0000000..d71c15b --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/IdFactory/Interface/IIdFactory.cs @@ -0,0 +1,24 @@ +namespace Fantasy.IdFactory +{ + /// + /// EntityId生成器接口类 + /// + public interface IEntityIdFactory + { + /// + /// 创建一个新的Id + /// + public long Create { get; } + } + + /// + /// RuntimeId生成器接口类 + /// + public interface IRuntimeIdFactory + { + /// + /// 创建一个新的Id + /// + public long Create { get; } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/IdFactory/Interface/IIdFactory.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/IdFactory/Interface/IIdFactory.cs.meta new file mode 100644 index 0000000..8e27d4f --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/IdFactory/Interface/IIdFactory.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3ea306d05c1a64e6ea13d96d275f8c79 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/IdFactory/Interface/IIdFactoryTool.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/IdFactory/Interface/IIdFactoryTool.cs new file mode 100644 index 0000000..8dd1e99 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/IdFactory/Interface/IIdFactoryTool.cs @@ -0,0 +1,27 @@ +namespace Fantasy.IdFactory +{ + /// + /// Id扩展工具接口 + /// + public interface IIdFactoryTool + { + /// + /// 获得创建时间 + /// + /// + /// + public uint GetTime(ref long entityId); + /// + /// 获得SceneId + /// + /// + /// + public uint GetSceneId(ref long entityId); + /// + /// 获得WorldId + /// + /// + /// + public byte GetWorldId(ref long entityId); + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/IdFactory/Interface/IIdFactoryTool.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/IdFactory/Interface/IIdFactoryTool.cs.meta new file mode 100644 index 0000000..c32d5a7 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/IdFactory/Interface/IIdFactoryTool.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 15e1bd161b8634ac9b3c68489f693da0 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/IdFactory/World.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/IdFactory/World.meta new file mode 100644 index 0000000..e9f6b9c --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/IdFactory/World.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 74a4a5284009e4c62abe1d7a391dea0c +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/IdFactory/World/WorldEntityIdFactory.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/IdFactory/World/WorldEntityIdFactory.cs new file mode 100644 index 0000000..a4aafba --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/IdFactory/World/WorldEntityIdFactory.cs @@ -0,0 +1,153 @@ +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using Fantasy.Helper; + +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member + +namespace Fantasy.IdFactory +{ + /// + /// 表示一个唯一实体的ID。 + /// + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct WorldEntityIdStruct + { + // EntityId:39 + 8 + 8 + 18 = 64 + // +-------------------+--------------------------+-----------------------+------------------------------------+ + // | time(30) 最大34年 | SceneId(8) 最多255个Scene | WordId(8) 最多255个世界 | sequence(18) 每秒每个进程能生产262143个 + // +-------------------+--------------------------+-----------------------+------------------------------------+ + public uint Time { get; private set; } + public uint SceneId { get; private set; } + public byte WordId { get; private set; } + public uint Sequence { get; private set; } + + public const uint MaskSequence = 0x3FFFF; + public const uint MaskSceneId = 0xFF; + public const uint MaskWordId = 0xFF; + public const uint MaskTime = 0x3FFFFFFF; + + /// + /// WorldEntityIdStruct(如果超过下面参数的设定该ID会失效)。 + /// + /// time不能超过1073741823 + /// sceneId不能超过255 + /// wordId不能超过255 + /// sequence不能超过262143 + public WorldEntityIdStruct(uint time, uint sceneId, byte wordId, uint sequence) + { + // 因为都是在配置表里拿到参数、所以这个不做边界判定、能节省一点点性能。 + Time = time; + SceneId = sceneId; + WordId = wordId; + Sequence = sequence; + } + + public static implicit operator long(WorldEntityIdStruct entityIdStruct) + { + ulong result = 0; + result |= entityIdStruct.Sequence; + result |= (ulong)entityIdStruct.WordId << 18; + result |= (ulong)(entityIdStruct.SceneId % (entityIdStruct.WordId * 1000)) << 26; + result |= (ulong)entityIdStruct.Time << 34; + return (long)result; + } + + public static implicit operator WorldEntityIdStruct(long entityId) + { + var result = (ulong) entityId; + var entityIdStruct = new WorldEntityIdStruct + { + Sequence = (uint)(result & MaskSequence) + }; + result >>= 18; + entityIdStruct.WordId = (byte)(result & MaskWordId); + result >>= 8; + entityIdStruct.SceneId = (uint)(result & MaskSceneId) + (uint)entityIdStruct.WordId * 1000; + result >>= 8; + entityIdStruct.Time = (uint)(result & MaskTime); + return entityIdStruct; + } + } + + public sealed class WorldEntityIdFactory : IEntityIdFactory + { + private readonly uint _sceneId; + private readonly byte _worldId; + + private uint _lastTime; + private uint _lastSequence; + private static readonly long Epoch1970 = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).Ticks / 10000; + private static readonly long EpochThisYear = new DateTime(DateTime.Now.Year, 1, 1, 0, 0, 0, DateTimeKind.Utc).Ticks / 10000 - Epoch1970; + + private WorldEntityIdFactory() { } + + public WorldEntityIdFactory(uint sceneId, byte worldId) + { + switch (sceneId) + { + case > 255255: + { + throw new NotSupportedException($"sceneId:{sceneId} cannot be greater than 255255"); + } + case < 1001: + { + throw new NotSupportedException($"sceneId:{sceneId} cannot be less than 1001"); + } + default: + { + _sceneId = sceneId; + _worldId = worldId; + break; + } + } + } + + public long Create + { + get + { + var time = (uint)((TimeHelper.Now - EpochThisYear) / 1000); + + if (time > _lastTime) + { + _lastTime = time; + _lastSequence = 0; + } + else if (++_lastSequence > WorldEntityIdStruct.MaskSequence - 1) + { + _lastTime++; + _lastSequence = 0; + } + + return new WorldEntityIdStruct(time, _sceneId, _worldId, _lastSequence); + } + } + } + + public sealed class WorldEntityIdFactoryTool : IIdFactoryTool + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public uint GetTime(ref long entityId) + { + var result = (ulong)entityId >> 34; + return (uint)(result & WorldEntityIdStruct.MaskTime); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public uint GetSceneId(ref long entityId) + { + var result = (ulong)entityId >> 18; + var worldId = (uint)(result & WorldEntityIdStruct.MaskWordId) * 1000; + result >>= 8; + return (uint)(result & WorldEntityIdStruct.MaskSceneId) + worldId; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public byte GetWorldId(ref long entityId) + { + var result = (ulong)entityId >> 18; + return (byte)(result & WorldEntityIdStruct.MaskWordId); + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/IdFactory/World/WorldEntityIdFactory.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/IdFactory/World/WorldEntityIdFactory.cs.meta new file mode 100644 index 0000000..850ed42 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/IdFactory/World/WorldEntityIdFactory.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2c1f04d6b9470445498b7ff767733d66 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/IdFactory/World/WorldRuntimeIdFactory.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/IdFactory/World/WorldRuntimeIdFactory.cs new file mode 100644 index 0000000..a5d582b --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/IdFactory/World/WorldRuntimeIdFactory.cs @@ -0,0 +1,155 @@ +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using Fantasy.Helper; + +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member + +namespace Fantasy.IdFactory +{ + /// + /// 表示一个运行时的ID。 + /// + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct WorldRuntimeIdStruct + { + // RuntimeId:23 + 8 + 8 + 25 = 64 + // +-------------------+--------------------------+-----------------------+--------------------------------------+ + // | time(23) 最大60天 | SceneId(8) 最多255个Scene | WordId(8) 最多255个世界 | sequence(25) 每秒每个进程能生产33554431个 + // +-------------------+--------------------------+-----------------------+--------------------------------------+ + public uint Time { get; private set; } + public uint SceneId { get; private set; } + public byte WordId { get; private set; } + public uint Sequence { get; private set; } + + public const uint MaskSequence = 0x1FFFFFF; + public const uint MaskSceneId = 0xFF; + public const uint MaskWordId = 0xFF; + public const uint MaskTime = 0x7FFFFF; + + /// + /// WorldRuntimeIdStruct(如果超过下面参数的设定该ID会失效)。 + /// + /// time不能超过8388607 + /// sceneId不能超过255 + /// wordId不能超过255 + /// sequence不能超过33554431 + public WorldRuntimeIdStruct(uint time, uint sceneId, byte wordId, uint sequence) + { + // 因为都是在配置表里拿到参数、所以这个不做边界判定、能节省一点点性能。 + Time = time; + SceneId = sceneId; + WordId = wordId; + Sequence = sequence; + } + + public static implicit operator long(WorldRuntimeIdStruct runtimeIdStruct) + { + ulong result = runtimeIdStruct.Sequence; + result |= (ulong)runtimeIdStruct.WordId << 25; + result |= (ulong)(runtimeIdStruct.SceneId % (runtimeIdStruct.WordId * 1000)) << 33; + result |= (ulong)runtimeIdStruct.Time << 41; + return (long)result; + } + + public static implicit operator WorldRuntimeIdStruct(long runtimeId) + { + var result = (ulong)runtimeId; + var runtimeIdStruct = new WorldRuntimeIdStruct + { + Sequence = (uint)(result & MaskSequence) + }; + result >>= 25; + runtimeIdStruct.WordId = (byte)(result & MaskWordId); + result >>= 8; + runtimeIdStruct.SceneId = (uint)(result & MaskSceneId) + (uint)runtimeIdStruct.WordId * 1000; + result >>= 8; + runtimeIdStruct.Time = (uint)(result & MaskTime); + return runtimeIdStruct; + } + } + + public sealed class WorldRuntimeIdFactory : IRuntimeIdFactory + { + private readonly uint _sceneId; + private readonly byte _worldId; + + private uint _lastTime; + private uint _lastSequence; + private readonly long _epochNow; + private readonly long _epoch1970 = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).Ticks / 10000; + + private WorldRuntimeIdFactory() { } + + public WorldRuntimeIdFactory(uint sceneId, byte worldId) : this(TimeHelper.Now, sceneId, worldId) { } + + public WorldRuntimeIdFactory(long epochNow, uint sceneId, byte worldId) + { + switch (sceneId) + { + case > 255255: + { + throw new NotSupportedException($"sceneId:{sceneId} cannot be greater than 255255"); + } + case < 1001: + { + throw new NotSupportedException($"sceneId:{sceneId} cannot be less than 1001"); + } + default: + { + _sceneId = sceneId; + _worldId = worldId; + _epochNow = epochNow - _epoch1970; + break; + } + } + } + + public long Create + { + get + { + var time = (uint)((TimeHelper.Now - _epochNow) / 1000); + + if (time > _lastTime) + { + _lastTime = time; + _lastSequence = 0; + } + else if (++_lastSequence > WorldRuntimeIdStruct.MaskSequence - 1) + { + _lastTime++; + _lastSequence = 0; + } + + return new WorldRuntimeIdStruct(time, _sceneId, _worldId, _lastSequence); + } + } + } + + public sealed class WorldRuntimeIdFactoryTool : IIdFactoryTool + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public uint GetTime(ref long runtimeId) + { + var result = (ulong)runtimeId >> 41; + return (uint)(result & WorldRuntimeIdStruct.MaskTime); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public uint GetSceneId(ref long runtimeId) + { + var result = (ulong)runtimeId >> 25; + var worldId = (uint)(result & WorldRuntimeIdStruct.MaskWordId) * 1000; + result >>= 8; + return (uint)(result & WorldRuntimeIdStruct.MaskSceneId) + worldId; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public byte GetWorldId(ref long runtimeId) + { + var result = (ulong)runtimeId >> 25; + return (byte)(result & WorldRuntimeIdStruct.MaskWordId); + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/IdFactory/World/WorldRuntimeIdFactory.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/IdFactory/World/WorldRuntimeIdFactory.cs.meta new file mode 100644 index 0000000..bafd4ac --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/IdFactory/World/WorldRuntimeIdFactory.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9ab9228f312a44378a94772f24598212 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/InnerErrorCode.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/InnerErrorCode.cs new file mode 100644 index 0000000..3510b76 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/InnerErrorCode.cs @@ -0,0 +1,31 @@ +namespace Fantasy.Network +{ + /// + /// 定义 Fantasy 框架中的内部错误代码。 + /// + public class InnerErrorCode + { + private InnerErrorCode() { } + /// + /// 表示 Rpc 消息发送失败的错误代码。 + /// + public const uint ErrRpcFail = 100000002; + /// + /// 表示未找到 Route 消息的错误代码。 + /// + public const uint ErrNotFoundRoute = 100000003; + + /// + /// 表示发送 Route 消息超时的错误代码。 + /// + public const uint ErrRouteTimeout = 100000004; + /// + /// 表示未找到实体的错误代码。 + /// + public const uint ErrEntityNotFound = 100000008; + /// + /// 表示传送过程中发生错误的错误代码。 + /// + public const uint ErrTransfer = 100000009; + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/InnerErrorCode.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/InnerErrorCode.cs.meta new file mode 100644 index 0000000..55bf9bc --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/InnerErrorCode.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 20d260b595ed246d3804b2c64e541cd9 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Log.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Log.meta new file mode 100644 index 0000000..3ff8e73 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Log.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: c03babc2b23544aa391f909918cd152e +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Log/ConsoleLog.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Log/ConsoleLog.cs new file mode 100644 index 0000000..0d57e22 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Log/ConsoleLog.cs @@ -0,0 +1,144 @@ +#if FANTASY_NET +using Fantasy.Platform.Net; +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member + +namespace Fantasy; + +/// +/// 标准的控制台Log +/// +public sealed class ConsoleLog : ILog +{ + /// + /// 初始化方法 + /// + /// + public void Initialize(ProcessMode processMode) { } + + /// + /// 记录跟踪级别的日志消息。 + /// + /// 日志消息。 + public void Trace(string message) + { + Console.ForegroundColor = ConsoleColor.White; + Console.WriteLine(message); + } + + /// + /// 记录警告级别的日志消息。 + /// + /// 日志消息。 + public void Warning(string message) + { + Console.ForegroundColor = ConsoleColor.Yellow; + Console.WriteLine(message); + } + + /// + /// 记录信息级别的日志消息。 + /// + /// 日志消息。 + public void Info(string message) + { + Console.ForegroundColor = ConsoleColor.Gray; + Console.WriteLine(message); + } + + /// + /// 记录调试级别的日志消息。 + /// + /// 日志消息。 + public void Debug(string message) + { + Console.ForegroundColor = ConsoleColor.DarkGreen; + Console.WriteLine(message); + } + + /// + /// 记录错误级别的日志消息。 + /// + /// 日志消息。 + public void Error(string message) + { + Console.ForegroundColor = ConsoleColor.DarkRed; + Console.WriteLine(message); + } + + /// + /// 记录严重错误级别的日志消息。 + /// + /// 日志消息。 + public void Fatal(string message) + { + Console.ForegroundColor = ConsoleColor.Red; + Console.WriteLine(message); + } + + /// + /// 记录跟踪级别的格式化日志消息。 + /// + /// 日志消息模板。 + /// 格式化参数。 + public void Trace(string message, params object[] args) + { + Console.ForegroundColor = ConsoleColor.White; + Console.WriteLine(message, args); + } + + /// + /// 记录警告级别的格式化日志消息。 + /// + /// 日志消息模板。 + /// 格式化参数。 + public void Warning(string message, params object[] args) + { + Console.ForegroundColor = ConsoleColor.Yellow; + Console.WriteLine(message, args); + } + + /// + /// 记录信息级别的格式化日志消息。 + /// + /// 日志消息模板。 + /// 格式化参数。 + public void Info(string message, params object[] args) + { + Console.ForegroundColor = ConsoleColor.Gray; + Console.WriteLine(message, args); + } + + /// + /// 记录调试级别的格式化日志消息。 + /// + /// 日志消息模板。 + /// 格式化参数。 + public void Debug(string message, params object[] args) + { + Console.ForegroundColor = ConsoleColor.DarkGreen; + Console.WriteLine(message, args); + } + + /// + /// 记录错误级别的格式化日志消息。 + /// + /// 日志消息模板。 + /// 格式化参数。 + public void Error(string message, params object[] args) + { + Console.ForegroundColor = ConsoleColor.DarkRed; + Console.WriteLine(message, args); + } + + /// + /// 记录严重错误级别的格式化日志消息。 + /// + /// 日志消息模板。 + /// 格式化参数。 + public void Fatal(string message, params object[] args) + { + Console.ForegroundColor = ConsoleColor.Red; + Console.WriteLine(message, args); + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Log/ConsoleLog.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Log/ConsoleLog.cs.meta new file mode 100644 index 0000000..a61215a --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Log/ConsoleLog.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: cc11e6d3846d64f8799313ac7b5c7ffd +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Log/ILog.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Log/ILog.cs new file mode 100644 index 0000000..b01e857 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Log/ILog.cs @@ -0,0 +1,74 @@ +#if FANTASY_NET +using Fantasy.Platform.Net; +#endif +namespace Fantasy +{ + /// + /// 定义日志记录功能的接口。 + /// + public interface ILog + { +#if FANTASY_NET + /// + /// 初始化 + /// + /// + void Initialize(ProcessMode processMode); +#endif + /// + /// 记录跟踪级别的日志消息。 + /// + /// 日志消息。 + void Trace(string message); + /// + /// 记录警告级别的日志消息。 + /// + /// 日志消息。 + void Warning(string message); + /// + /// 记录信息级别的日志消息。 + /// + /// 日志消息。 + void Info(string message); + /// + /// 记录调试级别的日志消息。 + /// + /// 日志消息。 + void Debug(string message); + /// + /// 记录错误级别的日志消息。 + /// + /// 日志消息。 + void Error(string message); + /// + /// 记录跟踪级别的格式化日志消息。 + /// + /// 日志消息模板。 + /// 格式化参数。 + void Trace(string message, params object[] args); + /// + /// 记录警告级别的格式化日志消息。 + /// + /// 日志消息模板。 + /// 格式化参数。 + void Warning(string message, params object[] args); + /// + /// 记录信息级别的格式化日志消息。 + /// + /// 日志消息模板。 + /// 格式化参数。 + void Info(string message, params object[] args); + /// + /// 记录调试级别的格式化日志消息。 + /// + /// 日志消息模板。 + /// 格式化参数。 + void Debug(string message, params object[] args); + /// + /// 记录错误级别的格式化日志消息。 + /// + /// 日志消息模板。 + /// 格式化参数。 + void Error(string message, params object[] args); + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Log/ILog.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Log/ILog.cs.meta new file mode 100644 index 0000000..f70cb9f --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Log/ILog.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 16ffac81f7ac6485ebd425c88ada6c96 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Log/Log.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Log/Log.cs new file mode 100644 index 0000000..8069fff --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Log/Log.cs @@ -0,0 +1,189 @@ +using System; +using System.Diagnostics; +#if FANTASY_NET +using Fantasy.Platform.Net; +#endif + +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. + +namespace Fantasy +{ + /// + /// 提供日志记录功能的静态类。 + /// + public static class Log + { + private static ILog _logCore; + private static bool _isRegister; +#if FANTASY_NET + /// + /// 初始化Log系统 + /// + public static void Initialize() + { + if (!_isRegister) + { + Register(new ConsoleLog()); + return; + } + + var processMode = ProcessMode.None; + + switch (ProcessDefine.Options.Mode) + { + case "Develop": + { + processMode = ProcessMode.Develop; + break; + } + case "Release": + { + processMode = ProcessMode.Release; + break; + } + } + + _logCore.Initialize(processMode); + } +#endif + /// + /// 注册一个日志系统 + /// + /// + public static void Register(ILog log) + { + if (_isRegister) + { + return; + } + + _logCore = log; + _isRegister = true; + } + + /// + /// 记录跟踪级别的日志消息。 + /// + /// 日志消息。 + public static void Trace(string msg) + { + var st = new StackTrace(1, true); + _logCore.Trace($"{msg}\n{st}"); + } + + /// + /// 记录调试级别的日志消息。 + /// + /// 日志消息。 + public static void Debug(string msg) + { + _logCore.Debug(msg); + } + + /// + /// 记录信息级别的日志消息。 + /// + /// 日志消息。 + public static void Info(string msg) + { + _logCore.Info(msg); + } + + /// + /// 记录跟踪级别的日志消息,并附带调用栈信息。 + /// + /// 日志消息。 + public static void TraceInfo(string msg) + { + var st = new StackTrace(1, true); + _logCore.Trace($"{msg}\n{st}"); + } + + /// + /// 记录警告级别的日志消息。 + /// + /// 日志消息。 + public static void Warning(string msg) + { + _logCore.Warning(msg); + } + + /// + /// 记录错误级别的日志消息,并附带调用栈信息。 + /// + /// 日志消息。 + public static void Error(string msg) + { + var st = new StackTrace(1, true); + _logCore.Error($"{msg}\n{st}"); + } + + /// + /// 记录异常的错误级别的日志消息,并附带调用栈信息。 + /// + /// 异常对象。 + public static void Error(Exception e) + { + if (e.Data.Contains("StackTrace")) + { + _logCore.Error($"{e.Data["StackTrace"]}\n{e}"); + return; + } + var str = e.ToString(); + _logCore.Error(str); + } + + /// + /// 记录跟踪级别的格式化日志消息,并附带调用栈信息。 + /// + /// 日志消息模板。 + /// 格式化参数。 + public static void Trace(string message, params object[] args) + { + var st = new StackTrace(1, true); + _logCore.Trace($"{string.Format(message, args)}\n{st}"); + } + + /// + /// 记录警告级别的格式化日志消息。 + /// + /// 日志消息模板。 + /// 格式化参数。 + public static void Warning(string message, params object[] args) + { + _logCore.Warning(string.Format(message, args)); + } + + /// + /// 记录信息级别的格式化日志消息。 + /// + /// 日志消息模板。 + /// 格式化参数。 + public static void Info(string message, params object[] args) + { + _logCore.Info(string.Format(message, args)); + } + + /// + /// 记录调试级别的格式化日志消息。 + /// + /// 日志消息模板。 + /// 格式化参数。 + public static void Debug(string message, params object[] args) + { + _logCore.Debug(string.Format(message, args)); + } + + /// + /// 记录错误级别的格式化日志消息,并附带调用栈信息。 + /// + /// 日志消息模板。 + /// 格式化参数。 + public static void Error(string message, params object[] args) + { + var st = new StackTrace(1, true); + var s = string.Format(message, args) + '\n' + st; + _logCore.Error(s); + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Log/Log.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Log/Log.cs.meta new file mode 100644 index 0000000..feae74a --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Log/Log.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 59c957edf5e8940d28d5b13e0311184e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Log/UnityLog.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Log/UnityLog.cs new file mode 100644 index 0000000..c381528 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Log/UnityLog.cs @@ -0,0 +1,182 @@ +#if UNITY_EDITOR +using System; +using System.Reflection; +using System.Text.RegularExpressions; +using UnityEditor; +using UnityEditor.Callbacks; +using UnityEditorInternal; +#else +using System; +#endif + +#if FANTASY_UNITY +namespace Fantasy +{ + public class UnityLog : ILog + { + public void Trace(string msg) + { + UnityEngine.Debug.Log(msg); + } + + public void Debug(string msg) + { + UnityEngine.Debug.Log(msg); + } + + public void Info(string msg) + { + UnityEngine.Debug.Log(msg); + } + + public void Warning(string msg) + { + UnityEngine.Debug.LogWarning(msg); + } + + public void Error(string msg) + { + UnityEngine.Debug.LogError(msg); + } + + public void Error(Exception e) + { + UnityEngine.Debug.LogException(e); + } + + public void Trace(string message, params object[] args) + { + UnityEngine.Debug.LogFormat(message, args); + } + + public void Warning(string message, params object[] args) + { + UnityEngine.Debug.LogWarningFormat(message, args); + } + + public void Info(string message, params object[] args) + { + UnityEngine.Debug.LogFormat(message, args); + } + + public void Debug(string message, params object[] args) + { + UnityEngine.Debug.LogFormat(message, args); + } + + public void Error(string message, params object[] args) + { + UnityEngine.Debug.LogErrorFormat(message, args); + } + } +} +#endif + +#if UNITY_EDITOR +namespace Fantasy +{ + /// + /// 日志重定向相关的实用函数。 + /// + internal static class LogRedirection + { + [OnOpenAsset(0)] + private static bool OnOpenAsset(int instanceID, int line) + { + if (line <= 0) + { + return false; + } + + // 获取资源路径 + string assetPath = AssetDatabase.GetAssetPath(instanceID); + + // 判断资源类型 + if (!assetPath.EndsWith(".cs")) + { + return false; + } + + bool autoFirstMatch = assetPath.Contains("Log.cs") || + assetPath.Contains("UnityLog.cs"); + + var stackTrace = GetStackTrace(); + if (!string.IsNullOrEmpty(stackTrace)) + + { + if (!autoFirstMatch) + { + var fullPath = UnityEngine.Application.dataPath.Substring(0, UnityEngine.Application.dataPath.LastIndexOf("Assets", StringComparison.Ordinal)); + fullPath = $"{fullPath}{assetPath}"; + // 跳转到目标代码的特定行 + InternalEditorUtility.OpenFileAtLineExternal(fullPath.Replace('/', '\\'), line); + return true; + } + + // 使用正则表达式匹配at的哪个脚本的哪一行 + var matches = Regex.Match(stackTrace, @"\(at (.+)\)", + RegexOptions.IgnoreCase); + while (matches.Success) + { + var pathLine = matches.Groups[1].Value; + + if (!pathLine.Contains("Log.cs") && + !pathLine.Contains("UnityLog.cs")) + { + var splitIndex = pathLine.LastIndexOf(":", StringComparison.Ordinal); + // 脚本路径 + var path = pathLine.Substring(0, splitIndex); + // 行号 + line = Convert.ToInt32(pathLine.Substring(splitIndex + 1)); + var fullPath = UnityEngine.Application.dataPath.Substring(0, UnityEngine.Application.dataPath.LastIndexOf("Assets", StringComparison.Ordinal)); + fullPath = $"{fullPath}{path}"; + // 跳转到目标代码的特定行 + InternalEditorUtility.OpenFileAtLineExternal(fullPath.Replace('/', '\\'), line); + break; + } + + matches = matches.NextMatch(); + } + + return true; + } + + return false; + } + + /// + /// 获取当前日志窗口选中的日志的堆栈信息。 + /// + /// 选中日志的堆栈信息实例。 + private static string GetStackTrace() + { + // 通过反射获取ConsoleWindow类 + var consoleWindowType = typeof(EditorWindow).Assembly.GetType("UnityEditor.ConsoleWindow"); + // 获取窗口实例 + var fieldInfo = consoleWindowType.GetField("ms_ConsoleWindow", + BindingFlags.Static | + BindingFlags.NonPublic); + if (fieldInfo != null) + { + var consoleInstance = fieldInfo.GetValue(null); + if (consoleInstance != null) + if (EditorWindow.focusedWindow == (EditorWindow)consoleInstance) + { + // 获取m_ActiveText成员 + fieldInfo = consoleWindowType.GetField("m_ActiveText", + BindingFlags.Instance | + BindingFlags.NonPublic); + // 获取m_ActiveText的值 + if (fieldInfo != null) + { + var activeText = fieldInfo.GetValue(consoleInstance).ToString(); + return activeText; + } + } + } + + return null; + } + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Log/UnityLog.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Log/UnityLog.cs.meta new file mode 100644 index 0000000..93addc6 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Log/UnityLog.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a972d9201cbac4103896d0fabe482806 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network.meta new file mode 100644 index 0000000..52d3780 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 3c0f4a22b15ea4a8facdf51886436af8 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Addressable.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Addressable.meta new file mode 100644 index 0000000..068e801 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Addressable.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 804eec4fd3cf746289014cb3cfe99f10 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Addressable/AddressableHelper.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Addressable/AddressableHelper.cs new file mode 100644 index 0000000..098ba8a --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Addressable/AddressableHelper.cs @@ -0,0 +1,141 @@ +#if FANTASY_NET +using Fantasy.Async; +using Fantasy.InnerMessage; +using Fantasy.Platform.Net; +namespace Fantasy.Network.Route +{ + /// + /// 提供操作地址映射的辅助方法。 + /// + public static class AddressableHelper + { + // 声明一个私有静态只读列表 AddressableScenes,用于存储地址映射的场景配置信息 + private static readonly List AddressableScenes = new List(); + + static AddressableHelper() + { + // 遍历场景配置信息,筛选出地址映射类型的场景,并添加到 AddressableScenes 列表中 + foreach (var sceneConfig in SceneConfigData.Instance.List) + { + if (sceneConfig.SceneTypeString == "Addressable") + { + AddressableScenes.Add(new AddressableScene(sceneConfig)); + } + } + } + + /// + /// 添加地址映射并返回操作结果。 + /// + /// 场景实例。 + /// 地址映射的唯一标识。 + /// 路由 ID。 + /// 是否锁定。 + public static async FTask AddAddressable(Scene scene, long addressableId, long routeId, bool isLock = true) + { + // 获取指定索引的地址映射场景配置信息 + var addressableScene = AddressableScenes[(int)addressableId % AddressableScenes.Count]; + // 调用内部路由方法,发送添加地址映射的请求并等待响应 + var response = await scene.NetworkMessagingComponent.CallInnerRoute(addressableScene.RunTimeId, + new I_AddressableAdd_Request + { + AddressableId = addressableId, RouteId = routeId, IsLock = isLock + }); + if (response.ErrorCode != 0) + { + Log.Error($"AddAddressable error is {response.ErrorCode}"); + } + } + + /// + /// 获取地址映射的路由 ID。 + /// + /// 场景实例。 + /// 地址映射的唯一标识。 + /// 地址映射的路由 ID。 + public static async FTask GetAddressableRouteId(Scene scene, long addressableId) + { + // 获取指定索引的地址映射场景配置信息 + var addressableScene = AddressableScenes[(int)addressableId % AddressableScenes.Count]; + // 调用内部路由方法,发送获取地址映射路由 ID 的请求并等待响应 + var response = (I_AddressableGet_Response) await scene.NetworkMessagingComponent.CallInnerRoute(addressableScene.RunTimeId, + new I_AddressableGet_Request + { + AddressableId = addressableId + }); + // 检查响应错误码,如果为零,返回路由 ID;否则,输出错误信息并返回 0 + if (response.ErrorCode == 0) + { + return response.RouteId; + } + + Log.Error($"GetAddressable error is {response.ErrorCode} addressableId:{addressableId}"); + return 0; + } + + /// + /// 移除指定地址映射。 + /// + /// 场景实例。 + /// 地址映射的唯一标识。 + public static async FTask RemoveAddressable(Scene scene, long addressableId) + { + var addressableScene = AddressableScenes[(int)addressableId % AddressableScenes.Count]; + var response = await scene.NetworkMessagingComponent.CallInnerRoute(addressableScene.RunTimeId, + new I_AddressableRemove_Request + { + AddressableId = addressableId + }); + + if (response.ErrorCode != 0) + { + Log.Error($"RemoveAddressable error is {response.ErrorCode}"); + } + } + + /// + /// 锁定指定地址映射。 + /// + /// 场景实例。 + /// 地址映射的唯一标识。 + public static async FTask LockAddressable(Scene scene, long addressableId) + { + var addressableScene = AddressableScenes[(int)addressableId % AddressableScenes.Count]; + var response = await scene.NetworkMessagingComponent.CallInnerRoute(addressableScene.RunTimeId, + new I_AddressableLock_Request + { + AddressableId = addressableId + }); + + if (response.ErrorCode != 0) + { + Log.Error($"LockAddressable error is {response.ErrorCode}"); + } + } + + /// + /// 解锁指定地址映射。 + /// + /// 场景实例。 + /// 地址映射的唯一标识。 + /// 路由 ID。 + /// 解锁来源。 + public static async FTask UnLockAddressable(Scene scene, long addressableId, long routeId, string source) + { + var addressableScene = AddressableScenes[(int)addressableId % AddressableScenes.Count]; + var response = await scene.NetworkMessagingComponent.CallInnerRoute(addressableScene.RunTimeId, + new I_AddressableUnLock_Request + { + AddressableId = addressableId, + RouteId = routeId, + Source = source + }); + + if (response.ErrorCode != 0) + { + Log.Error($"UnLockAddressable error is {response.ErrorCode}"); + } + } + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Addressable/AddressableHelper.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Addressable/AddressableHelper.cs.meta new file mode 100644 index 0000000..316c4c2 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Addressable/AddressableHelper.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 66702f6e5c88f49ad95b95d5342dac17 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Addressable/AddressableManageComponent.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Addressable/AddressableManageComponent.cs new file mode 100644 index 0000000..8d08f08 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Addressable/AddressableManageComponent.cs @@ -0,0 +1,144 @@ +#if FANTASY_NET +using System; +using System.Collections.Generic; +using Fantasy.Async; +using Fantasy.Entitas; +using Fantasy.Entitas.Interface; + +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. +#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. +#pragma warning disable CS8600 // Converting null literal or possible null value to non-nullable type. + +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member +namespace Fantasy.Network.Route +{ + public class AddressableManageComponentAwakeSystem : AwakeSystem + { + protected override void Awake(AddressableManageComponent self) + { + self.AddressableLock = self.Scene.CoroutineLockComponent.Create(self.GetType().TypeHandle.Value.ToInt64()); + } + } + + public class AddressableManageComponentDestroySystem : DestroySystem + { + protected override void Destroy(AddressableManageComponent self) + { + foreach (var (_, waitCoroutineLock) in self.Locks) + { + waitCoroutineLock.Dispose(); + } + + self.Locks.Clear(); + self.Addressable.Clear(); + self.AddressableLock.Dispose(); + self.AddressableLock = null; + } + } + + public sealed class AddressableManageComponent : Entity + { + public CoroutineLock AddressableLock; + public readonly Dictionary Addressable = new(); + public readonly Dictionary Locks = new(); + + /// + /// 添加地址映射。 + /// + /// 地址映射的唯一标识。 + /// 路由 ID。 + /// 是否进行锁定。 + public async FTask Add(long addressableId, long routeId, bool isLock) + { + WaitCoroutineLock waitCoroutineLock = null; + + try + { + if (isLock) + { + waitCoroutineLock = await AddressableLock.Wait(addressableId); + } + + Addressable[addressableId] = routeId; +#if FANTASY_DEVELOP + Log.Debug($"AddressableManageComponent Add addressableId:{addressableId} routeId:{routeId}"); +#endif + } + catch (Exception e) + { + Log.Error(e); + } + finally + { + waitCoroutineLock?.Dispose(); + } + } + + /// + /// 获取地址映射的路由 ID。 + /// + /// 地址映射的唯一标识。 + /// 地址映射的路由 ID。 + public async FTask Get(long addressableId) + { + using (await AddressableLock.Wait(addressableId)) + { + Addressable.TryGetValue(addressableId, out var routeId); + return routeId; + } + } + + /// + /// 移除地址映射。 + /// + /// 地址映射的唯一标识。 + public async FTask Remove(long addressableId) + { + using (await AddressableLock.Wait(addressableId)) + { + Addressable.Remove(addressableId); +#if FANTASY_DEVELOP + Log.Debug($"Addressable Remove addressableId: {addressableId} _addressable:{Addressable.Count}"); +#endif + } + } + + /// + /// 锁定地址映射。 + /// + /// 地址映射的唯一标识。 + public async FTask Lock(long addressableId) + { + var waitCoroutineLock = await AddressableLock.Wait(addressableId); + Locks.Add(addressableId, waitCoroutineLock); + } + + /// + /// 解锁地址映射。 + /// + /// 地址映射的唯一标识。 + /// 新的路由 ID。 + /// 解锁来源。 + public void UnLock(long addressableId, long routeId, string source) + { + if (!Locks.Remove(addressableId, out var coroutineLock)) + { + Log.Error($"Addressable unlock not found addressableId: {addressableId} Source:{source}"); + return; + } + + Addressable.TryGetValue(addressableId, out var oldAddressableId); + + if (routeId != 0) + { + Addressable[addressableId] = routeId; + } + + coroutineLock.Dispose(); +#if FANTASY_DEVELOP + Log.Debug($"Addressable UnLock key: {addressableId} oldAddressableId : {oldAddressableId} routeId: {routeId} Source:{source}"); +#endif + } + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Addressable/AddressableManageComponent.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Addressable/AddressableManageComponent.cs.meta new file mode 100644 index 0000000..c23fdd0 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Addressable/AddressableManageComponent.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b752c543b1cd44fe1956b407ec94fd6e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Addressable/AddressableMessageComponent.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Addressable/AddressableMessageComponent.cs new file mode 100644 index 0000000..9227374 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Addressable/AddressableMessageComponent.cs @@ -0,0 +1,91 @@ +using Fantasy.Async; +using Fantasy.Entitas; +using Fantasy.Entitas.Interface; + +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member +#if FANTASY_NET +namespace Fantasy.Network.Route +{ + public class AddressableMessageComponentDestroySystem : DestroySystem + { + protected override void Destroy(AddressableMessageComponent self) + { + if (self.AddressableId != 0) + { + AddressableHelper.RemoveAddressable(self.Scene, self.AddressableId).Coroutine(); + self.AddressableId = 0; + } + } + } + + /// + /// 可寻址消息组件、挂载了这个组件可以接收Addressable消息 + /// + public sealed class AddressableMessageComponent : Entity + { + /// + /// 可寻址消息组件的唯一标识。 + /// + public long AddressableId; + + /// + /// 注册可寻址消息组件。 + /// + /// 是否进行锁定。 + public FTask Register(bool isLock = true) + { + if (Parent == null) + { + throw new Exception("AddressableRouteComponent must be mounted under a component"); + } + + AddressableId = Parent.Id; + + if (AddressableId == 0) + { + throw new Exception("AddressableRouteComponent.Parent.Id is null"); + } + +#if FANTASY_DEVELOP + Log.Debug($"AddressableMessageComponent Register addressableId:{AddressableId} RouteId:{Parent.RuntimeId}"); +#endif + return AddressableHelper.AddAddressable(Scene, AddressableId, Parent.RuntimeId, isLock); + } + + /// + /// 锁定可寻址消息组件。 + /// + public FTask Lock() + { +#if FANTASY_DEVELOP + Log.Debug($"AddressableMessageComponent Lock {Parent.Id}"); +#endif + return AddressableHelper.LockAddressable(Scene, Parent.Id); + } + + /// + /// 解锁可寻址消息组件。 + /// + /// 解锁来源。 + public FTask UnLock(string source) + { +#if FANTASY_DEVELOP + Log.Debug($"AddressableMessageComponent UnLock {Parent.Id} {Parent.RuntimeId}"); +#endif + return AddressableHelper.UnLockAddressable(Scene, Parent.Id, Parent.RuntimeId, source); + } + + /// + /// 锁定可寻址消息并且释放掉AddressableMessageComponent组件。 + /// 该方法不会自动取Addressable中心删除自己的信息。 + /// 用于传送或转移到其他服务器时使用 + /// + public async FTask LockAndRelease() + { + await Lock(); + AddressableId = 0; + Dispose(); + } + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Addressable/AddressableMessageComponent.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Addressable/AddressableMessageComponent.cs.meta new file mode 100644 index 0000000..6e5528b --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Addressable/AddressableMessageComponent.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1eddf2d176eed4bba9f5cf8c3725318d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Addressable/AddressableRouteComponent.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Addressable/AddressableRouteComponent.cs new file mode 100644 index 0000000..d7914a1 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Addressable/AddressableRouteComponent.cs @@ -0,0 +1,216 @@ +using Fantasy.Async; +using Fantasy.Entitas; +using Fantasy.Entitas.Interface; +using Fantasy.Helper; +using Fantasy.Network.Interface; +using Fantasy.PacketParser.Interface; +using Fantasy.Scheduler; +using Fantasy.Timer; + +#pragma warning disable CS8603 // Possible null reference return. +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. +#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. +#pragma warning disable CS8600 // Converting null literal or possible null value to non-nullable type. +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member +#if FANTASY_NET +namespace Fantasy.Network.Route +{ + public class AddressableRouteComponentAwakeSystem : AwakeSystem + { + protected override void Awake(AddressableRouteComponent self) + { + var selfScene = self.Scene; + self.TimerComponent = selfScene.TimerComponent; + self.NetworkMessagingComponent = selfScene.NetworkMessagingComponent; + self.MessageDispatcherComponent = selfScene.MessageDispatcherComponent; + self.AddressableRouteLock = + selfScene.CoroutineLockComponent.Create(self.GetType().TypeHandle.Value.ToInt64()); + } + } + + public class AddressableRouteComponentDestroySystem : DestroySystem + { + protected override void Destroy(AddressableRouteComponent self) + { + self.AddressableRouteLock.Dispose(); + + self.RouteId = 0; + self.AddressableId = 0; + self.TimerComponent = null; + self.AddressableRouteLock = null; + self.NetworkMessagingComponent = null; + self.MessageDispatcherComponent = null; + } + } + + /// + /// 可寻址路由消息组件,挂载了这个组件可以接收和发送 Addressable 消息。 + /// + public sealed class AddressableRouteComponent : Entity + { + public long RouteId; + public long AddressableId; + public CoroutineLock AddressableRouteLock; + public TimerComponent TimerComponent; + public NetworkMessagingComponent NetworkMessagingComponent; + public MessageDispatcherComponent MessageDispatcherComponent; + + internal void Send(IAddressableRouteMessage message) + { + Call(message).Coroutine(); + } + + internal async FTask Send(Type requestType, APackInfo packInfo) + { + await Call(requestType, packInfo); + } + + internal async FTask Call(Type requestType, APackInfo packInfo) + { + if (IsDisposed) + { + return MessageDispatcherComponent.CreateResponse(requestType, InnerErrorCode.ErrNotFoundRoute); + } + + packInfo.IsDisposed = true; + var failCount = 0; + var runtimeId = RuntimeId; + IResponse iRouteResponse = null; + + try + { + using (await AddressableRouteLock.Wait(AddressableId, "AddressableRouteComponent Call MemoryStream")) + { + while (!IsDisposed) + { + if (RouteId == 0) + { + RouteId = await AddressableHelper.GetAddressableRouteId(Scene, AddressableId); + } + + if (RouteId == 0) + { + return MessageDispatcherComponent.CreateResponse(requestType, + InnerErrorCode.ErrNotFoundRoute); + } + + iRouteResponse = await NetworkMessagingComponent.CallInnerRoute(RouteId, requestType, packInfo); + + if (runtimeId != RuntimeId) + { + iRouteResponse.ErrorCode = InnerErrorCode.ErrRouteTimeout; + } + + switch (iRouteResponse.ErrorCode) + { + case InnerErrorCode.ErrRouteTimeout: + { + return iRouteResponse; + } + case InnerErrorCode.ErrNotFoundRoute: + { + if (++failCount > 20) + { + Log.Error($"AddressableComponent.Call failCount > 20 route send message fail, routeId: {RouteId} AddressableRouteComponent:{Id}"); + return iRouteResponse; + } + + await TimerComponent.Net.WaitAsync(100); + + if (runtimeId != RuntimeId) + { + iRouteResponse.ErrorCode = InnerErrorCode.ErrRouteTimeout; + } + + RouteId = 0; + continue; + } + default: + { + return iRouteResponse; // 对于其他情况,直接返回响应,无需额外处理 + } + } + } + } + } + finally + { + packInfo.Dispose(); + } + + + return iRouteResponse; + } + + /// + /// 调用可寻址路由消息并等待响应。 + /// + /// 可寻址路由请求。 + private async FTask Call(IAddressableRouteMessage request) + { + if (IsDisposed) + { + return MessageDispatcherComponent.CreateResponse(request.GetType(), InnerErrorCode.ErrNotFoundRoute); + } + + var failCount = 0; + var runtimeId = RuntimeId; + + using (await AddressableRouteLock.Wait(AddressableId, "AddressableRouteComponent Call")) + { + while (true) + { + if (RouteId == 0) + { + RouteId = await AddressableHelper.GetAddressableRouteId(Scene, AddressableId); + } + + if (RouteId == 0) + { + return MessageDispatcherComponent.CreateResponse(request.GetType(), + InnerErrorCode.ErrNotFoundRoute); + } + + var iRouteResponse = await NetworkMessagingComponent.CallInnerRoute(RouteId, request); + + if (runtimeId != RuntimeId) + { + iRouteResponse.ErrorCode = InnerErrorCode.ErrRouteTimeout; + } + + switch (iRouteResponse.ErrorCode) + { + case InnerErrorCode.ErrNotFoundRoute: + { + if (++failCount > 20) + { + Log.Error( + $"AddressableRouteComponent.Call failCount > 20 route send message fail, routeId: {RouteId} AddressableRouteComponent:{Id}"); + return iRouteResponse; + } + + await TimerComponent.Net.WaitAsync(500); + + if (runtimeId != RuntimeId) + { + iRouteResponse.ErrorCode = InnerErrorCode.ErrRouteTimeout; + } + + RouteId = 0; + continue; + } + case InnerErrorCode.ErrRouteTimeout: + { + return iRouteResponse; + } + default: + { + return iRouteResponse; + } + } + } + } + } + } +} +#endif diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Addressable/AddressableRouteComponent.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Addressable/AddressableRouteComponent.cs.meta new file mode 100644 index 0000000..079e10f --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Addressable/AddressableRouteComponent.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f0277349ccc64403aafb08a5b077c921 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Addressable/AddressableScene.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Addressable/AddressableScene.cs new file mode 100644 index 0000000..3105fca --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Addressable/AddressableScene.cs @@ -0,0 +1,31 @@ +#if FANTASY_NET +using Fantasy.IdFactory; +using Fantasy.Platform.Net; + +namespace Fantasy.Network.Route +{ + /// + /// AddressableScene + /// + public sealed class AddressableScene + { + /// + /// Id + /// + public readonly long Id; + /// + /// RunTimeId + /// + public readonly long RunTimeId; + /// + /// 构造方法 + /// + /// sceneConfig + public AddressableScene(SceneConfig sceneConfig) + { + Id = IdFactoryHelper.EntityId(0, sceneConfig.Id, (byte)sceneConfig.WorldConfigId, 0); + RunTimeId = IdFactoryHelper.RuntimeId(0, sceneConfig.Id, (byte)sceneConfig.WorldConfigId, 0); + } + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Addressable/AddressableScene.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Addressable/AddressableScene.cs.meta new file mode 100644 index 0000000..8e7a05b --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Addressable/AddressableScene.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 127ac839634c149d786e5e0a434f3535 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Addressable/Handler.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Addressable/Handler.meta new file mode 100644 index 0000000..184f1cb --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Addressable/Handler.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b8a3fe1b1d90e4811b4a93dee5ec24bc +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Addressable/Handler/I_AddressableAddHandler.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Addressable/Handler/I_AddressableAddHandler.cs new file mode 100644 index 0000000..847625b --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Addressable/Handler/I_AddressableAddHandler.cs @@ -0,0 +1,26 @@ +using Fantasy.Async; +using Fantasy.InnerMessage; +using Fantasy.Network.Interface; + +#if FANTASY_NET +namespace Fantasy.Network.Route +{ + /// + /// 声明一个 sealed 类 I_AddressableAddHandler,继承自 RouteRPC 类,并指定泛型参数 + /// + public sealed class I_AddressableAddHandler : RouteRPC + { + /// + /// 在收到地址映射添加请求时执行的逻辑。 + /// + /// 当前场景实例。 + /// 包含请求信息的 I_AddressableAdd_Request 实例。 + /// 用于构建响应的 I_AddressableAdd_Response 实例。 + /// 执行响应的回调操作。 + protected override async FTask Run(Scene scene, I_AddressableAdd_Request request, I_AddressableAdd_Response response, Action reply) + { + await scene.GetComponent().Add(request.AddressableId, request.RouteId, request.IsLock); + } + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Addressable/Handler/I_AddressableAddHandler.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Addressable/Handler/I_AddressableAddHandler.cs.meta new file mode 100644 index 0000000..8ced75a --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Addressable/Handler/I_AddressableAddHandler.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 46065fb3bfb094e599df0b688ed5774e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Addressable/Handler/I_AddressableGetHandler.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Addressable/Handler/I_AddressableGetHandler.cs new file mode 100644 index 0000000..f53c1f1 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Addressable/Handler/I_AddressableGetHandler.cs @@ -0,0 +1,26 @@ +using Fantasy.Async; +using Fantasy.InnerMessage; +using Fantasy.Network.Interface; + +#if FANTASY_NET +namespace Fantasy.Network.Route +{ + /// + /// 声明一个 sealed 类 I_AddressableGetHandler,继承自 RouteRPC 类,并指定泛型参数 + /// + public sealed class I_AddressableGetHandler : RouteRPC + { + /// + /// 在收到地址映射获取请求时执行的逻辑。 + /// + /// 当前场景实例。 + /// 包含请求信息的 I_AddressableGet_Request 实例。 + /// 用于构建响应的 I_AddressableGet_Response 实例。 + /// 执行响应的回调操作。 + protected override async FTask Run(Scene scene, I_AddressableGet_Request request, I_AddressableGet_Response response, Action reply) + { + response.RouteId = await scene.GetComponent().Get(request.AddressableId); + } + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Addressable/Handler/I_AddressableGetHandler.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Addressable/Handler/I_AddressableGetHandler.cs.meta new file mode 100644 index 0000000..4a92614 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Addressable/Handler/I_AddressableGetHandler.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a56b75147cb624b488dcd13c47194864 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Addressable/Handler/I_AddressableLockHandler.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Addressable/Handler/I_AddressableLockHandler.cs new file mode 100644 index 0000000..b964274 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Addressable/Handler/I_AddressableLockHandler.cs @@ -0,0 +1,26 @@ +using Fantasy.Async; +using Fantasy.InnerMessage; +using Fantasy.Network.Interface; + +#if FANTASY_NET +namespace Fantasy.Network.Route +{ + /// + /// 声明一个 sealed 类 I_AddressableLockHandler,继承自 RouteRPC 类,并指定泛型参数 + /// + public sealed class I_AddressableLockHandler : RouteRPC + { + /// + /// 在收到地址映射锁定请求时执行的逻辑。 + /// + /// 当前场景实例。 + /// 包含请求信息的 I_AddressableLock_Request 实例。 + /// 用于构建响应的 I_AddressableLock_Response 实例。 + /// 执行响应的回调操作。 + protected override async FTask Run(Scene scene, I_AddressableLock_Request request, I_AddressableLock_Response response, Action reply) + { + await scene.GetComponent().Lock(request.AddressableId); + } + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Addressable/Handler/I_AddressableLockHandler.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Addressable/Handler/I_AddressableLockHandler.cs.meta new file mode 100644 index 0000000..887c16f --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Addressable/Handler/I_AddressableLockHandler.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b21a0f316703745ab94bb0379a8abd23 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Addressable/Handler/I_AddressableRemoveHandler.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Addressable/Handler/I_AddressableRemoveHandler.cs new file mode 100644 index 0000000..c4e9654 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Addressable/Handler/I_AddressableRemoveHandler.cs @@ -0,0 +1,26 @@ +using Fantasy.Async; +using Fantasy.InnerMessage; +using Fantasy.Network.Interface; + +#if FANTASY_NET +namespace Fantasy.Network.Route +{ + /// + /// 声明一个 sealed 类 I_AddressableRemoveHandler,继承自 RouteRPC 类,并指定泛型参数 + /// + public sealed class I_AddressableRemoveHandler : RouteRPC + { + /// + /// 在收到地址映射移除请求时执行的逻辑。 + /// + /// 当前场景实例。 + /// 包含请求信息的 I_AddressableRemove_Request 实例。 + /// 用于构建响应的 I_AddressableRemove_Response 实例。 + /// 执行响应的回调操作。 + protected override async FTask Run(Scene scene, I_AddressableRemove_Request request, I_AddressableRemove_Response response, Action reply) + { + await scene.GetComponent().Remove(request.AddressableId); + } + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Addressable/Handler/I_AddressableRemoveHandler.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Addressable/Handler/I_AddressableRemoveHandler.cs.meta new file mode 100644 index 0000000..c7d830b --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Addressable/Handler/I_AddressableRemoveHandler.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f6204e4b7c87848cc8654d03e097ce2e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Addressable/Handler/I_AddressableUnLockHandler.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Addressable/Handler/I_AddressableUnLockHandler.cs new file mode 100644 index 0000000..1ab3937 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Addressable/Handler/I_AddressableUnLockHandler.cs @@ -0,0 +1,27 @@ +using Fantasy.Async; +using Fantasy.InnerMessage; +using Fantasy.Network.Interface; + +#if FANTASY_NET +namespace Fantasy.Network.Route +{ + /// + /// 声明一个 sealed 类 I_AddressableUnLockHandler,继承自 RouteRPC 类,并指定泛型参数 + /// + public sealed class I_AddressableUnLockHandler : RouteRPC + { + /// + /// 在收到地址映射解锁请求时执行的逻辑。 + /// + /// 当前场景实例。 + /// 包含请求信息的 I_AddressableUnLock_Request 实例。 + /// 用于构建响应的 I_AddressableUnLock_Response 实例。 + /// 执行响应的回调操作。 + protected override async FTask Run(Scene scene, I_AddressableUnLock_Request request, I_AddressableUnLock_Response response, Action reply) + { + scene.GetComponent().UnLock(request.AddressableId, request.RouteId, request.Source); + await FTask.CompletedTask; + } + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Addressable/Handler/I_AddressableUnLockHandler.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Addressable/Handler/I_AddressableUnLockHandler.cs.meta new file mode 100644 index 0000000..b156c14 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Addressable/Handler/I_AddressableUnLockHandler.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c95afece21cd04b708b4c29e2f639d9a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/MemoryStreamBufferPool.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/MemoryStreamBufferPool.cs new file mode 100644 index 0000000..6e6d4f7 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/MemoryStreamBufferPool.cs @@ -0,0 +1,96 @@ +using System; +using System.Collections.Generic; +using Fantasy.Serialize; +#pragma warning disable CS8603 // Possible null reference return. + +namespace Fantasy.Network +{ + /// + /// MemoryStreamBuffer对象池类 + /// + public sealed class MemoryStreamBufferPool : IDisposable + { + private readonly int _poolSize; + private readonly int _maxMemoryStreamSize; + private readonly Queue _memoryStreamPool = new Queue(); + + /// + /// 构造方法 + /// + /// + /// + public MemoryStreamBufferPool(int maxMemoryStreamSize = 2048, int poolSize = 512) + { + _poolSize = poolSize; + _maxMemoryStreamSize = maxMemoryStreamSize; + } + + /// + /// 租借MemoryStream + /// + /// + /// + /// + public MemoryStreamBuffer RentMemoryStream(MemoryStreamBufferSource memoryStreamBufferSource, int size = 0) + { + if (size > _maxMemoryStreamSize) + { + return new MemoryStreamBuffer(memoryStreamBufferSource, size); + } + + if (size < _maxMemoryStreamSize) + { + size = _maxMemoryStreamSize; + } + + if (_memoryStreamPool.Count == 0) + { + return new MemoryStreamBuffer(memoryStreamBufferSource, size); + } + + if (_memoryStreamPool.TryDequeue(out var memoryStream)) + { + memoryStream.MemoryStreamBufferSource = memoryStreamBufferSource; + return memoryStream; + } + + return new MemoryStreamBuffer(memoryStreamBufferSource, size); + } + + /// + /// 归还ReturnMemoryStream + /// + /// + public void ReturnMemoryStream(MemoryStreamBuffer memoryStreamBuffer) + { + if (memoryStreamBuffer.Capacity > _maxMemoryStreamSize) + { + return; + } + + if (_memoryStreamPool.Count > _poolSize) + { + // 设置该值只能是内网或服务器转发的时候可能在连接之前发送的数据过多的情况下可以修改。 + // 设置过大会导致内存占用过大,所以要谨慎设置。 + return; + } + + memoryStreamBuffer.SetLength(0); + memoryStreamBuffer.MemoryStreamBufferSource = MemoryStreamBufferSource.None; + _memoryStreamPool.Enqueue(memoryStreamBuffer); + } + + /// + /// 销毁方法 + /// + public void Dispose() + { + foreach (var memoryStreamBuffer in _memoryStreamPool) + { + memoryStreamBuffer.MemoryStreamBufferSource = MemoryStreamBufferSource.None; + memoryStreamBuffer.Dispose(); + } + _memoryStreamPool.Clear(); + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/MemoryStreamBufferPool.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/MemoryStreamBufferPool.cs.meta new file mode 100644 index 0000000..183c9e1 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/MemoryStreamBufferPool.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3f24c32bf558c48ff8e21e4915589cfd +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message.meta new file mode 100644 index 0000000..ba20ecf --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 2f8b2faba89c949528b8639b2b6f3aae +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/Dispatcher.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/Dispatcher.meta new file mode 100644 index 0000000..6e3bd77 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/Dispatcher.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d5aa2194ae17943c2bdef0980223e18e +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/Dispatcher/Interface.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/Dispatcher/Interface.meta new file mode 100644 index 0000000..ab43ba4 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/Dispatcher/Interface.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d4d6dc6851edd49279319bb39e3ee406 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/Dispatcher/Interface/IMessageHandler.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/Dispatcher/Interface/IMessageHandler.cs new file mode 100644 index 0000000..d8f928e --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/Dispatcher/Interface/IMessageHandler.cs @@ -0,0 +1,220 @@ +// ReSharper disable InconsistentNaming + +using System; +using System.Collections.Generic; +using Fantasy.Async; +using Fantasy.Network; +using Fantasy.Serialize; + +namespace Fantasy.Network.Interface +{ + /// + /// 表示消息处理器的接口,处理特定类型的消息。 + /// + public interface IMessageHandler + { + /// + /// 获取处理的消息类型。 + /// + /// 消息类型。 + public Type Type(); + /// + /// 处理消息的方法。 + /// + /// 会话对象。 + /// RPC标识。 + /// 消息类型代码。 + /// 要处理的消息。 + /// 异步任务。 + FTask Handle(Session session, uint rpcId, uint messageTypeCode, object message); + } + + /// + /// 泛型消息基类,实现了 接口。 + /// + public abstract class Message : IMessageHandler + { + /// + /// 获取处理的消息类型。 + /// + /// 消息类型。 + public Type Type() + { + return typeof(T); + } + + /// + /// 处理消息的方法。 + /// + /// 会话对象。 + /// RPC标识。 + /// 消息类型代码。 + /// 要处理的消息。 + /// 异步任务。 + public async FTask Handle(Session session, uint rpcId, uint messageTypeCode, object message) + { + try + { + await Run(session, (T) message); + } + catch (Exception e) + { + Log.Error(e); + } + } + + /// + /// 运行消息处理逻辑。 + /// + /// 会话对象。 + /// 要处理的消息。 + /// 异步任务。 + protected abstract FTask Run(Session session, T message); + } + + /// + /// 泛型消息RPC基类,实现了 接口,用于处理请求和响应类型的消息。 + /// + public abstract class MessageRPC : IMessageHandler where TRequest : IRequest where TResponse : AMessage, IResponse, new() + { + /// + /// 获取处理的消息类型。 + /// + /// 消息类型。 + public Type Type() + { + return typeof(TRequest); + } + + /// + /// 处理消息的方法。 + /// + /// 会话对象。 + /// RPC标识。 + /// 消息类型代码。 + /// 要处理的消息。 + /// 异步任务。 + public async FTask Handle(Session session, uint rpcId, uint messageTypeCode, object message) + { + if (message is not TRequest request) + { + Log.Error($"消息类型转换错误: {message.GetType().Name} to {typeof(TRequest).Name}"); + return; + } + + var response = new TResponse(); + var isReply = false; + + void Reply() + { + if (isReply) + { + return; + } + + isReply = true; + + if (session.IsDisposed) + { + return; + } + + session.Send(response, rpcId); + } + + try + { + await Run(session, request, response, Reply); + } + catch (Exception e) + { + Log.Error(e); + response.ErrorCode = InnerErrorCode.ErrRpcFail; + } + finally + { + Reply(); + } + } + + /// + /// 运行消息处理逻辑。 + /// + /// 会话对象。 + /// 请求消息。 + /// 响应消息。 + /// 发送响应的方法。 + /// 异步任务。 + protected abstract FTask Run(Session session, TRequest request, TResponse response, Action reply); + } +#if FANTASY_UNITY + public interface IMessageDelegateHandler + { + /// + /// 注册消息处理器。 + /// + /// + public void Register(object @delegate); + /// + /// 取消注册消息处理器。 + /// + /// + public int UnRegister(object @delegate); + /// + /// 处理消息的方法。 + /// + /// + /// + public void Handle(Session session, object message); + } + public delegate FTask MessageDelegate(Session session, T msg) where T : IMessage; + public sealed class MessageDelegateHandler : IMessageDelegateHandler, IDisposable where T : IMessage + { + private readonly List> _delegates = new List>(); + + public Type Type() + { + return typeof(T); + } + + public void Register(object @delegate) + { + var a = (MessageDelegate)@delegate; + + if (_delegates.Contains(a)) + { + Log.Error($"{typeof(T).Name} already register action delegateName:{a.Method.Name}"); + return; + } + + _delegates.Add(a); + } + + public int UnRegister(object @delegate) + { + _delegates.Remove((MessageDelegate)@delegate); + return _delegates.Count; + } + + public void Handle(Session session, object message) + { + foreach (var registerDelegate in _delegates) + { + try + { + registerDelegate(session, (T)message).Coroutine(); + } + catch (Exception e) + { + Log.Error(e); + } + } + } + + public void Dispose() + { + _delegates.Clear(); + } + } +#endif +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/Dispatcher/Interface/IMessageHandler.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/Dispatcher/Interface/IMessageHandler.cs.meta new file mode 100644 index 0000000..df81f04 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/Dispatcher/Interface/IMessageHandler.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c8d500d1bea9d477dac23323bd387d47 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/Dispatcher/Interface/IRouteMessageHandler.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/Dispatcher/Interface/IRouteMessageHandler.cs new file mode 100644 index 0000000..f027aec --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/Dispatcher/Interface/IRouteMessageHandler.cs @@ -0,0 +1,338 @@ +using Fantasy.Async; +using Fantasy.Entitas; +using Fantasy.InnerMessage; +using Fantasy.Network; +using Fantasy.Serialize; + +#if FANTASY_NET +// ReSharper disable InconsistentNaming + +namespace Fantasy.Network.Interface +{ + /// + /// 表示路由消息处理器的接口,处理特定类型的路由消息。 + /// + public interface IRouteMessageHandler + { + /// + /// 获取处理的消息类型。 + /// + /// 消息类型。 + public Type Type(); + + /// + /// 处理路由消息的方法。 + /// + /// 会话对象。 + /// 实体对象。 + /// RPC标识。 + /// 要处理的路由消息。 + /// 异步任务。 + FTask Handle(Session session, Entity entity, uint rpcId, object routeMessage); + } + + /// + /// 泛型路由基类,实现了 接口,用于处理特定实体和路由消息类型的路由。 + /// + /// 实体类型。 + /// 路由消息类型。 + public abstract class Route : IRouteMessageHandler where TEntity : Entity where TMessage : IRouteMessage + { + /// + /// 获取处理的消息类型。 + /// + /// 消息类型。 + public Type Type() + { + return typeof(TMessage); + } + + /// + /// 处理路由消息的方法。 + /// + /// 会话对象。 + /// 实体对象。 + /// RPC标识。 + /// 要处理的路由消息。 + /// 异步任务。 + public async FTask Handle(Session session, Entity entity, uint rpcId, object routeMessage) + { + if (routeMessage is not TMessage ruteMessage) + { + Log.Error($"Message type conversion error: {routeMessage.GetType().FullName} to {typeof(TMessage).Name}"); + return; + } + + if (entity is not TEntity tEntity) + { + Log.Error($"Route type conversion error: {entity.GetType().Name} to {nameof(TEntity)}"); + return; + } + + try + { + await Run(tEntity, ruteMessage); + } + catch (Exception e) + { + if (entity is not Scene scene) + { + scene = entity.Scene; + } + + Log.Error($"SceneConfigId:{session.Scene.SceneConfigId} ProcessConfigId:{scene.Process.Id} SceneType:{scene.SceneType} EntityId {tEntity.Id} : Error {e}"); + } + } + + /// + /// 运行路由消息处理逻辑。 + /// + /// 实体对象。 + /// 要处理的路由消息。 + /// 异步任务。 + protected abstract FTask Run(TEntity entity, TMessage message); + } + + /// + /// 泛型路由RPC基类,实现了 接口,用于处理请求和响应类型的路由。 + /// + /// 实体类型。 + /// 路由请求类型。 + /// 路由响应类型。 + public abstract class RouteRPC : IRouteMessageHandler where TEntity : Entity where TRouteRequest : IRouteRequest where TRouteResponse : AMessage, IRouteResponse, new() + { + /// + /// 获取处理的消息类型。 + /// + /// 消息类型。 + public Type Type() + { + return typeof(TRouteRequest); + } + + /// + /// 处理路由消息的方法。 + /// + /// 会话对象。 + /// 实体对象。 + /// RPC标识。 + /// 要处理的路由消息。 + /// 异步任务。 + public async FTask Handle(Session session, Entity entity, uint rpcId, object routeMessage) + { + if (routeMessage is not TRouteRequest tRouteRequest) + { + Log.Error($"Message type conversion error: {routeMessage.GetType().FullName} to {typeof(TRouteRequest).Name}"); + return; + } + + if (entity is not TEntity tEntity) + { + Log.Error($"Route type conversion error: {entity.GetType().Name} to {nameof(TEntity)}"); + return; + } + + var isReply = false; + var response = new TRouteResponse(); + + void Reply() + { + if (isReply) + { + return; + } + + isReply = true; + + if (session.IsDisposed) + { + return; + } + + session.Send(response, rpcId); + } + + try + { + await Run(tEntity, tRouteRequest, response, Reply); + } + catch (Exception e) + { + if (entity is not Scene scene) + { + scene = entity.Scene; + } + + Log.Error($"SceneConfigId:{session.Scene.SceneConfigId} ProcessConfigId:{scene.Process.Id} SceneType:{scene.SceneType} EntityId {tEntity.Id} : Error {e}"); + response.ErrorCode = InnerErrorCode.ErrRpcFail; + } + finally + { + Reply(); + } + } + + /// + /// 运行路由消息处理逻辑。 + /// + /// 实体对象。 + /// 请求路由消息。 + /// 响应路由消息。 + /// 发送响应的方法。 + /// 异步任务。 + protected abstract FTask Run(TEntity entity, TRouteRequest request, TRouteResponse response, Action reply); + } + + /// + /// 泛型可寻址路由基类,实现了 接口,用于处理特定实体和可寻址路由消息类型的路由。 + /// + /// 实体类型。 + /// 可寻址路由消息类型。 + public abstract class Addressable : IRouteMessageHandler where TEntity : Entity where TMessage : IAddressableRouteMessage + { + /// + /// 获取消息类型。 + /// + /// 消息类型。 + public Type Type() + { + return typeof(TMessage); + } + + /// + /// 处理可寻址路由消息。 + /// + /// 会话。 + /// 实体。 + /// RPC标识。 + /// 可寻址路由消息。 + public async FTask Handle(Session session, Entity entity, uint rpcId, object routeMessage) + { + if (routeMessage is not TMessage ruteMessage) + { + Log.Error($"Message type conversion error: {routeMessage.GetType().FullName} to {typeof(TMessage).Name}"); + return; + } + + if (entity is not TEntity tEntity) + { + Log.Error($"Route type conversion error: {entity.GetType().Name} to {nameof(TEntity)}"); + return; + } + + try + { + await Run(tEntity, ruteMessage); + } + catch (Exception e) + { + if (entity is not Scene scene) + { + scene = entity.Scene; + } + + Log.Error($"SceneConfigId:{session.Scene.SceneConfigId} ProcessConfigId:{scene.Process.Id} SceneType:{scene.SceneType} EntityId {tEntity.Id} : Error {e}"); + } + finally + { + session.Send(new RouteResponse(), rpcId); + } + } + + /// + /// 运行处理可寻址路由消息。 + /// + /// 实体。 + /// 可寻址路由消息。 + protected abstract FTask Run(TEntity entity, TMessage message); + } + + /// + /// 泛型可寻址RPC路由基类,实现了 接口,用于处理特定实体和可寻址RPC路由请求类型的路由。 + /// + /// 实体类型。 + /// 可寻址RPC路由请求类型。 + /// 可寻址RPC路由响应类型。 + public abstract class AddressableRPC : IRouteMessageHandler where TEntity : Entity where TRouteRequest : IAddressableRouteRequest where TRouteResponse : IAddressableRouteResponse, new() + { + /// + /// 获取消息类型。 + /// + /// 消息类型。 + public Type Type() + { + return typeof(TRouteRequest); + } + + /// + /// 处理可寻址RPC路由请求。 + /// + /// 会话。 + /// 实体。 + /// RPC标识。 + /// 可寻址RPC路由请求。 + public async FTask Handle(Session session, Entity entity, uint rpcId, object routeMessage) + { + if (routeMessage is not TRouteRequest tRouteRequest) + { + Log.Error($"Message type conversion error: {routeMessage.GetType().FullName} to {typeof(TRouteRequest).Name}"); + return; + } + + if (entity is not TEntity tEntity) + { + Log.Error($"Route type conversion error: {entity.GetType().Name} to {nameof(TEntity)}"); + return; + } + + var isReply = false; + var response = new TRouteResponse(); + + void Reply() + { + if (isReply) + { + return; + } + + isReply = true; + + if (session.IsDisposed) + { + return; + } + + session.Send(response, rpcId); + } + + try + { + await Run(tEntity, tRouteRequest, response, Reply); + } + catch (Exception e) + { + if (entity is not Scene scene) + { + scene = entity.Scene; + } + + Log.Error($"SceneConfigId:{session.Scene.SceneConfigId} ProcessConfigId:{scene.Process.Id} SceneType:{scene.SceneType} EntityId {tEntity.Id} : Error {e}"); + response.ErrorCode = InnerErrorCode.ErrRpcFail; + } + finally + { + Reply(); + } + } + + /// + /// 运行处理可寻址RPC路由请求。 + /// + /// 实体。 + /// 可寻址RPC路由请求。 + /// 可寻址RPC路由响应。 + /// 回复操作。 + protected abstract FTask Run(TEntity entity, TRouteRequest request, TRouteResponse response, Action reply); + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/Dispatcher/Interface/IRouteMessageHandler.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/Dispatcher/Interface/IRouteMessageHandler.cs.meta new file mode 100644 index 0000000..c019cad --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/Dispatcher/Interface/IRouteMessageHandler.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1d2e3f63e08dc406c858a416337569f7 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/Dispatcher/MessageDispatcherComponent.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/Dispatcher/MessageDispatcherComponent.cs new file mode 100644 index 0000000..c3462d6 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/Dispatcher/MessageDispatcherComponent.cs @@ -0,0 +1,427 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Fantasy.Assembly; +using Fantasy.Async; +using Fantasy.DataStructure.Collection; +using Fantasy.DataStructure.Dictionary; +using Fantasy.Entitas; +using Fantasy.InnerMessage; +using Fantasy.Network; + +#pragma warning disable CS8602 // Dereference of a possibly null reference. +#pragma warning disable CS8600 // Converting null literal or possible null value to non-nullable type. +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. + +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member +namespace Fantasy.Network.Interface +{ + /// + /// 用于存储消息处理器的信息,包括类型和对象实例。 + /// + /// 消息处理器的类型 + internal sealed class HandlerInfo + { + /// + /// 获取或设置消息处理器对象。 + /// + public T Obj; + /// + /// 获取或设置消息处理器的类型。 + /// + public Type Type; + } + + /// + /// 网络消息分发组件。 + /// + public sealed class MessageDispatcherComponent : Entity, IAssembly + { + public long AssemblyIdentity { get; set; } + private readonly Dictionary _responseTypes = new Dictionary(); + private readonly DoubleMapDictionary _networkProtocols = new DoubleMapDictionary(); + private readonly Dictionary _messageHandlers = new Dictionary(); + private readonly OneToManyList _assemblyResponseTypes = new OneToManyList(); + private readonly OneToManyList _assemblyNetworkProtocols = new OneToManyList(); + private readonly OneToManyList> _assemblyMessageHandlers = new OneToManyList>(); +#if FANTASY_UNITY + + private readonly Dictionary _messageDelegateHandlers = new Dictionary(); +#endif +#if FANTASY_NET + private readonly Dictionary _customRouteMap = new Dictionary(); + private readonly OneToManyList _assemblyCustomRouteMap = new OneToManyList(); + private readonly Dictionary _routeMessageHandlers = new Dictionary(); + private readonly OneToManyList> _assemblyRouteMessageHandlers = new OneToManyList>(); +#endif + private CoroutineLock _receiveRouteMessageLock; + + #region Initialize + + internal async FTask Initialize() + { + _receiveRouteMessageLock = Scene.CoroutineLockComponent.Create(GetType().TypeHandle.Value.ToInt64()); + await AssemblySystem.Register(this); + return this; + } + + public async FTask Load(long assemblyIdentity) + { + var tcs = FTask.Create(false); + Scene.ThreadSynchronizationContext.Post(() => + { + LoadInner(assemblyIdentity); + tcs.SetResult(); + }); + await tcs; + } + + private void LoadInner(long assemblyIdentity) + { + // 遍历所有实现了IMessage接口的类型,获取OpCode并添加到_networkProtocols字典中 + foreach (var type in AssemblySystem.ForEach(assemblyIdentity, typeof(IMessage))) + { + var obj = (IMessage) Activator.CreateInstance(type); + var opCode = obj.OpCode(); + + _networkProtocols.Add(opCode, type); + + var responseType = type.GetProperty("ResponseType"); + + // 如果类型具有ResponseType属性,将其添加到_responseTypes字典中 + if (responseType != null) + { + _responseTypes.Add(type, responseType.PropertyType); + _assemblyResponseTypes.Add(assemblyIdentity, type); + } + + _assemblyNetworkProtocols.Add(assemblyIdentity, opCode); + } + + // 遍历所有实现了IMessageHandler接口的类型,创建实例并添加到_messageHandlers字典中 + foreach (var type in AssemblySystem.ForEach(assemblyIdentity, typeof(IMessageHandler))) + { + var obj = (IMessageHandler) Activator.CreateInstance(type); + + if (obj == null) + { + throw new Exception($"message handle {type.Name} is null"); + } + + var key = obj.Type(); + _messageHandlers.Add(key, obj); + _assemblyMessageHandlers.Add(assemblyIdentity, new HandlerInfo() + { + Obj = obj, Type = key + }); + } + + // 如果编译符号FANTASY_NET存在,遍历所有实现了IRouteMessageHandler接口的类型,创建实例并添加到_routeMessageHandlers字典中 +#if FANTASY_NET + foreach (var type in AssemblySystem.ForEach(assemblyIdentity, typeof(IRouteMessageHandler))) + { + var obj = (IRouteMessageHandler) Activator.CreateInstance(type); + + if (obj == null) + { + throw new Exception($"message handle {type.Name} is null"); + } + + var key = obj.Type(); + _routeMessageHandlers.Add(key, obj); + _assemblyRouteMessageHandlers.Add(assemblyIdentity, new HandlerInfo() + { + Obj = obj, Type = key + }); + } + + foreach (var type in AssemblySystem.ForEach(assemblyIdentity, typeof(ICustomRoute))) + { + var obj = (ICustomRoute) Activator.CreateInstance(type); + + if (obj == null) + { + throw new Exception($"message handle {type.Name} is null"); + } + + var opCode = obj.OpCode(); + _customRouteMap[opCode] = obj.RouteType; + _assemblyCustomRouteMap.Add(assemblyIdentity, opCode); + } +#endif + } + + public async FTask ReLoad(long assemblyIdentity) + { + var tcs = FTask.Create(false); + Scene.ThreadSynchronizationContext.Post(() => + { + OnUnLoadInner(assemblyIdentity); + LoadInner(assemblyIdentity); + tcs.SetResult(); + }); + await tcs; + } + + public async FTask OnUnLoad(long assemblyIdentity) + { + var tcs = FTask.Create(false); + Scene.ThreadSynchronizationContext.Post(() => + { + OnUnLoadInner(assemblyIdentity); + tcs.SetResult(); + }); + await tcs; + } + + private void OnUnLoadInner(long assemblyIdentity) + { + // 移除程序集对应的ResponseType类型和OpCode信息 + if (_assemblyResponseTypes.TryGetValue(assemblyIdentity, out var removeResponseTypes)) + { + foreach (var removeResponseType in removeResponseTypes) + { + _responseTypes.Remove(removeResponseType); + } + + _assemblyResponseTypes.RemoveByKey(assemblyIdentity); + } + + if (_assemblyNetworkProtocols.TryGetValue(assemblyIdentity, out var removeNetworkProtocols)) + { + foreach (var removeNetworkProtocol in removeNetworkProtocols) + { + _networkProtocols.RemoveByKey(removeNetworkProtocol); + } + + _assemblyNetworkProtocols.RemoveByKey(assemblyIdentity); + } + + // 移除程序集对应的消息处理器信息 + if (_assemblyMessageHandlers.TryGetValue(assemblyIdentity, out var removeMessageHandlers)) + { + foreach (var removeMessageHandler in removeMessageHandlers) + { + _messageHandlers.Remove(removeMessageHandler.Type); + } + + _assemblyMessageHandlers.RemoveByKey(assemblyIdentity); + } + + // 如果编译符号FANTASY_NET存在,移除程序集对应的路由消息处理器信息 +#if FANTASY_NET + if (_assemblyRouteMessageHandlers.TryGetValue(assemblyIdentity, out var removeRouteMessageHandlers)) + { + foreach (var removeRouteMessageHandler in removeRouteMessageHandlers) + { + _routeMessageHandlers.Remove(removeRouteMessageHandler.Type); + } + + _assemblyRouteMessageHandlers.RemoveByKey(assemblyIdentity); + } + + if (_assemblyCustomRouteMap.TryGetValue(assemblyIdentity, out var removeCustomRouteMap)) + { + foreach (var removeCustom in removeCustomRouteMap) + { + _customRouteMap.Remove(removeCustom); + } + + _assemblyCustomRouteMap.RemoveByKey(assemblyIdentity); + } +#endif + } + +#if FANTASY_UNITY + /// + /// 手动注册一个消息处理器。 + /// + /// + /// + public void RegisterHandler(MessageDelegate @delegate) where T : IMessage + { + var type = typeof(T); + + if (!_messageDelegateHandlers.TryGetValue(type, out var messageDelegate)) + { + messageDelegate = new MessageDelegateHandler(); + _messageDelegateHandlers.Add(type,messageDelegate); + } + + messageDelegate.Register(@delegate); + } + + /// + /// 手动卸载一个消息处理器,必须是通过RegisterHandler方法注册的消息处理器。 + /// + /// + /// + public void UnRegisterHandler(MessageDelegate @delegate) where T : IMessage + { + var type = typeof(T); + + if (!_messageDelegateHandlers.TryGetValue(type, out var messageDelegate)) + { + return; + } + + if (messageDelegate.UnRegister(@delegate) != 0) + { + return; + } + + _messageDelegateHandlers.Remove(type); + } +#endif + + #endregion + + /// + /// 处理普通消息,将消息分发给相应的消息处理器。 + /// + /// 会话对象 + /// 消息类型 + /// 消息对象 + /// RPC标识 + /// 协议码 + public void MessageHandler(Session session, Type type, object message, uint rpcId, uint protocolCode) + { +#if FANTASY_UNITY + if(_messageDelegateHandlers.TryGetValue(type,out var messageDelegateHandler)) + { + messageDelegateHandler.Handle(session, message); + return; + } +#endif + if (!_messageHandlers.TryGetValue(type, out var messageHandler)) + { + Log.Warning($"Scene:{session.Scene.Id} Found Unhandled Message: {message.GetType()}"); + return; + } + + // 调用消息处理器的Handle方法并启动协程执行处理逻辑 + messageHandler.Handle(session, rpcId, protocolCode, message).Coroutine(); + } + + // 如果编译符号FANTASY_NET存在,定义处理路由消息的方法 +#if FANTASY_NET + /// + /// 处理路由消息,将消息分发给相应的路由消息处理器。 + /// + /// 会话对象 + /// 消息类型 + /// 实体对象 + /// 消息对象 + /// RPC标识 + public async FTask RouteMessageHandler(Session session, Type type, Entity entity, object message, uint rpcId) + { + if (!_routeMessageHandlers.TryGetValue(type, out var routeMessageHandler)) + { + Log.Warning($"Scene:{session.Scene.Id} Found Unhandled RouteMessage: {message.GetType()}"); + + if (message is IRouteRequest request) + { + FailRouteResponse(session, request.GetType(), InnerErrorCode.ErrEntityNotFound, rpcId); + } + + return; + } + + var runtimeId = entity.RuntimeId; + var sessionRuntimeId = session.RuntimeId; + + if (entity is Scene) + { + // 如果是Scene的话、就不要加锁了、如果加锁很一不小心就可能会造成死锁 + await routeMessageHandler.Handle(session, entity, rpcId, message); + return; + } + + // 使用协程锁来确保多线程安全 + using (await _receiveRouteMessageLock.Wait(runtimeId)) + { + if (sessionRuntimeId != session.RuntimeId) + { + return; + } + + if (runtimeId != entity.RuntimeId) + { + if (message is IRouteRequest request) + { + FailRouteResponse(session, request.GetType(), InnerErrorCode.ErrEntityNotFound, rpcId); + } + + return; + } + + await routeMessageHandler.Handle(session, entity, rpcId, message); + } + } + + internal bool GetCustomRouteType(long protocolCode,out int routeType) + { + return _customRouteMap.TryGetValue(protocolCode, out routeType); + } +#endif + internal void FailRouteResponse(Session session, Type requestType, uint error, uint rpcId) + { + var response = CreateRouteResponse(requestType, error); + session.Send(response, rpcId); + } + + internal IResponse CreateResponse(Type requestType, uint error) + { + IResponse response; + + if (_responseTypes.TryGetValue(requestType, out var responseType)) + { + response = (IResponse) Activator.CreateInstance(responseType); + } + else + { + response = new Response(); + } + + response.ErrorCode = error; + return response; + } + + internal IRouteResponse CreateRouteResponse(Type requestType, uint error) + { + IRouteResponse response; + + if (_responseTypes.TryGetValue(requestType, out var responseType)) + { + response = (IRouteResponse) Activator.CreateInstance(responseType); + } + else + { + response = new RouteResponse(); + } + + response.ErrorCode = error; + return response; + } + + /// + /// 根据消息类型获取对应的OpCode。 + /// + /// 消息类型 + /// 消息对应的OpCode + public uint GetOpCode(Type type) + { + return _networkProtocols.GetKeyByValue(type); + } + + /// + /// 根据OpCode获取对应的消息类型。 + /// + /// OpCode + /// OpCode对应的消息类型 + public Type GetOpCodeType(uint code) + { + return _networkProtocols.GetValueByKey(code); + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/Dispatcher/MessageDispatcherComponent.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/Dispatcher/MessageDispatcherComponent.cs.meta new file mode 100644 index 0000000..2979d9d --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/Dispatcher/MessageDispatcherComponent.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 56299d59c80c145b4b680252e4fd4202 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/IMessage.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/IMessage.cs new file mode 100644 index 0000000..704b736 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/IMessage.cs @@ -0,0 +1,83 @@ +using System; +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member + +namespace Fantasy.Network.Interface +{ + /// + /// 表示通用消息接口。 + /// + public interface IMessage + { + /// + /// 获取消息的操作代码。 + /// + /// 操作代码。 + uint OpCode(); + } + + /// + /// 表示请求消息接口。 + /// + public interface IRequest : IMessage + { + + } + + /// + /// 表示响应消息接口。 + /// + public interface IResponse : IMessage + { + /// + /// 获取或设置错误代码。 + /// + uint ErrorCode { get; set; } + } + // 普通路由消息 + /// + /// 表示普通路由消息的接口,继承自请求接口。 + /// + public interface IRouteMessage : IRequest + { + + } + + /// + /// 普通路由请求接口,继承自普通路由消息接口。 + /// + public interface IRouteRequest : IRouteMessage { } + /// + /// 普通路由响应接口,继承自响应接口。 + /// + public interface IRouteResponse : IResponse { } + // 可寻址协议 + /// + /// 表示可寻址协议的普通路由消息接口,继承自普通路由消息接口。 + /// + public interface IAddressableRouteMessage : IRouteMessage { } + /// + /// 可寻址协议的普通路由请求接口,继承自可寻址协议的普通路由消息接口。 + /// + public interface IAddressableRouteRequest : IRouteRequest { } + /// + /// 可寻址协议的普通路由响应接口,继承自普通路由响应接口。 + /// + public interface IAddressableRouteResponse : IRouteResponse { } + // 自定义Route协议 + public interface ICustomRoute : IMessage + { + int RouteType { get; } + } + /// + /// 表示自定义Route协议的普通路由消息接口,继承自普通路由消息接口。 + /// + public interface ICustomRouteMessage : IRouteMessage, ICustomRoute { } + /// + /// 自定义Route协议的普通路由请求接口,继承自自定义Route协议的普通路由消息接口。 + /// + public interface ICustomRouteRequest : IRouteRequest, ICustomRoute { } + /// + /// 自定义Route协议的普通路由响应接口,继承自普通路由响应接口。 + /// + public interface ICustomRouteResponse : IRouteResponse { } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/IMessage.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/IMessage.cs.meta new file mode 100644 index 0000000..7b9f6c6 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/IMessage.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 601b2373608f44b0eb7d4a6f8aa44ea5 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/InnerMessage.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/InnerMessage.cs new file mode 100644 index 0000000..8910a34 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/InnerMessage.cs @@ -0,0 +1,209 @@ +using Fantasy.Network.Interface; +using Fantasy.Serialize; +using ProtoBuf; + +// ReSharper disable InconsistentNaming +// ReSharper disable PropertyCanBeMadeInitOnly.Global +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member + +namespace Fantasy.InnerMessage +{ + [ProtoContract] + public sealed partial class BenchmarkMessage : AMessage, IMessage + { + public uint OpCode() + { + return Fantasy.Network.OpCode.BenchmarkMessage; + } + } + [ProtoContract] + public partial class BenchmarkRequest : AMessage, IRequest + { + public uint OpCode() + { + return Fantasy.Network.OpCode.BenchmarkRequest; + } + [ProtoIgnore] + public BenchmarkResponse ResponseType { get; set; } + [ProtoMember(1)] + public long RpcId { get; set; } + } + + [ProtoContract] + public partial class BenchmarkResponse : AMessage, IResponse + { + public uint OpCode() + { + return Fantasy.Network.OpCode.BenchmarkResponse; + } + [ProtoMember(1)] + public long RpcId { get; set; } + [ProtoMember(2)] + public uint ErrorCode { get; set; } + } + public sealed partial class Response : AMessage, IResponse + { + public uint OpCode() + { + return Fantasy.Network.OpCode.DefaultResponse; + } + [ProtoMember(1)] + public long RpcId { get; set; } + [ProtoMember(2)] + public uint ErrorCode { get; set; } + } + [ProtoContract] + public sealed partial class RouteResponse : AMessage, IRouteResponse + { + public uint OpCode() + { + return Fantasy.Network.OpCode.DefaultRouteResponse; + } + [ProtoMember(1)] + public long RpcId { get; set; } + [ProtoMember(2)] + public uint ErrorCode { get; set; } + } + [ProtoContract] + public partial class PingRequest : AMessage, IRequest + { + public uint OpCode() + { + return Fantasy.Network.OpCode.PingRequest; + } + [ProtoIgnore] + public PingResponse ResponseType { get; set; } + [ProtoMember(1)] + public long RpcId { get; set; } + } + + [ProtoContract] + public partial class PingResponse : AMessage, IResponse + { + public uint OpCode() + { + return Fantasy.Network.OpCode.PingResponse; + } + [ProtoMember(1)] + public long RpcId { get; set; } + [ProtoMember(2)] + public uint ErrorCode { get; set; } + [ProtoMember(3)] + public long Now; + } + [ProtoContract] + public partial class I_AddressableAdd_Request : AMessage, IRouteRequest + { + [ProtoIgnore] + public I_AddressableAdd_Response ResponseType { get; set; } + public uint OpCode() { return Fantasy.Network.OpCode.AddressableAddRequest; } + public long RouteTypeOpCode() { return 1; } + [ProtoMember(1)] + public long AddressableId { get; set; } + [ProtoMember(2)] + public long RouteId { get; set; } + [ProtoMember(3)] + public bool IsLock { get; set; } + } + [ProtoContract] + public partial class I_AddressableAdd_Response : AMessage, IRouteResponse + { + public uint OpCode() { return Fantasy.Network.OpCode.AddressableAddResponse; } + [ProtoMember(1)] + public uint ErrorCode { get; set; } + } + [ProtoContract] + public partial class I_AddressableGet_Request : AMessage, IRouteRequest + { + [ProtoIgnore] + public I_AddressableGet_Response ResponseType { get; set; } + public uint OpCode() { return Fantasy.Network.OpCode.AddressableGetRequest; } + public long RouteTypeOpCode() { return 1; } + [ProtoMember(1)] + public long AddressableId { get; set; } + } + [ProtoContract] + public partial class I_AddressableGet_Response : AMessage, IRouteResponse + { + public uint OpCode() { return Fantasy.Network.OpCode.AddressableGetResponse; } + [ProtoMember(2)] + public uint ErrorCode { get; set; } + [ProtoMember(1)] + public long RouteId { get; set; } + } + [ProtoContract] + public partial class I_AddressableRemove_Request : AMessage, IRouteRequest + { + [ProtoIgnore] + public I_AddressableRemove_Response ResponseType { get; set; } + public uint OpCode() { return Fantasy.Network.OpCode.AddressableRemoveRequest; } + public long RouteTypeOpCode() { return 1; } + [ProtoMember(1)] + public long AddressableId { get; set; } + } + [ProtoContract] + public partial class I_AddressableRemove_Response : AMessage, IRouteResponse + { + public uint OpCode() { return Fantasy.Network.OpCode.AddressableRemoveResponse; } + [ProtoMember(1)] + public uint ErrorCode { get; set; } + } + [ProtoContract] + public partial class I_AddressableLock_Request : AMessage, IRouteRequest + { + [ProtoIgnore] + public I_AddressableLock_Response ResponseType { get; set; } + public uint OpCode() { return Fantasy.Network.OpCode.AddressableLockRequest; } + public long RouteTypeOpCode() { return 1; } + [ProtoMember(1)] + public long AddressableId { get; set; } + } + [ProtoContract] + public partial class I_AddressableLock_Response : AMessage, IRouteResponse + { + public uint OpCode() { return Fantasy.Network.OpCode.AddressableLockResponse; } + [ProtoMember(1)] + public uint ErrorCode { get; set; } + } + [ProtoContract] + public partial class I_AddressableUnLock_Request : AMessage, IRouteRequest + { + [ProtoIgnore] + public I_AddressableUnLock_Response ResponseType { get; set; } + public uint OpCode() { return Fantasy.Network.OpCode.AddressableUnLockRequest; } + public long RouteTypeOpCode() { return 1; } + [ProtoMember(1)] + public long AddressableId { get; set; } + [ProtoMember(2)] + public long RouteId { get; set; } + [ProtoMember(3)] + public string Source { get; set; } + } + [ProtoContract] + public partial class I_AddressableUnLock_Response : AMessage, IRouteResponse + { + public uint OpCode() { return Fantasy.Network.OpCode.AddressableUnLockResponse; } + [ProtoMember(1)] + public uint ErrorCode { get; set; } + } + [ProtoContract] + public partial class LinkEntity_Request : AMessage, IRouteRequest + { + public uint OpCode() { return Fantasy.Network.OpCode.LinkEntityRequest; } + public long RouteTypeOpCode() { return 1; } + [ProtoMember(1)] + public int EntityType { get; set; } + [ProtoMember(2)] + public long RuntimeId { get; set; } + [ProtoMember(3)] + public long LinkGateSessionRuntimeId { get; set; } + } + [ProtoContract] + public partial class LinkEntity_Response : AMessage, IRouteResponse + { + public uint OpCode() { return Fantasy.Network.OpCode.LinkEntityResponse; } + [ProtoMember(1)] + public uint ErrorCode { get; set; } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/InnerMessage.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/InnerMessage.cs.meta new file mode 100644 index 0000000..4806975 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/InnerMessage.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 15efa930197b84bbf90cfc342ffe33e3 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/PacketParser.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/PacketParser.meta new file mode 100644 index 0000000..4defc49 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/PacketParser.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 56103a3dd3e924bdd9505d769cb1cc88 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/PacketParser/Handler.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/PacketParser/Handler.meta new file mode 100644 index 0000000..e2bb99d --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/PacketParser/Handler.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e0bcbd023c1f442f9b96be44fd32441a +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/PacketParser/Handler/BufferPacketParser.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/PacketParser/Handler/BufferPacketParser.cs new file mode 100644 index 0000000..e4d1540 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/PacketParser/Handler/BufferPacketParser.cs @@ -0,0 +1,386 @@ +using System; +using System.Buffers; +using System.IO; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using Fantasy.Helper; +using Fantasy.Network; +using Fantasy.Network.Interface; +using Fantasy.PacketParser.Interface; +using Fantasy.Serialize; + +// ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member + +#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. +namespace Fantasy.PacketParser +{ + /// + /// BufferPacketParser消息格式化器抽象类 + /// 这个不会用在TCP协议中、因此不用考虑分包和粘包的问题。 + /// 目前这个只会用在KCP协议中、因为KCP出来的就是一个完整的包、所以可以一次性全部解析出来。 + /// 如果是用在其他协议上可能会出现问题。 + /// + public abstract class BufferPacketParser : APacketParser + { + protected uint RpcId; + protected long RouteId; + protected uint ProtocolCode; + protected int MessagePacketLength; + public override void Dispose() + { + RpcId = 0; + RouteId = 0; + ProtocolCode = 0; + MessagePacketLength = 0; + base.Dispose(); + } + /// + /// 解包方法 + /// + /// buffer + /// count + /// packInfo + /// + public abstract bool UnPack(byte[] buffer, ref int count, out APackInfo packInfo); + } +#if FANTASY_NET + /// + /// 服务器之间专用的BufferPacketParser消息格式化器 + /// + public sealed class InnerBufferPacketParser : BufferPacketParser + { + /// + /// + /// + /// + /// + /// + /// + /// + public override unsafe bool UnPack(byte[] buffer, ref int count, out APackInfo packInfo) + { + packInfo = null; + + if (buffer.Length < count) + { + throw new ScanException($"The buffer length is less than the specified count. buffer.Length={buffer.Length} count={count}"); + } + + if (count < Packet.InnerPacketHeadLength) + { + // 如果内存资源中的数据长度小于内部消息头的长度,无法解析 + return false; + } + + fixed (byte* bufferPtr = buffer) + { + MessagePacketLength = *(int*)bufferPtr; + + if (MessagePacketLength > Packet.PacketBodyMaxLength || count < MessagePacketLength) + { + // 检查消息体长度是否超出限制 + throw new ScanException($"The received information exceeds the maximum limit = {MessagePacketLength}"); + } + + ProtocolCode = *(uint*)(bufferPtr + Packet.PacketLength); + RpcId = *(uint*)(bufferPtr + Packet.InnerPacketRpcIdLocation); + RouteId = *(long*)(bufferPtr + Packet.InnerPacketRouteRouteIdLocation); + } + + packInfo = InnerPackInfo.Create(Network); + packInfo.RpcId = RpcId; + packInfo.RouteId = RouteId; + packInfo.ProtocolCode = ProtocolCode; + packInfo.RentMemoryStream(MemoryStreamBufferSource.UnPack, count).Write(buffer, 0, count); + return true; + } + + public override MemoryStreamBuffer Pack(ref uint rpcId, ref long routeId, MemoryStreamBuffer memoryStream, IMessage message) + { + return memoryStream == null ? Pack(ref rpcId, ref routeId, message) : Pack(ref rpcId, ref routeId, memoryStream); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private unsafe MemoryStreamBuffer Pack(ref uint rpcId, ref long routeId, MemoryStreamBuffer memoryStream) + { + fixed (byte* bufferPtr = memoryStream.GetBuffer()) + { + *(uint*)(bufferPtr + Packet.InnerPacketRpcIdLocation) = rpcId; + *(long*)(bufferPtr + Packet.InnerPacketRouteRouteIdLocation) = routeId; + } + + return memoryStream; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private unsafe MemoryStreamBuffer Pack(ref uint rpcId, ref long routeId, IMessage message) + { + var memoryStreamLength = 0; + var messageType = message.GetType(); + var memoryStream = Network.MemoryStreamBufferPool.RentMemoryStream(MemoryStreamBufferSource.Pack); + OpCodeIdStruct opCodeIdStruct = message.OpCode(); + memoryStream.Seek(Packet.InnerPacketHeadLength, SeekOrigin.Begin); + + if (SerializerManager.TryGetSerializer(opCodeIdStruct.OpCodeProtocolType, out var serializer)) + { + serializer.Serialize(messageType, message, memoryStream); + memoryStreamLength = (int)memoryStream.Position; + } + else + { + Log.Error($"type:{messageType} Does not support processing protocol"); + } + + var opCode = Scene.MessageDispatcherComponent.GetOpCode(messageType); + var packetBodyCount = memoryStreamLength - Packet.InnerPacketHeadLength; + + if (packetBodyCount == 0) + { + // protoBuf做了一个优化、就是当序列化的对象里的属性和字段都为默认值的时候就不会序列化任何东西。 + // 为了TCP的分包和粘包、需要判定下是当前包数据不完整还是本应该如此、所以用-1代表。 + packetBodyCount = -1; + } + + if (packetBodyCount > Packet.PacketBodyMaxLength) + { + // 检查消息体长度是否超出限制 + throw new Exception($"Message content exceeds {Packet.PacketBodyMaxLength} bytes"); + } + + fixed (byte* bufferPtr = memoryStream.GetBuffer()) + { + *(int*)bufferPtr = packetBodyCount; + *(uint*)(bufferPtr + Packet.PacketLength) = opCode; + *(uint*)(bufferPtr + Packet.InnerPacketRpcIdLocation) = rpcId; + *(long*)(bufferPtr + Packet.InnerPacketRouteRouteIdLocation) = routeId; + } + + return memoryStream; + } + } +#endif + /// + /// 客户端和服务器之间专用的BufferPacketParser消息格式化器 + /// + public sealed class OuterBufferPacketParser : BufferPacketParser + { + /// + /// + /// + /// + /// + /// + /// + /// + public override unsafe bool UnPack(byte[] buffer, ref int count, out APackInfo packInfo) + { + packInfo = null; + + if (buffer.Length < count) + { + throw new ScanException($"The buffer length is less than the specified count. buffer.Length={buffer.Length} count={count}"); + } + + if (count < Packet.OuterPacketHeadLength) + { + // 如果内存资源中的数据长度小于内部消息头的长度,无法解析 + return false; + } + + fixed (byte* bufferPtr = buffer) + { + MessagePacketLength = *(int*)bufferPtr; + + if (MessagePacketLength > Packet.PacketBodyMaxLength || count < MessagePacketLength) + { + // 检查消息体长度是否超出限制 + throw new ScanException($"The received information exceeds the maximum limit = {MessagePacketLength}"); + } + + ProtocolCode = *(uint*)(bufferPtr + Packet.PacketLength); + RpcId = *(uint*)(bufferPtr + Packet.OuterPacketRpcIdLocation); + } + + packInfo = OuterPackInfo.Create(Network); + packInfo.RpcId = RpcId; + packInfo.ProtocolCode = ProtocolCode; + packInfo.RentMemoryStream(MemoryStreamBufferSource.UnPack, count).Write(buffer, 0, count); + return true; + } + + public override MemoryStreamBuffer Pack(ref uint rpcId, ref long routeId, MemoryStreamBuffer memoryStream, IMessage message) + { + return memoryStream == null ? Pack(ref rpcId, message) : Pack(ref rpcId, memoryStream); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private unsafe MemoryStreamBuffer Pack(ref uint rpcId, MemoryStreamBuffer memoryStream) + { + fixed (byte* bufferPtr = memoryStream.GetBuffer()) + { + *(uint*)(bufferPtr + Packet.InnerPacketRpcIdLocation) = rpcId; + } + + return memoryStream; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private unsafe MemoryStreamBuffer Pack(ref uint rpcId, IMessage message) + { + var memoryStreamLength = 0; + var messageType = message.GetType(); + var memoryStream = Network.MemoryStreamBufferPool.RentMemoryStream(MemoryStreamBufferSource.Pack); + OpCodeIdStruct opCodeIdStruct = message.OpCode(); + memoryStream.Seek(Packet.OuterPacketHeadLength, SeekOrigin.Begin); + + if (SerializerManager.TryGetSerializer(opCodeIdStruct.OpCodeProtocolType, out var serializer)) + { + serializer.Serialize(messageType, message, memoryStream); + memoryStreamLength = (int)memoryStream.Position; + } + else + { + Log.Error($"type:{messageType} Does not support processing protocol"); + } + + var opCode = Scene.MessageDispatcherComponent.GetOpCode(messageType); + var packetBodyCount = memoryStreamLength - Packet.OuterPacketHeadLength; + + if (packetBodyCount == 0) + { + // protoBuf做了一个优化、就是当序列化的对象里的属性和字段都为默认值的时候就不会序列化任何东西。 + // 为了TCP的分包和粘包、需要判定下是当前包数据不完整还是本应该如此、所以用-1代表。 + packetBodyCount = -1; + } + + if (packetBodyCount > Packet.PacketBodyMaxLength) + { + // 检查消息体长度是否超出限制 + throw new Exception($"Message content exceeds {Packet.PacketBodyMaxLength} bytes"); + } + + fixed (byte* bufferPtr = memoryStream.GetBuffer()) + { + *(int*)bufferPtr = packetBodyCount; + *(uint*)(bufferPtr + Packet.PacketLength) = opCode; + *(uint*)(bufferPtr + Packet.OuterPacketRpcIdLocation) = rpcId; + } + + return memoryStream; + } + } + /// + /// Webgl专用的客户端和服务器之间专用的BufferPacketParser消息格式化器 + /// + public sealed class OuterWebglBufferPacketParser : BufferPacketParser + { + /// + /// + /// + /// + /// + /// + /// + /// + public override bool UnPack(byte[] buffer, ref int count, out APackInfo packInfo) + { + packInfo = null; + + if (buffer.Length < count) + { + throw new ScanException($"The buffer length is less than the specified count. buffer.Length={buffer.Length} count={count}"); + } + + if (count < Packet.OuterPacketHeadLength) + { + // 如果内存资源中的数据长度小于内部消息头的长度,无法解析 + return false; + } + + MessagePacketLength = BitConverter.ToInt32(buffer, 0); + + if (MessagePacketLength > Packet.PacketBodyMaxLength || count < MessagePacketLength) + { + // 检查消息体长度是否超出限制 + throw new ScanException($"The received information exceeds the maximum limit = {MessagePacketLength}"); + } + + ProtocolCode = BitConverter.ToUInt32(buffer, Packet.PacketLength); + RpcId = BitConverter.ToUInt32(buffer, Packet.OuterPacketRpcIdLocation); + + packInfo = OuterPackInfo.Create(Network); + packInfo.RpcId = RpcId; + packInfo.ProtocolCode = ProtocolCode; + packInfo.RentMemoryStream(MemoryStreamBufferSource.UnPack, count).Write(buffer, 0, count); + return true; + } + + public override MemoryStreamBuffer Pack(ref uint rpcId, ref long routeId, MemoryStreamBuffer memoryStream, IMessage message) + { + return memoryStream == null ? Pack(ref rpcId, message) : Pack(ref rpcId, memoryStream); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private MemoryStreamBuffer Pack(ref uint rpcId, MemoryStreamBuffer memoryStream) + { + var buffer = memoryStream.GetBuffer().AsSpan(); +#if FANTASY_NET + MemoryMarshal.Write(buffer.Slice(Packet.OuterPacketRpcIdLocation, sizeof(uint)), in rpcId); +#endif +#if FANTASY_UNITY + MemoryMarshal.Write(buffer.Slice(Packet.OuterPacketRpcIdLocation, sizeof(uint)), ref rpcId); +#endif + return memoryStream; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private MemoryStreamBuffer Pack(ref uint rpcId, IMessage message) + { + var memoryStreamLength = 0; + var messageType = message.GetType(); + var memoryStream = Network.MemoryStreamBufferPool.RentMemoryStream(MemoryStreamBufferSource.UnPack); + OpCodeIdStruct opCodeIdStruct = message.OpCode(); + memoryStream.Seek(Packet.OuterPacketHeadLength, SeekOrigin.Begin); + + if (SerializerManager.TryGetSerializer(opCodeIdStruct.OpCodeProtocolType, out var serializer)) + { + serializer.Serialize(messageType, message, memoryStream); + memoryStreamLength = (int)memoryStream.Position; + } + else + { + Log.Error($"type:{messageType} Does not support processing protocol"); + } + + var opCode = Scene.MessageDispatcherComponent.GetOpCode(messageType); + var packetBodyCount = memoryStreamLength - Packet.OuterPacketHeadLength; + + if (packetBodyCount == 0) + { + // protoBuf做了一个优化、就是当序列化的对象里的属性和字段都为默认值的时候就不会序列化任何东西。 + // 为了TCP的分包和粘包、需要判定下是当前包数据不完整还是本应该如此、所以用-1代表。 + packetBodyCount = -1; + } + + if (packetBodyCount > Packet.PacketBodyMaxLength) + { + // 检查消息体长度是否超出限制 + throw new Exception($"Message content exceeds {Packet.PacketBodyMaxLength} bytes"); + } + + var buffer = memoryStream.GetBuffer().AsSpan(); +#if FANTASY_NET + MemoryMarshal.Write(buffer, in packetBodyCount); + MemoryMarshal.Write(buffer.Slice(Packet.PacketLength, sizeof(uint)), in opCode); + MemoryMarshal.Write(buffer.Slice(Packet.OuterPacketRpcIdLocation, sizeof(uint)), in rpcId); +#endif +#if FANTASY_UNITY + MemoryMarshal.Write(buffer, ref packetBodyCount); + MemoryMarshal.Write(buffer.Slice(Packet.PacketLength, sizeof(uint)), ref opCode); + MemoryMarshal.Write(buffer.Slice(Packet.OuterPacketRpcIdLocation, sizeof(uint)), ref rpcId); +#endif + return memoryStream; + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/PacketParser/Handler/BufferPacketParser.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/PacketParser/Handler/BufferPacketParser.cs.meta new file mode 100644 index 0000000..32698e5 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/PacketParser/Handler/BufferPacketParser.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0967856d30d1f464b82d88330920914a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/PacketParser/Handler/CircularBufferPacketParser.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/PacketParser/Handler/CircularBufferPacketParser.cs new file mode 100644 index 0000000..24c368b --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/PacketParser/Handler/CircularBufferPacketParser.cs @@ -0,0 +1,170 @@ +// using System.Runtime.CompilerServices; +// // ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract +// #pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. +// +// namespace Fantasy +// { +// // 这个对处理分包和粘包逻辑不完整、考虑现在没有任何地方使用了、就先不修改了。 +// // 后面用到了再修改、现在这个只是留做备份、万一以后用到了呢。 +// public abstract class CircularBufferPacketParser : APacketParser +// { +// protected uint RpcId; +// protected long RouteId; +// protected uint ProtocolCode; +// protected int MessagePacketLength; +// protected bool IsUnPackHead = true; +// protected readonly byte[] MessageHead = new byte[Packet.InnerPacketHeadLength]; +// public abstract bool UnPack(CircularBuffer buffer, out APackInfo packInfo); +// } +// +// #if FANTASY_NET +// public sealed class InnerCircularBufferPacketParser : CircularBufferPacketParser, IInnerPacketParser +// { +// public override bool UnPack(CircularBuffer buffer, out APackInfo packInfo) +// { +// packInfo = null; +// +// // 在对象没有被释放的情况下循环解析数据 +// while (!IsDisposed) +// { +// if (IsUnPackHead) +// { +// // 如果缓冲区中的数据长度小于内部消息头的长度,无法解析 +// if (buffer.Length < Packet.InnerPacketHeadLength) +// { +// return false; +// } +// +// // 从缓冲区中读取内部消息头的数据 +// _ = buffer.Read(MessageHead, 0, Packet.InnerPacketHeadLength); +// MessagePacketLength = BitConverter.ToInt32(MessageHead, 0); +// +// // 检查消息体长度是否超出限制 +// if (MessagePacketLength > Packet.PacketBodyMaxLength) +// { +// throw new ScanException( +// $"The received information exceeds the maximum limit = {MessagePacketLength}"); +// } +// +// // 解析协议编号、RPC ID 和 Route ID +// ProtocolCode = BitConverter.ToUInt32(MessageHead, Packet.PacketLength); +// RpcId = BitConverter.ToUInt32(MessageHead, Packet.InnerPacketRpcIdLocation); +// RouteId = BitConverter.ToInt64(MessageHead, Packet.InnerPacketRouteRouteIdLocation); +// IsUnPackHead = false; +// } +// +// try +// { +// // 如果缓冲区中的数据长度小于消息体的长度,无法解析 +// if (MessagePacketLength < 0 || buffer.Length < MessagePacketLength) +// { +// return false; +// } +// +// IsUnPackHead = true; +// packInfo = InnerPackInfo.Create(Network); +// var memoryStream = packInfo.RentMemoryStream(MessagePacketLength); +// memoryStream.SetLength(MessagePacketLength); +// buffer.Read(memoryStream, MessagePacketLength); +// packInfo.RpcId = RpcId; +// packInfo.RouteId = RouteId; +// packInfo.ProtocolCode = ProtocolCode; +// packInfo.MessagePacketLength = MessagePacketLength; +// return true; +// } +// catch (Exception e) +// { +// // 在发生异常时,释放 packInfo 并记录日志 +// packInfo?.Dispose(); +// Log.Error(e); +// return false; +// } +// } +// +// return false; +// } +// +// public override MemoryStream Pack(ref uint rpcId, ref long routeTypeOpCode, ref long routeId, +// MemoryStream memoryStream, object message) +// { +// return memoryStream == null +// ? Pack(ref rpcId, ref routeId, message) +// : Pack(ref rpcId, ref routeId, memoryStream); +// } +// +// [MethodImpl(MethodImplOptions.AggressiveInlining)] +// private unsafe MemoryStream Pack(ref uint rpcId, ref long routeId, MemoryStream memoryStream) +// { +// var buffer = memoryStream.GetBuffer(); +// +// fixed (byte* bufferPtr = buffer) +// { +// var rpcIdPtr = bufferPtr + Packet.InnerPacketRpcIdLocation; +// var routeIdPtr = bufferPtr + Packet.InnerPacketRouteRouteIdLocation; +// *(uint*)rpcIdPtr = rpcId; +// *(long*)routeIdPtr = routeId; +// } +// +// memoryStream.Seek(0, SeekOrigin.Begin); +// return memoryStream; +// } +// +// [MethodImpl(MethodImplOptions.AggressiveInlining)] +// private unsafe MemoryStream Pack(ref uint rpcId, ref long routeId, object message) +// { +// var memoryStream = Network.RentMemoryStream(); +// memoryStream.Seek(Packet.InnerPacketHeadLength, SeekOrigin.Begin); +// +// switch (message) +// { +// case IBsonMessage: +// { +// MongoHelper.SerializeTo(message, memoryStream); +// break; +// } +// default: +// { +// ProtoBuffHelper.ToStream(message, memoryStream); +// break; +// } +// } +// +// var opCode = Scene.MessageDispatcherComponent.GetOpCode(message.GetType()); +// var packetBodyCount = (int)(memoryStream.Position - Packet.InnerPacketHeadLength); +// +// if (packetBodyCount == 0) +// { +// // protoBuf做了一个优化、就是当序列化的对象里的属性和字段都为默认值的时候就不会序列化任何东西。 +// // 为了TCP的分包和粘包、需要判定下是当前包数据不完整还是本应该如此、所以用-1代表。 +// packetBodyCount = -1; +// } +// +// // 检查消息体长度是否超出限制 +// if (packetBodyCount > Packet.PacketBodyMaxLength) +// { +// throw new Exception($"Message content exceeds {Packet.PacketBodyMaxLength} bytes"); +// } +// +// var buffer = memoryStream.GetBuffer(); +// +// fixed (byte* bufferPtr = buffer) +// { +// var opCodePtr = bufferPtr + Packet.PacketLength; +// var rpcIdPtr = bufferPtr + Packet.InnerPacketRpcIdLocation; +// var routeIdPtr = bufferPtr + Packet.InnerPacketRouteRouteIdLocation; +// *(int*)bufferPtr = packetBodyCount; +// *(uint*)opCodePtr = opCode; +// *(uint*)rpcIdPtr = rpcId; +// *(long*)routeIdPtr = routeId; +// } +// +// memoryStream.Seek(0, SeekOrigin.Begin); +// return memoryStream; +// } +// } +// #endif +// } +// +// +// +// diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/PacketParser/Handler/CircularBufferPacketParser.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/PacketParser/Handler/CircularBufferPacketParser.cs.meta new file mode 100644 index 0000000..375b2d6 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/PacketParser/Handler/CircularBufferPacketParser.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: be4359634faca4ed99469ac0078203f3 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/PacketParser/Handler/OuterBufferPacketParserHelper.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/PacketParser/Handler/OuterBufferPacketParserHelper.cs new file mode 100644 index 0000000..a6e66ca --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/PacketParser/Handler/OuterBufferPacketParserHelper.cs @@ -0,0 +1,72 @@ +#if FANTASY_NET +using System.Runtime.CompilerServices; +using Fantasy.Helper; +using Fantasy.Network; +using Fantasy.Network.Interface; +using Fantasy.Serialize; + +namespace Fantasy.PacketParser +{ + /// + /// 打包Outer消息的帮助类 + /// + public static class OuterBufferPacketParserHelper + { + /// + /// 打包一个网络消息 + /// + /// scene + /// 如果是RPC消息需要传递一个rpcId + /// 打包的网络消息 + /// 序列化后流的长度 + /// 打包完成会返回一个MemoryStreamBuffer + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe MemoryStreamBuffer Pack(Scene scene, uint rpcId, IMessage message, out int memoryStreamLength) + { + memoryStreamLength = 0; + var messageType = message.GetType(); + var memoryStream = new MemoryStreamBuffer(); + memoryStream.MemoryStreamBufferSource = MemoryStreamBufferSource.Pack; + OpCodeIdStruct opCodeIdStruct = message.OpCode(); + memoryStream.Seek(Packet.OuterPacketHeadLength, SeekOrigin.Begin); + + if (SerializerManager.TryGetSerializer(opCodeIdStruct.OpCodeProtocolType, out var serializer)) + { + serializer.Serialize(messageType, message, memoryStream); + memoryStreamLength = (int)memoryStream.Position; + } + else + { + Log.Error($"type:{messageType} Does not support processing protocol"); + } + + var opCode = scene.MessageDispatcherComponent.GetOpCode(messageType); + var packetBodyCount = memoryStreamLength - Packet.OuterPacketHeadLength; + + if (packetBodyCount == 0) + { + // protoBuf做了一个优化、就是当序列化的对象里的属性和字段都为默认值的时候就不会序列化任何东西。 + // 为了TCP的分包和粘包、需要判定下是当前包数据不完整还是本应该如此、所以用-1代表。 + packetBodyCount = -1; + } + + if (packetBodyCount > Packet.PacketBodyMaxLength) + { + // 检查消息体长度是否超出限制 + throw new Exception($"Message content exceeds {Packet.PacketBodyMaxLength} bytes"); + } + + fixed (byte* bufferPtr = memoryStream.GetBuffer()) + { + *(int*)bufferPtr = packetBodyCount; + *(uint*)(bufferPtr + Packet.PacketLength) = opCode; + *(uint*)(bufferPtr + Packet.OuterPacketRpcIdLocation) = rpcId; + } + + return memoryStream; + } + } +} + +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/PacketParser/Handler/OuterBufferPacketParserHelper.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/PacketParser/Handler/OuterBufferPacketParserHelper.cs.meta new file mode 100644 index 0000000..0a0785e --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/PacketParser/Handler/OuterBufferPacketParserHelper.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d0d3a0cf7619f4a1db394e6dc0d8a089 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/PacketParser/Handler/ReadOnlyMemoryPacketParser.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/PacketParser/Handler/ReadOnlyMemoryPacketParser.cs new file mode 100644 index 0000000..758ec17 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/PacketParser/Handler/ReadOnlyMemoryPacketParser.cs @@ -0,0 +1,357 @@ +using System; +using System.IO; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using Fantasy.Helper; +using Fantasy.Network; +using Fantasy.Network.Interface; +using Fantasy.PacketParser.Interface; +using Fantasy.Serialize; + +// ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. +#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. + +namespace Fantasy.PacketParser +{ + internal abstract class ReadOnlyMemoryPacketParser : APacketParser + { + /// + /// 一个网络消息包 + /// + protected APackInfo PackInfo; + + protected int Offset; + protected int MessageHeadOffset; + protected int MessageBodyOffset; + protected int MessagePacketLength; + protected bool IsUnPackHead = true; + protected readonly byte[] MessageHead = new byte[20]; + public ReadOnlyMemoryPacketParser() { } + + public abstract bool UnPack(ref ReadOnlyMemory buffer, out APackInfo packInfo); + + public override void Dispose() + { + Offset = 0; + MessageHeadOffset = 0; + MessageBodyOffset = 0; + MessagePacketLength = 0; + IsUnPackHead = true; + PackInfo = null; + Array.Clear(MessageHead, 0, 20); + base.Dispose(); + } + } + +#if FANTASY_NET + internal sealed class InnerReadOnlyMemoryPacketParser : ReadOnlyMemoryPacketParser + { + public override unsafe bool UnPack(ref ReadOnlyMemory buffer, out APackInfo packInfo) + { + packInfo = null; + var readOnlySpan = buffer.Span; + var bufferLength = buffer.Length - Offset; + + if (bufferLength == 0) + { + // 没有剩余的数据需要处理、等待下一个包再处理。 + Offset = 0; + return false; + } + + if (IsUnPackHead) + { + fixed (byte* bufferPtr = readOnlySpan) + fixed (byte* messagePtr = MessageHead) + { + // 在当前buffer中拿到包头的数据 + var innerPacketHeadLength = Packet.InnerPacketHeadLength - MessageHeadOffset; + var copyLength = Math.Min(bufferLength, innerPacketHeadLength); + Buffer.MemoryCopy(bufferPtr + Offset, messagePtr + MessageHeadOffset, innerPacketHeadLength, copyLength); + Offset += copyLength; + MessageHeadOffset += copyLength; + // 检查是否有完整包头 + if (MessageHeadOffset == Packet.InnerPacketHeadLength) + { + // 通过指针直接读取协议编号、messagePacketLength protocolCode rpcId routeId + MessagePacketLength = *(int*)messagePtr; + // 检查消息体长度是否超出限制 + if (MessagePacketLength > Packet.PacketBodyMaxLength) + { + throw new ScanException($"The received information exceeds the maximum limit = {MessagePacketLength}"); + } + + PackInfo = InnerPackInfo.Create(Network); + var memoryStream = PackInfo.RentMemoryStream(MemoryStreamBufferSource.UnPack, Packet.InnerPacketHeadLength + MessagePacketLength); + PackInfo.RpcId = *(uint*)(messagePtr + Packet.InnerPacketRpcIdLocation); + PackInfo.ProtocolCode = *(uint*)(messagePtr + Packet.PacketLength); + PackInfo.RouteId = *(long*)(messagePtr + Packet.InnerPacketRouteRouteIdLocation); + memoryStream.Write(MessageHead); + IsUnPackHead = false; + bufferLength -= copyLength; + MessageHeadOffset = 0; + } + else + { + Offset = 0; + return false; + } + } + } + + if (MessagePacketLength == -1) + { + // protoBuf做了一个优化、就是当序列化的对象里的属性和字段都为默认值的时候就不会序列化任何东西。 + // 为了TCP的分包和粘包、需要判定下是当前包数据不完整还是本应该如此、所以用-1代表。 + packInfo = PackInfo; + PackInfo = null; + IsUnPackHead = true; + return true; + } + + if (bufferLength == 0) + { + // 没有剩余的数据需要处理、等待下一个包再处理。 + Offset = 0; + return false; + } + + // 处理包消息体 + var innerPacketBodyLength = MessagePacketLength - MessageBodyOffset; + var copyBodyLength = Math.Min(bufferLength, innerPacketBodyLength); + // 写入数据到消息体中 + PackInfo.MemoryStream.Write(readOnlySpan.Slice(Offset, copyBodyLength)); + Offset += copyBodyLength; + MessageBodyOffset += copyBodyLength; + // 检查是否是完整的消息体 + if (MessageBodyOffset == MessagePacketLength) + { + packInfo = PackInfo; + PackInfo = null; + IsUnPackHead = true; + MessageBodyOffset = 0; + return true; + } + Offset = 0; + return false; + } + + public override MemoryStreamBuffer Pack(ref uint rpcId, ref long routeId, MemoryStreamBuffer memoryStream, IMessage message) + { + return memoryStream == null ? Pack(ref rpcId, ref routeId, message) : Pack(ref rpcId, ref routeId, memoryStream); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private unsafe MemoryStreamBuffer Pack(ref uint rpcId, ref long routeId, MemoryStreamBuffer memoryStream) + { + fixed (byte* bufferPtr = memoryStream.GetBuffer()) + { + *(uint*)(bufferPtr + Packet.InnerPacketRpcIdLocation) = rpcId; + *(long*)(bufferPtr + Packet.InnerPacketRouteRouteIdLocation) = routeId; + } + + return memoryStream; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private unsafe MemoryStreamBuffer Pack(ref uint rpcId, ref long routeId, IMessage message) + { + var memoryStreamLength = 0; + var messageType = message.GetType(); + var memoryStream = Network.MemoryStreamBufferPool.RentMemoryStream(MemoryStreamBufferSource.Pack); + OpCodeIdStruct opCodeIdStruct = message.OpCode(); + memoryStream.Seek(Packet.InnerPacketHeadLength, SeekOrigin.Begin); + + if (SerializerManager.TryGetSerializer(opCodeIdStruct.OpCodeProtocolType, out var serializer)) + { + serializer.Serialize(messageType, message, memoryStream); + memoryStreamLength = (int)memoryStream.Position; + } + else + { + Log.Error($"type:{messageType} Does not support processing protocol"); + } + + var opCode = Scene.MessageDispatcherComponent.GetOpCode(messageType); + var packetBodyCount = memoryStreamLength - Packet.InnerPacketHeadLength; + + if (packetBodyCount == 0) + { + // protoBuf做了一个优化、就是当序列化的对象里的属性和字段都为默认值的时候就不会序列化任何东西。 + // 为了TCP的分包和粘包、需要判定下是当前包数据不完整还是本应该如此、所以用-1代表。 + // 其实可以不用设置-1、解包的时候判断如果是0也可以、但我仔细想了下,还是用-1代表更加清晰。 + packetBodyCount = -1; + } + + if (packetBodyCount > Packet.PacketBodyMaxLength) + { + // 检查消息体长度是否超出限制 + throw new Exception($"Message content exceeds {Packet.PacketBodyMaxLength} bytes"); + } + + fixed (byte* bufferPtr = memoryStream.GetBuffer()) + { + *(int*)bufferPtr = packetBodyCount; + *(uint*)(bufferPtr + Packet.PacketLength) = opCode; + *(uint*)(bufferPtr + Packet.InnerPacketRpcIdLocation) = rpcId; + *(long*)(bufferPtr + Packet.InnerPacketRouteRouteIdLocation) = routeId; + } + + return memoryStream; + } + } +#endif + internal sealed class OuterReadOnlyMemoryPacketParser : ReadOnlyMemoryPacketParser + { + public override unsafe bool UnPack(ref ReadOnlyMemory buffer, out APackInfo packInfo) + { + packInfo = null; + var readOnlySpan = buffer.Span; + var bufferLength = buffer.Length - Offset; + + if (bufferLength == 0) + { + // 没有剩余的数据需要处理、等待下一个包再处理。 + Offset = 0; + return false; + } + + if (IsUnPackHead) + { + fixed (byte* bufferPtr = readOnlySpan) + fixed (byte* messagePtr = MessageHead) + { + // 在当前buffer中拿到包头的数据 + var outerPacketHeadLength = Packet.OuterPacketHeadLength - MessageHeadOffset; + var copyLength = Math.Min(bufferLength, outerPacketHeadLength); + Buffer.MemoryCopy(bufferPtr + Offset, messagePtr + MessageHeadOffset, outerPacketHeadLength, copyLength); + Offset += copyLength; + MessageHeadOffset += copyLength; + // 检查是否有完整包头 + if (MessageHeadOffset == Packet.OuterPacketHeadLength) + { + // 通过指针直接读取协议编号、messagePacketLength protocolCode rpcId routeId + MessagePacketLength = *(int*)messagePtr; + // 检查消息体长度是否超出限制 + if (MessagePacketLength > Packet.PacketBodyMaxLength) + { + throw new ScanException($"The received information exceeds the maximum limit = {MessagePacketLength}"); + } + + PackInfo = OuterPackInfo.Create(Network); + PackInfo.ProtocolCode = *(uint*)(messagePtr + Packet.PacketLength); + PackInfo.RpcId = *(uint*)(messagePtr + Packet.OuterPacketRpcIdLocation); + var memoryStream = PackInfo.RentMemoryStream(MemoryStreamBufferSource.UnPack, Packet.OuterPacketHeadLength + MessagePacketLength); + memoryStream.Write(MessageHead); + IsUnPackHead = false; + bufferLength -= copyLength; + MessageHeadOffset = 0; + } + else + { + Offset = 0; + return false; + } + } + } + + if (MessagePacketLength == -1) + { + // protoBuf做了一个优化、就是当序列化的对象里的属性和字段都为默认值的时候就不会序列化任何东西。 + // 为了TCP的分包和粘包、需要判定下是当前包数据不完整还是本应该如此、所以用-1代表。 + packInfo = PackInfo; + PackInfo = null; + IsUnPackHead = true; + return true; + } + + if (bufferLength == 0) + { + // 没有剩余的数据需要处理、等待下一个包再处理。 + Offset = 0; + return false; + } + // 处理包消息体 + var outerPacketBodyLength = MessagePacketLength - MessageBodyOffset; + var copyBodyLength = Math.Min(bufferLength, outerPacketBodyLength); + // 写入数据到消息体中 + PackInfo.MemoryStream.Write(readOnlySpan.Slice(Offset, copyBodyLength)); + Offset += copyBodyLength; + MessageBodyOffset += copyBodyLength; + // 检查是否是完整的消息体 + if (MessageBodyOffset == MessagePacketLength) + { + packInfo = PackInfo; + PackInfo = null; + IsUnPackHead = true; + MessageBodyOffset = 0; + return true; + } + + Offset = 0; + return false; + } + + public override MemoryStreamBuffer Pack(ref uint rpcId, ref long routeId, MemoryStreamBuffer memoryStream, IMessage message) + { + return memoryStream == null ? Pack(ref rpcId, message) : Pack(ref rpcId, memoryStream); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private unsafe MemoryStreamBuffer Pack(ref uint rpcId, MemoryStreamBuffer memoryStream) + { + fixed (byte* bufferPtr = memoryStream.GetBuffer()) + { + *(uint*)(bufferPtr + Packet.OuterPacketRpcIdLocation) = rpcId; + } + + return memoryStream; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private unsafe MemoryStreamBuffer Pack(ref uint rpcId, IMessage message) + { + var memoryStreamLength = 0; + var messageType = message.GetType(); + var memoryStream = Network.MemoryStreamBufferPool.RentMemoryStream(MemoryStreamBufferSource.Pack); + OpCodeIdStruct opCodeIdStruct = message.OpCode(); + memoryStream.Seek(Packet.OuterPacketHeadLength, SeekOrigin.Begin); + + if (SerializerManager.TryGetSerializer(opCodeIdStruct.OpCodeProtocolType, out var serializer)) + { + serializer.Serialize(messageType, message, memoryStream); + memoryStreamLength = (int)memoryStream.Position; + } + else + { + Log.Error($"type:{messageType} Does not support processing protocol"); + } + + var opCode = Scene.MessageDispatcherComponent.GetOpCode(messageType); + var packetBodyCount = memoryStreamLength - Packet.OuterPacketHeadLength; + + if (packetBodyCount == 0) + { + // protoBuf做了一个优化、就是当序列化的对象里的属性和字段都为默认值的时候就不会序列化任何东西。 + // 为了TCP的分包和粘包、需要判定下是当前包数据不完整还是本应该如此、所以用-1代表。 + packetBodyCount = -1; + } + + if (packetBodyCount > Packet.PacketBodyMaxLength) + { + // 检查消息体长度是否超出限制 + throw new Exception($"Message content exceeds {Packet.PacketBodyMaxLength} bytes"); + } + + fixed (byte* bufferPtr = memoryStream.GetBuffer()) + { + *(int*)bufferPtr = packetBodyCount; + *(uint*)(bufferPtr + Packet.PacketLength) = opCode; + *(uint*)(bufferPtr + Packet.OuterPacketRpcIdLocation) = rpcId; + } + + return memoryStream; + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/PacketParser/Handler/ReadOnlyMemoryPacketParser.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/PacketParser/Handler/ReadOnlyMemoryPacketParser.cs.meta new file mode 100644 index 0000000..cfa37d9 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/PacketParser/Handler/ReadOnlyMemoryPacketParser.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ba02e3545888e431f896b40c391db7a8 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/PacketParser/Interface.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/PacketParser/Interface.meta new file mode 100644 index 0000000..815a8cf --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/PacketParser/Interface.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: c6a95f4bea72e435fba91ccf6f77883f +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/PacketParser/Interface/APackInfo.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/PacketParser/Interface/APackInfo.cs new file mode 100644 index 0000000..1ea6d6b --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/PacketParser/Interface/APackInfo.cs @@ -0,0 +1,61 @@ +using System; +using System.IO; +using Fantasy.Network; +using Fantasy.Network.Interface; +using Fantasy.Serialize; + +// ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. +#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member + +namespace Fantasy.PacketParser.Interface +{ + public abstract class APackInfo : IDisposable + { + internal ANetwork Network; + + public uint RpcId; + public long RouteId; + public long PackInfoId; + public bool IsDisposed; + private uint _protocolCode; + + public uint ProtocolCode + { + get => _protocolCode; + set + { + _protocolCode = value; + OpCodeIdStruct = value; + } + } + public OpCodeIdStruct OpCodeIdStruct { get; private set; } + public MemoryStreamBuffer MemoryStream { get; protected set; } + public abstract object Deserialize(Type messageType); + public abstract MemoryStreamBuffer RentMemoryStream(MemoryStreamBufferSource memoryStreamBufferSource, int size = 0); + public virtual void Dispose() + { + if (IsDisposed) + { + return; + } + + RpcId = 0; + RouteId = 0; + PackInfoId = 0; + ProtocolCode = 0; + _protocolCode = 0; + OpCodeIdStruct = default; + + if (MemoryStream != null) + { + Network.MemoryStreamBufferPool.ReturnMemoryStream(MemoryStream); + MemoryStream = null; + } + + IsDisposed = true; + Network = null; + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/PacketParser/Interface/APackInfo.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/PacketParser/Interface/APackInfo.cs.meta new file mode 100644 index 0000000..41d0927 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/PacketParser/Interface/APackInfo.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0cb78fb80aac6490cb0fde6f38195b3b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/PacketParser/Interface/APacketParser.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/PacketParser/Interface/APacketParser.cs new file mode 100644 index 0000000..579cf6f --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/PacketParser/Interface/APacketParser.cs @@ -0,0 +1,30 @@ +using System; +using System.Buffers; +using System.IO; +using Fantasy.Network.Interface; +using Fantasy.Serialize; + +#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member + +namespace Fantasy.PacketParser.Interface +{ + /// + /// 抽象的包解析器基类,用于解析网络通信数据包。 + /// + public abstract class APacketParser : IDisposable + { + internal Scene Scene; + internal ANetwork Network; + internal MessageDispatcherComponent MessageDispatcherComponent; + protected bool IsDisposed { get; private set; } + public abstract MemoryStreamBuffer Pack(ref uint rpcId, ref long routeId, MemoryStreamBuffer memoryStream, IMessage message); + public virtual void Dispose() + { + IsDisposed = true; + Scene = null; + MessageDispatcherComponent = null; + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/PacketParser/Interface/APacketParser.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/PacketParser/Interface/APacketParser.cs.meta new file mode 100644 index 0000000..e1bbd00 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/PacketParser/Interface/APacketParser.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b61358c7f6d9f4b58a26d9a57b79ba45 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/PacketParser/OpCode.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/PacketParser/OpCode.cs new file mode 100644 index 0000000..d02105d --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/PacketParser/OpCode.cs @@ -0,0 +1,106 @@ +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member +namespace Fantasy.Network +{ + public struct OpCodeIdStruct + { + // OpCodeIdStruct:5 + 4 + 23 = 32 + // +---------------------------+---------------------------------+-----------------------------+ + // | OpCodeType(5) 最多31种类型 | Protocol(4) 最多15种不同的网络协议 | Index(23) 最多8388607个协议 | + // +---------------------------+---------------------------------+-----------------------------+ + public uint OpCodeProtocolType { get; private set; } + public uint Protocol { get; private set; } + public uint Index { get; private set; } + + public OpCodeIdStruct(uint opCodeProtocolType, uint protocol, uint index) + { + OpCodeProtocolType = opCodeProtocolType; + Protocol = protocol; + Index = index; + } + + public static implicit operator uint(OpCodeIdStruct opCodeIdStruct) + { + var result = opCodeIdStruct.Index; + result |= opCodeIdStruct.OpCodeProtocolType << 23; + result |= opCodeIdStruct.Protocol << 27; + return result; + } + + public static implicit operator OpCodeIdStruct(uint opCodeId) + { + var opCodeIdStruct = new OpCodeIdStruct() + { + Index = opCodeId & 0x7FFFFF + }; + opCodeId >>= 23; + opCodeIdStruct.OpCodeProtocolType = opCodeId & 0xF; + opCodeId >>= 4; + opCodeIdStruct.Protocol = opCodeId & 0x1F; + return opCodeIdStruct; + } + } + + public static class OpCodeProtocolType + { + public const uint Bson = 1; + public const uint ProtoBuf = 0; + } + + public static class OpCodeType + { + public const uint OuterMessage = 1; + public const uint OuterRequest = 2; + public const uint OuterResponse = 3; + + public const uint InnerMessage = 4; + public const uint InnerRequest = 5; + public const uint InnerResponse = 6; + + public const uint InnerRouteMessage = 7; + public const uint InnerRouteRequest = 8; + public const uint InnerRouteResponse = 9; + + public const uint OuterAddressableMessage = 10; + public const uint OuterAddressableRequest = 11; + public const uint OuterAddressableResponse = 12; + + public const uint InnerAddressableMessage = 13; + public const uint InnerAddressableRequest = 14; + public const uint InnerAddressableResponse = 15; + + public const uint OuterCustomRouteMessage = 16; + public const uint OuterCustomRouteRequest = 17; + public const uint OuterCustomRouteResponse = 18; + + public const uint OuterPingRequest = 19; + public const uint OuterPingResponse = 20; + } + + public static class OpCode + { + public static readonly uint BenchmarkMessage = Create(OpCodeProtocolType.ProtoBuf, OpCodeType.OuterMessage, 8388607); + public static readonly uint BenchmarkRequest = Create(OpCodeProtocolType.ProtoBuf, OpCodeType.OuterRequest, 8388607); + public static readonly uint BenchmarkResponse = Create(OpCodeProtocolType.ProtoBuf, OpCodeType.OuterResponse, 8388607); + public static readonly uint PingRequest = Create(OpCodeProtocolType.ProtoBuf, OpCodeType.OuterPingRequest, 1); + public static readonly uint PingResponse = Create(OpCodeProtocolType.ProtoBuf, OpCodeType.OuterPingResponse, 1); + public static readonly uint DefaultResponse = Create(OpCodeProtocolType.ProtoBuf, OpCodeType.InnerResponse, 1); + public static readonly uint DefaultRouteResponse = Create(OpCodeProtocolType.ProtoBuf, OpCodeType.InnerRouteResponse, 7); + public static readonly uint AddressableAddRequest = Create(OpCodeProtocolType.ProtoBuf, OpCodeType.InnerRouteRequest, 1); + public static readonly uint AddressableAddResponse = Create(OpCodeProtocolType.ProtoBuf, OpCodeType.InnerRouteResponse, 1); + public static readonly uint AddressableGetRequest = Create(OpCodeProtocolType.ProtoBuf, OpCodeType.InnerRouteRequest, 2); + public static readonly uint AddressableGetResponse = Create(OpCodeProtocolType.ProtoBuf,OpCodeType.InnerRouteResponse,2); + public static readonly uint AddressableRemoveRequest = Create(OpCodeProtocolType.ProtoBuf, OpCodeType.InnerRouteRequest, 3); + public static readonly uint AddressableRemoveResponse = Create(OpCodeProtocolType.ProtoBuf, OpCodeType.InnerRouteResponse, 3); + public static readonly uint AddressableLockRequest = Create(OpCodeProtocolType.ProtoBuf, OpCodeType.InnerRouteRequest, 4); + public static readonly uint AddressableLockResponse = Create(OpCodeProtocolType.ProtoBuf, OpCodeType.InnerRouteResponse, 4); + public static readonly uint AddressableUnLockRequest = Create(OpCodeProtocolType.ProtoBuf, OpCodeType.InnerRouteRequest, 5); + public static readonly uint AddressableUnLockResponse = Create(OpCodeProtocolType.ProtoBuf, OpCodeType.InnerRouteResponse, 5); + public static readonly uint LinkEntityRequest = Create(OpCodeProtocolType.ProtoBuf, OpCodeType.InnerRouteRequest, 6); + public static readonly uint LinkEntityResponse = Create(OpCodeProtocolType.ProtoBuf, OpCodeType.InnerRouteResponse, 6); + + public static uint Create(uint opCodeProtocolType, uint protocol, uint index) + { + return new OpCodeIdStruct(opCodeProtocolType, protocol, index); + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/PacketParser/OpCode.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/PacketParser/OpCode.cs.meta new file mode 100644 index 0000000..ce6d498 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/PacketParser/OpCode.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8d44622c27a8c41048e995d634974dba +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/PacketParser/Pack.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/PacketParser/Pack.meta new file mode 100644 index 0000000..9e6ad48 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/PacketParser/Pack.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 43e4eed87e2c24c12b3d7f1be3382c25 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/PacketParser/Pack/InnerPackInfo.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/PacketParser/Pack/InnerPackInfo.cs new file mode 100644 index 0000000..e9870e7 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/PacketParser/Pack/InnerPackInfo.cs @@ -0,0 +1,79 @@ +// ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract + +using Fantasy.Network; +using Fantasy.Network.Interface; +using Fantasy.PacketParser.Interface; +using Fantasy.Pool; +using Fantasy.Serialize; + +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member +#pragma warning disable CS8600 // Converting null literal or possible null value to non-nullable type. +#pragma warning disable CS8603 // Possible null reference return. +#if FANTASY_NET +namespace Fantasy.PacketParser +{ + public sealed class InnerPackInfo : APackInfo + { + private readonly Dictionary> _createInstances = new Dictionary>(); + + public override void Dispose() + { + if (IsDisposed) + { + return; + } + + var network = Network; + base.Dispose(); + network.ReturnInnerPackInfo(this); + } + + public static InnerPackInfo Create(ANetwork network) + { + var innerPackInfo = network.RentInnerPackInfo(); + innerPackInfo.Network = network; + innerPackInfo.IsDisposed = false; + return innerPackInfo; + } + + public override MemoryStreamBuffer RentMemoryStream(MemoryStreamBufferSource memoryStreamBufferSource, int size = 0) + { + return MemoryStream ??= Network.MemoryStreamBufferPool.RentMemoryStream(memoryStreamBufferSource, size); + } + + public override object Deserialize(Type messageType) + { + if (MemoryStream == null) + { + Log.Debug("Deserialize MemoryStream is null"); + return null; + } + + MemoryStream.Seek(Packet.InnerPacketHeadLength, SeekOrigin.Begin); + + if (MemoryStream.Length == 0) + { + if (_createInstances.TryGetValue(messageType, out var createInstance)) + { + return createInstance(); + } + + createInstance = CreateInstance.CreateObject(messageType); + _createInstances.Add(messageType, createInstance); + return createInstance(); + } + + if (SerializerManager.TryGetSerializer(OpCodeIdStruct.OpCodeProtocolType, out var serializer)) + { + var obj = serializer.Deserialize(messageType, MemoryStream); + MemoryStream.Seek(0, SeekOrigin.Begin); + return obj; + } + + MemoryStream.Seek(0, SeekOrigin.Begin); + Log.Error($"protocolCode:{ProtocolCode} Does not support processing protocol"); + return null; + } + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/PacketParser/Pack/InnerPackInfo.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/PacketParser/Pack/InnerPackInfo.cs.meta new file mode 100644 index 0000000..b5e37e1 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/PacketParser/Pack/InnerPackInfo.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c7324100bcab9421b9534820f3274b7a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/PacketParser/Pack/OuterPackInfo.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/PacketParser/Pack/OuterPackInfo.cs new file mode 100644 index 0000000..8ce08b7 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/PacketParser/Pack/OuterPackInfo.cs @@ -0,0 +1,73 @@ +// ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract +using System; +using System.IO; +using Fantasy.Network; +using Fantasy.Network.Interface; +using Fantasy.PacketParser.Interface; +using Fantasy.Serialize; + +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member +#pragma warning disable CS8603 // Possible null reference return. +#pragma warning disable CS8600 // Converting null literal or possible null value to non-nullable type. +#pragma warning disable CS8602 // Dereference of a possibly null reference. +namespace Fantasy.PacketParser +{ + public sealed class OuterPackInfo : APackInfo + { + public override void Dispose() + { + if (IsDisposed) + { + return; + } + var network = Network; + base.Dispose(); + network.ReturnOuterPackInfo(this); + } + + public static OuterPackInfo Create(ANetwork network) + { + var outerPackInfo = network.RentOuterPackInfo(); + outerPackInfo.Network = network; + outerPackInfo.IsDisposed = false; + return outerPackInfo; + } + + public override MemoryStreamBuffer RentMemoryStream(MemoryStreamBufferSource memoryStreamBufferSource, int size = 0) + { + if (MemoryStream == null) + { + MemoryStream = Network.MemoryStreamBufferPool.RentMemoryStream(memoryStreamBufferSource, size); + } + + return MemoryStream; + } + + /// + /// 将消息数据从内存反序列化为指定的消息类型实例。 + /// + /// 目标消息类型。 + /// 反序列化后的消息类型实例。 + public override object Deserialize(Type messageType) + { + if (MemoryStream == null) + { + Log.Debug("Deserialize MemoryStream is null"); + return null; + } + + MemoryStream.Seek(Packet.OuterPacketHeadLength, SeekOrigin.Begin); + + if (SerializerManager.TryGetSerializer(OpCodeIdStruct.OpCodeProtocolType, out var serializer)) + { + var obj = serializer.Deserialize(messageType, MemoryStream); + MemoryStream.Seek(0, SeekOrigin.Begin); + return obj; + } + + MemoryStream.Seek(0, SeekOrigin.Begin); + Log.Error($"protocolCode:{ProtocolCode} Does not support processing protocol"); + return null; + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/PacketParser/Pack/OuterPackInfo.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/PacketParser/Pack/OuterPackInfo.cs.meta new file mode 100644 index 0000000..66f848f --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/PacketParser/Pack/OuterPackInfo.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 089b5fa434fce46a3898f46df31c53d1 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/PacketParser/Pack/ProcessPackInfo.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/PacketParser/Pack/ProcessPackInfo.cs new file mode 100644 index 0000000..f010858 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/PacketParser/Pack/ProcessPackInfo.cs @@ -0,0 +1,160 @@ +#if FANTASY_NET +using System.Collections.Concurrent; +using Fantasy.Network; +using Fantasy.Network.Interface; +using Fantasy.PacketParser.Interface; +using Fantasy.Pool; +using Fantasy.Serialize; + +// ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member +#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. +#pragma warning disable CS8600 // Converting null literal or possible null value to non-nullable type. +#pragma warning disable CS8603 // Possible null reference return. +namespace Fantasy.PacketParser +{ + public sealed class ProcessPackInfo : APackInfo + { + private int _disposeCount; + public Type MessageType { get; private set; } + private static readonly ConcurrentQueue Caches = new ConcurrentQueue(); + private readonly ConcurrentDictionary> _createInstances = new ConcurrentDictionary>(); + + public override void Dispose() + { + if (--_disposeCount > 0 || IsDisposed) + { + return; + } + + _disposeCount = 0; + MessageType = null; + base.Dispose(); + + if (Caches.Count > 2000) + { + return; + } + + Caches.Enqueue(this); + } + + public static unsafe ProcessPackInfo Create(Scene scene, T message, int disposeCount, uint rpcId = 0, long routeId = 0) where T : IRouteMessage + { + if (!Caches.TryDequeue(out var packInfo)) + { + packInfo = new ProcessPackInfo(); + } + + var type = typeof(T); + var memoryStreamLength = 0; + packInfo._disposeCount = disposeCount; + packInfo.MessageType = type; + packInfo.IsDisposed = false; + var memoryStream = new MemoryStreamBuffer(); + memoryStream.MemoryStreamBufferSource = MemoryStreamBufferSource.Pack; + OpCodeIdStruct opCodeIdStruct = message.OpCode(); + memoryStream.Seek(Packet.InnerPacketHeadLength, SeekOrigin.Begin); + + if (SerializerManager.TryGetSerializer(opCodeIdStruct.OpCodeProtocolType, out var serializer)) + { + serializer.Serialize(type, message, memoryStream); + memoryStreamLength = (int)memoryStream.Position; + } + else + { + Log.Error($"type:{type} Does not support processing protocol"); + } + + var opCode = scene.MessageDispatcherComponent.GetOpCode(packInfo.MessageType); + var packetBodyCount = memoryStreamLength - Packet.InnerPacketHeadLength; + + if (packetBodyCount == 0) + { + // protoBuf做了一个优化、就是当序列化的对象里的属性和字段都为默认值的时候就不会序列化任何东西。 + // 为了TCP的分包和粘包、需要判定下是当前包数据不完整还是本应该如此、所以用-1代表。 + packetBodyCount = -1; + } + + if (packetBodyCount > Packet.PacketBodyMaxLength) + { + // 检查消息体长度是否超出限制 + throw new Exception($"Message content exceeds {Packet.PacketBodyMaxLength} bytes"); + } + + var buffer = memoryStream.GetBuffer(); + + fixed (byte* bufferPtr = buffer) + { + var opCodePtr = bufferPtr + Packet.PacketLength; + var rpcIdPtr = bufferPtr + Packet.InnerPacketRpcIdLocation; + var routeIdPtr = bufferPtr + Packet.InnerPacketRouteRouteIdLocation; + *(int*)bufferPtr = packetBodyCount; + *(uint*)opCodePtr = opCode; + *(uint*)rpcIdPtr = rpcId; + *(long*)routeIdPtr = routeId; + } + + memoryStream.Seek(0, SeekOrigin.Begin); + packInfo.MemoryStream = memoryStream; + return packInfo; + } + + public unsafe void Set(uint rpcId, long routeId) + { + var buffer = MemoryStream.GetBuffer(); + + fixed (byte* bufferPtr = buffer) + { + var rpcIdPtr = bufferPtr + Packet.InnerPacketRpcIdLocation; + var routeIdPtr = bufferPtr + Packet.InnerPacketRouteRouteIdLocation; + *(uint*)rpcIdPtr = rpcId; + *(long*)routeIdPtr = routeId; + } + + MemoryStream.Seek(0, SeekOrigin.Begin); + } + + public override MemoryStreamBuffer RentMemoryStream(MemoryStreamBufferSource memoryStreamBufferSource, int size = 0) + { + throw new NotImplementedException(); + } + + public override object Deserialize(Type messageType) + { + if (MemoryStream == null) + { + Log.Debug("Deserialize MemoryStream is null"); + return null; + } + + object obj = null; + MemoryStream.Seek(Packet.InnerPacketHeadLength, SeekOrigin.Begin); + + if (MemoryStream.Length == 0) + { + if (_createInstances.TryGetValue(messageType, out var createInstance)) + { + return createInstance(); + } + + createInstance = CreateInstance.CreateObject(messageType); + _createInstances.TryAdd(messageType, createInstance); + return createInstance(); + } + + if (SerializerManager.TryGetSerializer(OpCodeIdStruct.OpCodeProtocolType, out var serializer)) + { + obj = serializer.Deserialize(messageType, MemoryStream); + MemoryStream.Seek(0, SeekOrigin.Begin); + return obj; + } + + MemoryStream.Seek(0, SeekOrigin.Begin); + Log.Error($"protocolCode:{ProtocolCode} Does not support processing protocol"); + return null; + } + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/PacketParser/Pack/ProcessPackInfo.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/PacketParser/Pack/ProcessPackInfo.cs.meta new file mode 100644 index 0000000..dc55c46 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/PacketParser/Pack/ProcessPackInfo.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 703b20fc55fb240df9156adfa9919907 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/PacketParser/Packet.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/PacketParser/Packet.cs new file mode 100644 index 0000000..7198af7 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/PacketParser/Packet.cs @@ -0,0 +1,49 @@ +namespace Fantasy.PacketParser +{ + /// + /// 提供关于消息包的常量定义。 + /// + public struct Packet + { + /// + /// 消息体最大长度 + /// + public const int PacketBodyMaxLength = ushort.MaxValue * 16; + /// + /// 消息体长度在消息头占用的长度 + /// + public const int PacketLength = sizeof(int); + /// + /// 协议编号在消息头占用的长度 + /// + public const int ProtocolCodeLength = sizeof(uint); + /// + /// RouteId长度 + /// + public const int PacketRouteIdLength = sizeof(long); + /// + /// RpcId在消息头占用的长度 + /// + public const int RpcIdLength = sizeof(uint); + /// + /// OuterRPCId所在的位置 + /// + public const int OuterPacketRpcIdLocation = PacketLength + ProtocolCodeLength; + /// + /// InnerRPCId所在的位置 + /// + public const int InnerPacketRpcIdLocation = PacketLength + ProtocolCodeLength; + /// + /// RouteId所在的位置 + /// + public const int InnerPacketRouteRouteIdLocation = PacketLength + ProtocolCodeLength + RpcIdLength; + /// + /// 外网消息头长度(消息体长度在消息头占用的长度 + 协议编号在消息头占用的长度 + RPCId长度 + RouteId长度) + /// + public const int OuterPacketHeadLength = PacketLength + ProtocolCodeLength + RpcIdLength + PacketRouteIdLength; + /// + /// 内网消息头长度(消息体长度在消息头占用的长度 + 协议编号在消息头占用的长度 + RPCId长度 + RouteId长度) + /// + public const int InnerPacketHeadLength = PacketLength + ProtocolCodeLength + RpcIdLength + PacketRouteIdLength; + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/PacketParser/Packet.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/PacketParser/Packet.cs.meta new file mode 100644 index 0000000..146d1f0 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/PacketParser/Packet.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b788ac48105e5489b97079cb9f94991e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/PacketParser/PacketParserFactory.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/PacketParser/PacketParserFactory.cs new file mode 100644 index 0000000..679f95d --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/PacketParser/PacketParserFactory.cs @@ -0,0 +1,173 @@ +using System; +using Fantasy.Network; +using Fantasy.Network.Interface; +using Fantasy.PacketParser.Interface; + +// ReSharper disable PossibleNullReferenceException +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member +#pragma warning disable CS8602 // Dereference of a possibly null reference. +#pragma warning disable CS8600 // Converting null literal or possible null value to non-nullable type. +#pragma warning disable CS8603 // Possible null reference return. +namespace Fantasy.PacketParser +{ + internal static class PacketParserFactory + { +#if FANTASY_NET + internal static ReadOnlyMemoryPacketParser CreateServerReadOnlyMemoryPacket(ANetwork network) + { + ReadOnlyMemoryPacketParser readOnlyMemoryPacketParser = null; + + switch (network.NetworkTarget) + { + case NetworkTarget.Inner: + { + readOnlyMemoryPacketParser = new InnerReadOnlyMemoryPacketParser(); + break; + } + case NetworkTarget.Outer: + { + readOnlyMemoryPacketParser = new OuterReadOnlyMemoryPacketParser(); + break; + } + } + + readOnlyMemoryPacketParser.Scene = network.Scene; + readOnlyMemoryPacketParser.Network = network; + readOnlyMemoryPacketParser.MessageDispatcherComponent = network.Scene.MessageDispatcherComponent; + return readOnlyMemoryPacketParser; + } + + public static BufferPacketParser CreateServerBufferPacket(ANetwork network) + { + BufferPacketParser bufferPacketParser = null; + + switch (network.NetworkTarget) + { + case NetworkTarget.Inner: + { + bufferPacketParser = new InnerBufferPacketParser(); + break; + } + case NetworkTarget.Outer: + { + bufferPacketParser = new OuterBufferPacketParser(); + break; + } + } + + bufferPacketParser.Scene = network.Scene; + bufferPacketParser.Network = network; + bufferPacketParser.MessageDispatcherComponent = network.Scene.MessageDispatcherComponent; + return bufferPacketParser; + } +#endif + internal static ReadOnlyMemoryPacketParser CreateClientReadOnlyMemoryPacket(ANetwork network) + { + ReadOnlyMemoryPacketParser readOnlyMemoryPacketParser = null; + + switch (network.NetworkTarget) + { +#if FANTASY_NET + case NetworkTarget.Inner: + { + readOnlyMemoryPacketParser = new InnerReadOnlyMemoryPacketParser(); + break; + } +#endif + case NetworkTarget.Outer: + { + readOnlyMemoryPacketParser = new OuterReadOnlyMemoryPacketParser(); + break; + } + } + + readOnlyMemoryPacketParser.Scene = network.Scene; + readOnlyMemoryPacketParser.Network = network; + readOnlyMemoryPacketParser.MessageDispatcherComponent = network.Scene.MessageDispatcherComponent; + return readOnlyMemoryPacketParser; + } + +#if !FANTASY_WEBGL + public static BufferPacketParser CreateClientBufferPacket(ANetwork network) + { + BufferPacketParser bufferPacketParser = null; + + switch (network.NetworkTarget) + { +#if FANTASY_NET + case NetworkTarget.Inner: + { + bufferPacketParser = new InnerBufferPacketParser(); + break; + } +#endif + case NetworkTarget.Outer: + { + bufferPacketParser = new OuterBufferPacketParser(); + break; + } + } + + bufferPacketParser.Scene = network.Scene; + bufferPacketParser.Network = network; + bufferPacketParser.MessageDispatcherComponent = network.Scene.MessageDispatcherComponent; + return bufferPacketParser; + } +#endif + public static T CreateClient(ANetwork network) where T : APacketParser + { + var packetParserType = typeof(T); + + switch (network.NetworkTarget) + { +#if FANTASY_NET + case NetworkTarget.Inner: + { + APacketParser innerPacketParser = null; + + if (packetParserType == typeof(ReadOnlyMemoryPacketParser)) + { + innerPacketParser = new InnerReadOnlyMemoryPacketParser(); + } + else if (packetParserType == typeof(BufferPacketParser)) + { + innerPacketParser = new InnerBufferPacketParser(); + } + // else if(packetParserType == typeof(CircularBufferPacketParser)) + // { + // innerPacketParser = new InnerCircularBufferPacketParser(); + // } + + innerPacketParser.Scene = network.Scene; + innerPacketParser.Network = network; + innerPacketParser.MessageDispatcherComponent = network.Scene.MessageDispatcherComponent; + return (T)innerPacketParser; + } +#endif + case NetworkTarget.Outer: + { + APacketParser outerPacketParser = null; + + if (packetParserType == typeof(ReadOnlyMemoryPacketParser)) + { + outerPacketParser = new OuterReadOnlyMemoryPacketParser(); + } + else if (packetParserType == typeof(BufferPacketParser)) + { +#if FANTASY_WEBGL + outerPacketParser = new OuterWebglBufferPacketParser(); +#else + outerPacketParser = new OuterBufferPacketParser(); +#endif + } + outerPacketParser.Scene = network.Scene; + outerPacketParser.Network = network; + outerPacketParser.MessageDispatcherComponent = network.Scene.MessageDispatcherComponent; + return (T)outerPacketParser; + } + default: + throw new ArgumentOutOfRangeException(); + } + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/PacketParser/PacketParserFactory.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/PacketParser/PacketParserFactory.cs.meta new file mode 100644 index 0000000..f7b450d --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/PacketParser/PacketParserFactory.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 555f2f9f48ed7406aaf831443714053c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/Scheduler.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/Scheduler.meta new file mode 100644 index 0000000..0a84f66 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/Scheduler.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 6bc659d65dda643d0bb0134c9c222523 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/Scheduler/ClientMessageScheduler.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/Scheduler/ClientMessageScheduler.cs new file mode 100644 index 0000000..baa7a59 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/Scheduler/ClientMessageScheduler.cs @@ -0,0 +1,93 @@ +using System; +using Fantasy.Async; +using Fantasy.Network; +using Fantasy.Network.Interface; +using Fantasy.PacketParser.Interface; + +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member + +namespace Fantasy.Scheduler +{ +#if FANTASY_UNITY || FANTASY_CONSOLE + /// + /// 提供了一个用于客户端网络消息调度和处理的抽象基类。 + /// + public sealed class ClientMessageScheduler : ANetworkMessageScheduler + { + public ClientMessageScheduler(Scene scene) : base(scene) { } + + public override async FTask Scheduler(Session session, APackInfo packInfo) + { + await FTask.CompletedTask; + switch (packInfo.OpCodeIdStruct.Protocol) + { + case OpCodeType.OuterMessage: + case OpCodeType.OuterRequest: + case OpCodeType.OuterAddressableMessage: + case OpCodeType.OuterAddressableRequest: + case OpCodeType.OuterCustomRouteMessage: + case OpCodeType.OuterCustomRouteRequest: + { + using (packInfo) + { + var messageType = MessageDispatcherComponent.GetOpCodeType(packInfo.ProtocolCode); + + if (messageType == null) + { + throw new Exception($"可能遭受到恶意发包或没有协议定义ProtocolCode ProtocolCode:{packInfo.ProtocolCode}"); + } + + var message = packInfo.Deserialize(messageType); + MessageDispatcherComponent.MessageHandler(session, messageType, message, packInfo.RpcId, packInfo.ProtocolCode); + } + + return; + } + case OpCodeType.OuterResponse: + case OpCodeType.OuterPingResponse: + case OpCodeType.OuterAddressableResponse: + case OpCodeType.OuterCustomRouteResponse: + { + using (packInfo) + { + var messageType = MessageDispatcherComponent.GetOpCodeType(packInfo.ProtocolCode); + + if (messageType == null) + { + throw new Exception($"可能遭受到恶意发包或没有协议定义ProtocolCode ProtocolCode:{packInfo.ProtocolCode}"); + } + + // 这个一般是客户端Session.Call发送时使用的、目前这个逻辑只有Unity客户端时使用 + + var aResponse = (IResponse)packInfo.Deserialize(messageType); + + if (!session.RequestCallback.Remove(packInfo.RpcId, out var action)) + { + Log.Error($"not found rpc {packInfo.RpcId}, response message: {aResponse.GetType().Name}"); + return; + } + + action.SetResult(aResponse); + } + + return; + } + default: + { + packInfo.Dispose(); + throw new NotSupportedException($"Received unsupported message protocolCode:{packInfo.ProtocolCode}"); + } + } + } + } +#endif +#if FANTASY_NET + internal sealed class ClientMessageScheduler(Scene scene) : ANetworkMessageScheduler(scene) + { + public override FTask Scheduler(Session session, APackInfo packInfo) + { + throw new NotSupportedException($"ClientMessageScheduler Received unsupported message protocolCode:{packInfo.ProtocolCode}"); + } + } +#endif +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/Scheduler/ClientMessageScheduler.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/Scheduler/ClientMessageScheduler.cs.meta new file mode 100644 index 0000000..45ad9be --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/Scheduler/ClientMessageScheduler.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 98e138214f0e74a7687aa06ffdce555e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/Scheduler/InnerMessageScheduler.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/Scheduler/InnerMessageScheduler.cs new file mode 100644 index 0000000..806ce63 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/Scheduler/InnerMessageScheduler.cs @@ -0,0 +1,204 @@ +#if FANTASY_NET +// ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract +using System.Runtime.CompilerServices; +using Fantasy.Async; +using Fantasy.Network; +using Fantasy.Network.Interface; +using Fantasy.PacketParser; +using Fantasy.PacketParser.Interface; +#pragma warning disable CS8604 // Possible null reference argument. + +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member +namespace Fantasy.Scheduler +{ + /// + /// 提供了一个机制来调度和处理内部网络消息。 + /// + internal sealed class InnerMessageScheduler(Scene scene) : ANetworkMessageScheduler(scene) + { + public override async FTask Scheduler(Session session, APackInfo packInfo) + { + var protocol = packInfo.OpCodeIdStruct.Protocol; + + switch (protocol) + { + case OpCodeType.InnerMessage: + case OpCodeType.InnerRequest: + { + var messageType = MessageDispatcherComponent.GetOpCodeType(packInfo.ProtocolCode); + + try + { + if (messageType == null) + { + throw new Exception($"可能遭受到恶意发包或没有协议定义ProtocolCode ProtocolCode:{packInfo.ProtocolCode}"); + } + + var message = packInfo.Deserialize(messageType); + MessageDispatcherComponent.MessageHandler(session, messageType, message, packInfo.RpcId, packInfo.ProtocolCode); + } + catch (Exception e) + { + Log.Error($"ANetworkMessageScheduler OuterResponse error messageProtocolCode:{packInfo.ProtocolCode} messageType:{messageType} SessionId {session.Id} IsDispose {session.IsDisposed} {e}"); + } + finally + { + packInfo.Dispose(); + } + + return; + } + case OpCodeType.InnerResponse: + case OpCodeType.InnerRouteResponse: + case OpCodeType.InnerAddressableResponse: + case OpCodeType.OuterAddressableResponse: + case OpCodeType.OuterCustomRouteResponse: + { + using (packInfo) + { + var messageType = MessageDispatcherComponent.GetOpCodeType(packInfo.ProtocolCode); + + if (messageType == null) + { + throw new Exception($"可能遭受到恶意发包或没有协议定义ProtocolCode ProtocolCode:{packInfo.ProtocolCode}"); + } + + NetworkMessagingComponent.ResponseHandler(packInfo.RpcId, (IResponse)packInfo.Deserialize(messageType)); + } + + return; + } + case OpCodeType.InnerRouteMessage: + case OpCodeType.InnerAddressableMessage: + { + using (packInfo) + { + var messageType = MessageDispatcherComponent.GetOpCodeType(packInfo.ProtocolCode); + + if (messageType == null) + { + throw new Exception($"InnerMessageScheduler error 可能遭受到恶意发包或没有协议定义ProtocolCode ProtocolCode:{packInfo.ProtocolCode}"); + } + + if (!Scene.TryGetEntity(packInfo.RouteId, out var entity)) + { + throw new Exception($"The Entity associated with RouteId = {packInfo.RouteId} was not found! messageType = {messageType.FullName}"); + } + + var obj = packInfo.Deserialize(messageType); + await Scene.MessageDispatcherComponent.RouteMessageHandler(session, messageType, entity, (IMessage)obj, packInfo.RpcId); + } + + return; + } + case OpCodeType.InnerRouteRequest: + case OpCodeType.InnerAddressableRequest: + { + using (packInfo) + { + var messageType = MessageDispatcherComponent.GetOpCodeType(packInfo.ProtocolCode); + + if (messageType == null) + { + throw new Exception($"InnerMessageScheduler error 可能遭受到恶意发包或没有协议定义ProtocolCode ProtocolCode:{packInfo.ProtocolCode}"); + } + + if (!Scene.TryGetEntity(packInfo.RouteId, out var entity)) + { + Scene.MessageDispatcherComponent.FailRouteResponse(session, messageType, InnerErrorCode.ErrNotFoundRoute, packInfo.RpcId); + return; + } + + var obj = packInfo.Deserialize(messageType); + await Scene.MessageDispatcherComponent.RouteMessageHandler(session, messageType, entity, (IMessage)obj, packInfo.RpcId); + } + + return; + } + case OpCodeType.OuterCustomRouteRequest: + case OpCodeType.OuterAddressableRequest: + case OpCodeType.OuterAddressableMessage: + case OpCodeType.OuterCustomRouteMessage: + { + var entity = Scene.GetEntity(packInfo.RouteId); + + switch (entity) + { + case null: + { + // 执行到这里有两种情况: + using (packInfo) + { + switch (Scene.SceneConfig.SceneTypeString) + { + case "Gate": + { + // 1、当前是Gate进行,需要转发消息给客户端,但当前这个Session已经断开了。 + // 这种情况不需要做任何处理。 + return; + } + default: + { + // 2、当前是其他Scene、消息通过Gate发送到这个Scene上面,但这个Scene上面没有这个Entity。 + // 因为这个是Gate转发消息到这个Scene的,如果没有找到Entity要返回错误给Gate。 + // 出现这个情况一定要打印日志,因为出现这个问题肯定是上层逻辑导致的,不应该出现这样的问题。 + var packInfoRouteId = packInfo.RouteId; + var messageType = MessageDispatcherComponent.GetOpCodeType(packInfo.ProtocolCode); + + switch (protocol) + { + case OpCodeType.OuterCustomRouteRequest: + case OpCodeType.OuterAddressableRequest: + case OpCodeType.OuterAddressableMessage: + { + Scene.MessageDispatcherComponent.FailRouteResponse(session, messageType, InnerErrorCode.ErrNotFoundRoute, packInfo.RpcId); + return; + } + } + + throw new Exception($"The Entity associated with RouteId = {packInfoRouteId} was not found! messageType = {messageType.FullName} protocol = {protocol}"); + } + } + } + } + case Session gateSession: + { + using (packInfo) + { + // 这里如果是Session只可能是Gate的Session、如果是的话、肯定是转发消息 + gateSession.Send(packInfo.MemoryStream, packInfo.RpcId); + } + + return; + } + default: + { + using (packInfo) + { + var messageType = MessageDispatcherComponent.GetOpCodeType(packInfo.ProtocolCode); + + if (messageType == null) + { + throw new Exception($"InnerMessageScheduler error 可能遭受到恶意发包或没有协议定义ProtocolCode ProtocolCode:{packInfo.ProtocolCode}"); + } + + var obj = packInfo.Deserialize(messageType); + await Scene.MessageDispatcherComponent.RouteMessageHandler(session, messageType, entity, (IMessage)obj, packInfo.RpcId); + } + + return; + } + } + } + default: + { + var infoProtocolCode = packInfo.ProtocolCode; + packInfo.Dispose(); + throw new NotSupportedException($"InnerMessageScheduler Received unsupported message protocolCode:{infoProtocolCode}"); + } + } + } + } +} +#endif + diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/Scheduler/InnerMessageScheduler.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/Scheduler/InnerMessageScheduler.cs.meta new file mode 100644 index 0000000..7133aa9 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/Scheduler/InnerMessageScheduler.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9e7e2db0df3c345ddab6ce79df0db347 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/Scheduler/Interface.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/Scheduler/Interface.meta new file mode 100644 index 0000000..b4ea2d0 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/Scheduler/Interface.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: a25819b011d8c49819efde1122c75a7d +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/Scheduler/Interface/ANetworkMessageScheduler.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/Scheduler/Interface/ANetworkMessageScheduler.cs new file mode 100644 index 0000000..b296cff --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/Scheduler/Interface/ANetworkMessageScheduler.cs @@ -0,0 +1,30 @@ +using System; +using System.IO; +using Fantasy.Async; +using Fantasy.Network; +using Fantasy.Network.Interface; +using Fantasy.PacketParser.Interface; +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member +// ReSharper disable UnassignedField.Global +#pragma warning disable CS8600 // Converting null literal or possible null value to non-nullable type. + +namespace Fantasy.Scheduler +{ + public abstract class ANetworkMessageScheduler + { + protected readonly Scene Scene; + protected readonly MessageDispatcherComponent MessageDispatcherComponent; +#if FANTASY_NET + protected readonly NetworkMessagingComponent NetworkMessagingComponent; +#endif + protected ANetworkMessageScheduler(Scene scene) + { + Scene = scene; + MessageDispatcherComponent = scene.MessageDispatcherComponent; +#if FANTASY_NET + NetworkMessagingComponent = scene.NetworkMessagingComponent; +#endif + } + public abstract FTask Scheduler(Session session, APackInfo packInfo); + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/Scheduler/Interface/ANetworkMessageScheduler.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/Scheduler/Interface/ANetworkMessageScheduler.cs.meta new file mode 100644 index 0000000..add8133 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/Scheduler/Interface/ANetworkMessageScheduler.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b66f417f0af774145a9bd64c0ec933e4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/Scheduler/MessageHelper.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/Scheduler/MessageHelper.meta new file mode 100644 index 0000000..08f554b --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/Scheduler/MessageHelper.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 17461e5c3d2cd41a1a11b4c92890b8ce +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/Scheduler/MessageHelper/MessageSender.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/Scheduler/MessageHelper/MessageSender.cs new file mode 100644 index 0000000..c645183 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/Scheduler/MessageHelper/MessageSender.cs @@ -0,0 +1,107 @@ +using System; +using Fantasy.Async; +using Fantasy.Helper; +using Fantasy.Network.Interface; + +#pragma warning disable CS8625 +#pragma warning disable CS8618 + +namespace Fantasy.Scheduler +{ + /// + /// 网络消息发送者的类。 + /// + public struct MessageSender : IDisposable + { + /// + /// 获取或设置 RPC ID。 + /// + public uint RpcId { get; private set; } + /// + /// 获取或设置路由 ID。 + /// + public long RouteId { get; private set; } + /// + /// 获取或设置创建时间。 + /// + public long CreateTime { get; private set; } + /// + /// 获取或设置消息类型。 + /// + public Type MessageType { get; private set; } + /// + /// 获取或设置请求消息。 + /// + public IMessage Request { get; private set; } + /// + /// 获取或设置任务。 + /// + public FTask Tcs { get; private set; } + + /// + /// 释放资源。 + /// + public void Dispose() + { + RpcId = 0; + RouteId = 0; + CreateTime = 0; + Tcs = null; + Request = null; + MessageType = null; + } + + /// + /// 创建一个 实例。 + /// + /// RPC ID。 + /// 请求消息类型。 + /// 任务。 + /// 创建的 实例。 + public static MessageSender Create(uint rpcId, Type requestType, FTask tcs) + { + var routeMessageSender = new MessageSender(); + routeMessageSender.Tcs = tcs; + routeMessageSender.RpcId = rpcId; + routeMessageSender.MessageType = requestType; + routeMessageSender.CreateTime = TimeHelper.Now; + return routeMessageSender; + } + + /// + /// 创建一个 实例。 + /// + /// RPC ID。 + /// 请求消息。 + /// 任务。 + /// 创建的 实例。 + public static MessageSender Create(uint rpcId, IRequest request, FTask tcs) + { + var routeMessageSender = new MessageSender(); + routeMessageSender.Tcs = tcs; + routeMessageSender.RpcId = rpcId; + routeMessageSender.Request = request; + routeMessageSender.CreateTime = TimeHelper.Now; + return routeMessageSender; + } + + /// + /// 创建一个 实例。 + /// + /// RPC ID。 + /// 路由 ID。 + /// 路由消息请求。 + /// 任务。 + /// 创建的 实例。 + public static MessageSender Create(uint rpcId, long routeId, IRouteMessage request, FTask tcs) + { + var routeMessageSender = new MessageSender(); + routeMessageSender.Tcs = tcs; + routeMessageSender.RpcId = rpcId; + routeMessageSender.RouteId = routeId; + routeMessageSender.Request = request; + routeMessageSender.CreateTime = TimeHelper.Now; + return routeMessageSender; + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/Scheduler/MessageHelper/MessageSender.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/Scheduler/MessageHelper/MessageSender.cs.meta new file mode 100644 index 0000000..0e7aab1 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/Scheduler/MessageHelper/MessageSender.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 57d40c852547547f0a8022bf3b4f6f91 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/Scheduler/MessageHelper/NetworkMessagingComponent.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/Scheduler/MessageHelper/NetworkMessagingComponent.cs new file mode 100644 index 0000000..7580dd9 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/Scheduler/MessageHelper/NetworkMessagingComponent.cs @@ -0,0 +1,273 @@ +#if FANTASY_NET +using Fantasy.Entitas; +using System.Runtime.CompilerServices; +using Fantasy.Async; +using Fantasy.Entitas.Interface; +using Fantasy.Helper; +using Fantasy.Network; +using Fantasy.Network.Interface; +using Fantasy.Network.Route; +using Fantasy.PacketParser; +using Fantasy.PacketParser.Interface; +using Fantasy.Timer; +// ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract +#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. +#pragma warning disable CS8603 // Possible null reference return. +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member +namespace Fantasy.Scheduler +{ + public struct NetworkMessageUpdate + { + public NetworkMessagingComponent NetworkMessagingComponent; + } + + public class NetworkMessagingComponentAwakeSystem : AwakeSystem + { + protected override void Awake(NetworkMessagingComponent self) + { + var selfScene = self.Scene; + self.TimerComponent = selfScene.TimerComponent; + self.MessageDispatcherComponent = selfScene.MessageDispatcherComponent; + self.AddressableRouteMessageLock = selfScene.CoroutineLockComponent.Create(self.GetType().TypeHandle.Value.ToInt64()); + + self.TimerId = self.TimerComponent.Net.RepeatedTimer(10000, new NetworkMessageUpdate() + { + NetworkMessagingComponent = self + }); + } + } + + public class NetworkMessagingComponentDestroySystem : DestroySystem + { + protected override void Destroy(NetworkMessagingComponent self) + { + if (self.TimerId != 0) + { + self.TimerComponent.Net.Remove(ref self.TimerId); + } + + foreach (var (rpcId, messageSender) in self.RequestCallback.ToDictionary()) + { + self.ReturnMessageSender(rpcId, messageSender); + } + + self.AddressableRouteMessageLock.Dispose(); + + self.RequestCallback.Clear(); + self.TimeoutRouteMessageSenders.Clear(); + self.TimerComponent = null; + self.MessageDispatcherComponent = null; + self.AddressableRouteMessageLock = null; + } + } + public sealed class NetworkMessagingComponent : Entity + { + public long TimerId; + private uint _rpcId; + public CoroutineLock AddressableRouteMessageLock; + public TimerComponent TimerComponent; + public MessageDispatcherComponent MessageDispatcherComponent; + public readonly SortedDictionary RequestCallback = new(); + public readonly Dictionary TimeoutRouteMessageSenders = new(); + + public void SendInnerRoute(long routeId, IRouteMessage message) + { + if (routeId == 0) + { + Log.Error($"SendInnerRoute appId == 0"); + return; + } + + Scene.GetSession(routeId).Send(message, 0, routeId); + } + + internal void SendInnerRoute(long routeId, Type messageType, APackInfo packInfo) + { + if (routeId == 0) + { + Log.Error($"SendInnerRoute routeId == 0"); + return; + } + + Scene.GetSession(routeId).Send(0, routeId, messageType, packInfo); + } + + public void SendInnerRoute(ICollection routeIdCollection, IRouteMessage message) + { + if (routeIdCollection.Count <= 0) + { + Log.Error("SendInnerRoute routeIdCollection.Count <= 0"); + return; + } + + using var processPackInfo = ProcessPackInfo.Create(Scene, message, routeIdCollection.Count); + foreach (var routeId in routeIdCollection) + { + processPackInfo.Set(0, routeId); + Scene.GetSession(routeId).Send(processPackInfo, 0, routeId); + } + } + + public async FTask SendAddressable(long addressableId, IRouteMessage message) + { + await CallAddressable(addressableId, message); + } + + internal async FTask CallInnerRoute(long routeId, Type requestType, APackInfo packInfo) + { + if (routeId == 0) + { + Log.Error($"CallInnerRoute routeId == 0"); + return null; + } + + var rpcId = ++_rpcId; + var session = Scene.GetSession(routeId); + var requestCallback = FTask.Create(false); + RequestCallback.Add(rpcId, MessageSender.Create(rpcId, requestType, requestCallback)); + session.Send(rpcId, routeId, requestType, packInfo); + return await requestCallback; + } + + public async FTask CallInnerRouteBySession(Session session, long routeId, IRouteMessage request) + { + var rpcId = ++_rpcId; + var requestCallback = FTask.Create(false); + RequestCallback.Add(rpcId, MessageSender.Create(rpcId, request, requestCallback)); + session.Send(request, rpcId, routeId); + return await requestCallback; + } + + public async FTask CallInnerRoute(long routeId, IRouteMessage request) + { + if (routeId == 0) + { + Log.Error($"CallInnerRoute routeId == 0"); + return null; + } + + var rpcId = ++_rpcId; + var session = Scene.GetSession(routeId); + var requestCallback = FTask.Create(false); + RequestCallback.Add(rpcId, MessageSender.Create(rpcId, request, requestCallback)); + session.Send(request, rpcId, routeId); + return await requestCallback; + } + + public async FTask CallAddressable(long addressableId, IRouteMessage request) + { + var failCount = 0; + + using (await AddressableRouteMessageLock.Wait(addressableId, "CallAddressable")) + { + var addressableRouteId = await AddressableHelper.GetAddressableRouteId(Scene, addressableId); + + while (true) + { + if (addressableRouteId == 0) + { + addressableRouteId = await AddressableHelper.GetAddressableRouteId(Scene, addressableId); + } + + if (addressableRouteId == 0) + { + return MessageDispatcherComponent.CreateResponse(request.GetType(), InnerErrorCode.ErrNotFoundRoute); + } + + var iRouteResponse = await CallInnerRoute(addressableRouteId, request); + + switch (iRouteResponse.ErrorCode) + { + case InnerErrorCode.ErrNotFoundRoute: + { + if (++failCount > 20) + { + Log.Error($"AddressableComponent.Call failCount > 20 route send message fail, routeId: {addressableRouteId} AddressableMessageComponent:{addressableId}"); + return iRouteResponse; + } + + await TimerComponent.Net.WaitAsync(500); + addressableRouteId = 0; + continue; + } + case InnerErrorCode.ErrRouteTimeout: + { + Log.Error($"CallAddressableRoute ErrorCode.ErrRouteTimeout Error:{iRouteResponse.ErrorCode} Message:{request}"); + return iRouteResponse; + } + default: + { + return iRouteResponse; + } + } + } + } + } + + public void ResponseHandler(uint rpcId, IResponse response) + { + if (!RequestCallback.Remove(rpcId, out var routeMessageSender)) + { + throw new Exception($"not found rpc, response.RpcId:{rpcId} response message: {response.GetType().Name} Process:{Scene.Process.Id} Scene:{Scene.SceneConfigId}"); + } + + ResponseHandler(routeMessageSender, response); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static void ResponseHandler(MessageSender messageSender, IResponse response) + { + if (response.ErrorCode == InnerErrorCode.ErrRouteTimeout) + { +#if FANTASY_DEVELOP + messageSender.Tcs.SetException(new Exception($"Rpc error: request, 注意RouteId消息超时,请注意查看是否死锁或者没有reply: RouteId: {messageSender.RouteId} {messageSender.Request.ToJson()}, response: {response}")); +#else + messageSender.Tcs.SetException(new Exception($"Rpc error: request, 注意RouteId消息超时,请注意查看是否死锁或者没有reply: RouteId: {messageSender.RouteId} {messageSender.Request}, response: {response}")); +#endif + messageSender.Dispose(); + return; + } + + messageSender.Tcs.SetResult(response); + messageSender.Dispose(); + } + + public void ReturnMessageSender(uint rpcId, MessageSender messageSender) + { + try + { + switch (messageSender.Request) + { + case IRouteMessage iRouteMessage: + { + // IRouteMessage是个特殊的RPC协议、这里不处理就可以了。 + break; + } + case IRequest iRequest: + { + var response = MessageDispatcherComponent.CreateResponse(iRequest.GetType(), InnerErrorCode.ErrRpcFail); + var responseRpcId = messageSender.RpcId; + ResponseHandler(responseRpcId, response); + Log.Warning($"timeout rpcId:{rpcId} responseRpcId:{responseRpcId} {iRequest.ToJson()}"); + break; + } + default: + { + Log.Error(messageSender.Request != null + ? $"Unsupported protocol type {messageSender.Request.GetType()} rpcId:{rpcId} messageSender.Request != null" + : $"Unsupported protocol type:{messageSender.MessageType.FullName} rpcId:{rpcId}"); + RequestCallback.Remove(rpcId); + break; + } + } + } + catch (Exception e) + { + Console.WriteLine(e); + throw; + } + } + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/Scheduler/MessageHelper/NetworkMessagingComponent.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/Scheduler/MessageHelper/NetworkMessagingComponent.cs.meta new file mode 100644 index 0000000..415bdd4 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/Scheduler/MessageHelper/NetworkMessagingComponent.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2edb273f5cbb94e8082501778cba1427 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/Scheduler/MessageHelper/OnNetworkMessageUpdateCheckTimeout.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/Scheduler/MessageHelper/OnNetworkMessageUpdateCheckTimeout.cs new file mode 100644 index 0000000..7dd2ea3 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/Scheduler/MessageHelper/OnNetworkMessageUpdateCheckTimeout.cs @@ -0,0 +1,60 @@ +using Fantasy.Helper; +using Fantasy.Timer; + +#if FANTASY_NET +// ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract +namespace Fantasy.Scheduler +{ + /// + /// 网络消息更新检查超时。 + /// + public sealed class OnNetworkMessageUpdateCheckTimeout : TimerHandler + { + /// + /// 超时时间(毫秒)。 + /// + private const long Timeout = 40000; + + /// + /// 处理网络消息更新检查超时。 + /// + /// + /// + protected override void Handler(NetworkMessageUpdate self) + { + var timeNow = TimeHelper.Now; + var selfNetworkMessagingComponent = self.NetworkMessagingComponent; + + // 遍历请求回调字典,检查是否有超时的请求,将超时请求添加到超时消息发送列表中。 + + foreach (var (rpcId, value) in selfNetworkMessagingComponent.RequestCallback) + { + if (timeNow < value.CreateTime + Timeout) + { + break; + } + + selfNetworkMessagingComponent.TimeoutRouteMessageSenders.Add(rpcId, value); + } + + // 如果没有超时的请求,直接返回。 + + if (selfNetworkMessagingComponent.TimeoutRouteMessageSenders.Count == 0) + { + return; + } + + // 处理超时的请求,根据请求类型生成相应的响应消息,并进行处理。 + + foreach (var (rpcId, routeMessageSender) in selfNetworkMessagingComponent.TimeoutRouteMessageSenders) + { + selfNetworkMessagingComponent.ReturnMessageSender(rpcId, routeMessageSender); + } + + // 清空超时消息发送列表。 + + selfNetworkMessagingComponent.TimeoutRouteMessageSenders.Clear(); + } + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/Scheduler/MessageHelper/OnNetworkMessageUpdateCheckTimeout.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/Scheduler/MessageHelper/OnNetworkMessageUpdateCheckTimeout.cs.meta new file mode 100644 index 0000000..2fc6aae --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/Scheduler/MessageHelper/OnNetworkMessageUpdateCheckTimeout.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0745c0a5c402e4b7982277a978693d5c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/Scheduler/OuterMessageScheduler.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/Scheduler/OuterMessageScheduler.cs new file mode 100644 index 0000000..58ac0a8 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/Scheduler/OuterMessageScheduler.cs @@ -0,0 +1,282 @@ +using System; +using Fantasy.Async; +using Fantasy.Network; +using Fantasy.PacketParser.Interface; +#if FANTASY_NET +using System.Text; +using Fantasy.Network.Interface; +using Fantasy.Network.Route; +using Fantasy.PacketParser; +using Fantasy.Helper; +using Fantasy.InnerMessage; +#endif + +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member + +// ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract + +namespace Fantasy.Scheduler +{ + /// + /// 提供了一个机制来调度和处理外部网络消息。 + /// +#if FANTASY_UNITY + public sealed class OuterMessageScheduler : ANetworkMessageScheduler + { + public OuterMessageScheduler(Scene scene) : base(scene) { } + + /// + /// 在Unity环境下,处理外部消息的方法。 + /// + /// 网络会话。 + /// 消息封包信息。 + public override FTask Scheduler(Session session, APackInfo packInfo) + { + throw new NotSupportedException($"Received unsupported message protocolCode:{packInfo.ProtocolCode}"); + } + } +#endif +#if FANTASY_NET + internal sealed class OuterMessageScheduler(Scene scene) : ANetworkMessageScheduler(scene) + { + private readonly PingResponse _pingResponse = new PingResponse(); + public override async FTask Scheduler(Session session, APackInfo packInfo) + { + if (session.IsDisposed) + { + return; + } + + switch (packInfo.OpCodeIdStruct.Protocol) + { + case OpCodeType.OuterPingRequest: + { + // 注意心跳目前只有外网才才会有、内网之间不需要心跳。 + + session.LastReceiveTime = TimeHelper.Now; + _pingResponse.Now = session.LastReceiveTime; + + using (packInfo) + { + session.Send(_pingResponse, packInfo.RpcId); + } + + return; + } + case OpCodeType.OuterMessage: + case OpCodeType.OuterRequest: + { + var messageType = MessageDispatcherComponent.GetOpCodeType(packInfo.ProtocolCode); + + try + { + if (messageType == null) + { + throw new Exception($"可能遭受到恶意发包或没有协议定义ProtocolCode ProtocolCode:{packInfo.ProtocolCode}"); + } + + var message = packInfo.Deserialize(messageType); + MessageDispatcherComponent.MessageHandler(session, messageType, message, packInfo.RpcId, packInfo.ProtocolCode); + } + catch (Exception e) + { + Log.Error($"ANetworkMessageScheduler OuterResponse error messageProtocolCode:{packInfo.ProtocolCode} messageType:{messageType} SessionId {session.Id} IsDispose {session.IsDisposed} {e}"); + } + finally + { + packInfo.Dispose(); + } + + return; + } + case OpCodeType.OuterResponse: + { + using (packInfo) + { + var messageType = MessageDispatcherComponent.GetOpCodeType(packInfo.ProtocolCode); + + if (messageType == null) + { + throw new Exception($"可能遭受到恶意发包或没有协议定义ProtocolCode ProtocolCode:{packInfo.ProtocolCode}"); + } + + NetworkMessagingComponent.ResponseHandler(packInfo.RpcId, (IResponse)packInfo.Deserialize(messageType)); + } + + return; + } + case OpCodeType.OuterAddressableMessage: + { + var packInfoPackInfoId = packInfo.PackInfoId; + + try + { + var messageType = MessageDispatcherComponent.GetOpCodeType(packInfo.ProtocolCode); + + if (messageType == null) + { + throw new Exception($"OuterMessageScheduler error 可能遭受到恶意发包或没有协议定义ProtocolCode ProtocolCode:{packInfo.ProtocolCode}"); + } + + var addressableRouteComponent = session.GetComponent(); + + if (addressableRouteComponent == null) + { + throw new Exception("OuterMessageScheduler error session does not have an AddressableRouteComponent component"); + } + + await addressableRouteComponent.Send(messageType, packInfo); + } + finally + { + if (packInfo.PackInfoId == packInfoPackInfoId) + { + packInfo.Dispose(); + } + } + + return; + } + case OpCodeType.OuterAddressableRequest: + { + var packInfoPackInfoId = packInfo.PackInfoId; + + try + { + var messageType = MessageDispatcherComponent.GetOpCodeType(packInfo.ProtocolCode); + + if (messageType == null) + { + throw new Exception($"OuterMessageScheduler error 可能遭受到恶意发包或没有协议定义ProtocolCode ProtocolCode:{packInfo.ProtocolCode}"); + } + + var addressableRouteComponent = session.GetComponent(); + + if (addressableRouteComponent == null) + { + throw new Exception("OuterMessageScheduler error session does not have an AddressableRouteComponent component"); + } + + var rpcId = packInfo.RpcId; + var runtimeId = session.RuntimeId; + var response = await addressableRouteComponent.Call(messageType, packInfo); + // session可能已经断开了,所以这里需要判断 + if (session.RuntimeId == runtimeId) + { + session.Send(response, rpcId); + } + } + finally + { + if (packInfo.PackInfoId == packInfoPackInfoId) + { + packInfo.Dispose(); + } + } + + return; + } + case OpCodeType.OuterCustomRouteMessage: + { + var packInfoProtocolCode = packInfo.ProtocolCode; + var packInfoPackInfoId = packInfo.PackInfoId; + + try + { + if (!MessageDispatcherComponent.GetCustomRouteType(packInfoProtocolCode, out var routeType)) + { + throw new Exception($"OuterMessageScheduler error 可能遭受到恶意发包或没有协议定义ProtocolCode ProtocolCode:{packInfo.ProtocolCode}"); + } + + var messageType = MessageDispatcherComponent.GetOpCodeType(packInfo.ProtocolCode); + + if (messageType == null) + { + throw new Exception($"OuterMessageScheduler error 可能遭受到恶意发包或没有协议定义ProtocolCode ProtocolCode:{packInfo.ProtocolCode}"); + } + + var routeComponent = session.GetComponent(); + + if (routeComponent == null) + { + throw new Exception($"OuterMessageScheduler CustomRouteType session does not have an routeComponent component messageType:{messageType.FullName} ProtocolCode:{packInfo.ProtocolCode}"); + } + + if (!routeComponent.TryGetRouteId(routeType, out var routeId)) + { + throw new Exception($"OuterMessageScheduler RouteComponent cannot find RouteId with RouteType {routeType}"); + } + + NetworkMessagingComponent.SendInnerRoute(routeId, messageType, packInfo); + } + finally + { + if (packInfo.PackInfoId == packInfoPackInfoId) + { + packInfo.Dispose(); + } + } + + return; + } + case OpCodeType.OuterCustomRouteRequest: + { + var packInfoProtocolCode = packInfo.ProtocolCode; + var packInfoPackInfoId = packInfo.PackInfoId; + + try + { + if (!MessageDispatcherComponent.GetCustomRouteType(packInfoProtocolCode, out var routeType)) + { + throw new Exception($"OuterMessageScheduler error 可能遭受到恶意发包或没有协议定义ProtocolCode ProtocolCode:{packInfo.ProtocolCode}"); + } + + var messageType = MessageDispatcherComponent.GetOpCodeType(packInfo.ProtocolCode); + + if (messageType == null) + { + throw new Exception($"OuterMessageScheduler error 可能遭受到恶意发包或没有协议定义ProtocolCode ProtocolCode:{packInfo.ProtocolCode}"); + } + + var routeComponent = session.GetComponent(); + + if (routeComponent == null) + { + throw new Exception("OuterMessageScheduler CustomRouteType session does not have an routeComponent component"); + } + + if (!routeComponent.TryGetRouteId(routeType, out var routeId)) + { + throw new Exception($"OuterMessageScheduler RouteComponent cannot find RouteId with RouteType {routeType}"); + } + + var rpcId = packInfo.RpcId; + var runtimeId = session.RuntimeId; + var response = await NetworkMessagingComponent.CallInnerRoute(routeId, messageType, packInfo); + // session可能已经断开了,所以这里需要判断 + if (session.RuntimeId == runtimeId) + { + session.Send(response, rpcId); + } + } + finally + { + if (packInfo.PackInfoId == packInfoPackInfoId) + { + packInfo.Dispose(); + } + } + + return; + } + default: + { + var ipAddress = session.IsDisposed ? "null" : session.RemoteEndPoint.ToString(); + packInfo.Dispose(); + throw new NotSupportedException($"OuterMessageScheduler Received unsupported message protocolCode:{packInfo.ProtocolCode}\n1、请检查该协议所在的程序集是否在框架初始化的时候添加到框架中。\n2、如果看到这个消息表示你有可能用的老版本的导出工具,请更换为最新的导出工具。\n IP地址:{ipAddress}"); + } + } + } + } +#endif +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/Scheduler/OuterMessageScheduler.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/Scheduler/OuterMessageScheduler.cs.meta new file mode 100644 index 0000000..2a06b06 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Message/Scheduler/OuterMessageScheduler.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 930429df1bd294cd4b38dd138fc43948 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol.meta new file mode 100644 index 0000000..182fffc --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: a02133269e172491b86c3e09afa4f7e8 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/Exception.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/Exception.meta new file mode 100644 index 0000000..8e24243 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/Exception.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 77e3add9ae69f48e2b054f8246914c2e +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/Exception/ScanException.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/Exception/ScanException.cs new file mode 100644 index 0000000..43c695a --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/Exception/ScanException.cs @@ -0,0 +1,21 @@ +using System; + +namespace Fantasy.Network +{ + /// + /// 在扫描过程中发生的异常。 + /// + public class ScanException : Exception + { + /// + /// 初始化 类的新实例。 + /// + public ScanException() { } + + /// + /// 使用指定的错误消息初始化 类的新实例。 + /// + /// 错误消息。 + public ScanException(string msg) : base(msg) { } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/Exception/ScanException.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/Exception/ScanException.cs.meta new file mode 100644 index 0000000..5ed0772 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/Exception/ScanException.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 91ac5b10fc1344aaf9e71ed8eb26ff92 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/HTTP.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/HTTP.meta new file mode 100644 index 0000000..c0d7ff1 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/HTTP.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 5bf4e2b57147246c6b32a7b458788c5e +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/HTTP/HTTPServerNetwork.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/HTTP/HTTPServerNetwork.cs new file mode 100644 index 0000000..9ca4eba --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/HTTP/HTTPServerNetwork.cs @@ -0,0 +1,128 @@ +#if FANTASY_NET +using System.IO; +using System.Net; +using System.Security.Cryptography.X509Certificates; +using System.Text; +using Fantasy.Assembly; +using Fantasy.Async; +using Fantasy.Network.Interface; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Server.Kestrel.Core; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Logging; + +#pragma warning disable CS8604 // Possible null reference argument. + +// ReSharper disable PossibleMultipleEnumeration + +namespace Fantasy.Network.HTTP +{ + /// + /// HTTP服务器 + /// + public sealed class HTTPServerNetwork : ANetwork + { + /// + /// 初始化入口 + /// + /// + /// + /// + public void Initialize(NetworkTarget networkTarget, string bindIp, int port) + { + base.Initialize(NetworkType.Server, NetworkProtocolType.HTTP, networkTarget); + + try + { + StartAsync(bindIp, port); + } + catch (HttpListenerException e) + { + if (e.ErrorCode == 5) + { + var sb = new StringBuilder(); + sb.AppendLine("CMD管理员中输入下面其中一个命令,具体根据您是HTTPS或HTTP决定:"); + sb.AppendLine($"HTTP请输入如下:netsh http add urlacl url=http://{bindIp}:{port}/ user=Everyone"); + sb.AppendLine($"HTTPS请输入如下:netsh http add urlacl url=https://{bindIp}:{port}/ user=Everyone"); + throw new Exception(sb.ToString(), e); + } + + Log.Error(e); + } + catch (Exception e) + { + Log.Error(e); + } + } + + private void StartAsync(string bindIp, int port) + { + var builder = WebApplication.CreateBuilder(); + // 配置日志级别为 Warning 或更高 + builder.Logging.ClearProviders(); + builder.Logging.AddConsole(); + builder.Logging.SetMinimumLevel(LogLevel.Warning); + // 将Scene注册到 DI 容器中,传递给控制器 + builder.Services.AddSingleton(Scene); + // 注册Scene同步过滤器 + builder.Services.AddScoped(); + // 注册控制器服务 + var addControllers = builder.Services.AddControllers() + .AddJsonOptions(options => { options.JsonSerializerOptions.PropertyNamingPolicy = null; }); + foreach (var assembly in AssemblySystem.ForEachAssembly) + { + addControllers.AddApplicationPart(assembly); + } + var listenUrl = ""; + var app = builder.Build(); + // 检测当前路径下是否有证书文件 + var certificatePath = Path.Combine(AppContext.BaseDirectory, $"certificate{bindIp}{port}"); + if (Directory.Exists(certificatePath)) + { + // 加载包含证书链的 PEM 文件 + var pemCertChain = File.ReadAllText(Path.Combine(certificatePath, "chain.pem")); + var pemPrivateKey = File.ReadAllText(Path.Combine(certificatePath, "private-key.pem")); + // 配置 HTTPS 监听并使用证书 + builder.WebHost.ConfigureKestrel(kestrelServerOptions => + { + kestrelServerOptions.ConfigureHttpsDefaults(https => + { + https.ServerCertificate = X509Certificate2.CreateFromPem(pemCertChain, pemPrivateKey); + }); + }); + listenUrl = $"https://{bindIp}:{port}/"; + app.Urls.Add(listenUrl); + app.UseHttpsRedirection(); + } + else + { + // 不安全的HTTP地址 + listenUrl = $"http://{bindIp}:{port}/"; + app.Urls.Add(listenUrl); + } + // 启用开发者工具 + if (app.Environment.IsDevelopment()) + { + app.UseDeveloperExceptionPage(); + } + // 路由注册 + app.MapControllers(); + // 开启监听 + app.RunAsync(); + Log.Info($"SceneConfigId = {Scene.SceneConfigId} HTTPServer Listen {listenUrl}"); + } + + /// + /// 移除Channel + /// + /// + /// + public override void RemoveChannel(uint channelId) + { + throw new NotImplementedException(); + } + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/HTTP/HTTPServerNetwork.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/HTTP/HTTPServerNetwork.cs.meta new file mode 100644 index 0000000..0f5c749 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/HTTP/HTTPServerNetwork.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 31856335ba0fe44a190c792ac8a00591 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/HTTP/SceneContextFilter.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/HTTP/SceneContextFilter.cs new file mode 100644 index 0000000..2688bdc --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/HTTP/SceneContextFilter.cs @@ -0,0 +1,54 @@ +#if FANTASY_NET +using Fantasy.Async; +using Microsoft.AspNetCore.Mvc.Filters; + +namespace Fantasy.Network.HTTP; + +/// +/// 让所有实现SceneContextFilter的控制器,都在执行的Scene下执行 +/// +public sealed class SceneContextFilter : IAsyncActionFilter +{ + private readonly Scene _scene; + + /// + /// 构造函数 + /// + /// + public SceneContextFilter(Scene scene) + { + _scene = scene; + } + + /// + /// OnActionExecutionAsync + /// + /// + /// + /// + public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next) + { + var tcs = FTask.Create(); + + _scene.ThreadSynchronizationContext.Post(() => + { + Action().Coroutine(); + }); + + await tcs; + return; + + async FTask Action() + { + try + { + await next(); + } + finally + { + tcs.SetResult(); + } + } + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/HTTP/SceneContextFilter.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/HTTP/SceneContextFilter.cs.meta new file mode 100644 index 0000000..2f747e4 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/HTTP/SceneContextFilter.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 21bf22052c50e4863a4ca66c0876ee41 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/Interface.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/Interface.meta new file mode 100644 index 0000000..81d84ae --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/Interface.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 88c6dddc716ee427c84ccbd728512576 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/Interface/AClientNetwork.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/Interface/AClientNetwork.cs new file mode 100644 index 0000000..322c811 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/Interface/AClientNetwork.cs @@ -0,0 +1,38 @@ +using System; +using System.IO; +using Fantasy.Serialize; + +// ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract +#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member + +namespace Fantasy.Network.Interface +{ + /// + /// 抽象客户端网络基类。 + /// + public abstract class AClientNetwork : ANetwork, INetworkChannel + { + protected bool IsInit; + public Session Session { get; protected set; } + public abstract Session Connect(string remoteAddress, Action onConnectComplete, Action onConnectFail, Action onConnectDisconnect, bool isHttps, int connectTimeout = 5000); + public abstract void Send(uint rpcId, long routeId, MemoryStreamBuffer memoryStream, IMessage message); + public override void Dispose() + { + IsInit = false; + + if (Session != null) + { + if (!Session.IsDisposed) + { + Session.Dispose(); + } + + Session = null; + } + + base.Dispose(); + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/Interface/AClientNetwork.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/Interface/AClientNetwork.cs.meta new file mode 100644 index 0000000..a1d2d54 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/Interface/AClientNetwork.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 5199ea30d15a6455e90c36094c43d539 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/Interface/ANetwork.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/Interface/ANetwork.cs new file mode 100644 index 0000000..fdb85f2 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/Interface/ANetwork.cs @@ -0,0 +1,149 @@ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.IO; +using Fantasy.Entitas; +using Fantasy.PacketParser; +using Fantasy.Scheduler; +using Fantasy.Serialize; + +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member + +namespace Fantasy.Network.Interface +{ + /// + /// 抽象网络基类。 + /// + public abstract class ANetwork : Entity + { + private long _outerPackInfoId; + private Queue _outerPackInfoPool; + public readonly MemoryStreamBufferPool MemoryStreamBufferPool = new MemoryStreamBufferPool(); + + public NetworkType NetworkType { get; private set; } + public NetworkTarget NetworkTarget { get; private set; } + public NetworkProtocolType NetworkProtocolType { get; private set; } + public ANetworkMessageScheduler NetworkMessageScheduler { get; private set; } + + protected void Initialize(NetworkType networkType, NetworkProtocolType networkProtocolType, NetworkTarget networkTarget) + { + NetworkType = networkType; + NetworkTarget = networkTarget; + NetworkProtocolType = networkProtocolType; +#if FANTASY_NET + if (networkProtocolType == NetworkProtocolType.HTTP) + { + return; + } + if (networkTarget == NetworkTarget.Inner) + { + _innerPackInfoPool = new Queue(); + NetworkMessageScheduler = new InnerMessageScheduler(Scene); + return; + } +#endif + switch (networkType) + { + case NetworkType.Client: + { + _outerPackInfoPool = new Queue(); + NetworkMessageScheduler = new ClientMessageScheduler(Scene); + break; + } +#if FANTASY_NET + case NetworkType.Server: + { + _outerPackInfoPool = new Queue(); + NetworkMessageScheduler = new OuterMessageScheduler(Scene); + break; + } +#endif + } + } + + public abstract void RemoveChannel(uint channelId); + public OuterPackInfo RentOuterPackInfo() + { + if (_outerPackInfoPool.Count == 0) + { + return new OuterPackInfo() + { + PackInfoId = ++_outerPackInfoId + }; + } + + if (!_outerPackInfoPool.TryDequeue(out var outerPackInfo)) + { + return new OuterPackInfo() + { + PackInfoId = ++_outerPackInfoId + }; + } + + outerPackInfo.PackInfoId = ++_outerPackInfoId; + return outerPackInfo; + } + + public void ReturnOuterPackInfo(OuterPackInfo outerPackInfo) + { + if (_outerPackInfoPool.Count > 512) + { + // 池子里最多缓存256个、其实这样设置有点多了、其实用不了512个。 + // 反而设置越大内存会占用越多。 + return; + } + + _outerPackInfoPool.Enqueue(outerPackInfo); + } +#if FANTASY_NET + private long _innerPackInfoId; + private Queue _innerPackInfoPool; + public InnerPackInfo RentInnerPackInfo() + { + if (_innerPackInfoPool.Count == 0) + { + return new InnerPackInfo() + { + PackInfoId = ++_innerPackInfoId + }; + } + + if (!_innerPackInfoPool.TryDequeue(out var innerPackInfo)) + { + return new InnerPackInfo() + { + PackInfoId = ++_innerPackInfoId + }; + } + + innerPackInfo.PackInfoId = ++_innerPackInfoId; + return innerPackInfo; + } + + public void ReturnInnerPackInfo(InnerPackInfo innerPackInfo) + { + if (_innerPackInfoPool.Count > 256) + { + // 池子里最多缓存256个、其实这样设置有点多了、其实用不了256个。 + // 反而设置越大内存会占用越多。 + return; + } + + _innerPackInfoPool.Enqueue(innerPackInfo); + } +#endif + public override void Dispose() + { + NetworkType = NetworkType.None; + NetworkTarget = NetworkTarget.None; + NetworkProtocolType = NetworkProtocolType.None; + MemoryStreamBufferPool.Dispose(); + _outerPackInfoPool?.Clear(); +#if FANTASY_NET + _innerPackInfoPool?.Clear(); +#endif + base.Dispose(); + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/Interface/ANetwork.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/Interface/ANetwork.cs.meta new file mode 100644 index 0000000..b6397b2 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/Interface/ANetwork.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 66036fdeeb81c43cab7485def9ddefaa +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/Interface/ANetworkServerChannel.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/Interface/ANetworkServerChannel.cs new file mode 100644 index 0000000..788a235 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/Interface/ANetworkServerChannel.cs @@ -0,0 +1,55 @@ +#if FANTASY_NET +using System.IO; +using System.Net; +using Fantasy.Serialize; + +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member + +namespace Fantasy.Network.Interface +{ + public abstract class ANetworkServerChannel : INetworkChannel + { + /// + /// 获取通道的唯一标识 ID。 + /// + public readonly uint Id; + /// + /// 获取通道的远程终端点。 + /// + public readonly EndPoint RemoteEndPoint; + /// + /// 获取或设置通道所属的场景。 + /// + public Scene Scene { get; protected set; } + /// + /// 获取或设置通道所属的会话。 + /// + public Session Session { get; protected set; } + /// + /// 获取通道是否已经被释放。 + /// + public bool IsDisposed { get; protected set; } + + protected ANetworkServerChannel(ANetwork network, uint id, EndPoint remoteEndPoint) + { + Id = id; + Scene = network.Scene; + RemoteEndPoint = remoteEndPoint; + Session = Session.Create(network.NetworkMessageScheduler, this, network.NetworkTarget); + } + + public virtual void Dispose() + { + IsDisposed = true; + + if (!Session.IsDisposed) + { + Session.Dispose(); + } + } + + public abstract void Send(uint rpcId, long routeId, MemoryStreamBuffer memoryStream, IMessage message); + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/Interface/ANetworkServerChannel.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/Interface/ANetworkServerChannel.cs.meta new file mode 100644 index 0000000..395fc6c --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/Interface/ANetworkServerChannel.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 014d26c6224c446bfabd518cdb90a331 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/Interface/INetworkChannel.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/Interface/INetworkChannel.cs new file mode 100644 index 0000000..52f341a --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/Interface/INetworkChannel.cs @@ -0,0 +1,14 @@ +using System; +using System.IO; +using Fantasy.Serialize; + +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member +namespace Fantasy.Network.Interface +{ + public interface INetworkChannel : IDisposable + { + public Session Session { get;} + public bool IsDisposed { get;} + public void Send(uint rpcId, long routeId, MemoryStreamBuffer memoryStream, IMessage message); + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/Interface/INetworkChannel.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/Interface/INetworkChannel.cs.meta new file mode 100644 index 0000000..216a6d2 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/Interface/INetworkChannel.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9b7c68ff50f634ca394b773b47d51176 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/KCP.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/KCP.meta new file mode 100644 index 0000000..774a538 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/KCP.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: f61404ce7928d45849910cc416c408e1 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/KCP/Base.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/KCP/Base.meta new file mode 100644 index 0000000..3b0a901 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/KCP/Base.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: fd62616e1f0334189977f45b5704df1d +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/KCP/Base/Kcp.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/KCP/Base/Kcp.cs new file mode 100644 index 0000000..b425a66 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/KCP/Base/Kcp.cs @@ -0,0 +1,626 @@ +#if UNITY_2021_3_OR_NEWER || GODOT +using System; +using System.Threading; +#endif +using static KCP.IKCP; + +#pragma warning disable CS8601 +#pragma warning disable CS8602 +#pragma warning disable CS8625 + +// ReSharper disable IdentifierTypo +// ReSharper disable GrammarMistakeInComment +// ReSharper disable PossibleNullReferenceException +// ReSharper disable ConvertToAutoPropertyWithPrivateSetter + +namespace KCP +{ + /// + /// Kcp + /// + public sealed unsafe class Kcp : IDisposable + { + /// + /// Kcp + /// + private IKCPCB* _kcp; + + /// + /// Output function + /// + private KcpCallback _output; + + /// + /// Buffer + /// + private byte[] _buffer; + + /// + /// Disposed + /// + private int _disposed; + + /// + /// Structure + /// + /// Output + public Kcp(KcpCallback output) : this(0, output) + { + } + + /// + /// Structure + /// + /// ConversationId + /// Output + public Kcp(uint conv, KcpCallback output) + { + _kcp = ikcp_create(conv, ref _buffer); + _output = output; + } + + /// + /// Set + /// + public bool IsSet => _kcp != null; + + /// + /// Conversation id + /// + public uint ConversationId => _kcp->conv; + + /// + /// Maximum transmission unit + /// + public uint MaximumTransmissionUnit => _kcp->mtu; + + /// + /// Maximum segment size + /// + public uint MaximumSegmentSize => _kcp->mss; + + /// + /// Connection state + /// + public int State => _kcp->state; + + /// + /// The sequence number of the first unacknowledged packet + /// + public uint SendUna => _kcp->snd_una; + + /// + /// The sequence number for the next packet to be sent + /// + public uint SendNext => _kcp->snd_nxt; + + /// + /// The sequence number for the next packet expected to be received + /// + public uint ReceiveNext => _kcp->rcv_nxt; + + /// + /// Slow start threshold for congestion control + /// + public uint SlowStartThreshold => _kcp->ssthresh; + + /// + /// Round-trip time variance + /// + public int RxRttval => _kcp->rx_rttval; + + /// + /// Smoothed round-trip time + /// + public int RxSrtt => _kcp->rx_srtt; + + /// + /// Retransmission timeout + /// + public int RxRto => _kcp->rx_rto; + + /// + /// Minimum retransmission timeout + /// + public int RxMinrto => _kcp->rx_minrto; + + /// + /// Send window size + /// + public uint SendWindowSize => _kcp->snd_wnd; + + /// + /// Receive window size + /// + public uint ReceiveWindowSize => _kcp->rcv_wnd; + + /// + /// Remote window size + /// + public uint RemoteWindowSize => _kcp->rmt_wnd; + + /// + /// Congestion window size + /// + public uint CongestionWindowSize => _kcp->cwnd; + + /// + /// Probe variable for fast recovery + /// + public uint Probe => _kcp->probe; + + /// + /// Current timestamp + /// + public uint Current => _kcp->current; + + /// + /// Flush interval + /// + public uint Interval => _kcp->interval; + + /// + /// Timestamp for the next flush + /// + public uint TimestampFlush => _kcp->ts_flush; + + /// + /// Number of retransmissions + /// + public uint Transmissions => _kcp->xmit; + + /// + /// Number of packets in the receive buffer + /// + public uint ReceiveBufferCount => _kcp->nrcv_buf; + + /// + /// Number of packets in the receive queue + /// + public uint ReceiveQueueCount => _kcp->nrcv_que; + + /// + /// Number of packets wait to receive + /// + public uint WaitReceiveCount => _kcp->nrcv_buf + _kcp->nrcv_que; + + /// + /// Number of packets in the send buffer + /// + public uint SendBufferCount => _kcp->nsnd_buf; + + /// + /// Number of packets in the send queue + /// + public uint SendQueueCount => _kcp->nsnd_que; + + /// + /// Number of packets wait to send + /// + public uint WaitSendCount => _kcp->nsnd_buf + _kcp->nsnd_que; + + /// + /// Whether Nagle's algorithm is disabled + /// + public uint NoDelay => _kcp->nodelay; + + /// + /// Whether the KCP connection has been updated + /// + public uint Updated => _kcp->updated; + + /// + /// Timestamp for the next probe + /// + public uint TimestampProbe => _kcp->ts_probe; + + /// + /// Probe wait time + /// + public uint ProbeWait => _kcp->probe_wait; + + /// + /// Incremental increase + /// + public uint Increment => _kcp->incr; + + /// + /// Pointer to the acknowledge list + /// + public uint* AckList => _kcp->acklist; + + /// + /// Count of acknowledges + /// + public uint AckCount => _kcp->ackcount; + + /// + /// Number of acknowledge blocks + /// + public uint AckBlock => _kcp->ackblock; + + /// + /// Buffer + /// + public byte[] Buffer => _buffer; + + /// + /// Fast resend trigger count + /// + public int FastResend => _kcp->fastresend; + + /// + /// Fast resend limit + /// + public int FastResendLimit => _kcp->fastlimit; + + /// + /// Whether congestion control is disabled + /// + public int NoCongestionWindow => _kcp->nocwnd; + + /// + /// Whether stream mode is enabled + /// + public int StreamMode => _kcp->stream; + + /// + /// Output function pointer + /// + public KcpCallback Output => _output; + + /// + /// Dispose + /// + public void Dispose() + { + if (Interlocked.CompareExchange(ref _disposed, 1, 0) != 0) + return; + ikcp_release(_kcp); + _kcp = null; + _output = null; + _buffer = null; + GC.SuppressFinalize(this); + } + + /// + /// Set output + /// + /// Output + public void SetOutput(KcpCallback output) => _output = output; + + /// + /// Destructure + /// + ~Kcp() => Dispose(); + + /// + /// Send + /// + /// Buffer + /// Sent bytes + public int Send(byte[] buffer) + { + fixed (byte* src = &buffer[0]) + return ikcp_send(_kcp, src, buffer.Length); + } + + /// + /// Send + /// + /// Buffer + /// Length + /// Sent bytes + public int Send(byte[] buffer, int length) + { + fixed (byte* src = &buffer[0]) + return ikcp_send(_kcp, src, length); + } + + /// + /// Send + /// + /// Buffer + /// Offset + /// Length + /// Sent bytes + public int Send(byte[] buffer, int offset, int length) + { + fixed (byte* src = &buffer[offset]) + return ikcp_send(_kcp, src, length); + } + + /// + /// Send + /// + /// Buffer + /// Sent bytes + public int Send(ReadOnlySpan buffer) + { + fixed (byte* src = &buffer[0]) + return ikcp_send(_kcp, src, buffer.Length); + } + + /// + /// Send + /// + /// Buffer + /// Sent bytes + public int Send(ReadOnlyMemory buffer) + { + fixed (byte* src = &buffer.Span[0]) + return ikcp_send(_kcp, src, buffer.Length); + } + + /// + /// Send + /// + /// Buffer + /// Sent bytes + public int Send(ArraySegment buffer) + { + fixed (byte* src = &buffer.Array[buffer.Offset]) + return ikcp_send(_kcp, src, buffer.Count); + } + + /// + /// Send + /// + /// Buffer + /// Length + /// Sent bytes + public int Send(byte* buffer, int length) => ikcp_send(_kcp, buffer, length); + + /// + /// Send + /// + /// Buffer + /// Offset + /// Length + /// Sent bytes + public int Send(byte* buffer, int offset, int length) => ikcp_send(_kcp, buffer + offset, length); + + /// + /// Input + /// + /// Buffer + /// Input bytes + public int Input(byte[] buffer) + { + fixed (byte* src = &buffer[0]) + return ikcp_input(_kcp, src, buffer.Length); + } + + /// + /// Input + /// + /// Buffer + /// Length + /// Input bytes + public int Input(byte[] buffer, int length) + { + fixed (byte* src = &buffer[0]) + return ikcp_input(_kcp, src, length); + } + + /// + /// Input + /// + /// Buffer + /// Offset + /// Length + /// Input bytes + public int Input(byte[] buffer, int offset, int length) + { + fixed (byte* src = &buffer[offset]) + return ikcp_input(_kcp, src, length); + } + + /// + /// Input + /// + /// Buffer + /// Input bytes + public int Input(ReadOnlySpan buffer) + { + fixed (byte* src = &buffer[0]) + return ikcp_input(_kcp, src, buffer.Length); + } + + /// + /// Input + /// + /// Buffer + /// Input bytes + public int Input(ReadOnlyMemory buffer) + { + fixed (byte* src = &buffer.Span[0]) + return ikcp_input(_kcp, src, buffer.Length); + } + + /// + /// Input + /// + /// Buffer + /// Input bytes + public int Input(ArraySegment buffer) + { + fixed (byte* src = &buffer.Array[buffer.Offset]) + return ikcp_input(_kcp, src, buffer.Count); + } + + /// + /// Input + /// + /// Buffer + /// Length + /// Input bytes + public int Input(byte* buffer, int length) => ikcp_input(_kcp, buffer, length); + + /// + /// Input + /// + /// Buffer + /// Offset + /// Length + /// Input bytes + public int Input(byte* buffer, int offset, int length) => ikcp_input(_kcp, buffer + offset, length); + + /// + /// Peek size + /// + /// Peeked size + public int PeekSize() => ikcp_peeksize(_kcp); + + /// + /// Receive + /// + /// Buffer + /// Received bytes + public int Receive(byte[] buffer) + { + fixed (byte* dest = &buffer[0]) + return ikcp_recv(_kcp, dest, buffer.Length); + } + + /// + /// Receive + /// + /// Buffer + /// Length + /// Received bytes + public int Receive(byte[] buffer, int length) + { + fixed (byte* dest = &buffer[0]) + return ikcp_recv(_kcp, dest, length); + } + + /// + /// Receive + /// + /// Buffer + /// Offset + /// Length + /// Received bytes + public int Receive(byte[] buffer, int offset, int length) + { + fixed (byte* dest = &buffer[offset]) + return ikcp_recv(_kcp, dest, length); + } + + /// + /// Receive + /// + /// Buffer + /// Received bytes + public int Receive(Span buffer) + { + fixed (byte* dest = &buffer[0]) + return ikcp_recv(_kcp, dest, buffer.Length); + } + + /// + /// Receive + /// + /// Buffer + /// Received bytes + public int Receive(Memory buffer) + { + fixed (byte* dest = &buffer.Span[0]) + return ikcp_recv(_kcp, dest, buffer.Length); + } + + /// + /// Receive + /// + /// Buffer + /// Received bytes + public int Receive(ArraySegment buffer) + { + fixed (byte* dest = &buffer.Array[buffer.Offset]) + return ikcp_recv(_kcp, dest, buffer.Count); + } + + /// + /// Receive + /// + /// Buffer + /// Length + /// Received bytes + public int Receive(byte* buffer, int length) => ikcp_recv(_kcp, buffer, length); + + /// + /// Receive + /// + /// Buffer + /// Offset + /// Length + /// Received bytes + public int Receive(byte* buffer, int offset, int length) => ikcp_recv(_kcp, buffer + offset, length); + + /// + /// Update + /// + /// Timestamp + public void Update(uint current) => ikcp_update(_kcp, current, _output, _buffer); + + /// + /// Check + /// + /// Timestamp + /// Next flush timestamp + public uint Check(uint current) => ikcp_check(_kcp, current); + + /// + /// Flush + /// + public void Flush() => ikcp_flush(_kcp, _output, _buffer); + + /// + /// Set maximum transmission unit + /// + /// Maximum transmission unit + /// Set + public int SetMtu(int mtu) => ikcp_setmtu(_kcp, mtu, ref _buffer); + + /// + /// Set flush interval + /// + /// Flush interval + public void SetInterval(int interval) => ikcp_interval(_kcp, interval); + + /// + /// Set no delay + /// + /// Whether Nagle's algorithm is disabled + /// Flush interval + /// Fast resend trigger count + /// No congestion window + public void SetNoDelay(int nodelay, int interval, int resend, int nc) => ikcp_nodelay(_kcp, nodelay, interval, resend, nc); + + /// + /// Set window size + /// + /// Send window size + /// Receive window size + public void SetWindowSize(int sndwnd, int rcvwnd) => ikcp_wndsize(_kcp, sndwnd, rcvwnd); + + /// + /// Set fast resend limit + /// + /// Fast resend limit + public void SetFastResendLimit(int fastlimit) => ikcp_fastresendlimit(_kcp, fastlimit); + + /// + /// Set whether stream mode is enabled + /// + /// Whether stream mode is enabled + public void SetStreamMode(int stream) => ikcp_streammode(_kcp, stream); + + /// + /// Set minimum retransmission timeout + /// + /// Minimum retransmission timeout + public void SetMinrto(int minrto) => ikcp_minrto(_kcp, minrto); + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/KCP/Base/Kcp.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/KCP/Base/Kcp.cs.meta new file mode 100644 index 0000000..f114766 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/KCP/Base/Kcp.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1f5d7dd29b23440a1bcddb58b7bd2a14 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/KCP/Base/ikcpc.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/KCP/Base/ikcpc.cs new file mode 100644 index 0000000..2575805 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/KCP/Base/ikcpc.cs @@ -0,0 +1,1218 @@ +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using Fantasy; +using static KCP.IQUEUEHEAD; +using static KCP.KCPBASIC; + +#pragma warning disable CS8600 +#pragma warning disable CS8602 +#pragma warning disable CS8981 + +// ReSharper disable IdentifierTypo +// ReSharper disable InconsistentNaming +// ReSharper disable ConvertIfStatementToSwitchStatement + +namespace KCP +{ + internal static unsafe class IKCP + { + private static void memcpy(void* dest, void* src, int n) + { + Unsafe.CopyBlockUnaligned(dest, src, (uint)n); + } + + private static void memcpy(void* dest, void* src, uint n) + { + Unsafe.CopyBlockUnaligned(dest, src, n); + } + + private static void* malloc(nint size) => +#if !UNITY_2021_3_OR_NEWER || NET6_0_OR_GREATER + NativeMemory.Alloc((nuint)size); +#else + (void*)Marshal.AllocHGlobal(size); +#endif + + private static void* malloc(nuint size) => +#if !UNITY_2021_3_OR_NEWER || NET6_0_OR_GREATER + NativeMemory.Alloc(size); +#else + (void*)Marshal.AllocHGlobal((nint)size); +#endif + + private static void free(void* ptr) => +#if !UNITY_2021_3_OR_NEWER || NET6_0_OR_GREATER + NativeMemory.Free(ptr); +#else + Marshal.FreeHGlobal((nint)ptr); +#endif + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static byte* ikcp_encode8u(byte* p, byte c) + { + *p++ = c; + return p; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static byte* ikcp_decode8u(byte* p, byte* c) + { + *c = *p++; + return p; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static byte* ikcp_encode16u(byte* p, ushort w) + { + memcpy(p, &w, 2); + p += 2; + return p; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static byte* ikcp_decode16u(byte* p, ushort* w) + { + memcpy(w, p, 2); + p += 2; + return p; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static byte* ikcp_encode32u(byte* p, uint l) + { + memcpy(p, &l, 4); + p += 4; + return p; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static byte* ikcp_decode32u(byte* p, uint* l) + { + memcpy(l, p, 4); + p += 4; + return p; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static uint _imin_(uint a, uint b) => a <= b ? a : b; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static uint _imax_(uint a, uint b) => a >= b ? a : b; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static uint _ibound_(uint lower, uint middle, uint upper) => _imin_(_imax_(lower, middle), upper); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static int _iclamp_(int x, uint min, uint max) => x < min ? (int)min : x > max ? (int)max : x; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static uint _iceilpow2_(uint x) + { + x--; + x |= x >> 1; + x |= x >> 2; + x |= x >> 4; + x |= x >> 8; + x |= x >> 16; + x++; + return x; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static int _itimediff(uint later, uint earlier) => (int)(later - earlier); + + private static void* ikcp_malloc(nint size) => malloc(size); + + private static void* ikcp_malloc(nuint size) => malloc(size); + + private static void ikcp_free(void* ptr) => free(ptr); + + private static IKCPSEG* ikcp_segment_new(IKCPCB* kcp, int size) => (IKCPSEG*)ikcp_malloc(sizeof(IKCPSEG) + size); + + private static void ikcp_segment_delete(IKCPCB* kcp, IKCPSEG* seg) => ikcp_free(seg); + + private static void ikcp_output(KcpCallback output, byte[] data, int size) + { + if (size == 0) + return; + output(data, ref size); + } + + public static IKCPCB* ikcp_create(uint conv, ref byte[] buffer) + { + var kcp = (IKCPCB*)ikcp_malloc(sizeof(IKCPCB)); + kcp->conv = conv; + kcp->snd_una = 0; + kcp->snd_nxt = 0; + kcp->rcv_nxt = 0; + kcp->ts_probe = 0; + kcp->probe_wait = 0; + kcp->snd_wnd = WND_SND; + kcp->rcv_wnd = WND_RCV; + kcp->rmt_wnd = WND_RCV; + kcp->cwnd = 0; + kcp->incr = 0; + kcp->probe = 0; + kcp->mtu = MTU_DEF; + kcp->mss = kcp->mtu - OVERHEAD; + kcp->stream = 0; + buffer = new byte[REVERSED_HEAD + (kcp->mtu + OVERHEAD) * 3]; + iqueue_init(&kcp->snd_queue); + iqueue_init(&kcp->rcv_queue); + iqueue_init(&kcp->snd_buf); + iqueue_init(&kcp->rcv_buf); + kcp->nrcv_buf = 0; + kcp->nsnd_buf = 0; + kcp->nrcv_que = 0; + kcp->nsnd_que = 0; + kcp->state = 0; + kcp->acklist = null; + kcp->ackblock = 0; + kcp->ackcount = 0; + kcp->rx_srtt = 0; + kcp->rx_rttval = 0; + kcp->rx_rto = (int)RTO_DEF; + kcp->rx_minrto = (int)RTO_MIN; + kcp->current = 0; + kcp->interval = INTERVAL; + kcp->ts_flush = INTERVAL; + kcp->nodelay = 0; + kcp->updated = 0; + kcp->ssthresh = THRESH_INIT; + kcp->fastresend = 0; + kcp->fastlimit = (int)FASTACK_LIMIT; + kcp->nocwnd = 0; + kcp->xmit = 0; + return kcp; + } + + public static void ikcp_release(IKCPCB* kcp) + { + if (kcp != null) + { + IKCPSEG* seg; + while (!iqueue_is_empty(&kcp->snd_buf)) + { + seg = iqueue_entry(kcp->snd_buf.next); + iqueue_del(&seg->node); + ikcp_segment_delete(kcp, seg); + } + + while (!iqueue_is_empty(&kcp->rcv_buf)) + { + seg = iqueue_entry(kcp->rcv_buf.next); + iqueue_del(&seg->node); + ikcp_segment_delete(kcp, seg); + } + + while (!iqueue_is_empty(&kcp->snd_queue)) + { + seg = iqueue_entry(kcp->snd_queue.next); + iqueue_del(&seg->node); + ikcp_segment_delete(kcp, seg); + } + + while (!iqueue_is_empty(&kcp->rcv_queue)) + { + seg = iqueue_entry(kcp->rcv_queue.next); + iqueue_del(&seg->node); + ikcp_segment_delete(kcp, seg); + } + + if (kcp->acklist != null) + ikcp_free(kcp->acklist); + kcp->nrcv_buf = 0; + kcp->nsnd_buf = 0; + kcp->nrcv_que = 0; + kcp->nsnd_que = 0; + kcp->ackcount = 0; + kcp->acklist = null; + ikcp_free(kcp); + } + } + + public static int ikcp_recv(IKCPCB* kcp, byte* buffer, int len) + { + if (iqueue_is_empty(&kcp->rcv_queue)) + return -1; + var peeksize = ikcp_peeksize_internal(kcp); + if (peeksize < 0) + return -2; + int recover; + IQUEUEHEAD* p; + IKCPSEG* seg; + if (len < 0) + { + len = -len; + if (peeksize > len) + return -3; + recover = kcp->nrcv_que >= kcp->rcv_wnd ? 1 : 0; + p = kcp->rcv_queue.next; + for (len = 0; p != &kcp->rcv_queue;) + { + seg = iqueue_entry(p); + p = p->next; + if (buffer != null) + { + memcpy(buffer, seg->data, seg->len); + buffer += seg->len; + } + + len += (int)seg->len; + var fragment = (int)seg->frg; + if (fragment == 0) + break; + } + } + else + { + if (peeksize > len) + return -3; + recover = kcp->nrcv_que >= kcp->rcv_wnd ? 1 : 0; + p = kcp->rcv_queue.next; + for (len = 0; p != &kcp->rcv_queue;) + { + seg = iqueue_entry(p); + p = p->next; + if (buffer != null) + { + memcpy(buffer, seg->data, seg->len); + buffer += seg->len; + } + + len += (int)seg->len; + var fragment = (int)seg->frg; + iqueue_del(&seg->node); + ikcp_segment_delete(kcp, seg); + kcp->nrcv_que--; + if (fragment == 0) + break; + } + } + + while (!iqueue_is_empty(&kcp->rcv_buf)) + { + seg = iqueue_entry(kcp->rcv_buf.next); + if (seg->sn == kcp->rcv_nxt && kcp->nrcv_que < kcp->rcv_wnd) + { + iqueue_del(&seg->node); + kcp->nrcv_buf--; + iqueue_add_tail(&seg->node, &kcp->rcv_queue); + kcp->nrcv_que++; + kcp->rcv_nxt++; + } + else + { + break; + } + } + + if (kcp->nrcv_que < kcp->rcv_wnd && recover != 0) + kcp->probe |= ASK_TELL; + return len; + } + + public static int ikcp_peeksize(IKCPCB* kcp) => iqueue_is_empty(&kcp->rcv_queue) ? -1 : ikcp_peeksize_internal(kcp); + + private static int ikcp_peeksize_internal(IKCPCB* kcp) + { + var seg = iqueue_entry(kcp->rcv_queue.next); + if (seg->frg == 0) + return (int)seg->len; + if (kcp->nrcv_que < seg->frg + 1) + return -1; + IQUEUEHEAD* p; + var length = 0; + for (p = kcp->rcv_queue.next; p != &kcp->rcv_queue; p = p->next) + { + seg = iqueue_entry(p); + length += (int)seg->len; + if (seg->frg == 0) + break; + } + + return length; + } + + public static int ikcp_send(IKCPCB* kcp, byte* buffer, int len) + { + if (len < 0) + return -1; + IKCPSEG* seg; + var sent = 0; + if (kcp->stream != 0) + { + if (!iqueue_is_empty(&kcp->snd_queue)) + { + var old = iqueue_entry(kcp->snd_queue.prev); + if (old->len < kcp->mss) + { + var capacity = (int)kcp->mss - (int)old->len; + var extend = len < capacity ? len : capacity; + seg = ikcp_segment_new(kcp, (int)old->len + extend); + iqueue_add_tail(&seg->node, &kcp->snd_queue); + memcpy(seg->data, old->data, old->len); + if (buffer != null) + { + memcpy(seg->data + old->len, buffer, extend); + buffer += extend; + } + + seg->len = old->len + (uint)extend; + seg->frg = 0; + len -= extend; + iqueue_del_init(&old->node); + ikcp_segment_delete(kcp, old); + sent = extend; + } + } + + if (len <= 0) + return sent; + int count; + if (len <= (int)kcp->mss) + { + count = 1; + } + else + { + count = (int)((len + kcp->mss - 1) / kcp->mss); + if (count >= (int)kcp->rcv_wnd) + return sent > 0 ? sent : -2; + if (count == 0) + count = 1; + } + + int i; + for (i = 0; i < count; ++i) + { + var size = len > (int)kcp->mss ? (int)kcp->mss : len; + seg = ikcp_segment_new(kcp, size); + if (buffer != null && len > 0) + memcpy(seg->data, buffer, size); + seg->len = (uint)size; + seg->frg = 0; + iqueue_init(&seg->node); + iqueue_add_tail(&seg->node, &kcp->snd_queue); + kcp->nsnd_que++; + if (buffer != null) + buffer += size; + len -= size; + sent += size; + } + } + else + { + int count; + if (len <= (int)kcp->mss) + { + count = 1; + } + else + { + count = (int)((len + kcp->mss - 1) / kcp->mss); + if (count > FRG_LIMIT || count >= (int)kcp->rcv_wnd) + return -2; + if (count == 0) + count = 1; + } + + int i; + for (i = 0; i < count; ++i) + { + var size = len > (int)kcp->mss ? (int)kcp->mss : len; + seg = ikcp_segment_new(kcp, size); + if (buffer != null && len > 0) + memcpy(seg->data, buffer, size); + seg->len = (uint)size; + seg->frg = (uint)(count - i - 1); + iqueue_init(&seg->node); + iqueue_add_tail(&seg->node, &kcp->snd_queue); + kcp->nsnd_que++; + if (buffer != null) + buffer += size; + len -= size; + sent += size; + } + } + + return sent; + } + + private static void ikcp_update_ack(IKCPCB* kcp, int rtt) + { + if (kcp->rx_srtt == 0) + { + kcp->rx_srtt = rtt; + kcp->rx_rttval = rtt / 2; + } + else + { + var delta = rtt - kcp->rx_srtt; + if (delta < 0) + delta = -delta; + kcp->rx_rttval = (3 * kcp->rx_rttval + delta) / 4; + kcp->rx_srtt = (7 * kcp->rx_srtt + rtt) / 8; + if (kcp->rx_srtt < 1) + kcp->rx_srtt = 1; + } + + var rto = (int)(kcp->rx_srtt + _imax_(kcp->interval, (uint)(4 * kcp->rx_rttval))); + kcp->rx_rto = (int)_ibound_((uint)kcp->rx_minrto, (uint)rto, RTO_MAX); + } + + private static void ikcp_shrink_buf(IKCPCB* kcp) + { + var p = kcp->snd_buf.next; + if (p != &kcp->snd_buf) + { + var seg = iqueue_entry(p); + kcp->snd_una = seg->sn; + } + else + { + kcp->snd_una = kcp->snd_nxt; + } + } + + private static void ikcp_parse_ack(IKCPCB* kcp, uint sn) + { + if (_itimediff(sn, kcp->snd_una) < 0 || _itimediff(sn, kcp->snd_nxt) >= 0) + return; + IQUEUEHEAD* p, next; + for (p = kcp->snd_buf.next; p != &kcp->snd_buf; p = next) + { + var seg = iqueue_entry(p); + next = p->next; + if (sn == seg->sn) + { + iqueue_del(p); + ikcp_segment_delete(kcp, seg); + kcp->nsnd_buf--; + break; + } + + if (_itimediff(sn, seg->sn) < 0) + break; + } + } + + private static void ikcp_parse_una(IKCPCB* kcp, uint una) + { + IQUEUEHEAD* p, next; + for (p = kcp->snd_buf.next; p != &kcp->snd_buf; p = next) + { + var seg = iqueue_entry(p); + next = p->next; + if (_itimediff(una, seg->sn) > 0) + { + iqueue_del(p); + ikcp_segment_delete(kcp, seg); + kcp->nsnd_buf--; + } + else + { + break; + } + } + } + + private static void ikcp_parse_fastack(IKCPCB* kcp, uint sn, uint ts) + { + if (_itimediff(sn, kcp->snd_una) < 0 || _itimediff(sn, kcp->snd_nxt) >= 0) + return; + IQUEUEHEAD* p, next; + for (p = kcp->snd_buf.next; p != &kcp->snd_buf; p = next) + { + var seg = iqueue_entry(p); + next = p->next; + if (_itimediff(sn, seg->sn) < 0) + break; + if (sn != seg->sn) + { +#if KCP_FASTACK_CONSERVE + seg->fastack++; +#else + if (_itimediff(ts, seg->ts) >= 0) + seg->fastack++; +#endif + } + } + } + + private static int ikcp_ack_push(IKCPCB* kcp, uint sn, uint ts) + { + var newsize = kcp->ackcount + 1; + if (newsize > kcp->ackblock) + { + var newblock = newsize <= 8 ? 8 : _iceilpow2_(newsize); + var acklist = (uint*)ikcp_malloc(newblock << 3); + if (kcp->acklist != null) + { + uint x; + for (x = 0; x < kcp->ackcount; ++x) + { + acklist[x * 2] = kcp->acklist[x * 2]; + acklist[x * 2 + 1] = kcp->acklist[x * 2 + 1]; + } + + ikcp_free(kcp->acklist); + } + + kcp->acklist = acklist; + kcp->ackblock = newblock; + } + + var ptr = &kcp->acklist[kcp->ackcount * 2]; + ptr[0] = sn; + ptr[1] = ts; + kcp->ackcount++; + return 0; + } + + private static void ikcp_ack_get(IKCPCB* kcp, int p, uint* sn, uint* ts) + { + if (sn != null) + sn[0] = kcp->acklist[p * 2]; + if (ts != null) + ts[0] = kcp->acklist[p * 2 + 1]; + } + + private static void ikcp_parse_data(IKCPCB* kcp, IKCPSEG* newseg) + { + var sn = newseg->sn; + if (_itimediff(sn, kcp->rcv_nxt + kcp->rcv_wnd) >= 0 || _itimediff(sn, kcp->rcv_nxt) < 0) + { + ikcp_segment_delete(kcp, newseg); + return; + } + + IQUEUEHEAD* p, prev; + var repeat = 0; + for (p = kcp->rcv_buf.prev; p != &kcp->rcv_buf; p = prev) + { + var seg = iqueue_entry(p); + prev = p->prev; + if (seg->sn == sn) + { + repeat = 1; + break; + } + + if (_itimediff(sn, seg->sn) > 0) + break; + } + + if (repeat == 0) + { + iqueue_init(&newseg->node); + iqueue_add(&newseg->node, p); + kcp->nrcv_buf++; + } + else + { + ikcp_segment_delete(kcp, newseg); + } + + while (!iqueue_is_empty(&kcp->rcv_buf)) + { + var seg = iqueue_entry(kcp->rcv_buf.next); + if (seg->sn == kcp->rcv_nxt && kcp->nrcv_que < kcp->rcv_wnd) + { + iqueue_del(&seg->node); + kcp->nrcv_buf--; + iqueue_add_tail(&seg->node, &kcp->rcv_queue); + kcp->nrcv_que++; + kcp->rcv_nxt++; + } + else + { + break; + } + } + } + + public static int ikcp_input(IKCPCB* kcp, byte* data, int size) + { + if (data == null || size < (int)OVERHEAD) + return -1; + var prev_una = kcp->snd_una; + uint maxack = 0, latest_ts = 0; + var flag = 0; + while (true) + { + uint ts, sn, len, una, conv; + ushort wnd; + byte cmd, frg; + if (size < (int)OVERHEAD) + break; + data = ikcp_decode32u(data, &conv); + if (conv != kcp->conv) + return -1; + data = ikcp_decode8u(data, &cmd); + data = ikcp_decode8u(data, &frg); + data = ikcp_decode16u(data, &wnd); + data = ikcp_decode32u(data, &ts); + data = ikcp_decode32u(data, &sn); + data = ikcp_decode32u(data, &una); + data = ikcp_decode32u(data, &len); + size -= (int)OVERHEAD; + if (size < len || (int)len < 0) + return -2; + if (cmd != CMD_PUSH && cmd != CMD_ACK && cmd != CMD_WASK && cmd != CMD_WINS) + return -3; + kcp->rmt_wnd = wnd; + ikcp_parse_una(kcp, una); + ikcp_shrink_buf(kcp); + if (cmd == CMD_ACK) + { + if (_itimediff(kcp->current, ts) >= 0) + ikcp_update_ack(kcp, _itimediff(kcp->current, ts)); + ikcp_parse_ack(kcp, sn); + ikcp_shrink_buf(kcp); + if (flag == 0) + { + flag = 1; + maxack = sn; + latest_ts = ts; + } + else + { + if (_itimediff(sn, maxack) > 0) + { +#if KCP_FASTACK_CONSERVE + maxack = sn; + latest_ts = ts; +#else + if (_itimediff(ts, latest_ts) > 0) + { + maxack = sn; + latest_ts = ts; + } +#endif + } + } + } + else if (cmd == CMD_PUSH) + { + if (_itimediff(sn, kcp->rcv_nxt + kcp->rcv_wnd) < 0) + { + if (ikcp_ack_push(kcp, sn, ts) != 0) + return -4; + if (_itimediff(sn, kcp->rcv_nxt) >= 0) + { + var seg = ikcp_segment_new(kcp, (int)len); + seg->conv = conv; + seg->cmd = cmd; + seg->frg = frg; + seg->wnd = wnd; + seg->ts = ts; + seg->sn = sn; + seg->una = una; + seg->len = len; + if (len > 0) + memcpy(seg->data, data, len); + ikcp_parse_data(kcp, seg); + } + } + } + else if (cmd == CMD_WASK) + { + kcp->probe |= ASK_TELL; + } + else if (cmd != CMD_WINS) + { + return -3; + } + + data += len; + size -= (int)len; + } + + if (flag != 0) + ikcp_parse_fastack(kcp, maxack, latest_ts); + if (_itimediff(kcp->snd_una, prev_una) > 0) + { + if (kcp->cwnd < kcp->rmt_wnd) + { + var mss = kcp->mss; + if (kcp->cwnd < kcp->ssthresh) + { + kcp->cwnd++; + kcp->incr += mss; + } + else + { + if (kcp->incr < mss) + kcp->incr = mss; + kcp->incr += mss * mss / kcp->incr + mss / 16; + if ((kcp->cwnd + 1) * mss <= kcp->incr) + kcp->cwnd = (kcp->incr + mss - 1) / (mss > 0 ? mss : 1); + } + + if (kcp->cwnd > kcp->rmt_wnd) + { + kcp->cwnd = kcp->rmt_wnd; + kcp->incr = kcp->rmt_wnd * mss; + } + } + } + + return 0; + } + + private static byte* ikcp_encode_seg(byte* ptr, IKCPSEG* seg) + { + ptr = ikcp_encode32u(ptr, seg->conv); + ptr = ikcp_encode8u(ptr, (byte)seg->cmd); + ptr = ikcp_encode8u(ptr, (byte)seg->frg); + ptr = ikcp_encode16u(ptr, (ushort)seg->wnd); + ptr = ikcp_encode32u(ptr, seg->ts); + ptr = ikcp_encode32u(ptr, seg->sn); + ptr = ikcp_encode32u(ptr, seg->una); + ptr = ikcp_encode32u(ptr, seg->len); + return ptr; + } + + private static int ikcp_wnd_unused(IKCPCB* kcp) => kcp->nrcv_que < kcp->rcv_wnd ? (int)(kcp->rcv_wnd - kcp->nrcv_que) : 0; + + public static void ikcp_flush(IKCPCB* kcp, KcpCallback output, byte[] bytes) + { + if (kcp->updated == 0) + return; + ikcp_flush_internal(kcp, output, bytes); + } + + private static void ikcp_flush_internal(IKCPCB* kcp, KcpCallback output, byte[] bytes) + { + var current = kcp->current; + fixed (byte* buffer = &bytes[REVERSED_HEAD]) + { + var ptr = buffer; + int size, i; + IQUEUEHEAD* p; + var change = 0; + var lost = 0; + IKCPSEG seg; + seg.conv = kcp->conv; + seg.cmd = CMD_ACK; + seg.frg = 0; + seg.wnd = (uint)ikcp_wnd_unused(kcp); + seg.una = kcp->rcv_nxt; + seg.len = 0; + seg.sn = 0; + seg.ts = 0; + var count = (int)kcp->ackcount; + for (i = 0; i < count; ++i) + { + size = (int)(ptr - buffer); + if (size + (int)OVERHEAD > (int)kcp->mtu) + { + ikcp_output(output, bytes, size); + ptr = buffer; + } + + ikcp_ack_get(kcp, i, &seg.sn, &seg.ts); + ptr = ikcp_encode_seg(ptr, &seg); + } + + kcp->ackcount = 0; + if (kcp->rmt_wnd == 0) + { + if (kcp->probe_wait == 0) + { + kcp->probe_wait = PROBE_INIT; + kcp->ts_probe = kcp->current + kcp->probe_wait; + } + else + { + if (_itimediff(kcp->current, kcp->ts_probe) >= 0) + { + if (kcp->probe_wait < PROBE_INIT) + kcp->probe_wait = PROBE_INIT; + kcp->probe_wait += kcp->probe_wait / 2; + if (kcp->probe_wait > PROBE_LIMIT) + kcp->probe_wait = PROBE_LIMIT; + kcp->ts_probe = kcp->current + kcp->probe_wait; + kcp->probe |= ASK_SEND; + } + } + } + else + { + kcp->ts_probe = 0; + kcp->probe_wait = 0; + } + + if ((kcp->probe != 0) & (ASK_SEND != 0)) + { + seg.cmd = CMD_WASK; + size = (int)(ptr - buffer); + if (size + (int)OVERHEAD > (int)kcp->mtu) + { + ikcp_output(output, bytes, size); + ptr = buffer; + } + + ptr = ikcp_encode_seg(ptr, &seg); + } + + if ((kcp->probe != 0) & (ASK_TELL != 0)) + { + seg.cmd = CMD_WINS; + size = (int)(ptr - buffer); + if (size + (int)OVERHEAD > (int)kcp->mtu) + { + ikcp_output(output, bytes, size); + ptr = buffer; + } + + ptr = ikcp_encode_seg(ptr, &seg); + } + + kcp->probe = 0; + var cwnd = _imin_(kcp->snd_wnd, kcp->rmt_wnd); + if (kcp->nocwnd == 0) + cwnd = _imin_(kcp->cwnd, cwnd); + while (_itimediff(kcp->snd_nxt, kcp->snd_una + cwnd) < 0) + { + if (iqueue_is_empty(&kcp->snd_queue)) + break; + var newseg = iqueue_entry(kcp->snd_queue.next); + iqueue_del(&newseg->node); + iqueue_add_tail(&newseg->node, &kcp->snd_buf); + kcp->nsnd_que--; + kcp->nsnd_buf++; + newseg->conv = kcp->conv; + newseg->cmd = CMD_PUSH; + newseg->wnd = seg.wnd; + newseg->ts = current; + newseg->sn = kcp->snd_nxt++; + newseg->una = kcp->rcv_nxt; + newseg->resendts = current; + newseg->rto = (uint)kcp->rx_rto; + newseg->fastack = 0; + newseg->xmit = 0; + } + + var resent = kcp->fastresend > 0 ? (uint)kcp->fastresend : 4294967295; + if (kcp->nodelay == 0) + { + var rtomin = (uint)(kcp->rx_rto >> 3); + for (p = kcp->snd_buf.next; p != &kcp->snd_buf; p = p->next) + { + var segment = iqueue_entry(p); + var needsend = 0; + if (segment->xmit == 0) + { + needsend = 1; + segment->xmit++; + segment->rto = (uint)kcp->rx_rto; + segment->resendts = current + segment->rto + rtomin; + } + else if (_itimediff(current, segment->resendts) >= 0) + { + needsend = 1; + segment->xmit++; + kcp->xmit++; + segment->rto += _imax_(segment->rto, (uint)kcp->rx_rto); + segment->resendts = current + segment->rto; + lost = 1; + } + else if (segment->fastack >= resent) + { + if ((int)segment->xmit <= kcp->fastlimit || kcp->fastlimit == 0) + { + needsend = 1; + segment->xmit++; + segment->fastack = 0; + segment->resendts = current + segment->rto; + change++; + } + } + + if (needsend != 0) + { + segment->ts = current; + segment->wnd = seg.wnd; + segment->una = kcp->rcv_nxt; + size = (int)(ptr - buffer); + var need = (int)(OVERHEAD + segment->len); + if (size + need > (int)kcp->mtu) + { + ikcp_output(output, bytes, size); + ptr = buffer; + } + + ptr = ikcp_encode_seg(ptr, segment); + if (segment->len > 0) + { + memcpy(ptr, segment->data, segment->len); + ptr += segment->len; + } + + if (segment->xmit >= DEADLINK) + kcp->state = -1; + } + } + } + else if (kcp->nodelay == 1) + { + for (p = kcp->snd_buf.next; p != &kcp->snd_buf; p = p->next) + { + var segment = iqueue_entry(p); + var needsend = 0; + if (segment->xmit == 0) + { + needsend = 1; + segment->xmit++; + segment->rto = (uint)kcp->rx_rto; + segment->resendts = current + segment->rto; + } + else if (_itimediff(current, segment->resendts) >= 0) + { + needsend = 1; + segment->xmit++; + kcp->xmit++; + var step = (int)segment->rto; + segment->rto += (uint)(step / 2); + segment->resendts = current + segment->rto; + lost = 1; + } + else if (segment->fastack >= resent) + { + if ((int)segment->xmit <= kcp->fastlimit || kcp->fastlimit == 0) + { + needsend = 1; + segment->xmit++; + segment->fastack = 0; + segment->resendts = current + segment->rto; + change++; + } + } + + if (needsend != 0) + { + segment->ts = current; + segment->wnd = seg.wnd; + segment->una = kcp->rcv_nxt; + size = (int)(ptr - buffer); + var need = (int)(OVERHEAD + segment->len); + if (size + need > (int)kcp->mtu) + { + ikcp_output(output, bytes, size); + ptr = buffer; + } + + ptr = ikcp_encode_seg(ptr, segment); + if (segment->len > 0) + { + memcpy(ptr, segment->data, segment->len); + ptr += segment->len; + } + + if (segment->xmit >= DEADLINK) + kcp->state = -1; + } + } + } + else + { + for (p = kcp->snd_buf.next; p != &kcp->snd_buf; p = p->next) + { + var segment = iqueue_entry(p); + var needsend = 0; + if (segment->xmit == 0) + { + needsend = 1; + segment->xmit++; + segment->rto = (uint)kcp->rx_rto; + segment->resendts = current + segment->rto; + } + else if (_itimediff(current, segment->resendts) >= 0) + { + needsend = 1; + segment->xmit++; + kcp->xmit++; + var step = (int)segment->rto; + segment->rto += (uint)(step / 2); + segment->resendts = current + segment->rto; + lost = 1; + } + else if (segment->fastack >= resent) + { + if ((int)segment->xmit <= kcp->fastlimit || kcp->fastlimit == 0) + { + needsend = 1; + segment->xmit++; + segment->fastack = 0; + segment->resendts = current + segment->rto; + change++; + } + } + + if (needsend != 0) + { + segment->ts = current; + segment->wnd = seg.wnd; + segment->una = kcp->rcv_nxt; + size = (int)(ptr - buffer); + var need = (int)(OVERHEAD + segment->len); + if (size + need > (int)kcp->mtu) + { + ikcp_output(output, bytes, size); + ptr = buffer; + } + + ptr = ikcp_encode_seg(ptr, segment); + if (segment->len > 0) + { + memcpy(ptr, segment->data, segment->len); + ptr += segment->len; + } + + if (segment->xmit >= DEADLINK) + kcp->state = -1; + } + } + } + + size = (int)(ptr - buffer); + if (size > 0) + ikcp_output(output, bytes, size); + if (change != 0) + { + var inflight = kcp->snd_nxt - kcp->snd_una; + kcp->ssthresh = inflight / 2; + if (kcp->ssthresh < THRESH_MIN) + kcp->ssthresh = THRESH_MIN; + kcp->cwnd = kcp->ssthresh + resent; + kcp->incr = kcp->cwnd * kcp->mss; + } + + if (lost != 0) + { + kcp->ssthresh = cwnd / 2; + if (kcp->ssthresh < THRESH_MIN) + kcp->ssthresh = THRESH_MIN; + kcp->cwnd = 1; + kcp->incr = kcp->mss; + } + + if (kcp->cwnd < 1) + { + kcp->cwnd = 1; + kcp->incr = kcp->mss; + } + } + } + + public static void ikcp_update(IKCPCB* kcp, uint current, KcpCallback output, byte[] bytes) + { + kcp->current = current; + if (kcp->updated == 0) + { + kcp->updated = 1; + kcp->ts_flush = kcp->current; + } + + var slap = _itimediff(kcp->current, kcp->ts_flush); + if (slap >= 10000 || slap < -10000) + { + kcp->ts_flush = kcp->current; + slap = 0; + } + + if (slap >= 0) + { + kcp->ts_flush += kcp->interval; + if (_itimediff(kcp->current, kcp->ts_flush) >= 0) + kcp->ts_flush = kcp->current + kcp->interval; + ikcp_flush_internal(kcp, output, bytes); + } + } + + public static uint ikcp_check(IKCPCB* kcp, uint current) + { + if (kcp->updated == 0) + return current; + var ts_flush = kcp->ts_flush; + if (_itimediff(current, ts_flush) >= 10000 || _itimediff(current, ts_flush) < -10000) + ts_flush = current; + if (_itimediff(current, ts_flush) >= 0) + return current; + var tm_packet = 2147483647; + var tm_flush = _itimediff(ts_flush, current); + IQUEUEHEAD* p; + for (p = kcp->snd_buf.next; p != &kcp->snd_buf; p = p->next) + { + var seg = iqueue_entry(p); + var diff = _itimediff(seg->resendts, current); + if (diff <= 0) + return current; + if (diff < tm_packet) + tm_packet = diff; + } + + var minimal = (uint)(tm_packet < tm_flush ? tm_packet : tm_flush); + if (minimal >= kcp->interval) + minimal = kcp->interval; + return current + minimal; + } + + public static int ikcp_setmtu(IKCPCB* kcp, int mtu, ref byte[] buffer) + { + if (kcp->mtu == (uint)mtu) + return 0; + if (mtu < (int)OVERHEAD) + return -1; + buffer = new byte[REVERSED_HEAD + (mtu + OVERHEAD) * 3]; + kcp->mtu = (uint)mtu; + kcp->mss = kcp->mtu - OVERHEAD; + return 0; + } + + public static void ikcp_interval(IKCPCB* kcp, int interval) + { + interval = _iclamp_(interval, INTERVAL_MIN, INTERVAL_LIMIT); + kcp->interval = (uint)interval; + } + + public static void ikcp_nodelay(IKCPCB* kcp, int nodelay, int interval, int resend, int nc) + { + nodelay = _iclamp_(nodelay, NODELAY_MIN, NODELAY_LIMIT); + kcp->nodelay = (uint)nodelay; + if (nodelay != 0) + kcp->rx_minrto = (int)RTO_NDL; + else + kcp->rx_minrto = (int)RTO_MIN; + interval = _iclamp_(interval, INTERVAL_MIN, INTERVAL_LIMIT); + kcp->interval = (uint)interval; + resend = _iclamp_(resend, 0, 4294967295); + kcp->fastresend = resend; + kcp->nocwnd = nc == 1 ? 1 : 0; + } + + public static void ikcp_wndsize(IKCPCB* kcp, int sndwnd, int rcvwnd) + { + sndwnd = _iclamp_(sndwnd, WND_SND, 2147483647); + rcvwnd = _iclamp_(rcvwnd, WND_RCV, 2147483647); + kcp->snd_wnd = (uint)sndwnd; + kcp->rcv_wnd = (uint)rcvwnd; + } + + public static void ikcp_fastresendlimit(IKCPCB* kcp, int fastlimit) + { + fastlimit = _iclamp_(fastlimit, FASTACK_MIN, FASTACK_LIMIT); + kcp->fastlimit = fastlimit; + } + + public static void ikcp_streammode(IKCPCB* kcp, int stream) => kcp->stream = stream == 1 ? 1 : 0; + + public static void ikcp_minrto(IKCPCB* kcp, int minrto) + { + minrto = _iclamp_(minrto, INTERVAL_MIN, RTO_MAX); + kcp->rx_minrto = minrto; + } + } +} diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/KCP/Base/ikcpc.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/KCP/Base/ikcpc.cs.meta new file mode 100644 index 0000000..0578192 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/KCP/Base/ikcpc.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1b0ee69cc284b4c52b9d0f55e73d8d5c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/KCP/Base/ikcph.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/KCP/Base/ikcph.cs new file mode 100644 index 0000000..ebd5cc6 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/KCP/Base/ikcph.cs @@ -0,0 +1,159 @@ +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +#pragma warning disable CS1591 +#pragma warning disable CS8981 + +// ReSharper disable IdentifierTypo +// ReSharper disable InconsistentNaming + +namespace KCP +{ + public delegate void KcpCallback(byte[] buffer, ref int length); + + internal unsafe struct IQUEUEHEAD + { + public IQUEUEHEAD* next; + public IQUEUEHEAD* prev; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void iqueue_init(IQUEUEHEAD* ptr) + { + ptr->next = ptr; + ptr->prev = ptr; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static IKCPSEG* iqueue_entry(IQUEUEHEAD* ptr) => (IKCPSEG*)(byte*)(IKCPSEG*)ptr; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool iqueue_is_empty(IQUEUEHEAD* entry) => entry == entry->next; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void iqueue_del(IQUEUEHEAD* entry) + { + entry->next->prev = entry->prev; + entry->prev->next = entry->next; + entry->next = null; + entry->prev = null; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void iqueue_del_init(IQUEUEHEAD* entry) + { + iqueue_del(entry); + iqueue_init(entry); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void iqueue_add(IQUEUEHEAD* node, IQUEUEHEAD* head) + { + node->prev = head; + node->next = head->next; + head->next->prev = node; + head->next = node; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void iqueue_add_tail(IQUEUEHEAD* node, IQUEUEHEAD* head) + { + node->prev = head->prev; + node->next = head; + head->prev->next = node; + head->prev = node; + } + } + + [StructLayout(LayoutKind.Sequential)] + internal unsafe struct IKCPSEG + { + public IQUEUEHEAD node; + public uint conv; + public uint cmd; + public uint frg; + public uint wnd; + public uint ts; + public uint sn; + public uint una; + public uint len; + public uint resendts; + public uint rto; + public uint fastack; + public uint xmit; + public fixed byte data[1]; + } + + [StructLayout(LayoutKind.Sequential)] + internal unsafe struct IKCPCB + { + public uint conv, mtu, mss; + public int state; + public uint snd_una, snd_nxt, rcv_nxt; + public uint ssthresh; + public int rx_rttval, rx_srtt, rx_rto, rx_minrto; + public uint snd_wnd, rcv_wnd, rmt_wnd, cwnd, probe; + public uint current, interval, ts_flush, xmit; + public uint nrcv_buf, nsnd_buf; + public uint nrcv_que, nsnd_que; + public uint nodelay, updated; + public uint ts_probe, probe_wait; + public uint incr; + public IQUEUEHEAD snd_queue; + public IQUEUEHEAD rcv_queue; + public IQUEUEHEAD snd_buf; + public IQUEUEHEAD rcv_buf; + public uint* acklist; + public uint ackcount; + public uint ackblock; + public int fastresend; + public int fastlimit; + public int nocwnd, stream; + } + + public static class KCPBASIC + { + public const uint RTO_NDL = 30; + public const uint RTO_MIN = 100; + public const uint RTO_DEF = 200; + public const uint RTO_MAX = 60000; + public const uint CMD_PUSH = 81; + public const uint CMD_ACK = 82; + public const uint CMD_WASK = 83; + public const uint CMD_WINS = 84; + public const uint ASK_SEND = 1; + public const uint ASK_TELL = 2; + public const uint WND_SND = 32; + public const uint WND_RCV = 128; + public const uint MTU_DEF = 1400; + public const uint ACK_FAST = 3; + public const uint INTERVAL = 100; + public const uint INTERVAL_MIN = 1; + public const uint INTERVAL_LIMIT = 5000; + public const uint OVERHEAD = 24; + public const uint DEADLINK = 20; + public const uint THRESH_INIT = 2; + public const uint THRESH_MIN = 2; + public const uint PROBE_INIT = 7000; + public const uint PROBE_LIMIT = 120000; + public const uint FRG_LIMIT = 255; + public const uint NODELAY_MIN = 0; + public const uint NODELAY_LIMIT = 2; + public const uint FASTACK_MIN = 0; + public const uint FASTACK_LIMIT = 5; + public const uint OUTPUT = 1; + public const uint INPUT = 2; + public const uint SEND = 4; + public const uint RECV = 8; + public const uint IN_DATA = 16; + public const uint IN_ACK = 32; + public const uint IN_PROBE = 64; + public const uint IN_WINS = 128; + public const uint OUT_DATA = 256; + public const uint OUT_ACK = 512; + public const uint OUT_PROBE = 1024; + public const uint OUT_WINS = 2048; + + // TODO: remove it if not needed + public const uint REVERSED_HEAD = 5; + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/KCP/Base/ikcph.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/KCP/Base/ikcph.cs.meta new file mode 100644 index 0000000..30dbc21 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/KCP/Base/ikcph.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 89a1db82f89dc4369b9b3478cd2d33c9 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/KCP/Client.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/KCP/Client.meta new file mode 100644 index 0000000..1004987 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/KCP/Client.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: a04e3efb5ed984e1aac1e1b7da7cd876 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/KCP/Client/KCPClientNetwork.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/KCP/Client/KCPClientNetwork.cs new file mode 100644 index 0000000..8881cfb --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/KCP/Client/KCPClientNetwork.cs @@ -0,0 +1,687 @@ +#if !FANTASY_WEBGL +using System; +using System.Buffers; +using System.Collections.Generic; +using System.IO; +using System.IO.Pipelines; +using System.Net; +using System.Net.Sockets; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Security.Cryptography; +using System.Threading; +using Fantasy.Async; +using Fantasy.Entitas.Interface; +using Fantasy.Helper; +using Fantasy.Network.Interface; +using Fantasy.PacketParser; +using Fantasy.Serialize; +using KCP; +// ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract +// ReSharper disable PossibleNullReferenceException +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. + +#pragma warning disable CS8622 // Nullability of reference types in type of parameter doesn't match the target delegate (possibly because of nullability attributes). + +#pragma warning disable CS8602 // Dereference of a possibly null reference. +namespace Fantasy.Network.KCP +{ + public sealed class KCPClientNetworkUpdateSystem : UpdateSystem + { + protected override void Update(KCPClientNetwork self) + { + self.CheckUpdate(); + } + } + public sealed class KCPClientNetwork : AClientNetwork + { + private Kcp _kcp; + private Socket _socket; + private int _maxSndWnd; + private long _startTime; + private bool _isConnected; + private bool _isDisconnect; + private uint _updateMinTime; + private bool _isInnerDispose; + private long _connectTimeoutId; + private bool _allowWraparound = true; + private IPEndPoint _remoteAddress; + private BufferPacketParser _packetParser; + private readonly Pipe _pipe = new Pipe(); + private readonly byte[] _sendBuff = new byte[5]; + private readonly byte[] _receiveBuffer = new byte[Packet.PacketBodyMaxLength + 20]; + private readonly List _updateTimeOutTime = new List(); + private readonly SortedSet _updateTimer = new SortedSet(); + private readonly SocketAsyncEventArgs _connectEventArgs = new SocketAsyncEventArgs(); + private readonly Queue _messageCache = new Queue(); + private readonly CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource(); +#if FANTASY_UNITY + private readonly EndPoint _ipEndPoint = new IPEndPoint(IPAddress.Any, 0); +#endif + private event Action OnConnectFail; + private event Action OnConnectComplete; + private event Action OnConnectDisconnect; + public uint ChannelId { get; private set; } + private uint TimeNow => (uint) (TimeHelper.Now - _startTime); + + public void Initialize(NetworkTarget networkTarget) + { + base.Initialize(NetworkType.Client, NetworkProtocolType.KCP, networkTarget); + _packetParser = PacketParserFactory.CreateClientBufferPacket(this); + } + + public override void Dispose() + { + if (IsDisposed || _isInnerDispose) + { + return; + } + + _isInnerDispose = true; + + if (!_isDisconnect) + { + SendDisconnect(); + } + + base.Dispose(); + ClearConnectTimeout(); + + if (!_cancellationTokenSource.IsCancellationRequested) + { + try + { + _cancellationTokenSource.Cancel(); + } + catch (OperationCanceledException) + { + // 通常情况下,此处的异常可以忽略 + } + } + + OnConnectDisconnect?.Invoke(); + _kcp.Dispose(); + + if (_socket.Connected) + { + _socket.Close(); + } + + _packetParser.Dispose(); + ChannelId = 0; + _isConnected = false; + _messageCache.Clear(); + } + + #region Connect + + public override Session Connect(string remoteAddress, Action onConnectComplete, Action onConnectFail, Action onConnectDisconnect, bool isHttps, int connectTimeout = 5000) + { + if (IsInit) + { + throw new NotSupportedException($"KCPClientNetwork Has already been initialized. If you want to call Connect again, please re instantiate it."); + } + + IsInit = true; + _startTime = TimeHelper.Now; + ChannelId = CreateChannelId(); + _remoteAddress = NetworkHelper.GetIPEndPoint(remoteAddress); + OnConnectFail = onConnectFail; + OnConnectComplete = onConnectComplete; + OnConnectDisconnect = onConnectDisconnect; + _connectEventArgs.Completed += OnConnectSocketCompleted; + _connectTimeoutId = Scene.TimerComponent.Net.OnceTimer(connectTimeout, () => + { + OnConnectFail?.Invoke(); + Dispose(); + }); + _connectEventArgs.RemoteEndPoint = _remoteAddress; + _socket = new Socket(_remoteAddress.AddressFamily, SocketType.Dgram, ProtocolType.Udp); + _socket.Blocking = false; + _socket.SetSocketBufferToOsLimit(); + _socket.SetSioUdpConnReset(); + _socket.Bind(new IPEndPoint(IPAddress.Any, 0)); + _kcp = KCPFactory.Create(NetworkTarget, ChannelId, KcpSpanCallback, out var kcpSettings); + _maxSndWnd = kcpSettings.MaxSendWindowSize; + + if (!_socket.ConnectAsync(_connectEventArgs)) + { + try + { + OnReceiveSocketComplete(); + } + catch (Exception e) + { + Log.Error(e); + OnConnectFail?.Invoke(); + } + } + + Session = Session.Create(this, _remoteAddress); + return Session; + } + + private void OnConnectSocketCompleted(object sender, SocketAsyncEventArgs asyncEventArgs) + { + if (_cancellationTokenSource.IsCancellationRequested) + { + return; + } + + if (asyncEventArgs.LastOperation == SocketAsyncOperation.Connect) + { + if (asyncEventArgs.SocketError == SocketError.Success) + { + Scene.ThreadSynchronizationContext.Post(OnReceiveSocketComplete); + } + else + { + Scene.ThreadSynchronizationContext.Post(() => + { + OnConnectFail?.Invoke(); + Dispose(); + }); + } + } + } + + private void OnReceiveSocketComplete() + { + SendRequestConnection(); + ReadPipeDataAsync().Coroutine(); + ReceiveSocketAsync().Coroutine(); + } + + #endregion + + #region ReceiveSocket + + private async FTask ReceiveSocketAsync() + { + while (!_cancellationTokenSource.IsCancellationRequested) + { + try + { + var memory = _pipe.Writer.GetMemory(8192); +#if FANTASY_UNITY + MemoryMarshal.TryGetArray(memory, out ArraySegment arraySegment); + var result = await _socket.ReceiveFromAsync(arraySegment, SocketFlags.None, _ipEndPoint); + _pipe.Writer.Advance(result.ReceivedBytes); + await _pipe.Writer.FlushAsync(); +#else + var result = await _socket.ReceiveAsync(memory, SocketFlags.None, _cancellationTokenSource.Token); + _pipe.Writer.Advance(result); + await _pipe.Writer.FlushAsync(); +#endif + } + catch (SocketException) + { + Dispose(); + break; + } + catch (OperationCanceledException) + { + break; + } + catch (ObjectDisposedException) + { + Dispose(); + break; + } + catch (Exception ex) + { + Log.Error($"Unexpected exception: {ex.Message}"); + } + } + + await _pipe.Writer.CompleteAsync(); + } + + #endregion + + #region ReceivePipeData + + private async FTask ReadPipeDataAsync() + { + var pipeReader = _pipe.Reader; + while (!_cancellationTokenSource.IsCancellationRequested) + { + ReadResult result = default; + + try + { + result = await pipeReader.ReadAsync(_cancellationTokenSource.Token); + } + catch (OperationCanceledException) + { + // 出现这个异常表示取消了_cancellationTokenSource。一般Channel断开会取消。 + break; + } + + var buffer = result.Buffer; + var consumed = buffer.Start; + var examined = buffer.End; + + while (TryReadMessage(ref buffer, out var header, out var channelId, out var message)) + { + ReceiveData(ref header, ref channelId, ref message); + consumed = buffer.Start; + } + + if (result.IsCompleted) + { + break; + } + + pipeReader.AdvanceTo(consumed, examined); + } + } + + private unsafe bool TryReadMessage(ref ReadOnlySequence buffer, out KcpHeader header, out uint channelId, out ReadOnlyMemory message) + { + if (buffer.Length < 5) + { + channelId = 0; + message = default; + header = KcpHeader.None; + if (buffer.Length > 0) + { + buffer = buffer.Slice(buffer.Length); + } + return false; + } + + var readOnlyMemory = buffer.First; + + if (MemoryMarshal.TryGetArray(readOnlyMemory, out var arraySegment)) + { + fixed (byte* bytePointer = &arraySegment.Array[arraySegment.Offset]) + { + header = (KcpHeader)bytePointer[0]; + channelId = Unsafe.ReadUnaligned(ref bytePointer[1]); + } + } + else + { + // 如果无法获取数组段,回退到安全代码来执行。这种情况几乎不会发生、为了保险还是写一下了。 + var firstSpan = readOnlyMemory.Span; + header = (KcpHeader)firstSpan[0]; + channelId = MemoryMarshal.Read(firstSpan.Slice(1, 4)); + + } + + message = readOnlyMemory.Slice(5); + buffer = buffer.Slice(readOnlyMemory.Length); + return true; + } + + private void ReceiveData(ref KcpHeader header, ref uint channelId, ref ReadOnlyMemory buffer) + { + switch (header) + { + // 发送握手给服务器 + case KcpHeader.RepeatChannelId: + { + // 到这里是客户端的channelId再服务器上已经存在、需要重新生成一个再次尝试连接 + ChannelId = CreateChannelId(); + SendRequestConnection(); + break; + } + // 收到服务器发送会来的确认握手 + case KcpHeader.WaitConfirmConnection: + { + if (channelId != ChannelId) + { + break; + } + + ClearConnectTimeout(); + SendConfirmConnection(); + OnConnectComplete?.Invoke(); + _isConnected = true; + while (_messageCache.TryDequeue(out var memoryStream)) + { + SendMemoryStream(memoryStream); + } + break; + } + // 收到服务器发送的消息 + case KcpHeader.ReceiveData: + { + if (buffer.Length == 5) + { + Log.Warning($"KCP Server KcpHeader.Data buffer.Length == 5"); + break; + } + + if (channelId != ChannelId) + { + break; + } + + Input(buffer); + break; + } + // 接收到服务器的断开连接消息 + case KcpHeader.Disconnect: + { + if (channelId != ChannelId) + { + break; + } + + _isDisconnect = true; + Dispose(); + break; + } + } + } + + private void Input(ReadOnlyMemory buffer) + { + _kcp.Input(buffer); + AddToUpdate(0); + + while (!_cancellationTokenSource.IsCancellationRequested) + { + try + { + var peekSize = _kcp.PeekSize(); + + if (peekSize < 0) + { + return; + } + + var receiveCount = _kcp.Receive(_receiveBuffer, peekSize); + + if (receiveCount != peekSize) + { + return; + } + + if (!_packetParser.UnPack(_receiveBuffer, ref receiveCount, out var packInfo)) + { + continue; + } + + Session.Receive(packInfo); + } + catch (ScanException e) + { + Log.Debug($"RemoteAddress:{_remoteAddress} \n{e}"); + Dispose(); + } + catch (Exception e) + { + Log.Error(e); + } + } + } + + #endregion + + #region Update + + public void CheckUpdate() + { + var nowTime = TimeNow; + _allowWraparound = nowTime < _updateMinTime; + + if (IsTimeGreaterThan(nowTime, _updateMinTime) && _updateTimer.Count > 0) + { + foreach (var timeId in _updateTimer) + { + if (IsTimeGreaterThan(timeId, nowTime)) + { + _updateMinTime = timeId; + break; + } + + _updateTimeOutTime.Add(timeId); + } + + foreach (var timeId in _updateTimeOutTime) + { + _updateTimer.Remove(timeId); + KcpUpdate(); + } + + _updateTimeOutTime.Clear(); + } + + _allowWraparound = true; + } + + private void AddToUpdate(uint tillTime) + { + if (tillTime == 0) + { + KcpUpdate(); + return; + } + + if (IsTimeGreaterThan(_updateMinTime, tillTime) || _updateMinTime == 0) + { + _updateMinTime = tillTime; + } + + _updateTimer.Add(tillTime); + } + + private void KcpUpdate() + { + var nowTime = TimeNow; + + try + { + _kcp.Update(nowTime); + } + catch (Exception e) + { + Log.Error(e); + } + + AddToUpdate(_kcp.Check(nowTime)); + } + + private const uint HalfMaxUint = uint.MaxValue / 2; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private bool IsTimeGreaterThan(uint timeId, uint nowTime) + { + if (!_allowWraparound) + { + return timeId > nowTime; + } + var diff = timeId - nowTime; + // 如果 diff 的值在 [0, HalfMaxUint] 范围内,说明 timeId 是在 nowTime 之后或相等。 + // 如果 diff 的值在 (HalfMaxUint, uint.MaxValue] 范围内,说明 timeId 是在 nowTime 之前(时间回绕的情况)。 + return diff < HalfMaxUint || diff == HalfMaxUint; + } + + #endregion + + #region Send + + private const byte KcpHeaderDisconnect = (byte)KcpHeader.Disconnect; + private const byte KcpHeaderReceiveData = (byte)KcpHeader.ReceiveData; + private const byte KcpHeaderRequestConnection = (byte)KcpHeader.RequestConnection; + private const byte KcpHeaderConfirmConnection = (byte)KcpHeader.ConfirmConnection; + + public override void Send(uint rpcId, long routeId, MemoryStreamBuffer memoryStream, IMessage message) + { + if (_cancellationTokenSource.IsCancellationRequested) + { + return; + } + + var buffer = _packetParser.Pack(ref rpcId, ref routeId, memoryStream, message); + + if (!_isConnected) + { + _messageCache.Enqueue(buffer); + return; + } + + SendMemoryStream(buffer); + } + + private void SendMemoryStream(MemoryStreamBuffer memoryStream) + { + if (_kcp.WaitSendCount > _maxSndWnd) + { + // 检查等待发送的消息,如果超出两倍窗口大小,KCP作者给的建议是要断开连接 + Log.Warning($"ERR_KcpWaitSendSizeTooLarge {_kcp.WaitSendCount} > {_maxSndWnd}"); + Dispose(); + return; + } + + try + { + _kcp.Send(memoryStream.GetBuffer(), 0, (int)memoryStream.Position); + AddToUpdate(0); + } + finally + { + if (memoryStream.MemoryStreamBufferSource == MemoryStreamBufferSource.Pack) + { + MemoryStreamBufferPool.ReturnMemoryStream(memoryStream); + } + } + } + + private unsafe void SendRequestConnection() + { + try + { + fixed (byte* p = _sendBuff) + { + p[0] = KcpHeaderRequestConnection; + *(uint*)(p + 1) = ChannelId; + } + + SendAsync(_sendBuff, 0, 5); + } + catch (Exception e) + { + Log.Error(e); + } + } + + private unsafe void SendConfirmConnection() + { + try + { + fixed (byte* p = _sendBuff) + { + p[0] = KcpHeaderConfirmConnection; + *(uint*)(p + 1) = ChannelId; + } + + SendAsync(_sendBuff, 0, 5); + } + catch (Exception e) + { + Log.Error(e); + } + } + + private unsafe void SendDisconnect() + { + try + { + fixed (byte* p = _sendBuff) + { + p[0] = KcpHeaderDisconnect; + *(uint*)(p + 1) = ChannelId; + } + + SendAsync(_sendBuff, 0, 5); + } + catch (Exception e) + { + Log.Error(e); + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void SendAsync(byte[] buffer, int offset, int count) + { + try + { + _socket.Send(new ArraySegment(buffer, offset, count), SocketFlags.None); + } + catch (ArgumentException ex) + { + Log.Error($"ArgumentException: {ex.Message}"); // 处理参数错误 + } + catch (SocketException) + { + //Log.Error($"SocketException: {ex.Message}"); // 处理网络错误 + Dispose(); + } + catch (ObjectDisposedException ex) + { + Log.Error($"ObjectDisposedException: {ex.Message}"); // 处理套接字已关闭的情况 + Dispose(); + } + catch (InvalidOperationException ex) + { + Log.Error($"InvalidOperationException: {ex.Message}"); // 处理无效操作 + } + catch (Exception ex) + { + Log.Error($"Exception: {ex.Message}"); // 捕获其他异常 + } + } + + private unsafe void KcpSpanCallback(byte[] buffer, ref int count) + { + if (IsDisposed) + { + return; + } + + if (count == 0) + { + throw new Exception("KcpOutput count 0"); + } + + fixed (byte* p = buffer) + { + p[0] = KcpHeaderReceiveData; + *(uint*)(p + 1) = ChannelId; + } + + SendAsync(buffer, 0, count + 5); + } + + #endregion + + public override void RemoveChannel(uint channelId) + { + Dispose(); + } + + private void ClearConnectTimeout() + { + if (_connectTimeoutId == 0) + { + return; + } + + Scene?.TimerComponent?.Net.Remove(ref _connectTimeoutId); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static unsafe uint CreateChannelId() + { + uint value; + RandomNumberGenerator.Fill(MemoryMarshal.CreateSpan(ref *(byte*)&value, 4)); + return 0xC0000000 | (value & int.MaxValue); + } + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/KCP/Client/KCPClientNetwork.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/KCP/Client/KCPClientNetwork.cs.meta new file mode 100644 index 0000000..0374b0b --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/KCP/Client/KCPClientNetwork.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 955df13b771de413ebebbdb3ac07be7d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/KCP/KCPSettings.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/KCP/KCPSettings.cs new file mode 100644 index 0000000..7e0d926 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/KCP/KCPSettings.cs @@ -0,0 +1,89 @@ +#if !FANTASY_WEBGL +using System; +using KCP; + +#pragma warning disable CS1591 +namespace Fantasy.Network.KCP +{ + public class KCPSettings + { + public int Mtu { get; private set; } + public int SendWindowSize { get; private set; } + public int ReceiveWindowSize { get; private set; } + public int MaxSendWindowSize { get; private set; } + + public static KCPSettings Create(NetworkTarget networkTarget) + { + var settings = new KCPSettings(); + + switch (networkTarget) + { + case NetworkTarget.Outer: + { + // 外网设置470的原因: + // 1、mtu设置过大有可能路由器过滤掉 + // 2、降低 mtu 到 470,同样数据虽然会发更多的包,但是小包在路由层优先级更高 + settings.Mtu = 470; +#if FANTASY_NET + settings.SendWindowSize = 8192; + settings.ReceiveWindowSize = 8192; + settings.MaxSendWindowSize = 8192 * 8192 * 7; +#endif +#if FANTASY_UNITY || FANTASY_CONSOLE + settings.SendWindowSize = 512; + settings.ReceiveWindowSize = 512; + settings.MaxSendWindowSize = 512 * 512 * 7; +#endif + + break; + } +#if FANTASY_NET + case NetworkTarget.Inner: + { + // 内网设置1400的原因 + // 1、一般都是同一台服务器来运行多个进程来处理 + // 2、内网每个进程跟其他进程只有一个通道进行发送、所以发送的数量会比较大 + // 3、如果不把窗口设置大点、会出现消息滞后。 + // 4、因为内网发送的可不只是外网转发数据、还有可能是其他进程的通讯 + settings.Mtu = 1200; + settings.SendWindowSize = 8192; + settings.ReceiveWindowSize = 8192; + settings.MaxSendWindowSize = 8192 * 8192 * 7; + break; + } +#endif + default: + { + throw new NotSupportedException($"KCPServerNetwork NotSupported NetworkType:{networkTarget}"); + } + } + + return settings; + } + } + + public static class KCPFactory + { + public static Kcp Create(NetworkTarget networkTarget, uint conv, KcpCallback output, out KCPSettings kcpSettings) + { + var kcp = new Kcp(conv, output); + kcpSettings = KCPSettings.Create(networkTarget); + kcp.SetNoDelay(1, 5, 2, 1); + kcp.SetWindowSize(kcpSettings.SendWindowSize, kcpSettings.ReceiveWindowSize); + kcp.SetMtu(kcpSettings.Mtu); + kcp.SetMinrto(30); + return kcp; + } + + public static Kcp Create(KCPSettings kcpSettings, uint conv, KcpCallback output) + { + var kcp = new Kcp(conv, output); + kcp.SetNoDelay(1, 5, 2, 1); + kcp.SetWindowSize(kcpSettings.SendWindowSize, kcpSettings.ReceiveWindowSize); + kcp.SetMtu(kcpSettings.Mtu); + kcp.SetMinrto(30); + return kcp; + } + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/KCP/KCPSettings.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/KCP/KCPSettings.cs.meta new file mode 100644 index 0000000..2f95b5f --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/KCP/KCPSettings.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2852b1058f3ea4df8bc1325fbbfbf903 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/KCP/KcpHeader.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/KCP/KcpHeader.cs new file mode 100644 index 0000000..28ddace --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/KCP/KcpHeader.cs @@ -0,0 +1,14 @@ +namespace Fantasy.Network.KCP +#pragma warning disable CS1591 +{ + public enum KcpHeader : byte + { + None = 0x00, + RequestConnection = 0x01, + WaitConfirmConnection = 0x02, + ConfirmConnection = 0x03, + RepeatChannelId = 0x04, + ReceiveData = 0x06, + Disconnect = 0x07 + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/KCP/KcpHeader.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/KCP/KcpHeader.cs.meta new file mode 100644 index 0000000..6c18868 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/KCP/KcpHeader.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1cb57f8f94f654626bbb5ce227e13537 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/KCP/Server.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/KCP/Server.meta new file mode 100644 index 0000000..25dc277 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/KCP/Server.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: c53c8541b8381438cb4af82d9f5dfcfe +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/KCP/Server/KCPServerNetwork.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/KCP/Server/KCPServerNetwork.cs new file mode 100644 index 0000000..54b550d --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/KCP/Server/KCPServerNetwork.cs @@ -0,0 +1,619 @@ +#if FANTASY_NET +using System.Buffers; +using System.IO.Pipelines; +using System.Net; +using System.Net.Sockets; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using Fantasy.Async; +using Fantasy.DataStructure.Collection; +using Fantasy.Entitas.Interface; +using Fantasy.Helper; +using Fantasy.Network.Interface; +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member + +// ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract +#pragma warning disable CS8604 // Possible null reference argument. +#pragma warning disable CS8600 // Converting null literal or possible null value to non-nullable type. +#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. +#pragma warning disable CS8602 // Dereference of a possibly null reference. + +#pragma warning disable CS8622 // Nullability of reference types in type of parameter doesn't match the target delegate (possibly because of nullability attributes). + +namespace Fantasy.Network.KCP +{ + public sealed class KCPServerNetworkUpdateSystem : UpdateSystem + { + protected override void Update(KCPServerNetwork self) + { + self.Update(); + } + } + + public struct PendingConnection + { + public readonly uint ChannelId; + public readonly uint TimeOutId; + public readonly IPEndPoint RemoteEndPoint; + + public PendingConnection(uint channelId, IPEndPoint remoteEndPoint, uint time) + { + ChannelId = channelId; + RemoteEndPoint = remoteEndPoint; + TimeOutId = time + 10 * 1000; // 设置10秒超时,如果10秒内没有确认连接则删除。 + } + } + + public sealed class KCPServerNetwork : ANetwork + { + private Socket _socket; + private long _startTime; + private uint _updateMinTime; + private uint _pendingMinTime; + private bool _allowWraparound = true; + private readonly Pipe _pipe = new Pipe(); + private readonly byte[] _sendBuff = new byte[5]; + private readonly List _pendingTimeOutTime = new List(); + private readonly HashSet _updateChannels = new HashSet(); + private readonly List _updateTimeOutTime = new List(); + private readonly Queue _endPoint = new Queue(); + private readonly CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource(); + private readonly SortedOneToManyList _updateTimer = new SortedOneToManyList(); + + private readonly Dictionary _pendingConnection = new Dictionary(); + private readonly SortedOneToManyList _pendingConnectionTimeOut = new SortedOneToManyList(); + private readonly Dictionary _connectionChannel = new Dictionary(); + + public KCPSettings Settings { get; private set; } + + private uint TimeNow => (uint)(TimeHelper.Now - _startTime); + + public void Initialize(NetworkTarget networkTarget, IPEndPoint address) + { + _startTime = TimeHelper.Now; + Settings = KCPSettings.Create(networkTarget); + base.Initialize(NetworkType.Server, NetworkProtocolType.KCP, networkTarget); + _socket = new Socket(address.AddressFamily, SocketType.Dgram, ProtocolType.Udp); + _socket.Blocking = false; + _socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, false); + if (address.AddressFamily == AddressFamily.InterNetworkV6) + { + _socket.SetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.IPv6Only, false); + } + + _socket.Blocking = false; + _socket.Bind(address); + _socket.SetSocketBufferToOsLimit(); + _socket.SetSioUdpConnReset(); + ReadPipeDataAsync().Coroutine(); + ReceiveSocketAsync().Coroutine(); + Log.Info($"SceneConfigId = {Scene.SceneConfigId} networkTarget = {networkTarget.ToString()} KCPServer Listen {address}"); + } + + public override void Dispose() + { + if (IsDisposed) + { + return; + } + + if (!_cancellationTokenSource.IsCancellationRequested) + { + try + { + _cancellationTokenSource.Cancel(); + } + catch (OperationCanceledException) + { + // 通常情况下,此处的异常可以忽略 + } + } + + foreach (var (_, channel) in _connectionChannel.ToArray()) + { + channel.Dispose(); + } + + _connectionChannel.Clear(); + _pendingConnection.Clear(); + + if (_socket != null) + { + _socket.Dispose(); + _socket = null; + } + + base.Dispose(); + } + + #region ReceiveSocket + + private async FTask ReceiveSocketAsync() + { + EndPoint remoteEndPoint = new IPEndPoint(IPAddress.Any, 0); + + while (!_cancellationTokenSource.IsCancellationRequested) + { + try + { + var memory = _pipe.Writer.GetMemory(8192); + var socketReceiveFromResult = await _socket.ReceiveFromAsync(memory, SocketFlags.None, remoteEndPoint, _cancellationTokenSource.Token); + var receivedBytes = socketReceiveFromResult.ReceivedBytes; + + if (receivedBytes == 5) + { + switch ((KcpHeader)memory.Span[0]) + { + case KcpHeader.RequestConnection: + case KcpHeader.ConfirmConnection: + { + _endPoint.Enqueue(socketReceiveFromResult.RemoteEndPoint.Clone()); + break; + } + } + } + + _pipe.Writer.Advance(receivedBytes); + await _pipe.Writer.FlushAsync(); + } + catch (SocketException ex) + { + Log.Error($"Socket exception: {ex.Message}"); + Dispose(); + break; + } + catch (OperationCanceledException) + { + break; + } + catch (ObjectDisposedException) + { + Dispose(); + break; + } + catch (Exception ex) + { + Log.Error($"Unexpected exception: {ex.Message}"); + } + } + + await _pipe.Writer.CompleteAsync(); + } + + #endregion + + #region ReceivePipeData + + private async FTask ReadPipeDataAsync() + { + var pipeReader = _pipe.Reader; + while (!_cancellationTokenSource.IsCancellationRequested) + { + ReadResult result = default; + + try + { + result = await pipeReader.ReadAsync(_cancellationTokenSource.Token); + } + catch (OperationCanceledException) + { + // 出现这个异常表示取消了_cancellationTokenSource。一般Channel断开会取消。 + break; + } + + var buffer = result.Buffer; + var consumed = buffer.Start; + var examined = buffer.End; + + while (TryReadMessage(ref buffer, out var header, out var channelId, out var message)) + { + ReceiveData(ref header, ref channelId, ref message); + consumed = buffer.Start; + } + + if (result.IsCompleted) + { + break; + } + + pipeReader.AdvanceTo(consumed, examined); + } + + await pipeReader.CompleteAsync(); + } + + private unsafe bool TryReadMessage(ref ReadOnlySequence buffer, out KcpHeader header, out uint channelId, out ReadOnlyMemory message) + { + if (buffer.Length < 5) + { + channelId = 0; + message = default; + header = KcpHeader.None; + if (buffer.Length > 0) + { + buffer = buffer.Slice(buffer.Length); + } + return false; + } + + var readOnlyMemory = buffer.First; + + if (MemoryMarshal.TryGetArray(readOnlyMemory, out var arraySegment)) + { + fixed (byte* bytePointer = &arraySegment.Array[arraySegment.Offset]) + { + header = (KcpHeader)bytePointer[0]; + channelId = Unsafe.ReadUnaligned(ref bytePointer[1]); + } + } + else + { + // 如果无法获取数组段,回退到安全代码来执行。这种情况几乎不会发生、为了保险还是写一下了。 + var firstSpan = readOnlyMemory.Span; + header = (KcpHeader)firstSpan[0]; + channelId = MemoryMarshal.Read(firstSpan.Slice(1, 4)); + } + + message = readOnlyMemory.Slice(5); + buffer = buffer.Slice(readOnlyMemory.Length); + return true; + } + + private void ReceiveData(ref KcpHeader header, ref uint channelId, ref ReadOnlyMemory buffer) + { + switch (header) + { + // 客户端请求建立KCP连接 + case KcpHeader.RequestConnection: + { + _endPoint.TryDequeue(out var ipEndPoint); + + if (_pendingConnection.TryGetValue(channelId, out var pendingConnection)) + { + if (!ipEndPoint.IPEndPointEquals(pendingConnection.RemoteEndPoint)) + { + // 重复通道ID,向客户端发送重复通道ID消息 + SendRepeatChannelId(ref channelId, ipEndPoint); + } + + break; + } + + if (_connectionChannel.ContainsKey(channelId)) + { + // 已存在的通道ID,向客户端发送重复通道ID消息 + SendRepeatChannelId(ref channelId, ipEndPoint); + break; + } + + AddPendingConnection(ref channelId, ipEndPoint); + break; + } + // 客户端确认建立KCP连接 + case KcpHeader.ConfirmConnection: + { + _endPoint.TryDequeue(out var ipEndPoint); + if (!ConfirmPendingConnection(ref channelId, ipEndPoint)) + { + break; + } + + AddConnection(ref channelId, ipEndPoint.Clone()); + break; + } + // 接收KCP的数据 + case KcpHeader.ReceiveData: + { + if (buffer.Length == 5) + { + Log.Warning($"KCP Server KcpHeader.Data buffer.Length == 5"); + break; + } + + if (_connectionChannel.TryGetValue(channelId, out var channel)) + { + channel.Input(buffer); + } + + break; + } + // 断开KCP连接 + case KcpHeader.Disconnect: + { + // 断开不需要清楚PendingConnection让ClearPendingConnection自动清楚就可以了,并且不一定有Pending。 + RemoveChannel(channelId); + break; + } + } + } + + #endregion + + #region Update + + public void Update() + { + var timeNow = TimeNow; + _allowWraparound = timeNow < _updateMinTime; + CheckUpdateTimerOut(ref timeNow); + UpdateChannel(ref timeNow); + PendingTimerOut(ref timeNow); + _allowWraparound = true; + } + + private void CheckUpdateTimerOut(ref uint nowTime) + { + if (_updateTimer.Count == 0) + { + return; + } + + if (IsTimeGreaterThan(_updateMinTime, nowTime)) + { + return; + } + + _updateTimeOutTime.Clear(); + + foreach (var kv in _updateTimer) + { + var timeId = kv.Key; + + if (IsTimeGreaterThan(timeId, nowTime)) + { + _updateMinTime = timeId; + break; + } + + _updateTimeOutTime.Add(timeId); + } + + foreach (var timeId in _updateTimeOutTime) + { + foreach (var channelId in _updateTimer[timeId]) + { + _updateChannels.Add(channelId); + } + + _updateTimer.RemoveKey(timeId); + } + } + + private void UpdateChannel(ref uint timeNow) + { + foreach (var channelId in _updateChannels) + { + if (!_connectionChannel.TryGetValue(channelId, out var channel)) + { + continue; + } + + if (channel.IsDisposed) + { + _connectionChannel.Remove(channelId); + continue; + } + + channel.Kcp.Update(timeNow); + AddUpdateChannel(channelId, channel.Kcp.Check(timeNow)); + } + + _updateChannels.Clear(); + } + + private void PendingTimerOut(ref uint timeNow) + { + if (_pendingConnectionTimeOut.Count == 0) + { + return; + } + + if (IsTimeGreaterThan(_pendingMinTime, timeNow)) + { + return; + } + + _pendingTimeOutTime.Clear(); + + foreach (var kv in _pendingConnectionTimeOut) + { + var timeId = kv.Key; + + if (IsTimeGreaterThan(timeId, timeNow)) + { + _pendingMinTime = timeId; + break; + } + + _pendingTimeOutTime.Add(timeId); + } + + foreach (var timeId in _pendingTimeOutTime) + { + foreach (var channelId in _pendingConnectionTimeOut[timeId]) + { + _pendingConnection.Remove(channelId); + } + + _pendingConnectionTimeOut.RemoveKey(timeId); + } + } + + public void AddUpdateChannel(uint channelId, uint tillTime) + { + if (tillTime == 0) + { + _updateChannels.Add(channelId); + return; + } + + if (IsTimeGreaterThan(_updateMinTime, tillTime)) + { + _updateMinTime = tillTime; + } + + _updateTimer.Add(tillTime, channelId); + } + + private const uint HalfMaxUint = uint.MaxValue / 2; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private bool IsTimeGreaterThan(uint timeId, uint nowTime) + { + if (!_allowWraparound) + { + return timeId > nowTime; + } + + var diff = timeId - nowTime; + // 如果 diff 的值在 [0, HalfMaxUint] 范围内,说明 timeId 是在 nowTime 之后或相等。 + // 如果 diff 的值在 (HalfMaxUint, uint.MaxValue] 范围内,说明 timeId 是在 nowTime 之前(时间回绕的情况)。 + return diff < HalfMaxUint || diff == HalfMaxUint; + } + + #endregion + + #region Pending + + private void AddPendingConnection(ref uint channelId, IPEndPoint ipEndPoint) + { + var now = TimeNow; + var pendingConnection = new PendingConnection(channelId, ipEndPoint, now); + + if (IsTimeGreaterThan(_pendingMinTime, pendingConnection.TimeOutId) || _pendingMinTime == 0) + { + _pendingMinTime = pendingConnection.TimeOutId; + } + + _pendingConnection.Add(channelId, pendingConnection); + _pendingConnectionTimeOut.Add(pendingConnection.TimeOutId, channelId); + SendWaitConfirmConnection(ref channelId, ipEndPoint); + } + + private bool ConfirmPendingConnection(ref uint channelId, EndPoint ipEndPoint) + { + if (!_pendingConnection.TryGetValue(channelId, out var pendingConnection)) + { + return false; + } + + if (!ipEndPoint.IPEndPointEquals(pendingConnection.RemoteEndPoint)) + { + Log.Error($"KCPSocket syn address diff: {channelId} {pendingConnection.RemoteEndPoint} {ipEndPoint}"); + return false; + } + + _pendingConnection.Remove(channelId); + _pendingConnectionTimeOut.RemoveValue(pendingConnection.TimeOutId, pendingConnection.ChannelId); +#if FANTASY_DEVELOP + Log.Debug($"KCPSocket _pendingConnection:{_pendingConnection.Count} _pendingConnectionTimer:{_pendingConnectionTimeOut.Count}"); +#endif + return true; + } + + #endregion + + #region Connection + + private void AddConnection(ref uint channelId, IPEndPoint ipEndPoint) + { + var eventArgs = new KCPServerNetworkChannel(this, channelId, ipEndPoint); + _connectionChannel.Add(channelId, eventArgs); +#if FANTASY_DEVELOP + Log.Debug($"AddConnection _connectionChannel:{_connectionChannel.Count()}"); +#endif + } + + public override void RemoveChannel(uint channelId) + { + if (!_connectionChannel.Remove(channelId, out var channel)) + { + return; + } + + if (!channel.IsDisposed) + { + SendDisconnect(ref channelId, channel.RemoteEndPoint); + channel.Dispose(); + } +#if FANTASY_DEVELOP + Log.Debug($"RemoveChannel _connectionChannel:{_connectionChannel.Count()}"); +#endif + } + + #endregion + + #region Send + + private const byte KcpHeaderDisconnect = (byte)KcpHeader.Disconnect; + private const byte KcpHeaderRepeatChannelId = (byte)KcpHeader.RepeatChannelId; + private const byte KcpHeaderWaitConfirmConnection = (byte)KcpHeader.WaitConfirmConnection; + + private unsafe void SendDisconnect(ref uint channelId, EndPoint clientEndPoint) + { + fixed (byte* p = _sendBuff) + { + p[0] = KcpHeaderDisconnect; + *(uint*)(p + 1) = channelId; + } + + SendAsync(_sendBuff, 0, 5, clientEndPoint); + } + + private unsafe void SendRepeatChannelId(ref uint channelId, EndPoint clientEndPoint) + { + fixed (byte* p = _sendBuff) + { + p[0] = KcpHeaderRepeatChannelId; + *(uint*)(p + 1) = channelId; + } + + SendAsync(_sendBuff, 0, 5, clientEndPoint); + } + + private unsafe void SendWaitConfirmConnection(ref uint channelId, EndPoint clientEndPoint) + { + fixed (byte* p = _sendBuff) + { + p[0] = KcpHeaderWaitConfirmConnection; + *(uint*)(p + 1) = channelId; + } + + SendAsync(_sendBuff, 0, 5, clientEndPoint); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void SendAsync(byte[] buffer, int offset, int count, EndPoint endPoint) + { + try + { + _socket.SendTo(new ArraySegment(buffer, offset, count), SocketFlags.None, endPoint); + } + catch (ArgumentException ex) + { + Log.Error($"ArgumentException: {ex.Message}"); // 处理参数错误 + } + catch (SocketException) + { + //Log.Error($"SocketException: {ex.Message}"); // 处理网络错误 + } + catch (ObjectDisposedException) + { + // 处理套接字已关闭的情况 + } + catch (InvalidOperationException ex) + { + Log.Error($"InvalidOperationException: {ex.Message}"); // 处理无效操作 + } + catch (Exception ex) + { + Log.Error($"Exception: {ex.Message}"); // 捕获其他异常 + } + } + + #endregion + } +} + +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/KCP/Server/KCPServerNetwork.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/KCP/Server/KCPServerNetwork.cs.meta new file mode 100644 index 0000000..591d1e8 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/KCP/Server/KCPServerNetwork.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a343a9ffd343542aa96d21c234cb0605 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/KCP/Server/KCPServerNetworkChannel.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/KCP/Server/KCPServerNetworkChannel.cs new file mode 100644 index 0000000..3d5be09 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/KCP/Server/KCPServerNetworkChannel.cs @@ -0,0 +1,155 @@ +#if FANTASY_NET +using System.Net; +using System.Net.Sockets; +using System.Runtime.CompilerServices; +using Fantasy.Helper; +using Fantasy.Network.Interface; +using Fantasy.PacketParser; +using Fantasy.Serialize; +using KCP; +// ReSharper disable ParameterHidesMember +#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. + +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member + +namespace Fantasy.Network.KCP +{ + /// + /// KCP 服务器网络通道,用于处理服务器与客户端之间的数据通信。 + /// + public class KCPServerNetworkChannel : ANetworkServerChannel + { + private bool _isInnerDispose; + private readonly int _maxSndWnd; + private KCPServerNetwork _kcpServerNetwork; + private readonly BufferPacketParser _packetParser; + private readonly byte[] _receiveBuffer = new byte[Packet.PacketBodyMaxLength + 20]; + public Kcp Kcp { get; private set; } + public uint ChannelId { get; private set; } + + public KCPServerNetworkChannel(KCPServerNetwork network, uint channelId, IPEndPoint ipEndPoint) : base(network, channelId, ipEndPoint) + { + _kcpServerNetwork = network; + ChannelId = channelId; + _maxSndWnd = network.Settings.MaxSendWindowSize; + Kcp = KCPFactory.Create(network.Settings, ChannelId, KcpSpanCallback); + _packetParser = PacketParserFactory.CreateServerBufferPacket(network); + } + + public override void Dispose() + { + if (IsDisposed || _isInnerDispose) + { + return; + } + + _isInnerDispose = true; + _kcpServerNetwork.RemoveChannel(Id); + base.Dispose(); + IsDisposed = true; + Kcp.Dispose(); + Kcp = null; + ChannelId = 0; + _kcpServerNetwork = null; + } + + public void Input(ReadOnlyMemory buffer) + { + Kcp.Input(buffer); + _kcpServerNetwork.AddUpdateChannel(ChannelId, 0); + + while (!IsDisposed) + { + try + { + var peekSize = Kcp.PeekSize(); + + if (peekSize < 0) + { + return; + } + + var receiveCount = Kcp.Receive(_receiveBuffer, peekSize); + + if (receiveCount != peekSize) + { + return; + } + + if (!_packetParser.UnPack(_receiveBuffer, ref receiveCount, out var packInfo)) + { + continue; + } + + Session.Receive(packInfo); + } + catch (ScanException e) + { + Log.Debug($"RemoteAddress:{RemoteEndPoint} \n{e}"); + Dispose(); + } + catch (Exception e) + { + Log.Error(e); + } + } + } + + public override void Send(uint rpcId, long routeId, MemoryStreamBuffer memoryStream, IMessage message) + { + if (IsDisposed) + { + return; + } + + if (Kcp.WaitSendCount > _maxSndWnd) + { + // 检查等待发送的消息,如果超出两倍窗口大小,KCP作者给的建议是要断开连接 + Log.Warning($"ERR_KcpWaitSendSizeTooLarge {Kcp.WaitSendCount} > {_maxSndWnd}"); + Dispose(); + return; + } + + var buffer = _packetParser.Pack(ref rpcId, ref routeId, memoryStream, message); + Kcp.Send(buffer.GetBuffer(), 0, (int)buffer.Position); + + if (buffer.MemoryStreamBufferSource == MemoryStreamBufferSource.Pack) + { + _kcpServerNetwork.MemoryStreamBufferPool.ReturnMemoryStream(buffer); + } + + _kcpServerNetwork.AddUpdateChannel(ChannelId, 0); + } + + private const byte KcpHeaderReceiveData = (byte)KcpHeader.ReceiveData; + + private unsafe void KcpSpanCallback(byte[] buffer, ref int count) + { + if (IsDisposed) + { + return; + } + + try + { + if (count == 0) + { + throw new Exception("KcpOutput count 0"); + } + + fixed (byte* p = buffer) + { + p[0] = KcpHeaderReceiveData; + *(uint*)(p + 1) = ChannelId; + } + + _kcpServerNetwork.SendAsync(buffer, 0, count + 5, RemoteEndPoint); + } + catch (Exception e) + { + Log.Error(e); + } + } + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/KCP/Server/KCPServerNetworkChannel.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/KCP/Server/KCPServerNetworkChannel.cs.meta new file mode 100644 index 0000000..7f81dae --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/KCP/Server/KCPServerNetworkChannel.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a8056a8265742483686fb10fb351d108 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/NetworkProtocolFactory.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/NetworkProtocolFactory.cs new file mode 100644 index 0000000..c7b6ecc --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/NetworkProtocolFactory.cs @@ -0,0 +1,95 @@ +using System; +using System.Net; +using Fantasy.Entitas; +using Fantasy.Helper; +using Fantasy.Network.Interface; +#if !FANTASY_WEBGL +using Fantasy.Network.TCP; +using Fantasy.Network.KCP; +#endif +#if FANTASY_NET +using Fantasy.Network.HTTP; +#endif +using Fantasy.Network.WebSocket; + +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member + +namespace Fantasy.Network +{ + internal static class NetworkProtocolFactory + { +#if FANTASY_NET + public static ANetwork CreateServer(Scene scene, NetworkProtocolType protocolType, NetworkTarget networkTarget, string bindIp, int port) + { + switch (protocolType) + { + case NetworkProtocolType.TCP: + { + var network = Entity.Create(scene, false, false); + var address = NetworkHelper.ToIPEndPoint(bindIp, port); + network.Initialize(networkTarget, address); + return network; + } + case NetworkProtocolType.KCP: + { + var network = Entity.Create(scene, false, true); + var address = NetworkHelper.ToIPEndPoint(bindIp, port); + network.Initialize(networkTarget, address); + return network; + } + case NetworkProtocolType.WebSocket: + { + var network = Entity.Create(scene, false, true); + network.Initialize(networkTarget, bindIp, port); + return network; + } + case NetworkProtocolType.HTTP: + { + var network = Entity.Create(scene, false, true); + network.Initialize(networkTarget, bindIp, port); + return network; + } + default: + { + throw new NotSupportedException($"Unsupported NetworkProtocolType:{protocolType}"); + } + } + } +#endif + public static AClientNetwork CreateClient(Scene scene, NetworkProtocolType protocolType, NetworkTarget networkTarget) + { +#if !FANTASY_WEBGL + switch (protocolType) + { + case NetworkProtocolType.TCP: + { + var network = Entity.Create(scene, false, false); + network.Initialize(networkTarget); + return network; + } + case NetworkProtocolType.KCP: + { + var network = Entity.Create(scene, false, true); + network.Initialize(networkTarget); + return network; + } + case NetworkProtocolType.WebSocket: + { + var network = Entity.Create(scene, false, true); + network.Initialize(networkTarget); + return network; + } + default: + { + throw new NotSupportedException($"Unsupported NetworkProtocolType:{protocolType}"); + } + } +#else + // Webgl平台只能用这个协议。 + var network = Entity.Create(scene, false, true); + network.Initialize(networkTarget); + return network; +#endif + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/NetworkProtocolFactory.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/NetworkProtocolFactory.cs.meta new file mode 100644 index 0000000..cea246f --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/NetworkProtocolFactory.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e9f2a5ed9c13448c89afe62abe02493b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/NetworkProtocolType.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/NetworkProtocolType.cs new file mode 100644 index 0000000..55a04c9 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/NetworkProtocolType.cs @@ -0,0 +1,69 @@ +namespace Fantasy.Network +{ + /// + /// 网络服务器类型 + /// + public enum NetworkType + { + /// + /// 默认 + /// + None = 0, + /// + /// 客户端网络 + /// + Client = 1, +#if FANTASY_NET + /// + /// 服务器网络 + /// + Server = 2 +#endif + } + /// + /// 网络服务的目标 + /// + public enum NetworkTarget + { + /// + /// 默认 + /// + None = 0, + /// + /// 对外 + /// + Outer = 1, +#if FANTASY_NET + /// + /// 对内 + /// + Inner = 2 +#endif + } + /// + /// 支持的网络协议 + /// + public enum NetworkProtocolType + { + /// + /// 默认 + /// + None = 0, + /// + /// KCP + /// + KCP = 1, + /// + /// TCP + /// + TCP = 2, + /// + /// WebSocket + /// + WebSocket = 3, + /// + /// HTTP + /// + HTTP = 4, + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/NetworkProtocolType.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/NetworkProtocolType.cs.meta new file mode 100644 index 0000000..077f676 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/NetworkProtocolType.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ff164a3b41dd74f5cad6a738ffd77591 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/NetworkThreadComponent.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/NetworkThreadComponent.cs new file mode 100644 index 0000000..c0c166b --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/NetworkThreadComponent.cs @@ -0,0 +1,100 @@ +#if !FANTASY_WEBGL +using System; +using System.Collections.Generic; +using System.Threading; +using Fantasy.Entitas; +// ReSharper disable ForCanBeConvertedToForeach +#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. + +namespace Fantasy.Network +{ + internal interface INetworkThreadUpdate + { + void Update(); + } + + /// + /// 网络线程组件 + /// + internal sealed class NetworkThreadComponent : Entity + { + private Thread _netWorkThread; + internal ThreadSynchronizationContext SynchronizationContext { get; private set; } + private readonly List _updates = new List(); + + internal NetworkThreadComponent Initialize() + { + SynchronizationContext = new ThreadSynchronizationContext(); + _netWorkThread = new Thread(Update) + { + IsBackground = true + }; + _netWorkThread.Start(); + return this; + } + + public override void Dispose() + { + if (IsDisposed) + { + return; + } + + SynchronizationContext.Post(() => + { + _updates.Clear(); + _netWorkThread.Join(); + _netWorkThread = null; + SynchronizationContext = null; + }); + + base.Dispose(); + } + + private void Update() + { + // 将同步上下文设置为网络线程的上下文,以确保操作在正确的线程上下文中执行。 + System.Threading.SynchronizationContext.SetSynchronizationContext(SynchronizationContext); + // 循环执行 + while (!IsDisposed) + { + for (var i = 0; i < _updates.Count; i++) + { + try + { + _updates[i].Update(); + } + catch (Exception e) + { + Log.Error(e); + } + } + SynchronizationContext.Update(); + Thread.Sleep(1); + } + } + + internal void AddNetworkThreadUpdate(INetworkThreadUpdate update) + { + SynchronizationContext.Post(() => + { + if (_updates.Contains(update)) + { + Log.Warning($"{update.GetType().FullName} Network thread update is already running"); + return; + } + _updates.Add(update); + }); + } + + internal void RemoveNetworkThreadUpdate(INetworkThreadUpdate update) + { + SynchronizationContext.Post(() => + { + _updates.Remove(update); + }); + } + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/NetworkThreadComponent.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/NetworkThreadComponent.cs.meta new file mode 100644 index 0000000..5b8dadd --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/NetworkThreadComponent.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: dd76246170d9546a2a504a922cda29ad +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/TCP.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/TCP.meta new file mode 100644 index 0000000..a540377 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/TCP.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 015b2c41a11614c19847def0749c75d3 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/TCP/Client.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/TCP/Client.meta new file mode 100644 index 0000000..9b97822 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/TCP/Client.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 637e4cf1e0eb049efb57f91f75d645e7 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/TCP/Client/TCPClientNetwork.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/TCP/Client/TCPClientNetwork.cs new file mode 100644 index 0000000..1caafd7 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/TCP/Client/TCPClientNetwork.cs @@ -0,0 +1,403 @@ +#if !FANTASY_WEBGL +using System; +using System.Buffers; +using System.Collections.Generic; +using System.IO; +using System.IO.Pipelines; +using System.Net; +using System.Net.Sockets; +using System.Runtime.InteropServices; +using System.Threading; +using Fantasy.Async; +using Fantasy.Helper; +using Fantasy.Network.Interface; +using Fantasy.PacketParser; +using Fantasy.Serialize; +// ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract +#pragma warning disable CS8602 // Dereference of a possibly null reference. +#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member + +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. +#pragma warning disable CS8604 // Possible null reference argument. +#pragma warning disable CS8600 // Converting null literal or possible null value to non-nullable type. +#pragma warning disable CS8622 // Nullability of reference types in type of parameter doesn't match the target delegate (possibly because of nullability attributes). + +namespace Fantasy.Network.TCP +{ + public sealed class TCPClientNetwork : AClientNetwork + { + private bool _isSending; + private bool _isInnerDispose; + private long _connectTimeoutId; + private Socket _socket; + private IPEndPoint _remoteEndPoint; + private SocketAsyncEventArgs _sendArgs; + private ReadOnlyMemoryPacketParser _packetParser; + private readonly Pipe _pipe = new Pipe(); + private readonly Queue _sendBuffers = new Queue(); + private readonly CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource(); + + private Action _onConnectFail; + private Action _onConnectComplete; + private Action _onConnectDisconnect; + + public uint ChannelId { get; private set; } + + public void Initialize(NetworkTarget networkTarget) + { + base.Initialize(NetworkType.Client, NetworkProtocolType.TCP, networkTarget); + } + + public override void Dispose() + { + if (IsDisposed || _isInnerDispose) + { + return; + } + + _isSending = false; + _isInnerDispose = true; + base.Dispose(); + ClearConnectTimeout(); + + if (!_cancellationTokenSource.IsCancellationRequested) + { + try + { + _cancellationTokenSource.Cancel(); + } + catch (OperationCanceledException) + { + // 通常情况下,此处的异常可以忽略 + } + } + + _onConnectDisconnect?.Invoke(); + + if (_socket.Connected) + { + _socket.Close(); + _socket = null; + } + + _sendBuffers.Clear(); + _packetParser?.Dispose(); + ChannelId = 0; + _sendArgs = null; + } + + /// + /// 连接到远程服务器。 + /// + /// 远程服务器的终端点。 + /// 连接成功时的回调。 + /// 连接失败时的回调。 + /// 连接断开时的回调。 + /// + /// 连接超时时间,单位:毫秒。 + /// 连接的会话。 + public override Session Connect(string remoteAddress, Action onConnectComplete, Action onConnectFail, Action onConnectDisconnect, bool isHttps, int connectTimeout = 5000) + { + // 如果已经初始化过一次,抛出异常,要求重新实例化 + + if (IsInit) + { + throw new NotSupportedException("TCPClientNetwork Has already been initialized. If you want to call Connect again, please re instantiate it."); + } + + IsInit = true; + _isSending = false; + _onConnectFail = onConnectFail; + _onConnectComplete = onConnectComplete; + _onConnectDisconnect = onConnectDisconnect; + // 设置连接超时定时器 + _connectTimeoutId = Scene.TimerComponent.Net.OnceTimer(connectTimeout, () => + { + _onConnectFail?.Invoke(); + Dispose(); + }); + _packetParser = PacketParserFactory.CreateClientReadOnlyMemoryPacket(this); + _remoteEndPoint = NetworkHelper.GetIPEndPoint(remoteAddress); + _socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); + _socket.NoDelay = true; + _socket.SetSocketBufferToOsLimit(); + _sendArgs = new SocketAsyncEventArgs(); + _sendArgs.Completed += OnSendCompleted; + var outArgs = new SocketAsyncEventArgs + { + RemoteEndPoint = _remoteEndPoint + }; + outArgs.Completed += OnConnectSocketCompleted; + + if (!_socket.ConnectAsync(outArgs)) + { + OnReceiveSocketComplete(); + } + + Session = Session.Create(this, _remoteEndPoint); + return Session; + } + + private void OnConnectSocketCompleted(object sender, SocketAsyncEventArgs asyncEventArgs) + { + if (_cancellationTokenSource.IsCancellationRequested) + { + return; + } + + if (asyncEventArgs.LastOperation == SocketAsyncOperation.Connect) + { + if (asyncEventArgs.SocketError == SocketError.Success) + { + Scene.ThreadSynchronizationContext.Post(OnReceiveSocketComplete); + } + else + { + Scene.ThreadSynchronizationContext.Post(() => + { + _onConnectFail?.Invoke(); + Dispose(); + }); + } + } + } + + private void OnReceiveSocketComplete() + { + ClearConnectTimeout(); + _onConnectComplete?.Invoke(); + ReadPipeDataAsync().Coroutine(); + ReceiveSocketAsync().Coroutine(); + } + + #region ReceiveSocket + + private async FTask ReceiveSocketAsync() + { + while (!_cancellationTokenSource.IsCancellationRequested) + { + try + { + var memory = _pipe.Writer.GetMemory(8192); +#if UNITY_2021 + // Unity2021.3.14f有个恶心的问题,使用ReceiveAsync会导致memory不能正确写入 + // 所有只能使用ReceiveFromAsync来接收消息,但ReceiveFromAsync只有一个接受ArraySegment的接口。 + MemoryMarshal.TryGetArray(memory, out ArraySegment arraySegment); + var result = await _socket.ReceiveFromAsync(arraySegment, SocketFlags.None, _remoteEndPoint); + _pipe.Writer.Advance(result.ReceivedBytes); +#else + var count = await _socket.ReceiveAsync(memory, SocketFlags.None, _cancellationTokenSource.Token); + _pipe.Writer.Advance(count); +#endif + await _pipe.Writer.FlushAsync(); + } + catch (SocketException) + { + Dispose(); + break; + } + catch (OperationCanceledException) + { + break; + } + catch (ObjectDisposedException) + { + Dispose(); + break; + } + catch (Exception ex) + { + Log.Error($"Unexpected exception: {ex.Message}"); + } + } + + await _pipe.Writer.CompleteAsync(); + } + + #endregion + + #region ReceivePipeData + + private async FTask ReadPipeDataAsync() + { + var pipeReader = _pipe.Reader; + while (!_cancellationTokenSource.IsCancellationRequested) + { + ReadResult result = default; + + try + { + result = await pipeReader.ReadAsync(_cancellationTokenSource.Token); + } + catch (OperationCanceledException) + { + // 出现这个异常表示取消了_cancellationTokenSource。一般Channel断开会取消。 + break; + } + + var buffer = result.Buffer; + var consumed = buffer.Start; + var examined = buffer.End; + + while (TryReadMessage(ref buffer, out var message)) + { + ReceiveData(ref message); + consumed = buffer.Start; + } + + if (result.IsCompleted) + { + break; + } + + pipeReader.AdvanceTo(consumed, examined); + } + + await pipeReader.CompleteAsync(); + } + + private bool TryReadMessage(ref ReadOnlySequence buffer, out ReadOnlyMemory message) + { + if (buffer.Length == 0) + { + message = default; + return false; + } + + message = buffer.First; + + if (message.Length == 0) + { + message = default; + return false; + } + + buffer = buffer.Slice(message.Length); + return true; + } + + private void ReceiveData(ref ReadOnlyMemory buffer) + { + try + { + while (_packetParser.UnPack(ref buffer, out var packInfo)) + { + if (_cancellationTokenSource.IsCancellationRequested) + { + return; + } + Session.Receive(packInfo); + } + } + catch (ScanException e) + { + Log.Warning(e.Message); + Dispose(); + } + catch (Exception e) + { + Log.Error(e); + Dispose(); + } + } + + #endregion + + #region Send + + public override void Send(uint rpcId, long routeId, MemoryStreamBuffer memoryStream, IMessage message) + { + _sendBuffers.Enqueue(_packetParser.Pack(ref rpcId, ref routeId, memoryStream, message)); + + if (!_isSending) + { + Send(); + } + } + + private void Send() + { + if (_isSending || IsDisposed) + { + return; + } + + _isSending = true; + + while (_sendBuffers.Count > 0) + { + var memoryStreamBuffer = _sendBuffers.Dequeue(); + _sendArgs.UserToken = memoryStreamBuffer; + _sendArgs.SetBuffer(new ArraySegment(memoryStreamBuffer.GetBuffer(), 0, (int)memoryStreamBuffer.Position)); + + try + { + if (_socket.SendAsync(_sendArgs)) + { + break; + } + + ReturnMemoryStream(memoryStreamBuffer); + } + catch + { + _isSending = false; + return; + } + } + + _isSending = false; + } + + private void ReturnMemoryStream(MemoryStreamBuffer memoryStream) + { + if (memoryStream.MemoryStreamBufferSource == MemoryStreamBufferSource.Pack) + { + MemoryStreamBufferPool.ReturnMemoryStream(memoryStream); + } + } + + private void OnSendCompleted(object sender, SocketAsyncEventArgs asyncEventArgs) + { + if (asyncEventArgs.SocketError != SocketError.Success || asyncEventArgs.BytesTransferred == 0) + { + _isSending = false; + return; + } + + var memoryStreamBuffer = (MemoryStreamBuffer)asyncEventArgs.UserToken; + Scene.ThreadSynchronizationContext.Post(() => + { + ReturnMemoryStream(memoryStreamBuffer); + + if (_sendBuffers.Count > 0) + { + Send(); + } + else + { + _isSending = false; + } + }); + } + + #endregion + + public override void RemoveChannel(uint channelId) + { + Dispose(); + } + + private void ClearConnectTimeout() + { + if (_connectTimeoutId == 0) + { + return; + } + + Scene.TimerComponent.Net.Remove(ref _connectTimeoutId); + } + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/TCP/Client/TCPClientNetwork.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/TCP/Client/TCPClientNetwork.cs.meta new file mode 100644 index 0000000..e8ac2c0 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/TCP/Client/TCPClientNetwork.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 5b29ef40368e94d9c90e051b8361a7f4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/TCP/Server.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/TCP/Server.meta new file mode 100644 index 0000000..41039fb --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/TCP/Server.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b700d7ce7028041c1a83dd03f7402b10 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/TCP/Server/TCPServerNetwork.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/TCP/Server/TCPServerNetwork.cs new file mode 100644 index 0000000..3f3d531 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/TCP/Server/TCPServerNetwork.cs @@ -0,0 +1,151 @@ +#if FANTASY_NET +using System.Net; +using System.Net.Sockets; +using Fantasy.Helper; +using Fantasy.Network.Interface; +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member + +// ReSharper disable GCSuppressFinalizeForTypeWithoutDestructor +#pragma warning disable CS8622 // Nullability of reference types in type of parameter doesn't match the target delegate (possibly because of nullability attributes). +#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. + +namespace Fantasy.Network.TCP +{ + public sealed class TCPServerNetwork : ANetwork + { + private Random _random; + private Socket _socket; + private SocketAsyncEventArgs _acceptAsync; + private readonly Dictionary _connectionChannel = new Dictionary(); + + public void Initialize(NetworkTarget networkTarget, IPEndPoint address) + { + base.Initialize(NetworkType.Server, NetworkProtocolType.TCP, networkTarget); + _random = new Random(); + _acceptAsync = new SocketAsyncEventArgs(); + _socket = new Socket(address.AddressFamily, SocketType.Stream, ProtocolType.Tcp); + _socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, false); + + if (address.AddressFamily == AddressFamily.InterNetworkV6) + { + _socket.SetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.IPv6Only, false); + } + + _socket.Bind(address); + _socket.Listen(int.MaxValue); + _socket.SetSocketBufferToOsLimit(); + Log.Info($"SceneConfigId = {Scene.SceneConfigId} networkTarget = {networkTarget.ToString()} TCPServer Listen {address}"); + _acceptAsync.Completed += OnCompleted; + AcceptAsync(); + } + + public override void Dispose() + { + if (IsDisposed) + { + return; + } + + foreach (var networkChannel in _connectionChannel.Values.ToArray()) + { + networkChannel.Dispose(); + } + + _connectionChannel.Clear(); + _random = null; + _socket.Dispose(); + _socket = null; + _acceptAsync.Dispose(); + _acceptAsync = null; + GC.SuppressFinalize(this); + base.Dispose(); + } + + private void AcceptAsync() + { + _acceptAsync.AcceptSocket = null; + + if (_socket.AcceptAsync(_acceptAsync)) + { + return; + } + + OnAcceptComplete(_acceptAsync); + } + + private void OnAcceptComplete(SocketAsyncEventArgs asyncEventArgs) + { + if (asyncEventArgs.AcceptSocket == null) + { + return; + } + + if (asyncEventArgs.SocketError != SocketError.Success) + { + Log.Error($"Socket Accept Error: {_acceptAsync.SocketError}"); + return; + } + + try + { + uint channelId; + do + { + channelId = 0xC0000000 | (uint)_random.Next(); + } while (_connectionChannel.ContainsKey(channelId)); + + _connectionChannel.Add(channelId, new TCPServerNetworkChannel(this, asyncEventArgs.AcceptSocket, channelId)); + } + catch (Exception e) + { + Log.Error(e); + } + finally + { + AcceptAsync(); + } + } + + public override void RemoveChannel(uint channelId) + { + if (IsDisposed || !_connectionChannel.Remove(channelId, out var channel)) + { + return; + } + + if (channel.IsDisposed) + { + return; + } + + channel.Dispose(); + } + + #region 网络线程(由Socket底层产生的线程) + + private void OnCompleted(object sender, SocketAsyncEventArgs asyncEventArgs) + { + switch (asyncEventArgs.LastOperation) + { + case SocketAsyncOperation.Accept: + { + Scene.ThreadSynchronizationContext.Post(() => + { + OnAcceptComplete(asyncEventArgs); + }); + break; + } + default: + { + throw new Exception($"Socket Accept Error: {asyncEventArgs.LastOperation}"); + } + } + } + + #endregion + } +} +#endif + + diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/TCP/Server/TCPServerNetwork.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/TCP/Server/TCPServerNetwork.cs.meta new file mode 100644 index 0000000..14db622 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/TCP/Server/TCPServerNetwork.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e618ab398f9d443a4b5b85ec4ed611c3 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/TCP/Server/TCPServerNetworkChannel.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/TCP/Server/TCPServerNetworkChannel.cs new file mode 100644 index 0000000..122a54f --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/TCP/Server/TCPServerNetworkChannel.cs @@ -0,0 +1,295 @@ +#if FANTASY_NET +using System.Buffers; +using System.IO.Pipelines; +using System.Net.Sockets; +using Fantasy.Async; +using Fantasy.Network.Interface; +using Fantasy.PacketParser; +using Fantasy.Serialize; +// ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract +#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member + +#pragma warning disable CS8600 // Converting null literal or possible null value to non-nullable type. +#pragma warning disable CS8602 // Dereference of a possibly null reference. + +#pragma warning disable CS8604 // Possible null reference argument. +#pragma warning disable CS8622 // Nullability of reference types in type of parameter doesn't match the target delegate (possibly because of nullability attributes). + +namespace Fantasy.Network.TCP +{ + public sealed class TCPServerNetworkChannel : ANetworkServerChannel + { + private bool _isSending; + private bool _isInnerDispose; + private readonly Socket _socket; + private readonly ANetwork _network; + private readonly Pipe _pipe = new Pipe(); + private readonly SocketAsyncEventArgs _sendArgs; + private readonly ReadOnlyMemoryPacketParser _packetParser; + private readonly Queue _sendBuffers = new Queue(); + private readonly CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource(); + + public TCPServerNetworkChannel(ANetwork network, Socket socket, uint id) : base(network, id, socket.RemoteEndPoint) + { + _socket = socket; + _network = network; + _socket.NoDelay = true; + _sendArgs = new SocketAsyncEventArgs(); + _sendArgs.Completed += OnSendCompletedHandler; + _packetParser = PacketParserFactory.CreateServerReadOnlyMemoryPacket(network); + ReadPipeDataAsync().Coroutine(); + ReceiveSocketAsync().Coroutine(); + } + + public override void Dispose() + { + if (IsDisposed || _isInnerDispose) + { + return; + } + + _isInnerDispose = true; + _network.RemoveChannel(Id); + + if (!_cancellationTokenSource.IsCancellationRequested) + { + try + { + _cancellationTokenSource.Cancel(); + } + catch (OperationCanceledException) + { + // 通常情况下,此处的异常可以忽略 + } + } + + base.Dispose(); + + if (_socket != null) + { + _socket.Shutdown(SocketShutdown.Both); + _socket.Close(); + } + + _sendBuffers.Clear(); + _packetParser.Dispose(); + _isSending = false; + } + + #region ReceiveSocket + + private async FTask ReceiveSocketAsync() + { + while (!_cancellationTokenSource.IsCancellationRequested) + { + try + { + var memory = _pipe.Writer.GetMemory(8192); + var count = await _socket.ReceiveAsync(memory, SocketFlags.None, _cancellationTokenSource.Token); + + if (count == 0) + { + Dispose(); + return; + } + + _pipe.Writer.Advance(count); + await _pipe.Writer.FlushAsync(); + } + catch (SocketException) + { + Dispose(); + break; + } + catch (OperationCanceledException) + { + break; + } + catch (ObjectDisposedException) + { + Dispose(); + break; + } + catch (Exception ex) + { + Log.Error($"Unexpected exception: {ex.Message}"); + } + } + + await _pipe.Writer.CompleteAsync(); + } + + #endregion + + #region ReceivePipeData + + private async FTask ReadPipeDataAsync() + { + var pipeReader = _pipe.Reader; + while (!_cancellationTokenSource.IsCancellationRequested) + { + ReadResult result = default; + + try + { + result = await pipeReader.ReadAsync(_cancellationTokenSource.Token); + } + catch (OperationCanceledException) + { + // 出现这个异常表示取消了_cancellationTokenSource。一般Channel断开会取消。 + break; + } + + var buffer = result.Buffer; + var consumed = buffer.Start; + var examined = buffer.End; + + while (TryReadMessage(ref buffer, out var message)) + { + ReceiveData(ref message); + consumed = buffer.Start; + } + + if (result.IsCompleted) + { + break; + } + + pipeReader.AdvanceTo(consumed, examined); + } + + await pipeReader.CompleteAsync(); + } + + private bool TryReadMessage(ref ReadOnlySequence buffer, out ReadOnlyMemory message) + { + if (buffer.Length == 0) + { + message = default; + return false; + } + + message = buffer.First; + + if (message.Length == 0) + { + message = default; + return false; + } + + buffer = buffer.Slice(message.Length); + return true; + } + + private void ReceiveData(ref ReadOnlyMemory buffer) + { + try + { + while (_packetParser.UnPack(ref buffer, out var packInfo)) + { + if (_cancellationTokenSource.IsCancellationRequested) + { + return; + } + + Session.Receive(packInfo); + } + } + catch (ScanException e) + { + Log.Warning($"RemoteAddress:{RemoteEndPoint} \n{e}"); + Dispose(); + } + catch (Exception e) + { + Log.Error($"RemoteAddress:{RemoteEndPoint} \n{e}"); + Dispose(); + } + } + + #endregion + + #region Send + + public override void Send(uint rpcId, long routeId, MemoryStreamBuffer memoryStream, IMessage message) + { + _sendBuffers.Enqueue(_packetParser.Pack(ref rpcId, ref routeId, memoryStream, message)); + + if (!_isSending) + { + Send(); + } + } + + private void Send() + { + if (_isSending || IsDisposed) + { + return; + } + + _isSending = true; + + while (_sendBuffers.Count > 0) + { + var memoryStreamBuffer = _sendBuffers.Dequeue(); + _sendArgs.UserToken = memoryStreamBuffer; + _sendArgs.SetBuffer(new ArraySegment(memoryStreamBuffer.GetBuffer(), 0, (int)memoryStreamBuffer.Position)); + + try + { + if (_socket.SendAsync(_sendArgs)) + { + break; + } + + ReturnMemoryStream(memoryStreamBuffer); + } + catch + { + _isSending = false; + return; + } + } + + _isSending = false; + } + + private void ReturnMemoryStream(MemoryStreamBuffer memoryStream) + { + if (memoryStream.MemoryStreamBufferSource == MemoryStreamBufferSource.Pack) + { + _network.MemoryStreamBufferPool.ReturnMemoryStream(memoryStream); + } + } + + private void OnSendCompletedHandler(object sender, SocketAsyncEventArgs asyncEventArgs) + { + if (asyncEventArgs.SocketError != SocketError.Success || asyncEventArgs.BytesTransferred == 0) + { + _isSending = false; + return; + } + + var memoryStreamBuffer = (MemoryStreamBuffer)asyncEventArgs.UserToken; + + Scene.ThreadSynchronizationContext.Post(() => + { + ReturnMemoryStream(memoryStreamBuffer); + + if (_sendBuffers.Count > 0) + { + Send(); + } + else + { + _isSending = false; + } + }); + } + + #endregion + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/TCP/Server/TCPServerNetworkChannel.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/TCP/Server/TCPServerNetworkChannel.cs.meta new file mode 100644 index 0000000..ef3711c --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/TCP/Server/TCPServerNetworkChannel.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b2a73037f999c4c049abbfe87bc204e8 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/WebSocket.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/WebSocket.meta new file mode 100644 index 0000000..78eb6b7 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/WebSocket.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 048697d76e7714069b65df11a8fe9301 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/WebSocket/Client.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/WebSocket/Client.meta new file mode 100644 index 0000000..3fafd07 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/WebSocket/Client.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 0334c898391de44599ca09be9f560dd3 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/WebSocket/Client/WebSocketClientNetwork.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/WebSocket/Client/WebSocketClientNetwork.cs new file mode 100644 index 0000000..ac041e0 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/WebSocket/Client/WebSocketClientNetwork.cs @@ -0,0 +1,334 @@ +#if FANTASY_NET || FANTASY_CONSOLE +using System.Buffers; +using System.IO.Pipelines; +using System.Net.WebSockets; +using Fantasy.Async; +using Fantasy.Helper; +using Fantasy.Network.Interface; +using Fantasy.PacketParser; +using Fantasy.Serialize; +// ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member +#pragma warning disable CS8603 // Possible null reference return. +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. +#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. +namespace Fantasy.Network.WebSocket +{ + public sealed class WebSocketClientNetwork : AClientNetwork + { + private bool _isSending; + private bool _isInnerDispose; + private long _connectTimeoutId; + private ClientWebSocket _clientWebSocket; + private ReadOnlyMemoryPacketParser _packetParser; + private readonly Pipe _pipe = new Pipe(); + private readonly Queue _sendBuffers = new Queue(); + private readonly CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource(); + + private Action _onConnectFail; + private Action _onConnectComplete; + private Action _onConnectDisconnect; + + public void Initialize(NetworkTarget networkTarget) + { + base.Initialize(NetworkType.Client, NetworkProtocolType.WebSocket, networkTarget); + _packetParser = PacketParserFactory.CreateClientReadOnlyMemoryPacket(this); + } + + public override void Dispose() + { + if (IsDisposed || _isInnerDispose) + { + return; + } + + _isInnerDispose = true; + if (!_cancellationTokenSource.IsCancellationRequested) + { + try + { + _cancellationTokenSource.Cancel(); + } + catch (OperationCanceledException) + { + // 通常情况下,此处的异常可以忽略 + } + } + + base.Dispose(); + ClearConnectTimeout(); + WebSocketClientDisposeAsync().Coroutine(); + _onConnectDisconnect?.Invoke(); + _packetParser.Dispose(); + _packetParser = null; + _isSending = false; + } + + private async FTask WebSocketClientDisposeAsync() + { + if (_clientWebSocket == null) + { + return; + } + + await _clientWebSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "Closing", CancellationToken.None); + _clientWebSocket.Dispose(); + _clientWebSocket = null; + } + + public override Session Connect(string remoteAddress, Action onConnectComplete, Action onConnectFail, Action onConnectDisconnect, bool isHttps, int connectTimeout = 5000) + { + if (IsInit) + { + throw new NotSupportedException( + $"WebSocketClientNetwork Id:{Id} Has already been initialized. If you want to call Connect again, please re instantiate it."); + } + + IsInit = true; + _onConnectFail = onConnectFail; + _onConnectComplete = onConnectComplete; + _onConnectDisconnect = onConnectDisconnect; + // 设置连接超时定时器 + _connectTimeoutId = Scene.TimerComponent.Net.OnceTimer(connectTimeout, () => + { + _onConnectFail?.Invoke(); + Dispose(); + }); + + _clientWebSocket = new ClientWebSocket(); + var webSocketAddress = WebSocketHelper.GetWebSocketAddress(remoteAddress, isHttps); + + try + { + _clientWebSocket.ConnectAsync(new Uri(webSocketAddress), _cancellationTokenSource.Token).Wait(); + + if (_cancellationTokenSource.IsCancellationRequested) + { + return null; + } + } + catch (WebSocketException wse) + { + Log.Error($"WebSocket error: {wse.Message}"); + Dispose(); + return null; + } + catch (Exception e) + { + Log.Error($"An error occurred: {e.Message}"); + Dispose(); + return null; + } + + ClearConnectTimeout(); + ReadPipeDataAsync().Coroutine(); + ReceiveSocketAsync().Coroutine(); + _onConnectComplete?.Invoke(); + Session = Session.Create(this, null); + return Session; + } + + #region ReceiveSocket + + private async FTask ReceiveSocketAsync() + { + while (!_cancellationTokenSource.IsCancellationRequested) + { + try + { + var memory = _pipe.Writer.GetMemory(8192); + // 这里接收的数据不一定是一个完整的包。如果大于8192就会分成多个包。 + var receiveResult = await _clientWebSocket.ReceiveAsync(memory, _cancellationTokenSource.Token); + + if (receiveResult.MessageType == WebSocketMessageType.Close) + { + break; + } + + var count = receiveResult.Count; + + if (count > 0) + { + await PipeWriterFlushAsync(count); + } + } + catch (OperationCanceledException) + { + break; + } + catch (ObjectDisposedException) + { + Dispose(); + break; + } + // 这个先暂时注释掉,因为有些时候会出现WebSocketException + // 因为会出现这个挥手的错误,下个版本处理一下。 + // The remote party closed the WebSocket connection without completing the close handshake. + // catch (WebSocketException wse) + // { + // Log.Error($"WebSocket error: {wse.Message}"); + // Dispose(); + // break; + // } + catch (Exception e) + { + Log.Error(e); + } + } + + await _pipe.Writer.CompleteAsync(); + } + + private async FTask PipeWriterFlushAsync(int count) + { + _pipe.Writer.Advance(count); + await _pipe.Writer.FlushAsync(); + } + + #endregion + + #region ReceivePipeData + + private async FTask ReadPipeDataAsync() + { + var pipeReader = _pipe.Reader; + while (!_cancellationTokenSource.IsCancellationRequested) + { + ReadResult result = default; + + try + { + result = await pipeReader.ReadAsync(_cancellationTokenSource.Token); + } + catch (OperationCanceledException) + { + // 出现这个异常表示取消了_cancellationTokenSource。一般Channel断开会取消。 + break; + } + + var buffer = result.Buffer; + var consumed = buffer.Start; + var examined = buffer.End; + + while (TryReadMessage(ref buffer, out var message)) + { + ReceiveData(ref message); + consumed = buffer.Start; + } + + if (result.IsCompleted) + { + break; + } + + pipeReader.AdvanceTo(consumed, examined); + } + + await pipeReader.CompleteAsync(); + } + + private bool TryReadMessage(ref ReadOnlySequence buffer, out ReadOnlyMemory message) + { + if (buffer.Length == 0) + { + message = default; + return false; + } + + message = buffer.First; + + if (message.Length == 0) + { + message = default; + return false; + } + + buffer = buffer.Slice(message.Length); + return true; + } + + private void ReceiveData(ref ReadOnlyMemory buffer) + { + try + { + while (_packetParser.UnPack(ref buffer, out var packInfo)) + { + if (_cancellationTokenSource.IsCancellationRequested) + { + return; + } + + Session.Receive(packInfo); + } + } + catch (ScanException e) + { + Log.Warning(e.Message); + Dispose(); + } + catch (Exception e) + { + Log.Error(e); + Dispose(); + } + } + + #endregion + + #region Send + + public override void Send(uint rpcId, long routeId, MemoryStreamBuffer memoryStream, IMessage message) + { + _sendBuffers.Enqueue(_packetParser.Pack(ref rpcId, ref routeId, memoryStream, message)); + + if (!_isSending) + { + Send().Coroutine(); + } + } + + private async FTask Send() + { + if (_isSending || IsDisposed) + { + return; + } + + _isSending = true; + + while (_isSending) + { + if (!_sendBuffers.TryDequeue(out var memoryStream)) + { + _isSending = false; + return; + } + + await _clientWebSocket.SendAsync(new ArraySegment(memoryStream.GetBuffer(), 0, (int)memoryStream.Position), WebSocketMessageType.Binary, true, _cancellationTokenSource.Token); + + if (memoryStream.MemoryStreamBufferSource == MemoryStreamBufferSource.Pack) + { + MemoryStreamBufferPool.ReturnMemoryStream(memoryStream); + } + } + } + + #endregion + + public override void RemoveChannel(uint channelId) + { + Dispose(); + } + + private void ClearConnectTimeout() + { + if (_connectTimeoutId == 0) + { + return; + } + + Scene.TimerComponent.Net.Remove(ref _connectTimeoutId); + } + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/WebSocket/Client/WebSocketClientNetwork.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/WebSocket/Client/WebSocketClientNetwork.cs.meta new file mode 100644 index 0000000..cba0fb3 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/WebSocket/Client/WebSocketClientNetwork.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e2b829921d07d451ab3f103fd1b89d5b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/WebSocket/Client/WebSocketClientNetworkWebgl.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/WebSocket/Client/WebSocketClientNetworkWebgl.cs new file mode 100644 index 0000000..39373f1 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/WebSocket/Client/WebSocketClientNetworkWebgl.cs @@ -0,0 +1,180 @@ +#if !FANTASY_NET && !FANTASY_CONSOLE +using System; +using System.Collections.Generic; +using System.IO; +using Fantasy.Helper; +using Fantasy.Network.Interface; +using Fantasy.PacketParser; +using Fantasy.Serialize; +using UnityWebSocket; + +namespace Fantasy.Network.WebSocket +{ + // 因为webgl的限制、注定这个要是在游戏主线程里。所以这个库不会再其他线程执行的。 + // WebGL:在WebGL环境下运行 + // 另外不是运行在WebGL环境下,也没必要使用WebSocket协议了。完全可以使用TCP或KCP运行。同样也不会有那个队列产生的GC。 + public class WebSocketClientNetwork : AClientNetwork + { + private UnityWebSocket.WebSocket _webSocket; + private bool _isInnerDispose; + private bool _isConnected; + private long _connectTimeoutId; + private BufferPacketParser _packetParser; + private readonly Queue _messageCache = new Queue(); + + private Action _onConnectFail; + private Action _onConnectComplete; + private Action _onConnectDisconnect; + + public void Initialize(NetworkTarget networkTarget) + { + base.Initialize(NetworkType.Client, NetworkProtocolType.WebSocket, networkTarget); + _packetParser = PacketParserFactory.CreateClient(this); + } + + public override void Dispose() + { + if (IsDisposed || _isInnerDispose) + { + return; + } + + _isInnerDispose = true; + base.Dispose(); + + if (_webSocket != null && _webSocket.ReadyState != WebSocketState.Closed) + { + _onConnectDisconnect?.Invoke(); + _webSocket.CloseAsync(); + } + + _packetParser.Dispose(); + ClearConnectTimeout(); + _messageCache.Clear(); + } + + public override Session Connect(string remoteAddress, Action onConnectComplete, Action onConnectFail, Action onConnectDisconnect, bool isHttps, int connectTimeout = 5000) + { + // 如果已经初始化过一次,抛出异常,要求重新实例化 + + if (IsInit) + { + throw new NotSupportedException($"WebSocketClientNetwork Id:{Id} Has already been initialized. If you want to call Connect again, please re instantiate it."); + } + + IsInit = true; + _onConnectFail = onConnectFail; + _onConnectComplete = onConnectComplete; + _onConnectDisconnect = onConnectDisconnect; + _connectTimeoutId = Scene.TimerComponent.Net.OnceTimer(connectTimeout, () => + { + _onConnectFail?.Invoke(); + Dispose(); + }); + var webSocketAddress = WebSocketHelper.GetWebSocketAddress(remoteAddress, isHttps); + _webSocket = new UnityWebSocket.WebSocket(webSocketAddress); + _webSocket.OnOpen += OnNetworkConnectComplete; + _webSocket.OnMessage += OnReceiveComplete; + _webSocket.OnClose += (sender, args) => + { + _onConnectDisconnect?.Invoke(); + Dispose(); + }; + _webSocket.ConnectAsync(); + Session = Session.Create(this, null); + return Session; + } + + private void OnNetworkConnectComplete(object sender, OpenEventArgs e) + { + if (IsDisposed) + { + return; + } + + _isConnected = true; + ClearConnectTimeout(); + _onConnectComplete?.Invoke(); + + while (_messageCache.TryDequeue(out var memoryStream)) + { + Send(memoryStream); + } + } + + #region Receive + + private void OnReceiveComplete(object sender, MessageEventArgs e) + { + try + { + // WebSocket 协议已经在协议层面处理了消息的边界问题,因此不需要额外的粘包处理逻辑。 + // 所以如果解包的时候出现任何错误只能是恶意攻击造成的。 + var rawDataLength = e.RawData.Length; + _packetParser.UnPack(e.RawData, ref rawDataLength, out var packInfo); + Session.Receive(packInfo); + } + catch (ScanException ex) + { + Log.Warning($"{ex}"); + Dispose(); + } + catch (Exception ex) + { + Log.Error($"{ex}"); + Dispose(); + } + } + + #endregion + + #region Send + + public override void Send(uint rpcId, long routeId, MemoryStreamBuffer memoryStream, IMessage message) + { + if (IsDisposed) + { + return; + } + + var buffer = _packetParser.Pack(ref rpcId, ref routeId, memoryStream, message); + + if (!_isConnected) + { + _messageCache.Enqueue(buffer); + return; + } + + Send(buffer); + } + + private void Send(MemoryStreamBuffer memoryStream) + { + _webSocket.SendAsync(memoryStream.GetBuffer(), 0, (int)memoryStream.Position); +#if !UNITY_EDITOR && UNITY_WEBGL + if (memoryStream.MemoryStreamBufferSource == MemoryStreamBufferSource.Pack) + { + MemoryStreamBufferPool.ReturnMemoryStream(memoryStream); + } +#endif + } + + #endregion + + public override void RemoveChannel(uint channelId) + { + Dispose(); + } + + private void ClearConnectTimeout() + { + if (_connectTimeoutId == 0) + { + return; + } + + Scene?.TimerComponent?.Net?.Remove(ref _connectTimeoutId); + } + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/WebSocket/Client/WebSocketClientNetworkWebgl.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/WebSocket/Client/WebSocketClientNetworkWebgl.cs.meta new file mode 100644 index 0000000..9f9f305 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/WebSocket/Client/WebSocketClientNetworkWebgl.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 5b52ea2d6356f484ba1a7a63bf549cce +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/WebSocket/Server.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/WebSocket/Server.meta new file mode 100644 index 0000000..2d32188 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/WebSocket/Server.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ae9532d905102432da68c4ac0ded270a +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/WebSocket/Server/WebSocketServerNetwork.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/WebSocket/Server/WebSocketServerNetwork.cs new file mode 100644 index 0000000..09feb2b --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/WebSocket/Server/WebSocketServerNetwork.cs @@ -0,0 +1,112 @@ +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member +#if FANTASY_NET +using System.Net; +using System.Security.Cryptography.X509Certificates; +using Fantasy.Async; +using Fantasy.Network.Interface; + +// ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract +// ReSharper disable PossibleMultipleEnumeration +#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. +namespace Fantasy.Network.WebSocket; + +public class WebSocketServerNetwork : ANetwork +{ + private Random _random; + private HttpListener _httpListener; + private readonly Dictionary _connectionChannel = new Dictionary(); + + public void Initialize(NetworkTarget networkTarget, string bindIp, int port) + { + base.Initialize(NetworkType.Server, NetworkProtocolType.WebSocket, networkTarget); + + try + { + _random = new Random(); + _httpListener = new HttpListener(); + StartAcceptAsync(bindIp, port).Coroutine(); + } + catch (HttpListenerException e) + { + if (e.ErrorCode == 5) + { + throw new Exception($"CMD管理员中输入: netsh http add urlacl url=http://*:8080/ user=Everyone", e); + } + + Log.Error(e); + } + catch (Exception e) + { + Log.Error(e); + } + } + + public override void Dispose() + { + if (IsDisposed) + { + return; + } + + if (_httpListener != null) + { + _httpListener.Close(); + _httpListener = null; + } + + foreach (var channel in _connectionChannel.Values.ToArray()) + { + channel.Dispose(); + } + + _connectionChannel.Clear(); + base.Dispose(); + } + + private async FTask StartAcceptAsync(string bindIp, int port) + { + var listenUrl = ""; + var certificatePath = Path.Combine(AppContext.BaseDirectory, $"certificate{bindIp}{port}"); + listenUrl = Directory.Exists(certificatePath) ? $"https://{bindIp}:{port}/" : $"http://{bindIp}:{port}/"; + _httpListener.Prefixes.Add(listenUrl); + _httpListener.Start(); + Log.Info($"SceneConfigId = {Scene.SceneConfigId} WebSocketServer Listen {listenUrl}"); + while (!IsDisposed) + { + try + { + var httpListenerContext = await _httpListener.GetContextAsync(); + var webSocketContext = await httpListenerContext.AcceptWebSocketAsync(null); + var channelId = 0xC0000000 | (uint) _random.Next(); + + while (_connectionChannel.ContainsKey(channelId)) + { + channelId = 0xC0000000 | (uint) _random.Next(); + } + + _connectionChannel.Add(channelId, new WebSocketServerNetworkChannel(this, channelId, webSocketContext, httpListenerContext.Request.RemoteEndPoint)); + } + catch (Exception e) + { + Log.Error(e); + } + } + } + + public override void RemoveChannel(uint channelId) + { + if (IsDisposed || !_connectionChannel.Remove(channelId, out var channel)) + { + return; + } + + if (channel.IsDisposed) + { + return; + } + + channel.Dispose(); + } +} +#endif diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/WebSocket/Server/WebSocketServerNetwork.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/WebSocket/Server/WebSocketServerNetwork.cs.meta new file mode 100644 index 0000000..6b61724 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/WebSocket/Server/WebSocketServerNetwork.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f1a965026757445edbe7433d9acb1d02 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/WebSocket/Server/WebSocketServerNetworkChannel.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/WebSocket/Server/WebSocketServerNetworkChannel.cs new file mode 100644 index 0000000..7e8c70c --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/WebSocket/Server/WebSocketServerNetworkChannel.cs @@ -0,0 +1,253 @@ +#if FANTASY_NET +using System.Buffers; +using System.IO.Pipelines; +using System.Net; +using System.Net.Sockets; +using System.Net.WebSockets; +using Fantasy.Async; +using Fantasy.Network.Interface; +using Fantasy.PacketParser; +using Fantasy.Serialize; +#pragma warning disable CS8602 // Dereference of a possibly null reference. +#pragma warning disable CS8600 // Converting null literal or possible null value to non-nullable type. +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member + +namespace Fantasy.Network.WebSocket; + +public sealed class WebSocketServerNetworkChannel : ANetworkServerChannel +{ + private bool _isSending; + private bool _isInnerDispose; + private readonly Pipe _pipe = new Pipe(); + private readonly System.Net.WebSockets.WebSocket _webSocket; + private readonly WebSocketServerNetwork _network; + private readonly ReadOnlyMemoryPacketParser _packetParser; + private readonly Queue _sendBuffers = new Queue(); + private readonly CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource(); + + public WebSocketServerNetworkChannel(ANetwork network, uint id, HttpListenerWebSocketContext httpListenerWebSocketContext, IPEndPoint remoteEndPoint) : base(network, id, remoteEndPoint) + { + _network = (WebSocketServerNetwork)network; + _webSocket = httpListenerWebSocketContext.WebSocket; + _packetParser = PacketParserFactory.CreateServerReadOnlyMemoryPacket(network); + ReadPipeDataAsync().Coroutine(); + ReceiveSocketAsync().Coroutine(); + } + + public override void Dispose() + { + if (IsDisposed || _isInnerDispose) + { + return; + } + + _isInnerDispose = true; + if (!_cancellationTokenSource.IsCancellationRequested) + { + try + { + _cancellationTokenSource.Cancel(); + } + catch (OperationCanceledException) + { + // 通常情况下,此处的异常可以忽略 + } + } + _sendBuffers.Clear(); + _network.RemoveChannel(Id); + base.Dispose(); + if (_webSocket.State == WebSocketState.Open || _webSocket.State == WebSocketState.CloseReceived) + { + _webSocket.CloseOutputAsync(WebSocketCloseStatus.NormalClosure, "Normal Closure", + _cancellationTokenSource.Token).GetAwaiter().GetResult(); + } + _webSocket.Dispose(); + _isSending = false; + } + + #region ReceiveSocket + + private async FTask ReceiveSocketAsync() + { + while (!_cancellationTokenSource.IsCancellationRequested) + { + try + { + var memory = _pipe.Writer.GetMemory(8192); + // 这里接收的数据不一定是一个完整的包。如果大于8192就会分成多个包。 + var receiveResult = await _webSocket.ReceiveAsync(memory, _cancellationTokenSource.Token); + + if (receiveResult.MessageType == WebSocketMessageType.Close) + { + Dispose(); + break; + } + + var count = receiveResult.Count; + + if (count > 0) + { + await PipeWriterFlushAsync(count); + } + } + catch (OperationCanceledException) + { + break; + } + catch (ObjectDisposedException) + { + Dispose(); + break; + } + catch (WebSocketException) + { + // Log.Error($"WebSocket error: {wse.Message}"); + Dispose(); + break; + } + catch (Exception e) + { + Log.Error(e); + } + } + + await _pipe.Writer.CompleteAsync(); + } + + private async FTask PipeWriterFlushAsync(int count) + { + _pipe.Writer.Advance(count); + await _pipe.Writer.FlushAsync(); + } + + #endregion + + #region ReceivePipeData + + private async FTask ReadPipeDataAsync() + { + var pipeReader = _pipe.Reader; + while (!_cancellationTokenSource.IsCancellationRequested) + { + ReadResult result = default; + + try + { + result = await pipeReader.ReadAsync(_cancellationTokenSource.Token); + } + catch (OperationCanceledException) + { + // 出现这个异常表示取消了_cancellationTokenSource。一般Channel断开会取消。 + break; + } + + var buffer = result.Buffer; + var consumed = buffer.Start; + var examined = buffer.End; + + while (TryReadMessage(ref buffer, out var message)) + { + ReceiveData(ref message); + consumed = buffer.Start; + } + + if (result.IsCompleted) + { + break; + } + + pipeReader.AdvanceTo(consumed, examined); + } + + await pipeReader.CompleteAsync(); + } + + private bool TryReadMessage(ref ReadOnlySequence buffer, out ReadOnlyMemory message) + { + if (buffer.Length == 0) + { + message = default; + return false; + } + + message = buffer.First; + + if (message.Length == 0) + { + message = default; + return false; + } + + buffer = buffer.Slice(message.Length); + return true; + } + + private void ReceiveData(ref ReadOnlyMemory buffer) + { + try + { + while (_packetParser.UnPack(ref buffer, out var packInfo)) + { + if (_cancellationTokenSource.IsCancellationRequested) + { + return; + } + + Session.Receive(packInfo); + } + } + catch (ScanException e) + { + Log.Warning($"RemoteAddress:{RemoteEndPoint} \n{e}"); + Dispose(); + } + catch (Exception e) + { + Log.Error($"RemoteAddress:{RemoteEndPoint} \n{e}"); + Dispose(); + } + } + + #endregion + + #region Send + + public override void Send(uint rpcId, long routeId, MemoryStreamBuffer memoryStream, IMessage message) + { + _sendBuffers.Enqueue(_packetParser.Pack(ref rpcId, ref routeId, memoryStream, message)); + + if (!_isSending) + { + Send().Coroutine(); + } + } + + private async FTask Send() + { + if (_isSending || IsDisposed) + { + return; + } + + _isSending = true; + + while (_isSending) + { + if (!_sendBuffers.TryDequeue(out var memoryStream)) + { + _isSending = false; + return; + } + + await _webSocket.SendAsync(new ArraySegment(memoryStream.GetBuffer(), 0, (int)memoryStream.Position), WebSocketMessageType.Binary, true, _cancellationTokenSource.Token); + + if (memoryStream.MemoryStreamBufferSource == MemoryStreamBufferSource.Pack) + { + _network.MemoryStreamBufferPool.ReturnMemoryStream(memoryStream); + } + } + } + + #endregion +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/WebSocket/Server/WebSocketServerNetworkChannel.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/WebSocket/Server/WebSocketServerNetworkChannel.cs.meta new file mode 100644 index 0000000..b660416 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Protocol/WebSocket/Server/WebSocketServerNetworkChannel.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d353b9b1e0e2940cb8b519317d26b7c7 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Route.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Route.meta new file mode 100644 index 0000000..4c6733b --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Route.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 7214c9850b6e5412d920a3db65416738 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Route/RouteComponent.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Route/RouteComponent.cs new file mode 100644 index 0000000..ba00add --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Route/RouteComponent.cs @@ -0,0 +1,65 @@ +using Fantasy.Entitas; + +#if FANTASY_NET +namespace Fantasy.Network; + +/// +/// 自定义Route组件、如果要自定义Route协议必须使用这个组件 +/// +public sealed class RouteComponent : Entity +{ + /// + /// 存储路由类型和路由ID的映射关系。 + /// + public readonly Dictionary RouteAddress = new Dictionary(); + + /// + /// 添加路由类型和路由ID的映射关系。 + /// + /// 路由类型。 + /// 路由ID。 + public void AddAddress(long routeType, long routeId) + { + RouteAddress.Add(routeType, routeId); + } + + /// + /// 移除指定路由类型的映射关系。 + /// + /// 路由类型。 + public void RemoveAddress(long routeType) + { + RouteAddress.Remove(routeType); + } + + /// + /// 获取指定路由类型的路由ID。 + /// + /// 路由类型。 + /// 路由ID。 + public long GetRouteId(long routeType) + { + return RouteAddress.GetValueOrDefault(routeType, 0); + } + + /// + /// 尝试获取指定路由类型的路由ID。 + /// + /// 路由类型。 + /// 输出的路由ID。 + /// 如果获取成功返回true,否则返回false。 + public bool TryGetRouteId(long routeType, out long routeId) + { + return RouteAddress.TryGetValue(routeType, out routeId); + } + + /// + /// 释放组件资源,清空映射关系。 + /// + public override void Dispose() + { + RouteAddress.Clear(); + base.Dispose(); + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Route/RouteComponent.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Route/RouteComponent.cs.meta new file mode 100644 index 0000000..ce869a4 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Route/RouteComponent.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 061c0d492751d4ca695e8ce5dff4253e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Session.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Session.meta new file mode 100644 index 0000000..6387ffa --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Session.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: caade9c96d7c84a1986570594ae5f5ec +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Session/Component.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Session/Component.meta new file mode 100644 index 0000000..f74fe28 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Session/Component.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 913e8547caf3843af95a4b3325cb03db +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Session/Component/ConsoleSessionHeartbeatComponent.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Session/Component/ConsoleSessionHeartbeatComponent.cs new file mode 100644 index 0000000..dc4677e --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Session/Component/ConsoleSessionHeartbeatComponent.cs @@ -0,0 +1,156 @@ +// ReSharper disable MemberCanBePrivate.Global + +#if FANTASY_CONSOLE + +using System; +using Fantasy.Async; +using Fantasy.Entitas; +using Fantasy.Entitas.Interface; +using Fantasy.Helper; +using Fantasy.InnerMessage; +using Fantasy.Timer; +#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. + +namespace Fantasy.Network +{ + public class SessionHeartbeatComponentAwakeSystem : AwakeSystem + { + protected override void Awake(SessionHeartbeatComponent self) + { + self.TimerComponent = self.Scene.TimerComponent; + } + } + + /// + /// 负责管理会话心跳的组件。 + /// + public class SessionHeartbeatComponent : Entity + { + public int TimeOut; + public long TimerId; + public long LastTime; + public long SelfRunTimeId; + public long TimeOutTimerId; + public long SessionRunTimeId; + public TimerComponent TimerComponent; + public EntityReference Session; + private readonly PingRequest _pingRequest = new PingRequest(); + + public int Ping { get; private set; } + + public override void Dispose() + { + if (IsDisposed) + { + return; + } + + Stop(); + Ping = 0; + Session = null; + TimeOut = 0; + SelfRunTimeId = 0; + base.Dispose(); + } + + /// + /// 使用指定的间隔启动心跳功能。 + /// + /// 以毫秒为单位的心跳请求发送间隔。 + /// 设置与服务器的通信超时时间,如果超过这个时间限制,将自动断开会话(Session)。 + /// 用于检测与服务器连接超时频率。 + public void Start(int interval, int timeOut = 2000, int timeOutInterval = 3000) + { + TimeOut = timeOut + interval; + Session = (Session)Parent; + SelfRunTimeId = RuntimeId; + LastTime = TimeHelper.Now; + + if (TimerComponent == null) + { + Log.Error("请在Unity的菜单执行Fantasy->Generate link.xml再重新打包"); + return; + } + + TimerId = TimerComponent.Net.RepeatedTimer(interval, () => RepeatedSend().Coroutine()); + TimeOutTimerId = TimerComponent.Net.RepeatedTimer(timeOutInterval, CheckTimeOut); + } + + private void CheckTimeOut() + { + if (TimeHelper.Now - LastTime < TimeOut) + { + return; + } + + Session entityReference = Session; + + if (entityReference == null) + { + return; + } + + entityReference.Dispose(); + } + + /// + /// 停止心跳功能。 + /// + public void Stop() + { + if (TimerId != 0) + { + TimerComponent?.Net.Remove(ref TimerId); + } + + if (TimeOutTimerId != 0) + { + TimerComponent?.Net.Remove(ref TimeOutTimerId); + } + } + + /// + /// 异步发送心跳请求并处理响应。 + /// + /// 表示进行中操作的异步任务。 + private async FTask RepeatedSend() + { + if (SelfRunTimeId != RuntimeId) + { + Stop(); + return; + } + + Session session = Session; + + if (session == null) + { + Dispose(); + return; + } + + try + { + var requestTime = TimeHelper.Now; + + var pingResponse = (PingResponse)await session.Call(_pingRequest); + + if (pingResponse.ErrorCode != 0) + { + return; + } + + var responseTime = TimeHelper.Now; + LastTime = responseTime; + Ping = (int)(responseTime - requestTime) / 2; + TimeHelper.TimeDiff = pingResponse.Now + Ping - responseTime; + } + catch (Exception) + { + Dispose(); + } + } + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Session/Component/ConsoleSessionHeartbeatComponent.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Session/Component/ConsoleSessionHeartbeatComponent.cs.meta new file mode 100644 index 0000000..c71229b --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Session/Component/ConsoleSessionHeartbeatComponent.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 99fb296c5f69d491d9c4d0450f42318f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Session/Component/SessionIdleCheckerComponent.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Session/Component/SessionIdleCheckerComponent.cs new file mode 100644 index 0000000..1edc1cf --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Session/Component/SessionIdleCheckerComponent.cs @@ -0,0 +1,104 @@ +using Fantasy.Entitas; +using Fantasy.Entitas.Interface; +using Fantasy.Helper; +using Fantasy.Timer; + +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. +#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member +#if FANTASY_NET +namespace Fantasy.Network; + +public class SessionIdleCheckerComponentAwakeSystem : AwakeSystem +{ + protected override void Awake(SessionIdleCheckerComponent self) + { + self.TimerComponent = self.Scene.TimerComponent; + } +} + +/// +/// 负责检查会话空闲超时的组件。 +/// +public class SessionIdleCheckerComponent : Entity +{ + /// + /// 空闲超时时间(毫秒) + /// + private long _timeOut; + /// + /// 检查计时器的 ID + /// + private long _timerId; + /// + /// 用于确保组件完整性的自身运行时 ID + /// + private long _selfRuntimeId; + /// + /// 对会话对象的引用 + /// + private Session _session; + public TimerComponent TimerComponent; + + /// + /// 重写 Dispose 方法以释放资源。 + /// + public override void Dispose() + { + Stop(); // 停止检查计时器 + _timeOut = 0; // 重置空闲超时时间 + _selfRuntimeId = 0; // 重置自身运行时 ID + _session = null; // 清除会话引用 + base.Dispose(); + } + + /// + /// 使用指定的间隔和空闲超时时间启动空闲检查功能。 + /// + /// 以毫秒为单位的检查间隔。 + /// 以毫秒为单位的空闲超时时间。 + public void Start(int interval, int timeOut) + { + _timeOut = timeOut; + _session = (Session)Parent; + _selfRuntimeId = RuntimeId; + // 安排重复计时器,在指定的间隔内执行 Check 方法 + _timerId = TimerComponent.Net.RepeatedTimer(interval, Check); + } + + /// + /// 停止空闲检查功能。 + /// + public void Stop() + { + if (_timerId == 0) + { + return; + } + + TimerComponent.Net.Remove(ref _timerId); + } + + /// + /// 执行空闲检查操作。 + /// + private void Check() + { + if (_selfRuntimeId != RuntimeId || IsDisposed || _session == null) + { + Stop(); + return; + } + + var timeNow = TimeHelper.Now; + + if (timeNow - _session.LastReceiveTime < _timeOut) + { + return; + } + + Log.Warning($"session timeout id:{Id} timeNow:{timeNow} _session.LastReceiveTime:{_session.LastReceiveTime} _timeOut:{_timeOut}"); + _session.Dispose(); + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Session/Component/SessionIdleCheckerComponent.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Session/Component/SessionIdleCheckerComponent.cs.meta new file mode 100644 index 0000000..8eae6c8 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Session/Component/SessionIdleCheckerComponent.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c6536d2ffd3214fdf87a649ad0914c90 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Session/Component/UnitySessionHeartbeatComponent.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Session/Component/UnitySessionHeartbeatComponent.cs new file mode 100644 index 0000000..83c7cbf --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Session/Component/UnitySessionHeartbeatComponent.cs @@ -0,0 +1,156 @@ +// ReSharper disable MemberCanBePrivate.Global + +using System; +using Fantasy.Async; +using Fantasy.Entitas; +using Fantasy.Entitas.Interface; +using Fantasy.Helper; +using Fantasy.InnerMessage; +using Fantasy.Timer; + +#if FANTASY_UNITY + +namespace Fantasy.Network +{ + public class SessionHeartbeatComponentAwakeSystem : AwakeSystem + { + protected override void Awake(SessionHeartbeatComponent self) + { + self.TimerComponent = self.Scene.TimerComponent; + } + } + + /// + /// 负责管理会话心跳的组件。 + /// + public class SessionHeartbeatComponent : Entity + { + public int TimeOut; + public long TimerId; + public long LastTime; + public long SelfRunTimeId; + public long TimeOutTimerId; + public TimerComponent TimerComponent; + public EntityReference Session; + private readonly PingRequest _pingRequest = new PingRequest(); + + public int Ping { get; private set; } + + public override void Dispose() + { + if (IsDisposed) + { + return; + } + + Stop(); + Ping = 0; + Session = null; + TimeOut = 0; + LastTime = 0; + SelfRunTimeId = 0; + base.Dispose(); + } + + /// + /// 使用指定的间隔启动心跳功能。 + /// + /// 以毫秒为单位的心跳请求发送间隔。 + /// 设置与服务器的通信超时时间,如果超过这个时间限制,将自动断开会话(Session)。 + /// 用于检测与服务器连接超时频率。 + public void Start(int interval, int timeOut = 5000, int timeOutInterval = 3000) + { + TimeOut = timeOut + interval; + Session = (Session)Parent; + SelfRunTimeId = RuntimeId; + LastTime = TimeHelper.Now; + + if (TimerComponent == null) + { + Log.Error("请在Unity的菜单执行Fantasy->Generate link.xml再重新打包"); + return; + } + + TimerId = TimerComponent.Unity.RepeatedTimer(interval, () => + { + RepeatedSend().Coroutine(); + }); + TimeOutTimerId = TimerComponent.Unity.RepeatedTimer(timeOutInterval, CheckTimeOut); + } + + private void CheckTimeOut() + { + if (TimeHelper.Now - LastTime < TimeOut) + { + return; + } + + Session entityReference = Session; + + if (entityReference == null) + { + return; + } + + entityReference.Dispose(); + } + + /// + /// 停止心跳功能。 + /// + public void Stop() + { + if (TimerId != 0) + { + TimerComponent?.Unity.Remove(ref TimerId); + } + + if (TimeOutTimerId != 0) + { + TimerComponent?.Unity.Remove(ref TimeOutTimerId); + } + } + + /// + /// 异步发送心跳请求并处理响应。 + /// + /// 表示进行中操作的异步任务。 + private async FTask RepeatedSend() + { + if (SelfRunTimeId != RuntimeId) + { + Stop(); + return; + } + + Session session = Session; + + if (session == null) + { + Dispose(); + return; + } + + try + { + var requestTime = TimeHelper.Now; + var pingResponse = (PingResponse)await session.Call(_pingRequest); + + if (pingResponse.ErrorCode != 0) + { + return; + } + + var responseTime = TimeHelper.Now; + LastTime = responseTime; + Ping = (int)(responseTime - requestTime) / 2; + TimeHelper.TimeDiff = pingResponse.Now + Ping - responseTime; + } + catch (Exception) + { + Dispose(); + } + } + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Session/Component/UnitySessionHeartbeatComponent.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Session/Component/UnitySessionHeartbeatComponent.cs.meta new file mode 100644 index 0000000..4749110 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Session/Component/UnitySessionHeartbeatComponent.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 457cbbb00597a4a50b1ff761ccd0335a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Session/ProcessSession.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Session/ProcessSession.meta new file mode 100644 index 0000000..361739c --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Session/ProcessSession.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: c344eba409d3d479295fec3e198e0376 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Session/ProcessSession/ProcessScheduler.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Session/ProcessSession/ProcessScheduler.cs new file mode 100644 index 0000000..345eb5b --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Session/ProcessSession/ProcessScheduler.cs @@ -0,0 +1,260 @@ +#if FANTASY_NET +// ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract +using Fantasy.IdFactory; +using Fantasy.Network; +using Fantasy.Network.Interface; +using Fantasy.PacketParser.Interface; +using Fantasy.Platform.Net; + +namespace Fantasy.Scheduler; + +internal static class ProcessScheduler +{ + public static void Scheduler(this ProcessSession session, Type messageType, uint rpcId, long routeId, APackInfo packInfo) + { + switch (packInfo.OpCodeIdStruct.Protocol) + { + case OpCodeType.InnerResponse: + case OpCodeType.InnerRouteResponse: + case OpCodeType.InnerAddressableResponse: + case OpCodeType.OuterAddressableResponse: + case OpCodeType.OuterCustomRouteResponse: + { + using (packInfo) + { + var sessionScene = session.Scene; + var message = packInfo.Deserialize(messageType); + sessionScene.ThreadSynchronizationContext.Post(() => + { + // 因为有可能是其他Scene线程下发送过来的、所以必须放到当前Scene进程下运行。 + sessionScene.NetworkMessagingComponent.ResponseHandler(rpcId, (IResponse)message); + }); + } + + return; + } + case OpCodeType.InnerRouteMessage: + { + using (packInfo) + { + var sceneId = IdFactoryHelper.RuntimeIdTool.GetSceneId(ref routeId); + + if (!Process.TryGetScene(sceneId, out var scene)) + { + throw new Exception($"not found scene routeId:{routeId}"); + } + + var message = packInfo.Deserialize(messageType); + + scene.ThreadSynchronizationContext.Post(() => + { + var entity = scene.GetEntity(routeId); + var sceneMessageDispatcherComponent = scene.MessageDispatcherComponent; + + if (entity == null || entity.IsDisposed) + { + return; + } + + sceneMessageDispatcherComponent.RouteMessageHandler(session, messageType, entity, message, rpcId).Coroutine(); + }); + } + + return; + } + case OpCodeType.InnerRouteRequest: + { + using (packInfo) + { + var sceneId = IdFactoryHelper.RuntimeIdTool.GetSceneId(ref routeId); + + if (!Process.TryGetScene(sceneId, out var scene)) + { + throw new Exception($"not found scene routeId:{routeId}"); + } + + var message = packInfo.Deserialize(messageType); + + scene.ThreadSynchronizationContext.Post(() => + { + var entity = scene.GetEntity(routeId); + var sceneMessageDispatcherComponent = scene.MessageDispatcherComponent; + + if (entity == null || entity.IsDisposed) + { + sceneMessageDispatcherComponent.FailRouteResponse(session, messageType, InnerErrorCode.ErrNotFoundRoute, rpcId); + return; + } + + sceneMessageDispatcherComponent.RouteMessageHandler(session, messageType, entity, message, rpcId).Coroutine(); + }); + } + + return; + } + case OpCodeType.OuterAddressableMessage: + case OpCodeType.OuterCustomRouteMessage: + case OpCodeType.OuterAddressableRequest: + case OpCodeType.OuterCustomRouteRequest: + { + using (packInfo) + { + var sceneId = IdFactoryHelper.RuntimeIdTool.GetSceneId(ref routeId); + + if (!Process.TryGetScene(sceneId, out var scene)) + { + throw new NotSupportedException($"not found scene routeId = {routeId}"); + } + + var message = packInfo.Deserialize(messageType); + + scene.ThreadSynchronizationContext.Post(() => + { + var entity = scene.GetEntity(routeId); + + if (entity == null || entity.IsDisposed) + { + scene.MessageDispatcherComponent.FailRouteResponse(session, messageType, InnerErrorCode.ErrNotFoundRoute, rpcId); + return; + } + + scene.MessageDispatcherComponent.RouteMessageHandler(session, messageType, entity, message, rpcId).Coroutine(); + }); + } + return; + } + default: + { + var packInfoProtocolCode = packInfo.ProtocolCode; + packInfo.Dispose(); + throw new NotSupportedException($"SessionInnerScheduler Received unsupported message protocolCode:{packInfoProtocolCode} messageType:{messageType}"); + } + } + } + + public static void Scheduler(this ProcessSession session, Type messageType, uint rpcId, long routeId, uint protocolCode, object message) + { + OpCodeIdStruct opCodeIdStruct = protocolCode; + + switch (opCodeIdStruct.Protocol) + { + case OpCodeType.InnerResponse: + case OpCodeType.InnerRouteResponse: + case OpCodeType.InnerAddressableResponse: + case OpCodeType.OuterAddressableResponse: + case OpCodeType.OuterCustomRouteResponse: + { + var sessionScene = session.Scene; + sessionScene.ThreadSynchronizationContext.Post(() => + { + var iResponse = (IResponse)session.Deserialize(messageType, message, ref opCodeIdStruct); + // 因为有可能是其他Scene线程下发送过来的、所以必须放到当前Scene进程下运行。 + sessionScene.NetworkMessagingComponent.ResponseHandler(rpcId, iResponse); + }); + + return; + } + case OpCodeType.InnerAddressableMessage: + case OpCodeType.InnerRouteMessage: + { + var sceneId = IdFactoryHelper.RuntimeIdTool.GetSceneId(ref routeId); + + if (!Process.TryGetScene(sceneId, out var scene)) + { + throw new Exception($"not found scene routeId:{routeId}"); + } + + var messageObject = session.Deserialize(messageType, message, ref opCodeIdStruct); + + scene.ThreadSynchronizationContext.Post(() => + { + var entity = scene.GetEntity(routeId); + var sceneMessageDispatcherComponent = scene.MessageDispatcherComponent; + + if (entity == null || entity.IsDisposed) + { + return; + } + + sceneMessageDispatcherComponent.RouteMessageHandler(session, messageType, entity, messageObject, rpcId).Coroutine(); + }); + + return; + } + case OpCodeType.InnerAddressableRequest: + case OpCodeType.InnerRouteRequest: + { + var sceneId = IdFactoryHelper.RuntimeIdTool.GetSceneId(ref routeId); + + if (!Process.TryGetScene(sceneId, out var scene)) + { + throw new Exception($"not found scene routeId:{routeId}"); + } + + var messageObject = session.Deserialize(messageType, message, ref opCodeIdStruct); + + scene.ThreadSynchronizationContext.Post(() => + { + var entity = scene.GetEntity(routeId); + var sceneMessageDispatcherComponent = scene.MessageDispatcherComponent; + + if (entity == null || entity.IsDisposed) + { + sceneMessageDispatcherComponent.FailRouteResponse(session, message.GetType(), InnerErrorCode.ErrNotFoundRoute, rpcId); + return; + } + + sceneMessageDispatcherComponent.RouteMessageHandler(session, messageType, entity, messageObject, rpcId).Coroutine(); + }); + + return; + } + case OpCodeType.OuterAddressableMessage: + case OpCodeType.OuterCustomRouteMessage: + { + var sceneId = IdFactoryHelper.RuntimeIdTool.GetSceneId(ref routeId); + + if (!Process.TryGetScene(sceneId, out var scene)) + { + Log.Error($"not found scene routeId:{routeId}"); + return; + } + + var messageObject = session.Deserialize(messageType, message, ref opCodeIdStruct); + + scene.ThreadSynchronizationContext.Post(() => + { + var entity = scene.GetEntity(routeId); + + switch (entity) + { + case null: + { + // 执行到这里是说明Session已经断开了 + // 因为这里是其他服务器Send到外网的数据、所以不需要给发送端返回就可以 + return; + } + case Session gateSession: + { + // 这里如果是Session只可能是Gate的Session、如果是的话、肯定是转发Address消息 + gateSession.Send((IMessage)messageObject, rpcId); + return; + } + default: + { + scene.MessageDispatcherComponent.RouteMessageHandler(session, messageType, entity, messageObject, rpcId).Coroutine(); + return; + } + } + }); + + return; + } + default: + { + throw new NotSupportedException($"SessionInnerScheduler Received unsupported message protocolCode:{protocolCode} messageType:{messageType}"); + } + } + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Session/ProcessSession/ProcessScheduler.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Session/ProcessSession/ProcessScheduler.cs.meta new file mode 100644 index 0000000..269c511 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Session/ProcessSession/ProcessScheduler.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a88ea22f28c7247039d360c1139b976e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Session/ProcessSession/ProcessSession.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Session/ProcessSession/ProcessSession.cs new file mode 100644 index 0000000..f576673 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Session/ProcessSession/ProcessSession.cs @@ -0,0 +1,125 @@ +using Fantasy.Async; +using Fantasy.Network.Interface; +using Fantasy.PacketParser; +using Fantasy.PacketParser.Interface; +using Fantasy.Pool; +using Fantasy.Scheduler; +using Fantasy.Serialize; +#pragma warning disable CS8604 // Possible null reference argument. +#pragma warning disable CS8603 // Possible null reference return. + +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member +#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. +#if FANTASY_NET +namespace Fantasy.Network; + +/// +/// 网络服务器内部会话。 +/// +public sealed class ProcessSession : Session +{ + private readonly MemoryStreamBufferPool _memoryStreamBufferPool = new MemoryStreamBufferPool(); + private readonly Dictionary> _createInstances = new Dictionary>(); + + /// + /// 发送消息到服务器内部。 + /// + /// 要发送的消息。 + /// RPC 标识符。 + /// 路由标识符。 + public override void Send(IMessage message, uint rpcId = 0, long routeId = 0) + { + if (IsDisposed) + { + return; + } + + this.Scheduler(message.GetType(), rpcId, routeId, message.OpCode(), message); + } + + /// + /// 发送路由消息到服务器内部。 + /// + /// 要发送的路由消息。 + /// RPC 标识符。 + /// 路由标识符。 + public override void Send(IRouteMessage routeMessage, uint rpcId = 0, long routeId = 0) + { + if (IsDisposed) + { + return; + } + + this.Scheduler(routeMessage.GetType(), rpcId, routeId, routeMessage.OpCode(), routeMessage); + } + + public override void Send(uint rpcId, long routeId, Type messageType, APackInfo packInfo) + { + if (IsDisposed) + { + return; + } + + this.Scheduler(messageType, rpcId, routeId, packInfo); + } + + public override void Send(ProcessPackInfo packInfo, uint rpcId = 0, long routeId = 0) + { + this.Scheduler(packInfo.MessageType, rpcId, routeId, packInfo); + } + + public override void Send(MemoryStreamBuffer memoryStream, uint rpcId = 0, long routeId = 0) + { + throw new Exception("The use of this method is not supported"); + } + + public override FTask Call(IRouteRequest request, long routeId = 0) + { + throw new Exception("The use of this method is not supported"); + } + + public override FTask Call(IRequest request, long routeId = 0) + { + throw new Exception("The use of this method is not supported"); + } + + public object Deserialize(Type messageType, object message, ref OpCodeIdStruct opCodeIdStruct) + { + var memoryStream = _memoryStreamBufferPool.RentMemoryStream(MemoryStreamBufferSource.None); + + try + { + if (SerializerManager.TryGetSerializer(opCodeIdStruct.OpCodeProtocolType, out var serializer)) + { + serializer.Serialize(messageType, message, memoryStream); + + if (memoryStream.Position == 0) + { + if (_createInstances.TryGetValue(messageType, out var createInstance)) + { + return createInstance(); + } + + createInstance = CreateInstance.CreateObject(messageType); + _createInstances.Add(messageType, createInstance); + return createInstance(); + } + + memoryStream.SetLength(memoryStream.Position); + memoryStream.Seek(0, SeekOrigin.Begin); + return serializer.Deserialize(messageType, memoryStream); + } + } + catch (Exception e) + { + Log.Error($"ProcessSession.Deserialize {e}"); + } + finally + { + _memoryStreamBufferPool.ReturnMemoryStream(memoryStream); + } + + throw new Exception($"type:{messageType} Does not support processing protocol"); + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Session/ProcessSession/ProcessSession.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Session/ProcessSession/ProcessSession.cs.meta new file mode 100644 index 0000000..6d2ab0e --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Session/ProcessSession/ProcessSession.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: af272d9643ac74c4dad1cf580f9f6ba6 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Session/ProcessSession/ProcessSessionInfo.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Session/ProcessSession/ProcessSessionInfo.cs new file mode 100644 index 0000000..6e3a534 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Session/ProcessSession/ProcessSessionInfo.cs @@ -0,0 +1,17 @@ +using Fantasy.Network.Interface; + +#if FANTASY_NET +namespace Fantasy.Network; + +internal sealed class ProcessSessionInfo(Session session, AClientNetwork aClientNetwork) : IDisposable +{ + public readonly Session Session = session; + public readonly AClientNetwork AClientNetwork = aClientNetwork; + + public void Dispose() + { + Session.Dispose(); + AClientNetwork?.Dispose(); + } +} +#endif diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Session/ProcessSession/ProcessSessionInfo.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Session/ProcessSession/ProcessSessionInfo.cs.meta new file mode 100644 index 0000000..b4df682 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Session/ProcessSession/ProcessSessionInfo.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 95db8925726a34b0dae70295cbd646f0 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Session/Session.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Session/Session.cs new file mode 100644 index 0000000..9fc7868 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Session/Session.cs @@ -0,0 +1,262 @@ +// ReSharper disable RedundantUsingDirective +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Net; +using Fantasy.Async; +using Fantasy.Entitas; +using Fantasy.Entitas.Interface; +using Fantasy.Helper; +using Fantasy.Network.Interface; +using Fantasy.PacketParser; +using Fantasy.PacketParser.Interface; +using Fantasy.Scheduler; +using Fantasy.Serialize; +#if FANTASY_NET +using Fantasy.Platform.Net; +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member +#endif +// ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract +#pragma warning disable CS8600 // Converting null literal or possible null value to non-nullable type. +#pragma warning disable CS8602 // Dereference of a possibly null reference. +#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. +#pragma warning disable CS8603 +#pragma warning disable CS8601 +#pragma warning disable CS8618 + +namespace Fantasy.Network +{ + /// + /// 网络会话的基类,用于管理网络通信。 + /// + public class Session : Entity, ISupportedMultiEntity + { + private uint _rpcId; + internal long LastReceiveTime; + /// + /// 关联的网络连接通道 + /// + public INetworkChannel Channel { get; private set; } + /// + /// 当前Session的终结点信息 + /// + public IPEndPoint RemoteEndPoint { get; private set; } + private ANetworkMessageScheduler NetworkMessageScheduler { get; set;} + public readonly Dictionary> RequestCallback = new(); + /// + /// Session的Dispose委托 + /// + public event Action OnDispose; +#if FANTASY_NET + internal static Session Create(ANetworkMessageScheduler networkMessageScheduler, ANetworkServerChannel channel, NetworkTarget networkTarget) + { + var session = Entity.Create(channel.Scene, false, true); + session.Channel = channel; + session.NetworkMessageScheduler = networkMessageScheduler; + session.RemoteEndPoint = channel.RemoteEndPoint as IPEndPoint; + session.OnDispose = channel.Dispose; + session.LastReceiveTime = TimeHelper.Now; + // 在外部网络目标下,添加会话空闲检查组件 + if (networkTarget == NetworkTarget.Outer) + { + var interval = ProcessDefine.SessionIdleCheckerInterval; + var timeOut = ProcessDefine.SessionIdleCheckerTimeout; + session.AddComponent().Start(interval, timeOut); + } + return session; + } +#endif + internal static Session Create(AClientNetwork network, IPEndPoint remoteEndPoint) + { + // 创建会话实例 + var session = Entity.Create(network.Scene, false, true); + session.Channel = network; + session.RemoteEndPoint = remoteEndPoint; + session.OnDispose = network.Dispose; + session.NetworkMessageScheduler = network.NetworkMessageScheduler; + session.LastReceiveTime = TimeHelper.Now; + return session; + } +#if FANTASY_NET + internal static ProcessSession CreateInnerSession(Scene scene) + { + var session = Entity.Create(scene, false, false); + session.NetworkMessageScheduler = new InnerMessageScheduler(scene); + return session; + } + + /// + /// 发送一个消息,框架内部使用建议不要用这个方法。 + /// + /// 如果是RPC消息需要传递一个RPCId + /// routeId + /// 消息的类型 + /// packInfo消息包 + public virtual void Send(uint rpcId, long routeId, Type messageType, APackInfo packInfo) + { + if (IsDisposed) + { + return; + } + + Channel.Send(rpcId, routeId, packInfo.MemoryStream, null); + } + + /// + /// 发送一个消息,框架内部使用建议不要用这个方法。 + /// + /// 一个ProcessPackInfo消息包 + /// 如果是RPC消息需要传递一个RPCId + /// routeId + public virtual void Send(ProcessPackInfo packInfo, uint rpcId = 0, long routeId = 0) + { + if (IsDisposed) + { + return; + } + + using (packInfo) + { + Channel.Send(rpcId, routeId, packInfo.MemoryStream, null); + } + } + + /// + /// 发送一个消息 + /// + /// 需要发送的MemoryStreamBuffer + /// 如果是RPC消息需要传递一个RPCId + /// routeId + public virtual void Send(MemoryStreamBuffer memoryStream, uint rpcId = 0, long routeId = 0) + { + if (IsDisposed) + { + return; + } + + Channel.Send(rpcId, routeId, memoryStream, null); + } +#endif + /// + /// 销毁一个Session,当执行了这个方法会自动断开网络的连接。 + /// + public override void Dispose() + { + if (IsDisposed) + { + return; + } + + _rpcId = 0; + LastReceiveTime = 0; + Channel = null; + RemoteEndPoint = null; + NetworkMessageScheduler = null; + base.Dispose(); + + // 终止所有等待中的请求回调 + foreach (var requestCallback in RequestCallback.Values.ToArray()) + { + requestCallback.SetException(new Exception($"session is dispose: {Id}")); + } + + RequestCallback.Clear(); + OnDispose?.Invoke(); + } + + /// + /// 发送一个消息 + /// + /// 消息的实例 + /// 如果是RPC消息需要传递一个RPCId + /// routeId + public virtual void Send(IMessage message, uint rpcId = 0, long routeId = 0) + { + if (IsDisposed) + { + return; + } + + Channel.Send(rpcId, routeId, null, message); + } + + /// + /// 发送一个消息 + /// + /// 消息的实例,不同的是这个是发送Route消息使用的 + /// 如果是RPC消息需要传递一个RPCId + /// routeId + public virtual void Send(IRouteMessage routeMessage, uint rpcId = 0, long routeId = 0) + { + if (IsDisposed) + { + return; + } + + Channel.Send(rpcId, routeId, null, routeMessage); + } + + /// + /// 发送一个RPC消息 + /// + /// 请求Route消息的实例 + /// routeId + /// + public virtual FTask Call(IRouteRequest request, long routeId = 0) + { + if (IsDisposed) + { + return null; + } + + var requestCallback = FTask.Create(); + var rpcId = ++_rpcId; + RequestCallback.Add(rpcId, requestCallback); + Send(request, rpcId, routeId); + return requestCallback; + } + + /// + /// 发送一个RPC消息 + /// + /// 请求消息的实例 + /// routeId + /// + public virtual FTask Call(IRequest request, long routeId = 0) + { + if (IsDisposed) + { + return null; + } + + var requestCallback = FTask.Create(); + var rpcId = ++_rpcId; + RequestCallback.Add(rpcId, requestCallback); + Send(request, rpcId, routeId); + return requestCallback; + } + + internal void Receive(APackInfo packInfo) + { + if (IsDisposed) + { + return; + } + + LastReceiveTime = TimeHelper.Now; + + try + { + NetworkMessageScheduler.Scheduler(this, packInfo).Coroutine(); + } + catch (Exception e) + { + // 如果解析失败,只有一种可能,那就是有人恶意发包。 + // 所以这里强制关闭了当前连接。不让对方一直发包。 + Dispose(); + Log.Error(e); + } + } + } +} diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Session/Session.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Session/Session.cs.meta new file mode 100644 index 0000000..ad17a41 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Network/Session/Session.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 5376c3723b02540d4955f019e0826a7a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform.meta new file mode 100644 index 0000000..282ef97 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 534116af9a7e44a71abe399bf23f89bb +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Console.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Console.meta new file mode 100644 index 0000000..251090e --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Console.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: bbb39d4a6a48a4fd1a301afe2b382364 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Console/Entry.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Console/Entry.cs new file mode 100644 index 0000000..e45d060 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Console/Entry.cs @@ -0,0 +1,101 @@ +#if FANTASY_CONSOLE +using Fantasy.Assembly; +using Fantasy.Async; +using Fantasy.Serialize; +#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. +#pragma warning disable CS8603 // Possible null reference return. +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. +namespace Fantasy.Platform.Console +{ + public struct OnFantasyInit + { + public Scene Scene; + } + + /// + /// 一般的控制台启动入口,可以适用大部分客户端环境 + /// + public sealed class Entry + { + private static bool _isInit; + private static Thread _updateThread; + public static Scene Scene { get; private set; } + + /// + /// 初始化框架 + /// + /// + public static async FTask Initialize(params System.Reflection.Assembly[] assemblies) + { + if (_isInit) + { + Log.Error("Fantasy has already been initialized and does not need to be initialized again!"); + return; + } + + // 初始化程序集管理系统 + await AssemblySystem.InnerInitialize(assemblies); + // 初始化序列化 + SerializerManager.Initialize(); + _isInit = true; + Log.Debug("Fantasy Initialize Complete!"); + } + + /// + /// 启动框架。 + /// 如果您的平台有每帧更新逻辑的方法,请不要调用这个方法。 + /// 如果没有实现每帧执行方法平台需要调用这个方法,目的是开启一个新的线程来每帧执行Update。 + /// 注意因为开启了一个新的线程来处理更新逻辑,所以要注意多线程的问题。 + /// + public static void StartUpdate() + { + _updateThread = new Thread(() => + { + while (_isInit) + { + ThreadScheduler.Update(); + Thread.Sleep(1); + } + }) + { + IsBackground = true + }; + _updateThread.Start(); + } + + /// + /// 在Entry中创建一个Scene,如果Scene已经被创建过,将先销毁Scene再创建。 + /// + /// + /// + public static async FTask CreateScene(string sceneRuntimeType = SceneRuntimeType.MainThread) + { + Scene?.Dispose(); + Scene = await Scene.Create(sceneRuntimeType); + await Scene.EventComponent.PublishAsync(new OnFantasyInit() + { + Scene = Scene + }); + return Scene; + } + + /// + /// 如果有的话一定要在每帧执行这个方法 + /// + public void Update() + { + ThreadScheduler.Update(); + } + + public static void Dispose() + { + AssemblySystem.Dispose(); + SerializerManager.Dispose(); + Scene?.Dispose(); + Scene = null; + _isInit = false; + } + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Console/Entry.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Console/Entry.cs.meta new file mode 100644 index 0000000..3da7a47 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Console/Entry.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: cc5c1ff7d14644495988c787b94e4221 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Console/ThreadSynchronizationContext.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Console/ThreadSynchronizationContext.cs new file mode 100644 index 0000000..29fd54a --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Console/ThreadSynchronizationContext.cs @@ -0,0 +1,38 @@ +#if FANTASY_CONSOLE +#pragma warning disable CS8601 // Possible null reference assignment. +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. +#pragma warning disable CS8765 // Nullability of type of parameter doesn't match overridden member (possibly because of nullability attributes). +namespace Fantasy +{ + public sealed class ThreadSynchronizationContext : SynchronizationContext + { + private Action _actionHandler; + private readonly Queue _queue = new(); + + public void Update() + { + while (_queue.TryDequeue(out _actionHandler)) + { + try + { + _actionHandler(); + } + catch (Exception e) + { + Log.Error(e); + } + } + } + + public override void Post(SendOrPostCallback callback, object state) + { + Post(() => callback(state)); + } + + public void Post(Action action) + { + _queue.Enqueue(action); + } + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Console/ThreadSynchronizationContext.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Console/ThreadSynchronizationContext.cs.meta new file mode 100644 index 0000000..e152d90 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Console/ThreadSynchronizationContext.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 48741dacd26f742bfb9f33dd96105ab6 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Net.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Net.meta new file mode 100644 index 0000000..c47d3c7 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Net.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: f5923944e3cd54cbe8935ea06d2478c7 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Net/ConfigTable.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Net/ConfigTable.meta new file mode 100644 index 0000000..2dd25b5 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Net/ConfigTable.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 53cf00bfe984149d9872dc9d2d337fc9 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Net/ConfigTable/MachineConfig.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Net/ConfigTable/MachineConfig.cs new file mode 100644 index 0000000..e09b00e --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Net/ConfigTable/MachineConfig.cs @@ -0,0 +1,88 @@ +#if FANTASY_NET +// ReSharper disable InconsistentNaming +using System.Collections.Concurrent; +using System.Runtime.Serialization; +using Fantasy.Helper; +using Newtonsoft.Json; +#pragma warning disable CS8601 // Possible null reference assignment. +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. +namespace Fantasy.Platform.Net +{ + /// + /// 用于记录服务器物理信息 + /// + public sealed class MachineConfigData + { + /// + /// 存放所有MachineConfigInfo信息 + /// + public List List; + [JsonIgnore] + [IgnoreDataMember] + private readonly ConcurrentDictionary _configs = new ConcurrentDictionary(); + /// + /// 获得MachineConfig的实例 + /// + public static MachineConfigData Instance { get; private set; } + /// + /// 初始化MachineConfig + /// + /// + public static void Initialize(string machineConfigJson) + { + Instance = machineConfigJson.Deserialize(); + foreach (var config in Instance.List) + { + Instance._configs.TryAdd(config.Id, config); + } + } + /// + /// 根据Id获取MachineConfig + /// + /// + /// + /// + public MachineConfig Get(uint id) + { + if (_configs.TryGetValue(id, out var machineConfigInfo)) + { + return machineConfigInfo; + } + + throw new FileNotFoundException($"MachineConfig not find {id} Id"); + } + /// + /// 根据Id获取MachineConfig + /// + /// + /// + /// + public bool TryGet(uint id, out MachineConfig config) + { + return _configs.TryGetValue(id, out config); + } + } + /// + /// 表示一个物理服务器的信息 + /// + public sealed class MachineConfig + { + /// + /// Id + /// + public uint Id { get; set; } + /// + /// 外网IP + /// + public string OuterIP { get; set; } + /// + /// 外网绑定IP + /// + public string OuterBindIP { get; set; } + /// + /// 内网绑定IP + /// + public string InnerBindIP { get; set; } + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Net/ConfigTable/MachineConfig.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Net/ConfigTable/MachineConfig.cs.meta new file mode 100644 index 0000000..a5fcd9a --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Net/ConfigTable/MachineConfig.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: dd753001cdd384069a959115f6ca365b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Net/ConfigTable/ProcessConfig.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Net/ConfigTable/ProcessConfig.cs new file mode 100644 index 0000000..4a400b0 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Net/ConfigTable/ProcessConfig.cs @@ -0,0 +1,100 @@ +#if FANTASY_NET +using System.Collections.Concurrent; +using System.Runtime.Serialization; +using Fantasy.Helper; +using Newtonsoft.Json; +// ReSharper disable CollectionNeverUpdated.Global +#pragma warning disable CS8601 // Possible null reference assignment. +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. + +namespace Fantasy.Platform.Net +{ + /// + /// 用于管理进程信息 + /// + public sealed class ProcessConfigData + { + /// + /// 存放所有ProcessConfig信息 + /// + public List List; + [JsonIgnore] + [IgnoreDataMember] + private readonly ConcurrentDictionary _configs = new ConcurrentDictionary(); + /// + /// 获得ProcessConfigData的实例 + /// + public static ProcessConfigData Instance { get; private set; } + /// + /// 初始化MachineConfig + /// + /// + public static void Initialize(string processConfigJson) + { + Instance = processConfigJson.Deserialize(); + foreach (var config in Instance.List) + { + Instance._configs.TryAdd(config.Id, config); + } + } + /// + /// 根据Id获取ProcessConfig + /// + /// + /// + /// + public ProcessConfig Get(uint id) + { + if (_configs.TryGetValue(id, out var processConfigInfo)) + { + return processConfigInfo; + } + + throw new FileNotFoundException($"MachineConfig not find {id} Id"); + } + /// + /// 根据Id获取ProcessConfig + /// + /// + /// + /// + public bool TryGet(uint id, out ProcessConfig config) + { + return _configs.TryGetValue(id, out config); + } + /// + /// 按照startupGroup寻找属于startupGroup组的ProcessConfig + /// + /// startupGroup + /// + public IEnumerable ForEachByStartupGroup(uint startupGroup) + { + foreach (var processConfig in List) + { + if (processConfig.StartupGroup == startupGroup) + { + yield return processConfig; + } + } + } + } + /// + /// 表示一个进程配置信息 + /// + public sealed class ProcessConfig + { + /// + /// 进程Id + /// + public uint Id { get; set; } + /// + /// 机器ID + /// + public uint MachineId { get; set; } + /// + /// 启动组 + /// + public uint StartupGroup { get; set; } + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Net/ConfigTable/ProcessConfig.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Net/ConfigTable/ProcessConfig.cs.meta new file mode 100644 index 0000000..9e572ae --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Net/ConfigTable/ProcessConfig.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 598e92164bf3143cb9ff0ab8b641571f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Net/ConfigTable/SceneConfig.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Net/ConfigTable/SceneConfig.cs new file mode 100644 index 0000000..9eff1aa --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Net/ConfigTable/SceneConfig.cs @@ -0,0 +1,196 @@ +#if FANTASY_NET +using System.Collections.Concurrent; +using System.Runtime.Serialization; +using Fantasy.DataStructure.Collection; +using Fantasy.DataStructure.Dictionary; +using Fantasy.Helper; +using Fantasy.IdFactory; +using Newtonsoft.Json; +#pragma warning disable CS8603 // Possible null reference return. +#pragma warning disable CS8601 // Possible null reference assignment. + +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. +namespace Fantasy.Platform.Net +{ + /// + /// 存放所有SceneConfigInfo信息 + /// + public sealed class SceneConfigData + { + /// + /// 存放所有SceneConfig信息 + /// + public List List; + [JsonIgnore] + [IgnoreDataMember] + private readonly ConcurrentDictionary _configs = new ConcurrentDictionary(); + [JsonIgnore] + [IgnoreDataMember] + private readonly OneToManyList _sceneConfigBySceneType = new OneToManyList(); + [JsonIgnore] + [IgnoreDataMember] + private readonly OneToManyList _sceneConfigByProcess = new OneToManyList(); + [JsonIgnore] [IgnoreDataMember] + private readonly Dictionary>> _worldSceneTypes = new Dictionary>>(); + /// + /// 获得SceneConfigData的实例 + /// + public static SceneConfigData Instance { get; private set; } + /// + /// 初始化SceneConfig + /// + /// + public static void Initialize(string sceneConfigJson) + { + Instance = sceneConfigJson.Deserialize(); + foreach (var config in Instance.List) + { + config.Initialize(); + Instance._configs.TryAdd(config.Id, config); + Instance._sceneConfigByProcess.Add(config.ProcessConfigId, config); + Instance._sceneConfigBySceneType.Add(config.SceneType, config); + + var configWorldConfigId = (int)config.WorldConfigId; + + if (!Instance._worldSceneTypes.TryGetValue(configWorldConfigId, out var sceneConfigDic)) + { + sceneConfigDic = new Dictionary>(); + Instance._worldSceneTypes.Add(configWorldConfigId, sceneConfigDic); + } + + if (!sceneConfigDic.TryGetValue(config.SceneType, out var sceneConfigList)) + { + sceneConfigList = new List(); + sceneConfigDic.Add(config.SceneType, sceneConfigList); + } + + sceneConfigList.Add(config); + } + } + + /// + /// 根据Id获取SceneConfig + /// + /// + /// + /// + public SceneConfig Get(uint id) + { + if (_configs.TryGetValue(id, out var sceneConfigInfo)) + { + return sceneConfigInfo; + } + + throw new FileNotFoundException($"WorldConfig not find {id} Id"); + } + + /// + /// 根据Id获取SceneConfig + /// + /// + /// + /// + public bool TryGet(uint id, out SceneConfig config) + { + return _configs.TryGetValue(id, out config); + } + + /// + /// 获得SceneConfig + /// + /// + /// + public List GetByProcess(uint serverConfigId) + { + return _sceneConfigByProcess.TryGetValue(serverConfigId, out var list) ? list : new List(); + } + + /// + /// 获得SceneConfig + /// + /// + /// + public List GetSceneBySceneType(int sceneType) + { + return !_sceneConfigBySceneType.TryGetValue(sceneType, out var list) ? new List() : list; + } + + /// + /// 获得SceneConfig + /// + /// + /// + /// + public List GetSceneBySceneType(int world, int sceneType) + { + if (!_worldSceneTypes.TryGetValue(world, out var sceneConfigDic)) + { + return new List(); + } + + if (!sceneConfigDic.TryGetValue(sceneType, out var list)) + { + return new List(); + } + + return list; + } + } + + /// + /// 表示一个Scene配置信息 + /// + public sealed class SceneConfig + { + /// + /// ID + /// + public uint Id { get; set; } + /// + /// 进程Id + /// + public uint ProcessConfigId { get; set; } + /// + /// 世界Id + /// + public uint WorldConfigId { get; set; } + /// + /// Scene运行类型 + /// + public string SceneRuntimeType { get; set; } + /// + /// Scene类型 + /// + public string SceneTypeString { get; set; } + /// + /// 协议类型 + /// + public string NetworkProtocol { get; set; } + /// + /// 外网端口 + /// + public int OuterPort { get; set; } + /// + /// 内网端口 + /// + public int InnerPort { get; set; } + /// + /// Scene类型 + /// + public int SceneType { get; set; } + /// + /// RouteId + /// + [JsonIgnore] + [IgnoreDataMember] + public long RouteId { get; private set; } + /// + /// 初始化方法 + /// + public void Initialize() + { + RouteId = IdFactoryHelper.RuntimeId(0, Id, (byte)WorldConfigId, 0); + } + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Net/ConfigTable/SceneConfig.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Net/ConfigTable/SceneConfig.cs.meta new file mode 100644 index 0000000..b92b264 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Net/ConfigTable/SceneConfig.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4aa38ea5c6e1e4773944e1c2f274098e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Net/ConfigTable/WorldConfig.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Net/ConfigTable/WorldConfig.cs new file mode 100644 index 0000000..9b0ede5 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Net/ConfigTable/WorldConfig.cs @@ -0,0 +1,93 @@ +#if FANTASY_NET +using System.Collections.Concurrent; +using System.Runtime.Serialization; +using Fantasy.Helper; +using Newtonsoft.Json; +#pragma warning disable CS8601 // Possible null reference assignment. + +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. +namespace Fantasy.Platform.Net +{ + /// + /// 存放所有WorldConfigInfo信息 + /// + public sealed class WorldConfigData + { + /// + /// 存放所有WorldConfigInfo信息 + /// + public List List; + [JsonIgnore] + [IgnoreDataMember] + private readonly ConcurrentDictionary _configs = new ConcurrentDictionary(); + /// + /// 获得WorldConfig的实例 + /// + public static WorldConfigData Instance { get; private set; } + /// + /// 初始化WorldConfig + /// + /// + public static void Initialize(string worldConfigJson) + { + Instance = worldConfigJson.Deserialize(); + foreach (var config in Instance.List) + { + Instance._configs.TryAdd(config.Id, config); + } + } + /// + /// 根据Id获取WorldConfig + /// + /// + /// + /// + public WorldConfig Get(uint id) + { + if (_configs.TryGetValue(id, out var worldConfigInfo)) + { + return worldConfigInfo; + } + + throw new FileNotFoundException($"WorldConfig not find {id} Id"); + } + /// + /// 根据Id获取WorldConfig + /// + /// + /// + /// + public bool TryGet(uint id, out WorldConfig config) + { + return _configs.TryGetValue(id, out config); + } + } + + /// + /// 表示一个世界配置信息 + /// + public sealed class WorldConfig + { + /// + /// Id + /// + public uint Id { get; set; } + /// + /// 名称 + /// + public string WorldName { get; set; } + /// + /// 数据库连接字符串 + /// + public string DbConnection { get; set; } + /// + /// 数据库名称 + /// + public string DbName { get; set; } + /// + /// 数据库类型 + /// + public string DbType { get; set; } + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Net/ConfigTable/WorldConfig.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Net/ConfigTable/WorldConfig.cs.meta new file mode 100644 index 0000000..e7ae127 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Net/ConfigTable/WorldConfig.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 117eb806dca2a4a67bbc173d57cf98f2 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Net/Entry.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Net/Entry.cs new file mode 100644 index 0000000..313ad0b --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Net/Entry.cs @@ -0,0 +1,121 @@ +#if FANTASY_NET +using CommandLine; +using Fantasy.Assembly; +using Fantasy.Async; +using Fantasy.Helper; +using Fantasy.IdFactory; +using Fantasy.Network; +using Fantasy.Serialize; +// ReSharper disable FunctionNeverReturns + +namespace Fantasy.Platform.Net; + +/// +/// Fantasy.Net 应用程序入口 +/// +/// 当命令行格式异常时抛出。 +/// 不支持的 ProcessType 类型异常。 +public static class Entry +{ + /// + /// 框架初始化 + /// + /// 注册的Assembly + public static async FTask Initialize(params System.Reflection.Assembly[] assemblies) + { + // 解析命令行参数 + Parser.Default.ParseArguments(Environment.GetCommandLineArgs()) + .WithNotParsed(error => throw new Exception("Command line format error!")) + .WithParsed(option => + { + ProcessDefine.Options = option; + ProcessDefine.InnerNetwork = Enum.Parse(option.InnerNetwork); + }); + // 初始化Log系统 + Log.Initialize(); + // 检查启动参数,后期可能有机器人等不同的启动参数 + switch (ProcessDefine.Options.ProcessType) + { + case "Game": + { + break; + } + default: + { + throw new NotSupportedException($"ProcessType is {ProcessDefine.Options.ProcessType} Unrecognized!"); + } + } + // 初始化程序集管理系统 + await AssemblySystem.InnerInitialize(assemblies); + // 初始化序列化 + SerializerManager.Initialize(); + // 精度处理(只针对Windows下有作用、其他系统没有这个问题、一般也不会用Windows来做服务器的) + WinPeriod.Initialize(); + } + + /// + /// 启动Fantasy.Net + /// + public static async FTask Start() + { + // 启动Process + StartProcess().Coroutine(); + await FTask.CompletedTask; + while (true) + { + ThreadScheduler.Update(); + Thread.Sleep(1); + } + } + + /// + /// 初始化并且启动框架 + /// + /// + public static async FTask Start(params System.Reflection.Assembly[] assemblies) + { + await Initialize(assemblies); + await Start(); + } + + private static async FTask StartProcess() + { + if (ProcessDefine.Options.StartupGroup != 0) + { + foreach (var processConfig in ProcessConfigData.Instance.ForEachByStartupGroup((uint)ProcessDefine.Options.StartupGroup)) + { + await Process.Create(processConfig.Id); + } + + return; + } + + switch (ProcessDefine.Options.Mode) + { + case "Develop": + { + foreach (var processConfig in ProcessConfigData.Instance.List) + { + await Process.Create(processConfig.Id); + } + + return; + } + case "Release": + { + await Process.Create(ProcessDefine.Options.ProcessId); + return; + } + } + } + + /// + /// 关闭 Fantasy + /// + public static void Close() + { + AssemblySystem.Dispose(); + SerializerManager.Dispose(); + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Net/Entry.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Net/Entry.cs.meta new file mode 100644 index 0000000..6006ac4 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Net/Entry.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7090806e21ca24bf0821db96a4e47b9f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Net/Process.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Net/Process.cs new file mode 100644 index 0000000..361ca74 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Net/Process.cs @@ -0,0 +1,150 @@ +#if FANTASY_NET +using System.Collections.Concurrent; +using Fantasy.Async; +using Fantasy.IdFactory; + +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. +#pragma warning disable CS8601 // Possible null reference assignment. +namespace Fantasy.Platform.Net; + +/// +/// 一个进程的实例 +/// +public sealed class Process : IDisposable +{ + /// + /// 当前进程的Id + /// + public readonly uint Id; + /// + /// 进程关联的MachineId + /// + public readonly uint MachineId; + private readonly ConcurrentDictionary _processScenes = new ConcurrentDictionary(); + private static readonly ConcurrentDictionary Scenes = new ConcurrentDictionary(); + private Process() {} + private Process(uint id, uint machineId) + { + Id = id; + MachineId = machineId; + } + + internal bool IsProcess(ref long routeId) + { + var sceneId = IdFactoryHelper.RuntimeIdTool.GetSceneId(ref routeId); + return _processScenes.ContainsKey(sceneId); + } + + internal bool IsProcess(ref uint sceneId) + { + return _processScenes.ContainsKey(sceneId); + } + + internal void AddSceneToProcess(Scene scene) + { + _processScenes.TryAdd(scene.SceneConfigId, scene); + } + + internal void RemoveSceneToProcess(Scene scene, bool isDispose) + { + _processScenes.Remove(scene.SceneConfigId, out _); + + if (isDispose) + { + scene.Dispose(); + } + } + + internal bool TryGetSceneToProcess(long routeId, out Scene scene) + { + var sceneId = IdFactoryHelper.RuntimeIdTool.GetSceneId(ref routeId); + return _processScenes.TryGetValue(sceneId, out scene); + } + + internal bool TryGetSceneToProcess(uint sceneId, out Scene scene) + { + return _processScenes.TryGetValue(sceneId, out scene); + } + /// + /// 销毁方法 + /// + public void Dispose() + { + if (_processScenes.IsEmpty) + { + return; + } + + var sceneQueue = new Queue(); + + foreach (var (_, scene) in _processScenes) + { + sceneQueue.Enqueue(scene); + } + + while (sceneQueue.TryDequeue(out var removeScene)) + { + removeScene.Dispose(); + } + + _processScenes.Clear(); + } + + internal static async FTask Create(uint processConfigId) + { + if (!ProcessConfigData.Instance.TryGet(processConfigId, out var processConfig)) + { + Log.Error($"not found processConfig by Id:{processConfigId}"); + return null; + } + + if (!MachineConfigData.Instance.TryGet(processConfig.MachineId, out var machineConfig)) + { + Log.Error($"not found machineConfig by Id:{processConfig.MachineId}"); + return null; + } + + var process = new Process(processConfigId, processConfig.MachineId); + var sceneConfigs = SceneConfigData.Instance.GetByProcess(processConfigId); + + foreach (var sceneConfig in sceneConfigs) + { + await Scene.Create(process, machineConfig, sceneConfig); + } + + Log.Info($"Process:{processConfigId} Startup Complete SceneCount:{sceneConfigs.Count}"); + return process; + } + + internal bool IsInAppliaction(ref uint sceneId) + { + return _processScenes.ContainsKey(sceneId); + } + + internal static void AddScene(Scene scene) + { + Scenes.TryAdd(scene.SceneConfigId, scene); + } + + internal static void RemoveScene(Scene scene, bool isDispose) + { + Scenes.Remove(scene.SceneConfigId, out _); + + if (isDispose) + { + scene.Dispose(); + } + } + + internal static bool TryGetScene(long routeId, out Scene scene) + { + var sceneId = IdFactoryHelper.RuntimeIdTool.GetSceneId(ref routeId); + return Scenes.TryGetValue(sceneId, out scene); + } + + internal static bool TryGetScene(uint sceneId, out Scene scene) + { + return Scenes.TryGetValue(sceneId, out scene); + } +} +#endif diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Net/Process.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Net/Process.cs.meta new file mode 100644 index 0000000..34b8913 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Net/Process.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0670c483737fa4507b7c48e609e91ed0 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Net/ProcessDefine.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Net/ProcessDefine.cs new file mode 100644 index 0000000..2bcc4e0 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Net/ProcessDefine.cs @@ -0,0 +1,99 @@ +#if FANTASY_NET +using CommandLine; +using Fantasy.Network; + +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. +namespace Fantasy.Platform.Net; + +/// +/// Process运行模式 +/// +public enum ProcessMode +{ + /// + /// 默认 + /// + None =0, + /// + /// 开发模式 + /// + Develop = 1, + /// + /// 发布模式 + /// + Release = 2 +} + +internal sealed class CommandLineOptions +{ + /// + /// 用于启动指定的进程,该进程的 ID 与 ProcessConfig 的 ID 相关联。此参数只能传递单个 ID,不支持传递多个 ID。 + /// + [Option("pid", Required = false, Default = (uint)0, HelpText = "Enter an ProcessIdId such as 1")] + public uint ProcessId { get; set; } + /// + /// Process类型,获取或设置应用程序的类型。 + /// Game - 游戏服务器Process + /// Robot - 机器人(暂未支持该功能) + /// + [Option('a', "ProcessType", Required = false, Default = "Game", HelpText = "Game")] + public string ProcessType { get; set; } + /// + /// 服务器运行模式,获取或设置服务器的运行模式。 + /// Develop - 开发模式(启动Process配置表中的所有Process) + /// Release - 发布模式(根据ProcessId启动Process) + /// + [Option('m', "Mode", Required = true, Default = "Release", HelpText = "Develop:启动Process配置表中的所有Process,\nRelease:根据ProcessId启动Process")] + public string Mode { get; set; } + /// + /// 服务器内部网络协议 + /// TCP - 服务器内部之间通讯使用TCP协议 + /// KCP - 服务器内部之间通讯使用KCP协议 + /// WebSocket - 服务器内部之间通讯使用WebSocket协议(不推荐、TCP或KCP) + /// + [Option('n', "InnerNetwork", Required = false, Default = "TCP", HelpText = "TCP、KCP、WebSocket")] + public string InnerNetwork { get; set; } + /// + /// 会话空闲检查超时时间。 + /// + [Option('t', "SessionIdleCheckerTimeout", Required = false, Default = 8000, HelpText = "Session idle check timeout")] + public int SessionIdleCheckerTimeout { get; set; } + /// + /// 会话空闲检查间隔。 + /// + [Option('i', "SessionIdleCheckerInterval", Required = false, Default = 5000, HelpText = "Session idle check interval")] + public int SessionIdleCheckerInterval { get; set; } + /// + /// 启动组。 + /// + [Option('g', "StartupGroup", Required = false, Default = 0, HelpText = "Used to start a group of Process")] + public int StartupGroup { get; set; } +} + +/// +/// AppDefine +/// +internal static class ProcessDefine +{ + /// + /// 命令行选项 + /// + public static CommandLineOptions Options; + /// + /// App程序Id + /// + public static uint ProcessId => Options.ProcessId; + /// + /// 会话空闲检查超时时间。 + /// + public static int SessionIdleCheckerTimeout => Options.SessionIdleCheckerTimeout; + /// + /// 会话空闲检查间隔。 + /// + public static int SessionIdleCheckerInterval => Options.SessionIdleCheckerInterval; + /// + /// 内部网络通讯协议类型 + /// + public static NetworkProtocolType InnerNetwork; +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Net/ProcessDefine.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Net/ProcessDefine.cs.meta new file mode 100644 index 0000000..519edca --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Net/ProcessDefine.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4277db03538f5471dacacbe0e8e24343 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Net/ThreadSynchronizationContext.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Net/ThreadSynchronizationContext.cs new file mode 100644 index 0000000..bb2948a --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Net/ThreadSynchronizationContext.cs @@ -0,0 +1,52 @@ +#if FANTASY_NET +using System.Collections.Concurrent; +#pragma warning disable CS8765 +#pragma warning disable CS8601 +#pragma warning disable CS8618 + +namespace Fantasy; + +/// +/// 线程的同步上下文 +/// +public sealed class ThreadSynchronizationContext : SynchronizationContext +{ + private readonly ConcurrentQueue _queue = new(); + /// + /// 执行当前上下文投递过的逻辑 + /// + public void Update() + { + while (_queue.TryDequeue(out var actionHandler)) + { + try + { + actionHandler(); + } + catch (Exception e) + { + Log.Error(e); + } + } + } + + /// + /// 投递一个逻辑到当前上下文 + /// + /// + /// + public override void Post(SendOrPostCallback callback, object state) + { + Post(() => callback(state)); + } + + /// + /// 投递一个逻辑到当前上下文 + /// + /// + public void Post(Action action) + { + _queue.Enqueue(action); + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Net/ThreadSynchronizationContext.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Net/ThreadSynchronizationContext.cs.meta new file mode 100644 index 0000000..7daf012 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Net/ThreadSynchronizationContext.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: cea36857aef5447079bd1baa46ab8e69 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Unity.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Unity.meta new file mode 100644 index 0000000..ae0c20d --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Unity.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 8b2867f300822489981d595e5b3ca9fc +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Unity/AppDefine.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Unity/AppDefine.cs new file mode 100644 index 0000000..d9d85ae --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Unity/AppDefine.cs @@ -0,0 +1,19 @@ +#if FANTASY_UNITY +namespace Fantasy.Platform.Unity +{ + public static class AppDefine + { + public static string RemoteUpdatePath; + public static bool EditorModel = true; + public const string VersionName = "version.bytes"; + public const string VersionMD5Name = "version.md5"; + public const string AssetBundleManifestName = "Fantasy"; + public static bool IsEditor => UnityEngine.Application.isEditor && EditorModel; + public static string AssetBundleSaveDirectory => "Assets/AssetBundles"; + public static string LocalAssetBundlePath => UnityEngine.Application.streamingAssetsPath; + public static string RemoteAssetBundlePath => UnityEngine.Application.persistentDataPath; + public static string PersistentDataVersion => $"{UnityEngine.Application.persistentDataPath}/{VersionName}"; + public static string StreamingAssetsVersion => $"{UnityEngine.Application.streamingAssetsPath}/{VersionName}"; + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Unity/AppDefine.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Unity/AppDefine.cs.meta new file mode 100644 index 0000000..5a0ff14 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Unity/AppDefine.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 83a8f65932d754f82818737683b6066b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Unity/Attributes.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Unity/Attributes.meta new file mode 100644 index 0000000..17b4bbd --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Unity/Attributes.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 59760e44e339e470d848463650cd929c +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Unity/Attributes/BsonDefaultValueAttribute.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Unity/Attributes/BsonDefaultValueAttribute.cs new file mode 100644 index 0000000..49914ec --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Unity/Attributes/BsonDefaultValueAttribute.cs @@ -0,0 +1,11 @@ +#if FANTASY_UNITY +using System; +namespace MongoDB.Bson.Serialization.Attributes +{ + [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)] + public class BsonDefaultValueAttribute : Attribute + { + public BsonDefaultValueAttribute(object defaultValue) { } + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Unity/Attributes/BsonDefaultValueAttribute.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Unity/Attributes/BsonDefaultValueAttribute.cs.meta new file mode 100644 index 0000000..2d6be4d --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Unity/Attributes/BsonDefaultValueAttribute.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0667920f73ddb4da4b61aaf8a6704520 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Unity/Attributes/BsonElementAttribute.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Unity/Attributes/BsonElementAttribute.cs new file mode 100644 index 0000000..3892727 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Unity/Attributes/BsonElementAttribute.cs @@ -0,0 +1,13 @@ +#if FANTASY_UNITY +using System; +namespace MongoDB.Bson.Serialization.Attributes +{ + [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)] + public class BsonElementAttribute : Attribute + { + public BsonElementAttribute() { } + + public BsonElementAttribute(string elementName) { } + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Unity/Attributes/BsonElementAttribute.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Unity/Attributes/BsonElementAttribute.cs.meta new file mode 100644 index 0000000..4de7566 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Unity/Attributes/BsonElementAttribute.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1bd8935bc9b394975ba1c0eeab13f817 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Unity/Attributes/BsonIdAttribute.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Unity/Attributes/BsonIdAttribute.cs new file mode 100644 index 0000000..48274d0 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Unity/Attributes/BsonIdAttribute.cs @@ -0,0 +1,11 @@ +#if FANTASY_UNITY +using System; +namespace MongoDB.Bson.Serialization.Attributes +{ + [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)] + public class BsonIdAttribute : Attribute + { + + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Unity/Attributes/BsonIdAttribute.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Unity/Attributes/BsonIdAttribute.cs.meta new file mode 100644 index 0000000..b014fb9 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Unity/Attributes/BsonIdAttribute.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a024b9c70f7be4dfd8d94e184d729f63 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Unity/Attributes/BsonIgnoreAttribute.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Unity/Attributes/BsonIgnoreAttribute.cs new file mode 100644 index 0000000..23e55c8 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Unity/Attributes/BsonIgnoreAttribute.cs @@ -0,0 +1,11 @@ +#if FANTASY_UNITY +using System; +namespace MongoDB.Bson.Serialization.Attributes +{ + [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)] + public class BsonIgnoreAttribute : Attribute + { + + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Unity/Attributes/BsonIgnoreAttribute.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Unity/Attributes/BsonIgnoreAttribute.cs.meta new file mode 100644 index 0000000..e2cc58c --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Unity/Attributes/BsonIgnoreAttribute.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e44cd65ae1ffc4545a329acf15eaf24b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Unity/Attributes/BsonIgnoreIfDefaultAttribute.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Unity/Attributes/BsonIgnoreIfDefaultAttribute.cs new file mode 100644 index 0000000..82dddde --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Unity/Attributes/BsonIgnoreIfDefaultAttribute.cs @@ -0,0 +1,13 @@ +#if FANTASY_UNITY +using System; +namespace MongoDB.Bson.Serialization.Attributes +{ + [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)] + public class BsonIgnoreIfDefaultAttribute : Attribute + { + public BsonIgnoreIfDefaultAttribute() { } + + public BsonIgnoreIfDefaultAttribute(bool value) { } + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Unity/Attributes/BsonIgnoreIfDefaultAttribute.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Unity/Attributes/BsonIgnoreIfDefaultAttribute.cs.meta new file mode 100644 index 0000000..e8488ad --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Unity/Attributes/BsonIgnoreIfDefaultAttribute.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 28808e0d128ab46e2b98ad3285c6fd3d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Unity/Attributes/BsonIgnoreIfNullAttribute.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Unity/Attributes/BsonIgnoreIfNullAttribute.cs new file mode 100644 index 0000000..f330a8b --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Unity/Attributes/BsonIgnoreIfNullAttribute.cs @@ -0,0 +1,11 @@ +#if FANTASY_UNITY +using System; +namespace MongoDB.Bson.Serialization.Attributes +{ + [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)] + public class BsonIgnoreIfNullAttribute : Attribute + { + + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Unity/Attributes/BsonIgnoreIfNullAttribute.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Unity/Attributes/BsonIgnoreIfNullAttribute.cs.meta new file mode 100644 index 0000000..e70b6ba --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Unity/Attributes/BsonIgnoreIfNullAttribute.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d6e7c0b5e3e9c4119aa3eddbe2bad2e0 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Unity/Entry.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Unity/Entry.cs new file mode 100644 index 0000000..fd05f75 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Unity/Entry.cs @@ -0,0 +1,101 @@ +#if FANTASY_UNITY +using System.Linq; +using Fantasy.Assembly; +using Fantasy.Async; +using Fantasy.Serialize; +using UnityEngine; + +#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. +#pragma warning disable CS8603 // Possible null reference return. +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. + +namespace Fantasy.Platform.Unity +{ + public sealed class FantasyObject : MonoBehaviour + { + public static GameObject FantasyObjectGameObject { get; private set; } + // 这个方法将在游戏启动时自动调用 + [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)] + static void OnRuntimeMethodLoad() + { + FantasyObjectGameObject = new GameObject("Fantasy.Net"); + DontDestroyOnLoad(FantasyObjectGameObject); + } + private void OnApplicationQuit() + { + Destroy(FantasyObjectGameObject); + } + } + + public struct OnSceneCreate + { + public Scene Scene; + public object Arg; + } + + public class Entry : MonoBehaviour + { + private static bool _isInit; + public static Scene Scene { get; private set; } + + /// + /// 初始化框架 + /// + /// + public static async FTask Initialize(params System.Reflection.Assembly[] assemblies) + { + if (_isInit) + { + Log.Error("Fantasy has already been initialized and does not need to be initialized again!"); + return; + } + Log.Register(new UnityLog()); + await AssemblySystem.InnerInitialize(assemblies); + // 初始化序列化 + SerializerManager.Initialize(); +#if FANTASY_WEBGL + ThreadSynchronizationContext.Initialize(); +#endif + _isInit = true; + FantasyObject.FantasyObjectGameObject.AddComponent(); + Log.Debug("Fantasy Initialize Complete!"); + } + + /// + /// 在Entry中创建一个Scene,如果Scene已经被创建过,将先销毁Scene再创建。 + /// + /// + /// + /// + public static async FTask CreateScene(object arg = null, string sceneRuntimeType = SceneRuntimeType.MainThread) + { + Scene?.Dispose(); + Scene = await Scene.Create(sceneRuntimeType); + await Scene.EventComponent.PublishAsync(new OnSceneCreate() + { + Arg = arg, + Scene = Scene + }); + return Scene; + } + + private void Update() + { + ThreadScheduler.Update(); + } + + private void OnDestroy() + { + AssemblySystem.Dispose(); + SerializerManager.Dispose(); + if (Scene != null) + { + Scene?.Dispose(); + Scene = null; + } + _isInit = false; + } + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Unity/Entry.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Unity/Entry.cs.meta new file mode 100644 index 0000000..e6847bc --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Unity/Entry.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 5933a48a517474c518cd76d492bb0660 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Unity/Temp.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Unity/Temp.cs new file mode 100644 index 0000000..399488f --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Unity/Temp.cs @@ -0,0 +1,108 @@ +// using System.Reflection; +// using Fantasy.Assembly; +// using Fantasy.Async; +// // using UnityEngine; +// #pragma warning disable CS0649 // Field is never assigned to, and will always have its default value +// #pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. +// #pragma warning disable CS8603 // Possible null reference return. +// #pragma warning disable CS1591 // Missing XML comment for publicly visible type or member +// #pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. +// +// namespace Fantasy.Platform.Unity +// { +// public class MonoBehaviour +// { +// +// } +// +// public class GameObject +// { +// public GameObject(string name) +// { +// +// } +// } +// +// internal enum RuntimeInitializeLoadType +// { +// BeforeSceneLoad = 1, +// } +// +// internal class RuntimeInitializeOnLoadMethodAttribute : Attribute +// { +// public RuntimeInitializeLoadType RuntimeInitializeLoadType; +// +// public RuntimeInitializeOnLoadMethodAttribute(RuntimeInitializeLoadType loadType) +// { +// +// } +// } +// +// public sealed class FantasyObject : MonoBehaviour +// { +// public static GameObject FantasyObjectGameObject { get; private set; } +// // 这个方法将在游戏启动时自动调用 +// [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)] +// static void OnRuntimeMethodLoad() +// { +// FantasyObjectGameObject = new GameObject("Fantasy.Net"); +// // DontDestroyOnLoad(FantasyObjectGameObject); +// } +// private void OnApplicationQuit() +// { +// // Destroy(FantasyObjectGameObject); +// } +// } +// +// public struct OnFantasyInit +// { +// public Scene Scene; +// } +// +// public class Entry : MonoBehaviour +// { +// private static bool _isInit; +// public static Scene Scene { get; private set; } +// /// +// /// 初始化框架 +// /// +// public static async FTask Initialize(params System.Reflection.Assembly[] assemblies) +// { +// Scene?.Dispose(); +// // 初始化程序集管理系统 +// AssemblySystem.Initialize(assemblies); +// if (!_isInit) +// { +// #if FANTASY_WEBGL +// ThreadSynchronizationContext.Initialize(); +// #endif +// _isInit = true; +// // FantasyObject.FantasyObjectGameObject.AddComponent(); +// } +// // Scene = await Scene.Create(SceneRuntimeType.MainThread); +// // await Scene.EventComponent.PublishAsync(new OnFantasyInit() +// // { +// // Scene = Scene +// // }); +// // return Scene; +// await FTask.CompletedTask; +// return null; +// } +// +// private void Update() +// { +// ThreadScheduler.Update(); +// } +// +// private void OnDestroy() +// { +// AssemblySystem.Dispose(); +// if (Scene != null) +// { +// Scene?.Dispose(); +// Scene = null; +// } +// _isInit = false; +// } +// } +// } diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Unity/Temp.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Unity/Temp.cs.meta new file mode 100644 index 0000000..16ecc76 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Unity/Temp.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 907556dab37dc4fff866197541010500 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Unity/ThreadSynchronizationContext.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Unity/ThreadSynchronizationContext.cs new file mode 100644 index 0000000..44b165a --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Unity/ThreadSynchronizationContext.cs @@ -0,0 +1,104 @@ +#if FANTASY_UNITY && !FANTASY_WEBGL +#pragma warning disable CS8765 +#pragma warning disable CS8601 +#pragma warning disable CS8618 +using System; +using System.Collections.Concurrent; +using System.Threading; + +namespace Fantasy +{ + public sealed class ThreadSynchronizationContext : SynchronizationContext + { + private Action _actionHandler; + private readonly ConcurrentQueue _queue = new(); + + public void Update() + { + while (_queue.TryDequeue(out _actionHandler)) + { + try + { + _actionHandler(); + } + catch (Exception e) + { + Log.Error(e); + } + } + } + + public override void Post(SendOrPostCallback callback, object state) + { + Post(() => callback(state)); + } + + public void Post(Action action) + { + _queue.Enqueue(action); + } + } +} +#endif +#if FANTASY_UNITY && FANTASY_WEBGL +using System; +using System.Collections.Generic; +using System.Threading; +using Fantasy; +using UnityEngine; +using Object = UnityEngine.Object; + +public class WebGLSynchronizationContextUpdater : MonoBehaviour +{ + private ThreadSynchronizationContext _context; + + public void Initialize(ThreadSynchronizationContext context) + { + _context = context; + } + + void Update() + { + _context.Update(); + } +} +public sealed class ThreadSynchronizationContext : SynchronizationContext +{ + private Action _actionHandler; + private readonly Queue _queue = new(); + + public static void Initialize() + { + var context = new ThreadSynchronizationContext(); + SetSynchronizationContext(context); + var go = new GameObject("WebGLSynchronizationContextUpdater"); + go.AddComponent().Initialize(context); + Object.DontDestroyOnLoad(go); + } + + public void Update() + { + while (_queue.TryDequeue(out _actionHandler)) + { + try + { + _actionHandler(); + } + catch (Exception e) + { + Log.Error(e); + } + } + } + + public override void Post(SendOrPostCallback callback, object state) + { + Post(() => callback(state)); + } + + public void Post(Action action) + { + _queue.Enqueue(action); + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Unity/ThreadSynchronizationContext.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Unity/ThreadSynchronizationContext.cs.meta new file mode 100644 index 0000000..342fd87 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Platform/Unity/ThreadSynchronizationContext.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e96cc25874c304ccd829d3e15f992501 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Pool.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Pool.meta new file mode 100644 index 0000000..7dcce41 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Pool.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 46bce4db32ba4430abfb962eb6636d2e +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Pool/Concurrent.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Pool/Concurrent.meta new file mode 100644 index 0000000..ff1cc58 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Pool/Concurrent.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 40200134f8074457ab6709111b2d3046 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Pool/Concurrent/MultiThreadPool.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Pool/Concurrent/MultiThreadPool.cs new file mode 100644 index 0000000..4c946d1 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Pool/Concurrent/MultiThreadPool.cs @@ -0,0 +1,37 @@ +#if !FANTASY_WEBGL +using System; +using System.Collections.Concurrent; +using System.Runtime.CompilerServices; +#pragma warning disable CS8603 // Possible null reference return. + +namespace Fantasy.Pool +{ + /// + /// 线程安全的静态通用对象池。 + /// + internal static class MultiThreadPool + { + private static readonly ConcurrentDictionary ObjectPools = new ConcurrentDictionary(); + + public static T Rent() where T : IPool, new() + { + return ObjectPools.GetOrAdd(typeof(T), t => new MultiThreadPoolQueue(2000, () => new T())).Rent(); + } + + public static IPool Rent(Type type) + { + return ObjectPools.GetOrAdd(type, t => new MultiThreadPoolQueue(2000, CreateInstance.CreateIPool(type))).Rent(); + } + + public static void Return(T obj) where T : IPool, new() + { + if (!obj.IsPool()) + { + return; + } + + ObjectPools.GetOrAdd(typeof(T), t => new MultiThreadPoolQueue(2000, () => new T())).Return(obj); + } + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Pool/Concurrent/MultiThreadPool.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Pool/Concurrent/MultiThreadPool.cs.meta new file mode 100644 index 0000000..e0ae74a --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Pool/Concurrent/MultiThreadPool.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f4295246cc4ad4e9ab1c09acbc4bbbc1 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Pool/Concurrent/MultiThreadPoolQueue.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Pool/Concurrent/MultiThreadPoolQueue.cs new file mode 100644 index 0000000..df15a1c --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Pool/Concurrent/MultiThreadPoolQueue.cs @@ -0,0 +1,76 @@ +#if !FANTASY_WEBGL +using System; +using System.Collections.Concurrent; +using System.Threading; +// ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract +#pragma warning disable CS8601 // Possible null reference assignment. +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. +#pragma warning disable CS8603 // Possible null reference return. + +namespace Fantasy.Pool +{ + /// + /// 线程安全的对象池。 + /// + internal class MultiThreadPoolQueue + { + private int _poolCount; + private readonly int _maxCapacity; + private readonly Func _createInstance; + private readonly ConcurrentQueue _poolQueue = new ConcurrentQueue(); + private MultiThreadPoolQueue() { } + + public MultiThreadPoolQueue(int maxCapacity, Func createInstance) + { + _maxCapacity = maxCapacity; + _createInstance = createInstance; + } + + public T Rent() where T : IPool, new() + { + if (!_poolQueue.TryDequeue(out var t)) + { + var pool = new T(); + pool.SetIsPool(true); + return pool; + } + + t.SetIsPool(true); + Interlocked.Decrement(ref _poolCount); + return (T)t; + } + + public IPool Rent() + { + if (!_poolQueue.TryDequeue(out var t)) + { + var instance = _createInstance(); + instance.SetIsPool(true); + return instance; + } + + t.SetIsPool(true); + Interlocked.Decrement(ref _poolCount); + return t; + } + + public void Return(IPool obj) + { + if (!obj.IsPool()) + { + return; + } + + obj.SetIsPool(false); + + if (Interlocked.Increment(ref _poolCount) <= _maxCapacity) + { + _poolQueue.Enqueue(obj); + return; + } + + Interlocked.Decrement(ref _poolCount); + } + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Pool/Concurrent/MultiThreadPoolQueue.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Pool/Concurrent/MultiThreadPoolQueue.cs.meta new file mode 100644 index 0000000..d9a3267 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Pool/Concurrent/MultiThreadPoolQueue.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 5520348a236554f5380103f259f87dfd +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Pool/Interface.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Pool/Interface.meta new file mode 100644 index 0000000..07e6c92 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Pool/Interface.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e11c514da50264cc986ac5c6a85ea450 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Pool/Interface/IPool.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Pool/Interface/IPool.cs new file mode 100644 index 0000000..1775f28 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Pool/Interface/IPool.cs @@ -0,0 +1,18 @@ +namespace Fantasy.Pool +{ + /// + /// 实现了这个接口代表支持对象池 + /// + public interface IPool + { + /// + /// 是否从池里创建的 + /// + bool IsPool(); + /// + /// 设置是否从池里创建的 + /// + /// + void SetIsPool(bool isPool); + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Pool/Interface/IPool.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Pool/Interface/IPool.cs.meta new file mode 100644 index 0000000..44c50ff --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Pool/Interface/IPool.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 91cd6661b42dc41cfaad00203a86ce3c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Pool/Normal.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Pool/Normal.meta new file mode 100644 index 0000000..08b4f53 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Pool/Normal.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 554c5e3bc9c1844f99046f84eb4c2de2 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Pool/Normal/Pool.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Pool/Normal/Pool.cs new file mode 100644 index 0000000..88006e1 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Pool/Normal/Pool.cs @@ -0,0 +1,77 @@ +using System; +using System.Collections.Generic; +// ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract +// ReSharper disable CheckNamespace + +namespace Fantasy.Pool +{ + /// + /// 静态的对象池系统,不支持多线程。 + /// + /// + public static class Pool where T : IPool, new() + { + private static readonly Queue PoolQueue = new Queue(); + /// + /// 池子里可用的数量 + /// + public static int Count => PoolQueue.Count; + + /// + /// 租借 + /// + /// + public static T Rent() + { + return PoolQueue.Count == 0 ? new T() : PoolQueue.Dequeue(); + } + + /// + /// 租借 + /// + /// 如果池子里没有,会先执行这个委托。 + /// + public static T Rent(Func generator) + { + return PoolQueue.Count == 0 ? generator() : PoolQueue.Dequeue(); + } + + /// + /// 返还 + /// + /// + public static void Return(T t) + { + if (t == null) + { + return; + } + + PoolQueue.Enqueue(t); + } + + /// + /// 返还 + /// + /// 返还的东西 + /// 返还后执行的委托 + public static void Return(T t, Action reset) + { + if (t == null) + { + return; + } + + reset(t); + PoolQueue.Enqueue(t); + } + + /// + /// 清空池子 + /// + public static void Clear() + { + PoolQueue.Clear(); + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Pool/Normal/Pool.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Pool/Normal/Pool.cs.meta new file mode 100644 index 0000000..ef447aa --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Pool/Normal/Pool.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6bf3e1dd4e39a4ae4ababd3770ed431d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Pool/Normal/PoolCore.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Pool/Normal/PoolCore.cs new file mode 100644 index 0000000..94144f1 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Pool/Normal/PoolCore.cs @@ -0,0 +1,203 @@ +using System; +using System.Collections.Generic; +using System.Runtime.CompilerServices; +using Fantasy.DataStructure.Collection; + +// ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract +#pragma warning disable CS8600 // Converting null literal or possible null value to non-nullable type. +#pragma warning disable CS8603 // Possible null reference return. + +namespace Fantasy.Pool +{ + /// + /// 对象池抽象接口,用于创建和管理可重复使用的对象实例。 + /// + public abstract class PoolCore : IDisposable + { + private int _poolCount; + private readonly int _maxCapacity; + /// + /// 池子里可用的数量 + /// + public int Count => _poolQueue.Count; + private readonly OneToManyQueue _poolQueue = new OneToManyQueue(); + private readonly Dictionary> _typeCheckCache = new Dictionary>(); + + /// + /// 构造函数 + /// + /// 初始的容量 + protected PoolCore(int maxCapacity) + { + _maxCapacity = maxCapacity; + } + + /// + /// 租借 + /// + /// + /// + public T Rent() where T : IPool, new() + { + if (!_poolQueue.TryDequeue(typeof(T), out var queue)) + { + queue = new T(); + } + + queue.SetIsPool(true); + _poolCount--; + return (T)queue; + } + + /// + /// 租借 + /// + /// 租借的类型 + /// + /// + public IPool Rent(Type type) + { + if (!_poolQueue.TryDequeue(type, out var queue)) + { + if (!_typeCheckCache.TryGetValue(type, out var createInstance)) + { + if (!typeof(IPool).IsAssignableFrom(type)) + { + throw new NotSupportedException($"{this.GetType().FullName} Type:{type.FullName} must inherit from IPool"); + } + else + { + createInstance = CreateInstance.CreateIPool(type); + _typeCheckCache[type] = createInstance; + } + } + + var instance = createInstance(); + instance.SetIsPool(true); + return instance; + } + + queue.SetIsPool(true); + _poolCount--; + return queue; + } + + /// + /// 返还 + /// + /// + /// + public void Return(Type type, IPool obj) + { + if (obj == null) + { + return; + } + + if (!obj.IsPool()) + { + return; + } + + if (_poolCount >= _maxCapacity) + { + return; + } + + _poolCount++; + obj.SetIsPool(false); + _poolQueue.Enqueue(type, obj); + } + + /// + /// 销毁方法 + /// + public virtual void Dispose() + { + _poolCount = 0; + _poolQueue.Clear(); + _typeCheckCache.Clear(); + } + } + + /// + /// 泛型对象池核心类,用于创建和管理可重复使用的对象实例。 + /// + /// 要池化的对象类型 + public abstract class PoolCore where T : IPool, new() + { + private int _poolCount; + private readonly int _maxCapacity; + private readonly Queue _poolQueue = new Queue(); + /// + /// 池子里可用的数量 + /// + public int Count => _poolQueue.Count; + + /// + /// 构造函数 + /// + /// 初始的容量 + protected PoolCore(int maxCapacity) + { + _maxCapacity = maxCapacity; + } + + /// + /// 租借 + /// + /// + public virtual T Rent() + { + T dequeue; + + if (_poolQueue.Count == 0) + { + dequeue = new T(); + } + else + { + _poolCount--; + dequeue = _poolQueue.Dequeue(); + } + + dequeue.SetIsPool(true); + return dequeue; + } + + /// + /// 返还 + /// + /// + public virtual void Return(T item) + { + if (item == null) + { + return; + } + + if (!item.IsPool()) + { + return; + } + + if (_poolCount >= _maxCapacity) + { + return; + } + + _poolCount++; + item.SetIsPool(false); + _poolQueue.Enqueue(item); + } + + /// + /// 销毁方法 + /// + public virtual void Dispose() + { + _poolCount = 0; + _poolQueue.Clear(); + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Pool/Normal/PoolCore.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Pool/Normal/PoolCore.cs.meta new file mode 100644 index 0000000..5ed7e6a --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Pool/Normal/PoolCore.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 12336238185b447c1af2fbd1eb1f2b7f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Pool/Normal/PoolWithDisposable.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Pool/Normal/PoolWithDisposable.cs new file mode 100644 index 0000000..3f97f1c --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Pool/Normal/PoolWithDisposable.cs @@ -0,0 +1,140 @@ +using System; +using System.Collections.Generic; +// ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract + +namespace Fantasy.Pool +{ + /// + /// 静态通用对象池,用于存储实现了 IDisposable 接口的对象。 + /// + /// 要存储在对象池中的对象类型,必须实现 IDisposable 接口。 + public abstract class PoolWithDisposable : IDisposable where T : IPool, IDisposable, new() + { + private int _poolCount; + private readonly int _maxCapacity; + private readonly Queue _poolQueue = new Queue(); + /// + /// 池子里可用的数量 + /// + public int Count => _poolQueue.Count; + + /// + /// 构造函数 + /// + /// 初始的容量 + protected PoolWithDisposable(int maxCapacity) + { + _maxCapacity = maxCapacity; + } + + /// + /// 租借 + /// + /// + public T Rent() + { + T dequeue; + if (_poolQueue.Count == 0) + { + dequeue = new T(); + } + else + { + _poolCount--; + dequeue = _poolQueue.Dequeue(); + } + + dequeue.SetIsPool(true); + return dequeue; + } + + /// + /// 租借 + /// + /// + /// + public T Rent(Func generator) + { + T dequeue; + + if (_poolQueue.Count == 0) + { + dequeue = generator(); + } + else + { + _poolCount--; + dequeue = _poolQueue.Dequeue(); + } + + dequeue.SetIsPool(true); + return dequeue; + } + + /// + /// 返还 + /// + /// + public void Return(T t) + { + if (t == null) + { + return; + } + + if (!t.IsPool()) + { + return; + } + + if (_poolCount >= _maxCapacity) + { + return; + } + + _poolCount++; + t.SetIsPool(true); + _poolQueue.Enqueue(t); + t.Dispose(); + } + + /// + /// 返还 + /// + /// + /// + public void Return(T t, Action reset) + { + if (t == null) + { + return; + } + + if (!t.IsPool()) + { + reset(t); + return; + } + + if (_poolCount >= _maxCapacity) + { + return; + } + + reset(t); + _poolCount++; + t.SetIsPool(false); + _poolQueue.Enqueue(t); + t.Dispose(); + } + + /// + /// 销毁方法 + /// + public virtual void Dispose() + { + _poolCount = 0; + _poolQueue.Clear(); + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Pool/Normal/PoolWithDisposable.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Pool/Normal/PoolWithDisposable.cs.meta new file mode 100644 index 0000000..9fa4476 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Pool/Normal/PoolWithDisposable.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 37d96a9ea60d8412c9c549446e970aaf +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Pool/PoolHelper.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Pool/PoolHelper.cs new file mode 100644 index 0000000..d9214fd --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Pool/PoolHelper.cs @@ -0,0 +1,79 @@ +using System; +using System.Reflection.Emit; +using Fantasy.Serialize; + +#pragma warning disable CS8604 // Possible null reference argument. + +namespace Fantasy.Pool +{ + internal static class CreateInstance where T : IPool + { + public static Func Create { get; } + + static CreateInstance() + { + var type = typeof(T); + var dynamicMethod = new DynamicMethod($"CreateInstance_{type.Name}", type, Type.EmptyTypes, true); + var il = dynamicMethod.GetILGenerator(); + il.Emit(OpCodes.Newobj, type.GetConstructor(Type.EmptyTypes)); + il.Emit(OpCodes.Ret); + Create = (Func) dynamicMethod.CreateDelegate(typeof(Func)); + } + } + + internal static class CreateInstance + { + public static Func CreateIPool(Type type) + { + var dynamicMethod = new DynamicMethod($"CreateInstance_{type.Name}", type, Type.EmptyTypes, true); + var il = dynamicMethod.GetILGenerator(); + il.Emit(OpCodes.Newobj, type.GetConstructor(Type.EmptyTypes)); + il.Emit(OpCodes.Ret); + return (Func)dynamicMethod.CreateDelegate(typeof(Func)); + } + + public static Func CreateObject(Type type) + { + var dynamicMethod = new DynamicMethod($"CreateInstance_{type.Name}", type, Type.EmptyTypes, true); + var il = dynamicMethod.GetILGenerator(); + il.Emit(OpCodes.Newobj, type.GetConstructor(Type.EmptyTypes)); + il.Emit(OpCodes.Ret); + return (Func)dynamicMethod.CreateDelegate(typeof(Func)); + } + + public static Func CreateMessage(Type type) + { + var dynamicMethod = new DynamicMethod($"CreateInstance_{type.Name}", type, Type.EmptyTypes, true); + var il = dynamicMethod.GetILGenerator(); + il.Emit(OpCodes.Newobj, type.GetConstructor(Type.EmptyTypes)); + il.Emit(OpCodes.Ret); + return (Func)dynamicMethod.CreateDelegate(typeof(Func)); + } + } + + // public static class CreateInstance + // { + // public static Func Create(Type type) + // { + // var dynamicMethod = new DynamicMethod($"CreateInstance_{type.Name}", type, Type.EmptyTypes, true); + // var il = dynamicMethod.GetILGenerator(); + // il.Emit(OpCodes.Newobj, type.GetConstructor(Type.EmptyTypes)); + // il.Emit(OpCodes.Ret); + // return (Func)dynamicMethod.CreateDelegate(typeof(Func)); + // } + // } + + // /// + // /// 利用泛型的特性来减少反射的使用。 + // /// + // /// + // public static class PoolChecker where T : new() + // { + // public static bool IsPool { get; } + // + // static PoolChecker() + // { + // IsPool = typeof(IPool).IsAssignableFrom(typeof(T)); + // } + // } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Pool/PoolHelper.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Pool/PoolHelper.cs.meta new file mode 100644 index 0000000..d7a30a7 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Pool/PoolHelper.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4ad79f875091b4737a22bfd0e0e686ea +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Scene.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Scene.meta new file mode 100644 index 0000000..2c4f375 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Scene.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d7ee3aae904e54dbfb290c22a09ff730 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Scene/ISceneUpdate.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Scene/ISceneUpdate.cs new file mode 100644 index 0000000..f736edf --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Scene/ISceneUpdate.cs @@ -0,0 +1,15 @@ +namespace Fantasy +{ + internal interface ISceneUpdate + { + void Update(); + } + + internal sealed class EmptySceneUpdate : ISceneUpdate + { + public void Update() + { + + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Scene/ISceneUpdate.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Scene/ISceneUpdate.cs.meta new file mode 100644 index 0000000..e84c60f --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Scene/ISceneUpdate.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 459c867d43e7443cd8e9b181b1f61b8c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Scene/OnCreateSceneEvent.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Scene/OnCreateSceneEvent.cs new file mode 100644 index 0000000..d192300 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Scene/OnCreateSceneEvent.cs @@ -0,0 +1,22 @@ +namespace Fantasy +{ + /// + /// 当Scene创建完成后发送的事件参数 + /// + public struct OnCreateScene + { + /// + /// 获取与事件关联的场景实体。 + /// + public readonly Scene Scene; + /// + /// 初始化一个新的 OnCreateScene 实例。 + /// + /// + public OnCreateScene(Scene scene) + { + Scene = scene; + } + } + +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Scene/OnCreateSceneEvent.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Scene/OnCreateSceneEvent.cs.meta new file mode 100644 index 0000000..108e36a --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Scene/OnCreateSceneEvent.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 5b47d13e99ac5412e88fb1b68d1da7b9 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Scene/Scene.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Scene/Scene.cs new file mode 100644 index 0000000..f0a08b7 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Scene/Scene.cs @@ -0,0 +1,543 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Fantasy.Async; +using Fantasy.Entitas; +using Fantasy.Event; +using Fantasy.IdFactory; +using Fantasy.Network; +using Fantasy.Network.Interface; +using Fantasy.Pool; +using Fantasy.Scheduler; +using Fantasy.Timer; +#if FANTASY_NET +using Fantasy.DataBase; +using Fantasy.Platform.Net; +using Fantasy.SingleCollection; +using System.Runtime.CompilerServices; +using Fantasy.Network.Route; +// ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract +#endif +#pragma warning disable CS8601 // Possible null reference assignment. +#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. +#pragma warning disable CS8603 // Possible null reference return. +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. +#pragma warning disable CS8602 // Dereference of a possibly null reference. +#pragma warning disable CS8600 // Converting null literal or possible null value to non-nullable type. +namespace Fantasy +{ + /// + /// 表示一个场景实体,用于创建与管理特定的游戏场景信息。 + /// + public partial class Scene : Entity + { + #region Members + /// + /// 当前Scene的父Scene,一般是用于实现子Scene的嵌套。 + /// 这个后期新版本会把Scene和SubScene分开,这里先暂时这样处理。 + /// + public Scene RootScene { get; internal set; } +#if FANTASY_NET + /// + /// Scene类型,对应SceneConfig的SceneType + /// + public int SceneType { get; private set; } + /// + /// 所属的世界 + /// + public World World { get; private set; } + /// + /// 所在的Process + /// + public Process Process { get; private set; } + /// + /// SceneConfig的Id + /// + public uint SceneConfigId { get; private set; } + internal ANetwork InnerNetwork { get; private set; } + internal ANetwork OuterNetwork { get; private set; } + internal SceneConfig SceneConfig => SceneConfigData.Instance.Get(SceneConfigId); + private readonly Dictionary _processSessionInfos = new Dictionary(); +#endif + /// + /// 当前Scene的上下文 + /// + public ThreadSynchronizationContext ThreadSynchronizationContext { get; internal set; } + /// + /// 当前Scene的下创建的Entity + /// + private readonly Dictionary _entities = new Dictionary(); + internal readonly Dictionary> TypeInstance = new Dictionary>(); + #endregion + + #region IdFactory + + /// + /// Entity实体Id的生成器 + /// + public IEntityIdFactory EntityIdFactory { get; private set; } + /// + /// Entity实体RuntimeId的生成器 + /// + public IRuntimeIdFactory RuntimeIdFactory { get; private set; } + + #endregion + + #region Pool + + internal EntityPool EntityPool; + internal EntityListPool EntityListPool; + internal EntitySortedDictionaryPool EntitySortedDictionaryPool; + + #endregion + + #region Component + + /// + /// Scene下的任务调度器系统组件 + /// + public TimerComponent TimerComponent { get; internal set; } + /// + /// Scene下的事件系统组件 + /// + public EventComponent EventComponent { get; internal set; } + /// + /// Scene下的ESC系统组件 + /// + public EntityComponent EntityComponent { get; internal set; } + /// + /// Scene下的网络消息对象池组件 + /// + public MessagePoolComponent MessagePoolComponent { get; internal set; } + /// + /// Scene下的协程锁组件 + /// + public CoroutineLockComponent CoroutineLockComponent { get; internal set; } + /// + /// Scene下的网络消息派发组件 + /// + internal MessageDispatcherComponent MessageDispatcherComponent { get; set; } +#if FANTASY_NET + /// + /// Scene下的Entity分表组件 + /// + public SingleCollectionComponent SingleCollectionComponent { get; internal set; } + /// + /// Scene下的内网消息发送组件 + /// + public NetworkMessagingComponent NetworkMessagingComponent { get; internal set; } +#endif + #endregion + + #region Initialize + + private async FTask Initialize() + { + EntityPool = new EntityPool(); + EntityListPool = new EntityListPool(); + EntitySortedDictionaryPool = new EntitySortedDictionaryPool(); + SceneUpdate = EntityComponent = await Create(this, false, false).Initialize(); + MessagePoolComponent = AddComponent(false); + EventComponent = await AddComponent(false).Initialize(); + TimerComponent = AddComponent(false).Initialize(); + CoroutineLockComponent = AddComponent(false).Initialize(); + MessageDispatcherComponent = await AddComponent(false).Initialize(); +#if FANTASY_NET + NetworkMessagingComponent = AddComponent(false); + SingleCollectionComponent = await AddComponent(false).Initialize(); +#endif + } + /// + /// Scene销毁方法,执行了该方法会把当前Scene下的所有实体都销毁掉。 + /// + public override void Dispose() + { + if (IsDisposed) + { + return; + } +#if FANTASY_NET + foreach (var (_, innerSession) in _processSessionInfos) + { + innerSession.Dispose(); + } + _processSessionInfos.Clear(); +#endif +#if FANTASY_UNITY + Session = null; + _unityWorldId--; + _unitySceneId--; + UnityNetwork?.Dispose(); +#endif + TypeInstance.Clear(); + EventComponent.Dispose(); + MessagePoolComponent.Dispose(); + EntityPool.Dispose(); + EntityListPool.Dispose(); + EntitySortedDictionaryPool.Dispose(); +#if FANTASY_NET + if (World != null) + { + if (RootScene == null) + { + World.Dispose(); + } + else + { + RootScene.RemoveEntity(RuntimeId); + RootScene = null; + } + + World = null; + } +#else + if (RootScene != null) + { + RootScene.RemoveEntity(RuntimeId); + RootScene = null; + } +#endif + base.Dispose(); + } + + #endregion + + internal ISceneUpdate SceneUpdate { get; set; } + + internal void Update() + { + try + { + SceneUpdate.Update(); + } + catch (Exception e) + { + Log.Error(e); + } + } + + #region Create + +#if FANTASY_UNITY || FANTASY_CONSOLE + private static uint _unitySceneId = 0; + private static byte _unityWorldId = 0; + public Session Session { get; private set; } + private AClientNetwork UnityNetwork { get; set; } + /// + /// 创建一个Unity的Scene,注意:该方法只能在主线程下使用。 + /// + /// 选择Scene的运行方式 + /// + /// + public static async FTask Create(string sceneRuntimeType = SceneRuntimeType.MainThread) + { + var world = ++_unityWorldId; + + if (world > byte.MaxValue - 1) + { + throw new Exception($"World ID ({world}) exceeds the maximum allowed value of 255."); + } + + var sceneId = (uint)(++_unitySceneId + world * 1000); + + if (sceneId > 255255) + { + throw new Exception($"Scene ID ({sceneId}) exceeds the maximum allowed value of 255255."); + } + + var scene = new Scene(); + scene.Scene = scene; + scene.Parent = scene; + scene.Type = typeof(Scene); + scene.EntityIdFactory = IdFactoryHelper.EntityIdFactory(sceneId, world); + scene.RuntimeIdFactory = IdFactoryHelper.RuntimeIdFactory(0, sceneId, world); + scene.Id = IdFactoryHelper.EntityId(0, sceneId, world, 0); + scene.RuntimeId = IdFactoryHelper.RuntimeId(0, sceneId, world, 0); + scene.AddEntity(scene); + await SetScheduler(scene, sceneRuntimeType); + scene.ThreadSynchronizationContext.Post(() => + { + scene.EventComponent.PublishAsync(new OnCreateScene(scene)).Coroutine(); + }); + return scene; + } + public Session Connect(string remoteAddress, NetworkProtocolType networkProtocolType, Action onConnectComplete, Action onConnectFail, Action onConnectDisconnect, bool isHttps, int connectTimeout = 5000) + { + UnityNetwork?.Dispose(); + UnityNetwork = NetworkProtocolFactory.CreateClient(this, networkProtocolType, NetworkTarget.Outer); + Session = UnityNetwork.Connect(remoteAddress, onConnectComplete, onConnectFail, onConnectDisconnect, isHttps, connectTimeout); + return Session; + } +#endif +#if FANTASY_NET + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static Scene Create(Process process, byte worldId, uint sceneConfigId) + { + var scene = new Scene(); + scene.Scene = scene; + scene.Parent = scene; + scene.Type = typeof(Scene); + scene.Process = process; + scene.EntityIdFactory = IdFactoryHelper.EntityIdFactory(sceneConfigId, worldId); + scene.RuntimeIdFactory = IdFactoryHelper.RuntimeIdFactory(0,sceneConfigId, worldId); + scene.Id = IdFactoryHelper.EntityId(0, sceneConfigId, worldId, 0); + scene.RuntimeId = IdFactoryHelper.RuntimeId(0, sceneConfigId, worldId, 0); + scene.AddEntity(scene); + return scene; + } + /// + /// 创建一个新的Scene + /// + /// 所属的Process + /// 对应的MachineConfig配置文件 + /// 对应的SceneConfig配置文件 + /// 创建成功后会返回创建的Scene的实例 + public static async FTask Create(Process process, MachineConfig machineConfig, SceneConfig sceneConfig) + { + var scene = Create(process, (byte)sceneConfig.WorldConfigId, sceneConfig.Id); + scene.SceneType = sceneConfig.SceneType; + scene.SceneConfigId = sceneConfig.Id; + await SetScheduler(scene, sceneConfig.SceneRuntimeType); + + if (sceneConfig.WorldConfigId != 0) + { + scene.World = World.Create(scene, (byte)sceneConfig.WorldConfigId); + } + + if (sceneConfig.InnerPort != 0) + { + // 创建内网网络服务器 + scene.InnerNetwork = NetworkProtocolFactory.CreateServer(scene, ProcessDefine.InnerNetwork, NetworkTarget.Inner, machineConfig.InnerBindIP, sceneConfig.InnerPort); + } + + if (sceneConfig.OuterPort != 0) + { + // 创建外网网络服务 + var networkProtocolType = Enum.Parse(sceneConfig.NetworkProtocol); + scene.OuterNetwork = NetworkProtocolFactory.CreateServer(scene, networkProtocolType, NetworkTarget.Outer, machineConfig.OuterBindIP, sceneConfig.OuterPort); + } + Process.AddScene(scene); + process.AddSceneToProcess(scene); + scene.ThreadSynchronizationContext.Post(() => + { + if (sceneConfig.SceneTypeString == "Addressable") + { + // 如果是AddressableScene,自动添加上AddressableManageComponent。 + scene.AddComponent(); + } + + scene.EventComponent.PublishAsync(new OnCreateScene(scene)).Coroutine(); + }); + return scene; + } + /// + /// 在Scene下面创建一个子Scene,一般用于副本,或者一些特殊的场景。 + /// + /// 主Scene的实例 + /// SceneType,可以在SceneType里找到,例如:SceneType.Addressable + /// 子Scene创建成功后执行的委托,可以传递null + /// + public static SubScene CreateSubScene(Scene parentScene, int sceneType, Action onSubSceneComplete = null) + { + var scene = new SubScene(); + scene.Scene = scene; + scene.Parent = scene; + scene.RootScene = parentScene; + scene.Type = typeof(SubScene); + scene.SceneType = sceneType; + scene.World = parentScene.World; + scene.Process = parentScene.Process; + scene.EntityIdFactory = parentScene.EntityIdFactory; + scene.RuntimeIdFactory = parentScene.RuntimeIdFactory; + scene.Id = scene.EntityIdFactory.Create; + scene.RuntimeId = scene.RuntimeIdFactory.Create; + scene.AddEntity(scene); + scene.Initialize(parentScene); + scene.ThreadSynchronizationContext.Post(() => OnEvent().Coroutine()); + return scene; + async FTask OnEvent() + { + await scene.EventComponent.PublishAsync(new OnCreateScene(scene)); + onSubSceneComplete?.Invoke(scene, parentScene); + } + } +#endif + private static async FTask SetScheduler(Scene scene, string sceneRuntimeType) + { + switch (sceneRuntimeType) + { + case "MainThread": + { + scene.ThreadSynchronizationContext = ThreadScheduler.MainScheduler.ThreadSynchronizationContext; + scene.SceneUpdate = new EmptySceneUpdate(); + ThreadScheduler.AddMainScheduler(scene); + await scene.Initialize(); + break; + } + case "MultiThread": + { +#if !FANTASY_WEBGL + scene.ThreadSynchronizationContext = new ThreadSynchronizationContext(); +#endif + scene.SceneUpdate = new EmptySceneUpdate(); + ThreadScheduler.AddToMultiThreadScheduler(scene); + await scene.Initialize(); + break; + } + case "ThreadPool": + { +#if !FANTASY_WEBGL + scene.ThreadSynchronizationContext = new ThreadSynchronizationContext(); +#endif + scene.SceneUpdate = new EmptySceneUpdate(); + ThreadScheduler.AddToThreadPoolScheduler(scene); + await scene.Initialize(); + break; + } + } + } + #endregion + + #region Entities + + /// + /// 添加一个实体到当前Scene下 + /// + /// 实体实例 + public virtual void AddEntity(Entity entity) + { + _entities.Add(entity.RuntimeId, entity); + } + + /// + /// 根据RunTimeId查询一个实体 + /// + /// 实体的RunTimeId + /// 返回的实体 + public virtual Entity GetEntity(long runTimeId) + { + return _entities.TryGetValue(runTimeId, out var entity) ? entity : null; + } + + /// + /// 根据RunTimeId查询一个实体 + /// + /// 实体的RunTimeId + /// 实体实例 + /// 返回一个bool值来提示是否查找到这个实体 + public virtual bool TryGetEntity(long runTimeId, out Entity entity) + { + return _entities.TryGetValue(runTimeId, out entity); + } + + /// + /// 根据RunTimeId查询一个实体 + /// + /// 实体的RunTimeId + /// 要查询实体的泛型类型 + /// 返回的实体 + public virtual T GetEntity(long runTimeId) where T : Entity + { + return _entities.TryGetValue(runTimeId, out var entity) ? (T)entity : null; + } + + /// + /// 根据RunTimeId查询一个实体 + /// + /// 实体的RunTimeId + /// 实体实例 + /// 要查询实体的泛型类型 + /// 返回一个bool值来提示是否查找到这个实体 + public virtual bool TryGetEntity(long runTimeId, out T entity) where T : Entity + { + if (_entities.TryGetValue(runTimeId, out var getEntity)) + { + entity = (T)getEntity; + return true; + } + + entity = null; + return false; + } + + /// + /// 删除一个实体,仅是删除不会指定实体的销毁方法 + /// + /// 实体的RunTimeId + /// 返回一个bool值来提示是否删除了这个实体 + public virtual bool RemoveEntity(long runTimeId) + { + return _entities.Remove(runTimeId); + } + + /// + /// 删除一个实体,仅是删除不会指定实体的销毁方法 + /// + /// 实体实例 + /// 返回一个bool值来提示是否删除了这个实体 + public virtual bool RemoveEntity(Entity entity) + { + return _entities.Remove(entity.RuntimeId); + } + + #endregion + + #region InnerSession + +#if FANTASY_NET + /// + /// 根据runTimeId获得Session + /// + /// + /// + /// + public virtual Session GetSession(long runTimeId) + { + var sceneId = IdFactoryHelper.RuntimeIdTool.GetSceneId(ref runTimeId); + + if (_processSessionInfos.TryGetValue(sceneId, out var processSessionInfo)) + { + if (!processSessionInfo.Session.IsDisposed) + { + return processSessionInfo.Session; + } + + _processSessionInfos.Remove(sceneId); + } + + if (Process.IsInAppliaction(ref sceneId)) + { + // 如果在同一个Process下,不需要通过Socket发送了,直接通过Process下转发。 + var processSession = Session.CreateInnerSession(Scene); + _processSessionInfos.Add(sceneId, new ProcessSessionInfo(processSession, null)); + return processSession; + } + + if (!SceneConfigData.Instance.TryGet(sceneId, out var sceneConfig)) + { + throw new Exception($"The scene with sceneId {sceneId} was not found in the configuration file"); + } + + if (!ProcessConfigData.Instance.TryGet(sceneConfig.ProcessConfigId, out var processConfig)) + { + throw new Exception($"The process with processId {sceneConfig.ProcessConfigId} was not found in the configuration file"); + } + + if (!MachineConfigData.Instance.TryGet(processConfig.MachineId, out var machineConfig)) + { + throw new Exception($"The machine with machineId {processConfig.MachineId} was not found in the configuration file"); + } + + var remoteAddress = $"{machineConfig.InnerBindIP}:{sceneConfig.InnerPort}"; + var client = NetworkProtocolFactory.CreateClient(Scene, ProcessDefine.InnerNetwork, NetworkTarget.Inner); + var session = client.Connect(remoteAddress, null, () => + { + Log.Error($"Unable to connect to the target server sourceServerId:{Scene.Process.Id} targetServerId:{sceneConfig.ProcessConfigId}"); + }, null, false); + _processSessionInfos.Add(sceneId, new ProcessSessionInfo(session, client)); + return session; + } +#endif + #endregion + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Scene/Scene.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Scene/Scene.cs.meta new file mode 100644 index 0000000..1d3f997 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Scene/Scene.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 968a867914cca474581795824737b521 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Scene/SceneRuntimeType.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Scene/SceneRuntimeType.cs new file mode 100644 index 0000000..f22e11a --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Scene/SceneRuntimeType.cs @@ -0,0 +1,21 @@ +namespace Fantasy +{ + /// + /// Scene的运行类型 + /// + public class SceneRuntimeType + { + /// + /// Scene在主线程中运行. + /// + public const string MainThread = "MainThread"; + /// + /// Scene在一个独立的线程中运行. + /// + public const string MultiThread = "MultiThread"; + /// + /// Scene在一个根据当前CPU核心数创建的线程池中运行. + /// + public const string ThreadPool = "ThreadPool"; + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Scene/SceneRuntimeType.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Scene/SceneRuntimeType.cs.meta new file mode 100644 index 0000000..d0481cf --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Scene/SceneRuntimeType.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: fce1a72d9b59c4611b4355bc1246a582 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Scene/Scheduler.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Scene/Scheduler.meta new file mode 100644 index 0000000..21b0c92 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Scene/Scheduler.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 430e21e71c301427fb3a568d44ec6afa +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Scene/Scheduler/ISceneScheduler.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Scene/Scheduler/ISceneScheduler.cs new file mode 100644 index 0000000..c04cc30 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Scene/Scheduler/ISceneScheduler.cs @@ -0,0 +1,11 @@ +using System; + +namespace Fantasy +{ + internal interface ISceneScheduler : IDisposable + { + void Add(Scene scene); + void Remove(Scene scene); + void Update(); + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Scene/Scheduler/ISceneScheduler.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Scene/Scheduler/ISceneScheduler.cs.meta new file mode 100644 index 0000000..0d3c372 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Scene/Scheduler/ISceneScheduler.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f39eba01f7f4a4b4eb94287997144b26 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Scene/Scheduler/MainScheduler.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Scene/Scheduler/MainScheduler.cs new file mode 100644 index 0000000..692def0 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Scene/Scheduler/MainScheduler.cs @@ -0,0 +1,83 @@ +using System.Collections.Generic; +#if FANTASY_UNITY || FANTASY_NET || !FANTASY_WEBGL +using System.Threading; +#endif +#if FANTASY_NET +using Fantasy.Platform.Net; +#endif +namespace Fantasy +{ + internal sealed class MainScheduler : ISceneScheduler + { + private readonly Queue _queue = new Queue(); + public readonly ThreadSynchronizationContext ThreadSynchronizationContext; + + public MainScheduler() + { + ThreadSynchronizationContext = new ThreadSynchronizationContext(); +#if !FANTASY_WEBGL + SynchronizationContext.SetSynchronizationContext(ThreadSynchronizationContext); +#endif + } + public void Dispose() + { + _queue.Clear(); + } + + public void Add(Scene scene) + { + ThreadSynchronizationContext.Post(() => + { + if (scene.IsDisposed) + { + return; + } + + _queue.Enqueue(scene); + }); + } + + public void Remove(Scene scene) + { + ThreadSynchronizationContext.Post(() => + { + if (scene.IsDisposed) + { + return; + } + + var initialCount = _queue.Count; + for (var i = 0; i < initialCount; i++) + { + var currentScene = _queue.Dequeue(); + if (currentScene != scene) + { + _queue.Enqueue(currentScene); + } + } + }); + } + + public void Update() + { + ThreadSynchronizationContext.Update(); + var initialCount = _queue.Count; + + while (initialCount-- > 0) + { + if(!_queue.TryDequeue(out var scene)) + { + continue; + } + + if (scene.IsDisposed) + { + continue; + } + + scene.Update(); + _queue.Enqueue(scene); + } + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Scene/Scheduler/MainScheduler.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Scene/Scheduler/MainScheduler.cs.meta new file mode 100644 index 0000000..b2dba50 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Scene/Scheduler/MainScheduler.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6c7398438bdaa4c1aa3ae9bd545acc76 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Scene/Scheduler/MultiThreadScheduler.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Scene/Scheduler/MultiThreadScheduler.cs new file mode 100644 index 0000000..28f2d42 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Scene/Scheduler/MultiThreadScheduler.cs @@ -0,0 +1,103 @@ +#if !FANTASY_WEBGL || !FANTASY_SINGLETHREAD +using System; +using System.Collections.Concurrent; +using System.Threading; +namespace Fantasy +{ + internal struct MultiThreadStruct : IDisposable + { + public readonly Thread Thread; + public readonly CancellationTokenSource Cts; + + public MultiThreadStruct(Thread thread, CancellationTokenSource cts) + { + Thread = thread; + Cts = cts; + } + + public void Dispose() + { + Cts.Cancel(); + if (Thread.IsAlive) + { + Thread.Join(); + } + Cts.Dispose(); + } + } + + internal sealed class MultiThreadScheduler : ISceneScheduler + { + private bool _isDisposed; + private readonly ConcurrentDictionary _threads = new ConcurrentDictionary(); + public int ThreadCount => _threads.Count; + + public void Dispose() + { + if (_isDisposed) + { + return; + } + + _isDisposed = true; + + foreach (var (_, multiThreadStruct) in _threads.ToArray()) + { + multiThreadStruct.Dispose(); + } + + _threads.Clear(); + } + + public void Add(Scene scene) + { + var cts = new CancellationTokenSource(); + var thread = new Thread(() => Loop(scene, cts.Token)); + _threads.TryAdd(scene.RuntimeId, new MultiThreadStruct(thread, cts)); + thread.Start(); + } + + public void Remove(Scene scene) + { + if (_threads.TryRemove(scene.RuntimeId, out var multiThreadStruct)) + { + multiThreadStruct.Dispose(); + } + } + + public void Update() + { + throw new NotImplementedException(); + } + + private void Loop(Scene scene, CancellationToken cancellationToken) + { + var sceneThreadSynchronizationContext = scene.ThreadSynchronizationContext; + SynchronizationContext.SetSynchronizationContext(sceneThreadSynchronizationContext); + + while (!cancellationToken.IsCancellationRequested) + { + try + { + if (scene.IsDisposed) + { + Remove(scene); + return; + } + + sceneThreadSynchronizationContext.Update(); + scene.Update(); + } + catch (Exception e) + { + Log.Error($"Error in MultiThreadScheduler loop: {e.Message}"); + } + finally + { + Thread.Sleep(1); + } + } + } + } +} +#endif diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Scene/Scheduler/MultiThreadScheduler.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Scene/Scheduler/MultiThreadScheduler.cs.meta new file mode 100644 index 0000000..3547e95 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Scene/Scheduler/MultiThreadScheduler.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 36b6da87c3a674cb5b2d2d9d270c397d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Scene/Scheduler/ThreadPoolScheduler.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Scene/Scheduler/ThreadPoolScheduler.cs new file mode 100644 index 0000000..9f5a44c --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Scene/Scheduler/ThreadPoolScheduler.cs @@ -0,0 +1,140 @@ +#if !FANTASY_WEBGL || !FANTASY_SINGLETHREAD +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Threading; +// ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract +#pragma warning disable CS8604 // Possible null reference argument. +namespace Fantasy +{ + internal sealed class ThreadPoolScheduler : ISceneScheduler + { + private bool _isDisposed; + private readonly List _threads; + private readonly ConcurrentBag _queue = new ConcurrentBag(); + private readonly CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource(); + + public ThreadPoolScheduler() + { + // 最大线程数、避免线程过多发生的资源抢占问题。 + // 但如果使用了MultiThreadScheduler,那么这里的线程数就算是设置了也有可能导致线程过多的问题。 + // 线程过多看每个线程的抢占情况,如果抢占资源占用不是很大也没什么大问题。如果过大的情况,就会有性能问题。 + // 所以根据情况来使用不同的调度器。 + var maxThreadCount = Environment.ProcessorCount; + _threads = new List(maxThreadCount); + + for (var i = 0; i < maxThreadCount; ++i) + { + Thread thread = new(() => Loop(_cancellationTokenSource.Token)) + { + IsBackground = true + }; + _threads.Add(thread); + thread.Start(); + } + } + + public void Dispose() + { + if (_isDisposed) + { + return; + } + + _isDisposed = true; + _cancellationTokenSource.Cancel(); + + foreach (var thread in _threads) + { + if (thread.IsAlive) + { + thread.Join(); + } + } + + _cancellationTokenSource.Dispose(); + _threads.Clear(); + } + + public void Add(Scene scene) + { + if (_isDisposed) + { + return; + } + + _queue.Add(scene); + } + + public void Remove(Scene scene) + { + if (_isDisposed) + { + return; + } + + var newQueue = new Queue(); + + while (!_queue.IsEmpty) + { + if (_queue.TryTake(out var currentScene)) + { + if (currentScene != scene) + { + newQueue.Enqueue(currentScene); + } + } + } + + while (newQueue.TryDequeue(out var newScene)) + { + _queue.Add(newScene); + } + } + + public void Update() + { + throw new NotImplementedException(); + } + + private void Loop(CancellationToken cancellationToken) + { + while (!cancellationToken.IsCancellationRequested) + { + if (_queue.TryTake(out var scene)) + { + if (scene == null || scene.IsDisposed) + { + continue; + } + + var sceneThreadSynchronizationContext = scene.ThreadSynchronizationContext; + SynchronizationContext.SetSynchronizationContext(sceneThreadSynchronizationContext); + + try + { + sceneThreadSynchronizationContext.Update(); + scene.Update(); + } + catch (Exception e) + { + Log.Error($"Error in ThreadPoolScheduler scene: {e.Message}"); + } + finally + { + SynchronizationContext.SetSynchronizationContext(null); + } + + _queue.Add(scene); + Thread.Sleep(1); + } + else + { + // 当队列为空的时候、避免无效循环消耗CPU。 + Thread.Sleep(10); + } + } + } + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Scene/Scheduler/ThreadPoolScheduler.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Scene/Scheduler/ThreadPoolScheduler.cs.meta new file mode 100644 index 0000000..e263f94 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Scene/Scheduler/ThreadPoolScheduler.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 12f33fe68e2b64ac98ecd79b8158e420 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Scene/Scheduler/ThreadScheduler.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Scene/Scheduler/ThreadScheduler.cs new file mode 100644 index 0000000..5bd0dea --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Scene/Scheduler/ThreadScheduler.cs @@ -0,0 +1,66 @@ +// ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. +namespace Fantasy +{ + /// + /// 线程调度器 + /// + internal static class ThreadScheduler + { + /// + /// 主线程调度器 + /// + public static MainScheduler MainScheduler { get; private set; } + /// + /// 多线程调度器,根据当前CPU核心数量创建的固定线程。 + /// + public static ISceneScheduler MultiThreadScheduler { get; private set; } + /// + /// 线程池调度器 + /// + public static ISceneScheduler ThreadPoolScheduler { get; private set; } + + static ThreadScheduler() + { + MainScheduler = new MainScheduler(); + } + + internal static void Update() + { + MainScheduler.Update(); + } + + internal static void AddMainScheduler(Scene scene) + { + MainScheduler.Add(scene); + } + + internal static void AddToMultiThreadScheduler(Scene scene) + { + if (MultiThreadScheduler == null) + { +#if FANTASY_SINGLETHREAD || FANTASY_WEBGL + MultiThreadScheduler = MainScheduler; +#else + MultiThreadScheduler = new MultiThreadScheduler(); +#endif + } + + MultiThreadScheduler.Add(scene); + } + + internal static void AddToThreadPoolScheduler(Scene scene) + { + if (ThreadPoolScheduler == null) + { +#if FANTASY_SINGLETHREAD || FANTASY_WEBGL + ThreadPoolScheduler = MainScheduler; +#else + ThreadPoolScheduler = new ThreadPoolScheduler(); +#endif + } + + ThreadPoolScheduler.Add(scene); + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Scene/Scheduler/ThreadScheduler.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Scene/Scheduler/ThreadScheduler.cs.meta new file mode 100644 index 0000000..476a3b7 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Scene/Scheduler/ThreadScheduler.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d9807e33a9ca94371885c6934ff42523 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Scene/SubScene.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Scene/SubScene.cs new file mode 100644 index 0000000..5e8296e --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Scene/SubScene.cs @@ -0,0 +1,123 @@ +using System.Runtime.Serialization; +using Fantasy.Entitas; +using Newtonsoft.Json; +using Fantasy.Network; +using MongoDB.Bson.Serialization.Attributes; +using ProtoBuf; + +#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring as nullable. + +namespace Fantasy +{ + /// + /// 代表一个Scene下的子Scene + /// + public sealed partial class SubScene : Scene + { + internal void Initialize(Scene rootScene) + { + EntityPool = rootScene.EntityPool; + EntityListPool = rootScene.EntityListPool; + EntitySortedDictionaryPool = rootScene.EntitySortedDictionaryPool; + SceneUpdate = rootScene.SceneUpdate; + TimerComponent = rootScene.TimerComponent; + EventComponent = rootScene.EventComponent; + EntityComponent = rootScene.EntityComponent; + MessagePoolComponent = rootScene.MessagePoolComponent; + CoroutineLockComponent = rootScene.CoroutineLockComponent; + MessageDispatcherComponent = rootScene.MessageDispatcherComponent; + #if FANTASY_NET + NetworkMessagingComponent = rootScene.NetworkMessagingComponent; + SingleCollectionComponent = rootScene.SingleCollectionComponent; + #endif + ThreadSynchronizationContext = rootScene.ThreadSynchronizationContext; + } + + /// + /// 添加一个实体到当前Scene下 + /// + /// 实体实例 + public override void AddEntity(Entity entity) + { + RootScene.AddEntity(entity); + } + + /// + /// 根据RunTimeId查询一个实体 + /// + /// 实体的RunTimeId + /// 返回的实体 + public override Entity GetEntity(long runTimeId) + { + return RootScene.GetEntity(runTimeId); + } + + /// + /// 根据RunTimeId查询一个实体 + /// + /// 实体的RunTimeId + /// 实体实例 + /// 返回一个bool值来提示是否查找到这个实体 + public override bool TryGetEntity(long runTimeId, out Entity entity) + { + return RootScene.TryGetEntity(runTimeId, out entity); + } + + /// + /// 根据RunTimeId查询一个实体 + /// + /// 实体的RunTimeId + /// 要查询实体的泛型类型 + /// 返回的实体 + public override T GetEntity(long runTimeId) + { + return RootScene.GetEntity(runTimeId); + } + + /// + /// 根据RunTimeId查询一个实体 + /// + /// 实体的RunTimeId + /// 实体实例 + /// 要查询实体的泛型类型 + /// 返回一个bool值来提示是否查找到这个实体 + public override bool TryGetEntity(long runTimeId, out T entity) + { + return RootScene.TryGetEntity(runTimeId, out entity); + } + + /// + /// 删除一个实体,仅是删除不会指定实体的销毁方法 + /// + /// 实体的RunTimeId + /// 返回一个bool值来提示是否删除了这个实体 + public override bool RemoveEntity(long runTimeId) + { + return RootScene.RemoveEntity(runTimeId); + } + + /// + /// 删除一个实体,仅是删除不会指定实体的销毁方法 + /// + /// 实体实例 + /// 返回一个bool值来提示是否删除了这个实体 + public override bool RemoveEntity(Entity entity) + { + return RootScene.RemoveEntity(entity); + } + +#if FANTASY_NET + /// + /// 根据runTimeId获得Session + /// + /// + /// + /// + public override Session GetSession(long runTimeId) + { + return RootScene.GetSession(runTimeId); + } + #endif + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Scene/SubScene.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Scene/SubScene.cs.meta new file mode 100644 index 0000000..9e9bd5d --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Scene/SubScene.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 38f07f37ebbca4379903da052249b06b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Serialize.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Serialize.meta new file mode 100644 index 0000000..5ded792 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Serialize.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: acd70d541dd3b4be5a68d4508bc5d5e3 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Serialize/BsonPack.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Serialize/BsonPack.meta new file mode 100644 index 0000000..1617db2 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Serialize/BsonPack.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 0a19189e3038447bb88d6d991d3f1228 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Serialize/BsonPack/BsonPackHelperNet.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Serialize/BsonPack/BsonPackHelperNet.cs new file mode 100644 index 0000000..bb5293b --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Serialize/BsonPack/BsonPackHelperNet.cs @@ -0,0 +1,311 @@ +#if FANTASY_NET +using System.Buffers; +using System.Collections; +using System.ComponentModel; +using System.Reflection; +using Fantasy.Assembly; +using Fantasy.Entitas; +using MongoDB.Bson; +using MongoDB.Bson.IO; +using MongoDB.Bson.Serialization; +using MongoDB.Bson.Serialization.Conventions; +using MongoDB.Bson.Serialization.Serializers; +#pragma warning disable CS8603 // Possible null reference return. +#pragma warning disable CS8600 // Converting null literal or possible null value to non-nullable type. +#pragma warning disable CS8602 // Dereference of a possibly null reference. + +namespace Fantasy.Serialize +{ + /// + /// BSON帮助方法 + /// + public class BsonPackHelper : ISerialize + { + /// + /// 序列化器的名字 + /// + public string SerializeName { get; } = "Bson"; + + /// + /// 构造函数 + /// + public BsonPackHelper() + { + // 清除掉注册过的LookupClassMap。 + + var classMapRegistryField = typeof(BsonClassMap).GetField("__classMaps", BindingFlags.Static | BindingFlags.NonPublic); + + if (classMapRegistryField != null) + { + ((Dictionary)classMapRegistryField.GetValue(null)).Clear(); + } + + // 清除掉注册过的ConventionRegistry。 + + var registryField = typeof(ConventionRegistry).GetField("_lookup", BindingFlags.Static | BindingFlags.NonPublic); + + if (registryField != null) + { + var registry = registryField.GetValue(null); + var dictionaryField = registry.GetType().GetField("_conventions", BindingFlags.Instance | BindingFlags.NonPublic); + if (dictionaryField != null) + { + ((IDictionary)dictionaryField.GetValue(registry)).Clear(); + } + } + + // 初始化ConventionRegistry、注册IgnoreExtraElements。 + + ConventionRegistry.Register("IgnoreExtraElements", new ConventionPack { new IgnoreExtraElementsConvention(true) }, type => true); + + // 注册一个自定义的序列化器。 + + // BsonSerializer.TryRegisterSerializer(typeof(float2), new StructBsonSerialize()); + // BsonSerializer.TryRegisterSerializer(typeof(float3), new StructBsonSerialize()); + // BsonSerializer.TryRegisterSerializer(typeof(float4), new StructBsonSerialize()); + // BsonSerializer.TryRegisterSerializer(typeof(quaternion), new StructBsonSerialize()); + BsonSerializer.RegisterSerializer(new ObjectSerializer(x => true)); + + // 注册LookupClassMap。 + + foreach (var type in AssemblySystem.ForEach()) + { + if (type.IsInterface || type.IsAbstract || type.IsGenericType || !typeof(Entity).IsAssignableFrom(type)) + { + continue; + } + + BsonClassMap.LookupClassMap(type); + } + } + + /// + /// 反序列化 + /// + /// + /// + /// + public T Deserialize(byte[] bytes) + { + var @object = BsonSerializer.Deserialize(bytes); + if (@object is ASerialize aSerialize) + { + aSerialize.AfterDeserialization(); + } + return @object; + } + + /// + /// 反序列化 + /// + /// + /// + /// + public T Deserialize(MemoryStreamBuffer buffer) + { + var @object = BsonSerializer.Deserialize(buffer); + if (@object is ASerialize aSerialize) + { + aSerialize.AfterDeserialization(); + } + return @object; + } + + /// + /// 反序列化 + /// + /// + /// + /// + public object Deserialize(Type type, byte[] bytes) + { + var @object = BsonSerializer.Deserialize(bytes, type); + if (@object is ASerialize aSerialize) + { + aSerialize.AfterDeserialization(); + } + return @object; + } + + /// + /// 反序列化 + /// + /// + /// + /// + public object Deserialize(Type type, MemoryStreamBuffer buffer) + { + var @object = BsonSerializer.Deserialize(buffer, type); + if (@object is ASerialize aSerialize) + { + aSerialize.AfterDeserialization(); + } + return @object; + } + + /// + /// 反序列化 + /// + /// + /// + /// + /// + /// + public unsafe T Deserialize(byte[] bytes, int index, int count) + { + T @object; + + fixed (byte* ptr = &bytes[index]) + { + using var stream = new UnmanagedMemoryStream(ptr, count); + @object = BsonSerializer.Deserialize(stream); + } + + if (@object is ASerialize aSerialize) + { + aSerialize.AfterDeserialization(); + } + + return @object; + } + + /// + /// 反序列化 + /// + /// + /// + /// + /// + /// + public unsafe object Deserialize(Type type, byte[] bytes, int index, int count) + { + object @object; + + fixed (byte* ptr = &bytes[index]) + { + using var stream = new UnmanagedMemoryStream(ptr, count); + @object = BsonSerializer.Deserialize(stream, type); + } + + if (@object is ASerialize aSerialize) + { + aSerialize.AfterDeserialization(); + } + + return @object; + } + + /// + /// 序列化 + /// + /// + /// + /// + public void Serialize(T @object, IBufferWriter buffer) + { + if (@object is ASerialize aSerialize) + { + aSerialize.BeginInit(); + } + + using IBsonWriter bsonWriter = + new BsonBinaryWriter((MemoryStream)buffer, BsonBinaryWriterSettings.Defaults); + BsonSerializer.Serialize(bsonWriter, @object); + } + + /// + /// 序列化 + /// + /// + /// + public void Serialize(object @object, IBufferWriter buffer) + { + if (@object is ASerialize aSerialize) + { + aSerialize.BeginInit(); + } + + using IBsonWriter bsonWriter = + new BsonBinaryWriter((MemoryStream)buffer, BsonBinaryWriterSettings.Defaults); + BsonSerializer.Serialize(bsonWriter, @object.GetType(), @object); + } + + /// + /// 序列化 + /// + /// + /// + /// + public void Serialize(Type type, object @object, IBufferWriter buffer) + { + if (@object is ASerialize aSerialize) + { + aSerialize.BeginInit(); + } + + using IBsonWriter bsonWriter = + new BsonBinaryWriter((MemoryStream)buffer, BsonBinaryWriterSettings.Defaults); + BsonSerializer.Serialize(bsonWriter, type, @object); + } + + /// + /// 序列化并返回的长度 + /// + /// + /// + /// + /// + public int SerializeAndReturnLength(Type type, object @object, MemoryStreamBuffer buffer) + { + if (@object is ASerialize aSerialize) + { + aSerialize.BeginInit(); + } + + using IBsonWriter bsonWriter = new BsonBinaryWriter(buffer, BsonBinaryWriterSettings.Defaults); + BsonSerializer.Serialize(bsonWriter, type, @object); + return (int)buffer.Length; + } + + /// + /// 序列化 + /// + /// + /// + public static byte[] Serialize(object @object) + { + if (@object is ASerialize aSerialize) + { + aSerialize.BeginInit(); + } + return @object.ToBson(@object.GetType()); + } + + /// + /// 序列化 + /// + /// + /// + /// + public static byte[] Serialize(T @object) + { + if (@object is ASerialize aSerialize) + { + aSerialize.BeginInit(); + } + return @object.ToBson(); + } + + /// + /// 克隆 + /// + /// + /// + /// + public T Clone(T t) + { + return Deserialize(Serialize(t)); + } + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Serialize/BsonPack/BsonPackHelperNet.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Serialize/BsonPack/BsonPackHelperNet.cs.meta new file mode 100644 index 0000000..10f177b --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Serialize/BsonPack/BsonPackHelperNet.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 82a45a2fc4bdd42d6aa09f9dbb84153e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Serialize/BsonPack/BsonPackHelperUnity.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Serialize/BsonPack/BsonPackHelperUnity.cs new file mode 100644 index 0000000..df44fcb --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Serialize/BsonPack/BsonPackHelperUnity.cs @@ -0,0 +1,60 @@ +#if FANTASY_UNITY +using System; +using System.Buffers; +namespace Fantasy.Serialize +{ + public class BsonPackHelper : ISerialize + { + public string SerializeName { get; } = "Bson"; + public T Deserialize(byte[] bytes) + { + throw new NotImplementedException(); + } + + public T Deserialize(MemoryStreamBuffer buffer) + { + throw new NotImplementedException(); + } + + public object Deserialize(Type type, byte[] bytes) + { + throw new NotImplementedException(); + } + + public object Deserialize(Type type, MemoryStreamBuffer buffer) + { + throw new NotImplementedException(); + } + + public T Deserialize(byte[] bytes, int index, int count) + { + throw new NotImplementedException(); + } + + public object Deserialize(Type type, byte[] bytes, int index, int count) + { + throw new NotImplementedException(); + } + + public void Serialize(T @object, IBufferWriter buffer) + { + throw new NotImplementedException(); + } + + public void Serialize(object @object, IBufferWriter buffer) + { + throw new NotImplementedException(); + } + + public void Serialize(Type type, object @object, IBufferWriter buffer) + { + throw new NotImplementedException(); + } + + public T Clone(T t) + { + throw new NotImplementedException(); + } + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Serialize/BsonPack/BsonPackHelperUnity.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Serialize/BsonPack/BsonPackHelperUnity.cs.meta new file mode 100644 index 0000000..6b18f45 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Serialize/BsonPack/BsonPackHelperUnity.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 564581ee1c8ee4e348fe55a0d02977ed +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Serialize/BsonPack/StructBsonSerialize.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Serialize/BsonPack/StructBsonSerialize.cs new file mode 100644 index 0000000..15d8663 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Serialize/BsonPack/StructBsonSerialize.cs @@ -0,0 +1,65 @@ +#if FANTASY_NET +using System.Reflection; +using MongoDB.Bson; +using MongoDB.Bson.IO; +using MongoDB.Bson.Serialization; +using MongoDB.Bson.Serialization.Serializers; + +namespace Fantasy.Serialize; + +/// +/// 提供对结构体类型进行 BSON 序列化和反序列化的辅助类。 +/// +/// 要序列化和反序列化的结构体类型。 +public class StructBsonSerialize : StructSerializerBase where TValue : struct +{ + /// + /// 将结构体对象序列化为 BSON 数据。 + /// + /// 序列化上下文。 + /// 序列化参数。 + /// 要序列化的结构体对象。 + public override void Serialize(BsonSerializationContext context, BsonSerializationArgs args, TValue value) + { + var nominalType = args.NominalType; + var bsonWriter = context.Writer; + bsonWriter.WriteStartDocument(); + var fields = nominalType.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); + foreach (var field in fields) + { + bsonWriter.WriteName(field.Name); + BsonSerializer.Serialize(bsonWriter, field.FieldType, field.GetValue(value)); + } + bsonWriter.WriteEndDocument(); + } + + /// + /// 将 BSON 数据反序列化为结构体对象。 + /// + /// 反序列化上下文。 + /// 反序列化参数。 + /// 反序列化得到的结构体对象。 + public override TValue Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args) + { + //boxing is required for SetValue to work + object obj = new TValue(); + var actualType = args.NominalType; + var bsonReader = context.Reader; + bsonReader.ReadStartDocument(); + while (bsonReader.ReadBsonType() != BsonType.EndOfDocument) + { + var name = bsonReader.ReadName(Utf8NameDecoder.Instance); + + var field = actualType.GetField(name, + BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); + if (field != null) + { + var value = BsonSerializer.Deserialize(bsonReader, field.FieldType); + field.SetValue(obj, value); + } + } + bsonReader.ReadEndDocument(); + return (TValue) obj; + } +} +#endif diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Serialize/BsonPack/StructBsonSerialize.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Serialize/BsonPack/StructBsonSerialize.cs.meta new file mode 100644 index 0000000..3864af5 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Serialize/BsonPack/StructBsonSerialize.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3965973989a254244818a3db5ba1d9fd +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Serialize/BsonPack/SupportInitializeChecker.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Serialize/BsonPack/SupportInitializeChecker.cs new file mode 100644 index 0000000..82c6829 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Serialize/BsonPack/SupportInitializeChecker.cs @@ -0,0 +1,17 @@ +#if FANTASY_NET +using System.ComponentModel; +using Fantasy.Entitas; + +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member +namespace Fantasy.Serialize; + +public static class SupportInitializeChecker where T : Entity +{ + public static bool IsSupported { get; } + + static SupportInitializeChecker() + { + IsSupported = typeof(ISupportInitialize).IsAssignableFrom(typeof(T)); + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Serialize/BsonPack/SupportInitializeChecker.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Serialize/BsonPack/SupportInitializeChecker.cs.meta new file mode 100644 index 0000000..b87cfa6 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Serialize/BsonPack/SupportInitializeChecker.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d6d731a2f55db4fa08667dc8195cd49a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Serialize/Interface.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Serialize/Interface.meta new file mode 100644 index 0000000..817a200 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Serialize/Interface.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 67cee2b81543348e8b18e5425e0e4863 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Serialize/Interface/ASerialize.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Serialize/Interface/ASerialize.cs new file mode 100644 index 0000000..7487b86 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Serialize/Interface/ASerialize.cs @@ -0,0 +1,60 @@ +using System; +using System.ComponentModel; +using System.Runtime.Serialization; +using Fantasy.Pool; +#if FANTASY_NET || FANTASY_UNITY || FANTASY_CONSOLE +using MongoDB.Bson.Serialization.Attributes; +#endif +using Newtonsoft.Json; +using ProtoBuf; +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member +#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. + +namespace Fantasy.Serialize +{ + public abstract class ASerialize : ISupportInitialize, IDisposable + { + public virtual void Dispose() { } + public virtual void BeginInit() { } + public virtual void EndInit() { } + public virtual void AfterDeserialization() => EndInit(); + } + + public abstract class AMessage : ASerialize, IPool + { +#if FANTASY_NET || FANTASY_UNITY || FANTASY_CONSOLE + [BsonIgnore] + [JsonIgnore] + [IgnoreDataMember] + [ProtoIgnore] + private Scene _scene; + protected Scene GetScene() + { + return _scene; + } + + public void SetScene(Scene scene) + { + _scene = scene; + } +#endif +#if FANTASY_NET + [BsonIgnore] +#endif + [JsonIgnore] + [IgnoreDataMember] + [ProtoIgnore] + private bool _isPool; + + public bool IsPool() + { + return _isPool; + } + + public void SetIsPool(bool isPool) + { + _isPool = isPool; + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Serialize/Interface/ASerialize.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Serialize/Interface/ASerialize.cs.meta new file mode 100644 index 0000000..9ab76f2 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Serialize/Interface/ASerialize.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c0d1f037ce81346e8a04a78f128b0e65 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Serialize/Interface/ISerialize.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Serialize/Interface/ISerialize.cs new file mode 100644 index 0000000..a3a9159 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Serialize/Interface/ISerialize.cs @@ -0,0 +1,87 @@ +using System; +using System.Buffers; + +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member +namespace Fantasy.Serialize +{ + public interface ISerialize + { + /// + /// 序列化器的名字,用于在协议里指定用什么协议序列化使用 + /// + string SerializeName { get; } + /// + /// 反序列化 + /// + /// + /// + /// + T Deserialize(byte[] bytes); + /// + /// 反序列化 + /// + /// + /// + /// + T Deserialize(MemoryStreamBuffer buffer); + /// + /// 反序列化 + /// + /// + /// + /// + object Deserialize(Type type, byte[] bytes); + /// + /// 反序列化 + /// + /// + /// + /// + object Deserialize(Type type, MemoryStreamBuffer buffer); + /// + /// 反序列化 + /// + /// + /// + /// + /// + /// + T Deserialize(byte[] bytes, int index, int count); + /// + /// 反序列化 + /// + /// + /// + /// + /// + /// + object Deserialize(Type type, byte[] bytes, int index, int count); + /// + /// 序列化 + /// + /// + /// + /// + void Serialize(T @object, IBufferWriter buffer); + /// + /// 序列化 + /// + /// + /// + void Serialize(object @object, IBufferWriter buffer); + /// + /// 序列化 + /// + /// + /// + /// + void Serialize(Type type, object @object, IBufferWriter buffer); + /// + /// 克隆 + /// + /// + /// + /// + T Clone(T t); + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Serialize/Interface/ISerialize.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Serialize/Interface/ISerialize.cs.meta new file mode 100644 index 0000000..e492336 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Serialize/Interface/ISerialize.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8a7d62fda7ac04f3fb7d1fd6955da409 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Serialize/MemoryStreamBuffer.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Serialize/MemoryStreamBuffer.cs new file mode 100644 index 0000000..d3176f1 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Serialize/MemoryStreamBuffer.cs @@ -0,0 +1,71 @@ +using System; +using System.Buffers; +using System.IO; +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member + +namespace Fantasy.Serialize +{ + public enum MemoryStreamBufferSource + { + None = 0, + Pack = 1, + UnPack = 2, + } + + public sealed class MemoryStreamBuffer : MemoryStream, IBufferWriter + { + public MemoryStreamBufferSource MemoryStreamBufferSource; + public MemoryStreamBuffer() { } + + public MemoryStreamBuffer(MemoryStreamBufferSource memoryStreamBufferSource, int capacity) : base(capacity) + { + MemoryStreamBufferSource = memoryStreamBufferSource; + } + public MemoryStreamBuffer(byte[] buffer): base(buffer) { } + + public void Advance(int count) + { + if (count < 0) + { + throw new ArgumentOutOfRangeException(nameof(count), count, "The value of 'count' cannot be negative."); + } + + var newLength = Position + count; + if (newLength > Length) + { + SetLength(newLength); + } + Position = newLength; + } + + public Memory GetMemory(int sizeHint = 0) + { + if (sizeHint < 0) + { + throw new ArgumentOutOfRangeException(nameof(sizeHint), sizeHint, "The value of 'count' cannot be negative."); + } + + if (Length - Position <= sizeHint) + { + SetLength(Position + sizeHint); + } + + return new Memory(GetBuffer(), (int)Position, (int)(Length - Position)); + } + + public Span GetSpan(int sizeHint = 0) + { + if (sizeHint < 0) + { + throw new ArgumentOutOfRangeException(nameof(sizeHint), sizeHint, "The value of 'count' cannot be negative."); + } + + if (Length - Position <= sizeHint) + { + SetLength(Position + sizeHint); + } + + return new Span(GetBuffer(), (int)Position, (int)(Length - Position)); + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Serialize/MemoryStreamBuffer.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Serialize/MemoryStreamBuffer.cs.meta new file mode 100644 index 0000000..21bbeed --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Serialize/MemoryStreamBuffer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8c6e3b5d66fc8451482eaf828663e6a1 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Serialize/ProtoBufPackHelper.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Serialize/ProtoBufPackHelper.meta new file mode 100644 index 0000000..b414d6f --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Serialize/ProtoBufPackHelper.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 0f56f731b0e9a4bdb931dce6773bc1e1 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Serialize/ProtoBufPackHelper/IProto.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Serialize/ProtoBufPackHelper/IProto.cs new file mode 100644 index 0000000..2267dd2 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Serialize/ProtoBufPackHelper/IProto.cs @@ -0,0 +1,9 @@ +namespace Fantasy.Serialize +{ + /// + /// 代表是一个ProtoBuf协议 + /// + public interface IProto + { + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Serialize/ProtoBufPackHelper/IProto.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Serialize/ProtoBufPackHelper/IProto.cs.meta new file mode 100644 index 0000000..eff9820 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Serialize/ProtoBufPackHelper/IProto.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d8890f4dc3e2c433fbd22b91ead3bfe4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Serialize/ProtoBufPackHelper/ProtoBufPackHelperNet.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Serialize/ProtoBufPackHelper/ProtoBufPackHelperNet.cs new file mode 100644 index 0000000..cda6b7b --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Serialize/ProtoBufPackHelper/ProtoBufPackHelperNet.cs @@ -0,0 +1,225 @@ +using System.Buffers; +using Fantasy.Assembly; +using ProtoBuf.Meta; + +#if FANTASY_NET || FANTASY_EXPORTER +namespace Fantasy.Serialize +{ + /// + /// ProtoBufP帮助类,Net平台使用 + /// + public sealed class ProtoBufPackHelper : ISerialize + { + /// + /// 序列化器的名字 + /// + public string SerializeName { get; } = "ProtoBuf"; + + /// + /// 构造函数 + /// + public ProtoBufPackHelper () + { +#if FANTASY_NET + RuntimeTypeModel.Default.AutoAddMissingTypes = true; + RuntimeTypeModel.Default.AllowParseableTypes = true; + RuntimeTypeModel.Default.AutoAddMissingTypes = true; + RuntimeTypeModel.Default.AutoCompile = true; + RuntimeTypeModel.Default.UseImplicitZeroDefaults = true; + RuntimeTypeModel.Default.InferTagFromNameDefault = true; + + foreach (var type in AssemblySystem.ForEach(typeof(IProto))) + { + RuntimeTypeModel.Default.Add(type, true); + } + + RuntimeTypeModel.Default.CompileInPlace(); +#endif + } + + /// + /// 使用ProtoBuf反序列化数据到实例 + /// + /// + /// + /// + public T Deserialize(byte[] bytes) + { + var memory = new ReadOnlyMemory(bytes); + var @object = RuntimeTypeModel.Default.Deserialize(memory); + if (@object is ASerialize aSerialize) + { + aSerialize.AfterDeserialization(); + } + return @object; + } + /// + /// 使用ProtoBuf反序列化数据到实例 + /// + /// + /// + /// + public T Deserialize(MemoryStreamBuffer buffer) + { + var @object = RuntimeTypeModel.Default.Deserialize(buffer); + if (@object is ASerialize aSerialize) + { + aSerialize.AfterDeserialization(); + } + + return @object; + } + /// + /// 使用ProtoBuf反序列化数据到实例 + /// + /// + /// + /// + public object Deserialize(Type type, byte[] bytes) + { + var memory = new ReadOnlyMemory(bytes); + var @object = RuntimeTypeModel.Default.Deserialize(type, memory); + if (@object is ASerialize aSerialize) + { + aSerialize.AfterDeserialization(); + } + + return @object; + } + /// + /// 使用ProtoBuf反序列化数据到实例 + /// + /// + /// + /// + public object Deserialize(Type type, MemoryStreamBuffer buffer) + { + var @object = RuntimeTypeModel.Default.Deserialize(type, buffer); + if (@object is ASerialize aSerialize) + { + aSerialize.AfterDeserialization(); + } + + return @object; + } + /// + /// 使用ProtoBuf反序列化数据到实例 + /// + /// + /// + /// + /// + /// + public T Deserialize(byte[] bytes, int index, int count) + { + var memory = new ReadOnlyMemory(bytes, index, count); + var @object = RuntimeTypeModel.Default.Deserialize(memory); + if (@object is ASerialize aSerialize) + { + aSerialize.AfterDeserialization(); + } + + return @object; + } + /// + /// 使用ProtoBuf反序列化数据到实例 + /// + /// + /// + /// + /// + /// + public object Deserialize(Type type, byte[] bytes, int index, int count) + { + var memory = new ReadOnlyMemory(bytes, index, count); + var @object = RuntimeTypeModel.Default.Deserialize(type, memory); + if (@object is ASerialize aSerialize) + { + aSerialize.AfterDeserialization(); + } + + return @object; + } + /// + /// 使用ProtoBuf序列化某一个实例到IBufferWriter中 + /// + /// + /// + /// + public void Serialize(T @object, IBufferWriter buffer) + { + if (@object is ASerialize aSerialize) + { + aSerialize.BeginInit(); + } + + RuntimeTypeModel.Default.Serialize(buffer, @object); + } + /// + /// 使用ProtoBuf序列化某一个实例到IBufferWriter中 + /// + /// + /// + public void Serialize(object @object, IBufferWriter buffer) + { + if (@object is ASerialize aSerialize) + { + aSerialize.BeginInit(); + } + + RuntimeTypeModel.Default.Serialize(buffer, @object); + } + /// + /// 使用ProtoBuf序列化某一个实例到IBufferWriter中 + /// + /// + /// + /// + public void Serialize(Type type, object @object, IBufferWriter buffer) + { + if (@object is ASerialize aSerialize) + { + aSerialize.BeginInit(); + } + + RuntimeTypeModel.Default.Serialize(buffer, @object); + } + internal byte[] Serialize(object @object) + { + if (@object is ASerialize aSerialize) + { + aSerialize.BeginInit(); + } + + using (var buffer = new MemoryStream()) + { + RuntimeTypeModel.Default.Serialize(buffer, @object); + return buffer.ToArray(); + } + } + private byte[] Serialize(T @object) + { + if (@object is ASerialize aSerialize) + { + aSerialize.BeginInit(); + } + + using (var buffer = new MemoryStream()) + { + RuntimeTypeModel.Default.Serialize(buffer, @object); + return buffer.ToArray(); + } + } + /// + /// 克隆 + /// + /// + /// + /// + public T Clone(T t) + { + return Deserialize(Serialize(t)); + } + } +} +#endif diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Serialize/ProtoBufPackHelper/ProtoBufPackHelperNet.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Serialize/ProtoBufPackHelper/ProtoBufPackHelperNet.cs.meta new file mode 100644 index 0000000..5378387 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Serialize/ProtoBufPackHelper/ProtoBufPackHelperNet.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d4c478636a67f47c0996ec35989d5b38 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Serialize/ProtoBufPackHelper/ProtoBufPackHelperUnity.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Serialize/ProtoBufPackHelper/ProtoBufPackHelperUnity.cs new file mode 100644 index 0000000..6df5903 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Serialize/ProtoBufPackHelper/ProtoBufPackHelperUnity.cs @@ -0,0 +1,202 @@ +#if FANTASY_UNITY || FANTASY_CONSOLE +using System; +using System.Buffers; +using System.IO; +using Fantasy.Assembly; +using ProtoBuf; +using ProtoBuf.Meta; + +namespace Fantasy.Serialize +{ + /// + /// ProtoBufP帮助类,Unity平台使用 + /// + public sealed class ProtoBufPackHelper : ISerialize + { + /// + /// 序列化器的名字 + /// + public string SerializeName { get; } = "ProtoBuf"; + + /// + /// 使用ProtoBuf反序列化数据到实例 + /// + /// + /// + /// + public unsafe T Deserialize(byte[] bytes) + { + fixed (byte* ptr = bytes) + { + using var stream = new UnmanagedMemoryStream(ptr, bytes.Length); + var @object = ProtoBuf.Serializer.Deserialize(stream); + if (@object is ASerialize aSerialize) + { + aSerialize.AfterDeserialization(); + } + return @object; + } + } + /// + /// 使用ProtoBuf反序列化数据到实例 + /// + /// + /// + /// + public T Deserialize(MemoryStreamBuffer buffer) + { + var @object = ProtoBuf.Serializer.Deserialize(buffer); + if (@object is ASerialize aSerialize) + { + aSerialize.AfterDeserialization(); + } + return @object; + } + /// + /// 使用ProtoBuf反序列化数据到实例 + /// + /// + /// + /// + public unsafe object Deserialize(Type type, byte[] bytes) + { + fixed (byte* ptr = bytes) + { + using var stream = new UnmanagedMemoryStream(ptr, bytes.Length); + var @object = ProtoBuf.Serializer.Deserialize(type, stream); + if (@object is ASerialize aSerialize) + { + aSerialize.AfterDeserialization(); + } + + return @object; + } + } + /// + /// 使用ProtoBuf反序列化数据到实例 + /// + /// + /// + /// + public object Deserialize(Type type, MemoryStreamBuffer buffer) + { + var @object = ProtoBuf.Serializer.Deserialize(type, buffer); + if (@object is ASerialize aSerialize) + { + aSerialize.AfterDeserialization(); + } + + return @object; + } + /// + /// 使用ProtoBuf反序列化数据到实例 + /// + /// + /// + /// + /// + /// + public unsafe T Deserialize(byte[] bytes, int index, int count) + { + fixed (byte* ptr = &bytes[index]) + { + using var stream = new UnmanagedMemoryStream(ptr, count); + var @object = ProtoBuf.Serializer.Deserialize(stream); + if (@object is ASerialize aSerialize) + { + aSerialize.AfterDeserialization(); + } + return @object; + } + } + /// + /// 使用ProtoBuf反序列化数据到实例 + /// + /// + /// + /// + /// + /// + public unsafe object Deserialize(Type type, byte[] bytes, int index, int count) + { + fixed (byte* ptr = &bytes[index]) + { + using var stream = new UnmanagedMemoryStream(ptr, count); + var @object = ProtoBuf.Serializer.Deserialize(type, stream); + if (@object is ASerialize aSerialize) + { + aSerialize.AfterDeserialization(); + } + return @object; + } + } + /// + /// 使用ProtoBuf序列化某一个实例到IBufferWriter中 + /// + /// + /// + /// + public void Serialize(T @object, IBufferWriter buffer) + { + if (@object is ASerialize aSerialize) + { + aSerialize.BeginInit(); + } + + RuntimeTypeModel.Default.Serialize((MemoryStream)buffer, @object); + } + /// + /// 使用ProtoBuf序列化某一个实例到IBufferWriter中 + /// + /// + /// + public void Serialize(object @object, IBufferWriter buffer) + { + if (@object is ASerialize aSerialize) + { + aSerialize.BeginInit(); + } + + RuntimeTypeModel.Default.Serialize((MemoryStream)buffer, @object); + } + /// + /// 使用ProtoBuf序列化某一个实例到IBufferWriter中 + /// + /// + /// + /// + public void Serialize(Type type, object @object, IBufferWriter buffer) + { + if (@object is ASerialize aSerialize) + { + aSerialize.BeginInit(); + } + + RuntimeTypeModel.Default.Serialize((MemoryStream)buffer, @object); + } + private byte[] Serialize(T @object) + { + if (@object is ASerialize aSerialize) + { + aSerialize.BeginInit(); + } + + using (var buffer = new MemoryStream()) + { + RuntimeTypeModel.Default.Serialize(buffer, @object); + return buffer.ToArray(); + } + } + /// + /// 克隆 + /// + /// + /// + /// + public T Clone(T t) + { + return Deserialize(Serialize(t)); + } + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Serialize/ProtoBufPackHelper/ProtoBufPackHelperUnity.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Serialize/ProtoBufPackHelper/ProtoBufPackHelperUnity.cs.meta new file mode 100644 index 0000000..acf19ee --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Serialize/ProtoBufPackHelper/ProtoBufPackHelperUnity.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b5e2bbc6d50014a4693df1cf25208d0d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Serialize/SerializerManager.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Serialize/SerializerManager.cs new file mode 100644 index 0000000..dc49bf0 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Serialize/SerializerManager.cs @@ -0,0 +1,153 @@ +using System; +using System.Collections.Generic; +using Fantasy.Assembly; +using Fantasy.Helper; +#if !FANTASY_EXPORTER +using Fantasy.Network; +#endif +using ProtoBuf; +#pragma warning disable CS8604 // Possible null reference argument. +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. +#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. +#pragma warning disable CS8602 // Dereference of a possibly null reference. +#pragma warning disable CS8600 // Converting null literal or possible null value to non-nullable type. + +namespace Fantasy.Serialize +{ + /// + /// 框架内置的序列化器类型 + /// + public static class FantasySerializerType + { + /// + /// ProtoBuf在SerializerManager的数组下标 + /// + public const int ProtoBuf = 0; + /// + /// Bson在SerializerManager的数组下标 + /// + public const int Bson = 1; + } + + /// + /// 管理序列化静态方法,主要是优化网络协议时使用。 + /// + public static class SerializerManager + { + private static ISerialize[] _serializers; + private static bool _isInitialized = false; + +#if FANTASY_NET || FANTASY_UNITY + /// + /// 初始化方法 + /// + public static void Initialize() + { + if (_isInitialized) + { + return; + } + + try + { + var sort = new SortedList(); + + foreach (var serializerType in AssemblySystem.ForEach(typeof(ISerialize))) + { + var serializer = (ISerialize)Activator.CreateInstance(serializerType); + var computeHash64 = HashCodeHelper.ComputeHash64(serializer.SerializeName); + sort.Add(computeHash64, serializer); + } + + var index = 1; + _serializers = new ISerialize[sort.Count]; + + foreach (var (_, serialize) in sort) + { + var serializerIndex = 0; + + switch (serialize) + { + case ProtoBufPackHelper: + { + serializerIndex = FantasySerializerType.ProtoBuf; + break; + } + case BsonPackHelper: + { + serializerIndex = FantasySerializerType.Bson; + break; + } + default: + { + serializerIndex = ++index; + break; + } + } + + _serializers[serializerIndex] = serialize; + } + + _isInitialized = true; + Log.Info($"初始化序列化器成功,数量为:{_serializers.Length}"); + } + catch (Exception e) + { + Log.Error(e); + Dispose(); + } + } +#else + /// + /// 初始化方法 + /// + public static void Initialize() + { + if (_isInitialized) + { + return; + } + + _serializers = new ISerialize[1]; + _serializers[0] = new ProtoBufPackHelper(); + } +#endif + + /// + /// 销毁方法 + /// + public static void Dispose() + { + _isInitialized = false; + Array.Clear(_serializers, 0, _serializers.Length); + } + + /// + /// 根据协议类型获取序列化器 + /// + /// + /// + public static ISerialize GetSerializer(uint opCodeProtocolType) + { + return _serializers[opCodeProtocolType]; + } + + /// + /// 获得一个序列化器 + /// + /// + /// + /// + public static bool TryGetSerializer(uint opCodeProtocolType, out ISerialize serializer) + { + if (opCodeProtocolType < _serializers.Length) + { + serializer = _serializers[opCodeProtocolType]; + return true; + } + + serializer = default; + return false; + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Serialize/SerializerManager.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Serialize/SerializerManager.cs.meta new file mode 100644 index 0000000..e4fd974 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Core/Serialize/SerializerManager.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 697ffcbc908194a5c9175595fd4e78e9 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins.meta new file mode 100644 index 0000000..84256f2 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 9903bfee614344015878f1daf14b44de +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Other.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Other.meta new file mode 100644 index 0000000..66d0161 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Other.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 66d4e7e54eaf44c4899b6a1ab0fea535 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Other/System.Collections.Immutable.dll b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Other/System.Collections.Immutable.dll new file mode 100644 index 0000000..3082288 Binary files /dev/null and b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Other/System.Collections.Immutable.dll differ diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Other/System.Collections.Immutable.dll.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Other/System.Collections.Immutable.dll.meta new file mode 100644 index 0000000..48ccb8b --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Other/System.Collections.Immutable.dll.meta @@ -0,0 +1,94 @@ +fileFormatVersion: 2 +guid: ce833409ea91b4422b820f1c70284317 +labels: +- NuGetForUnity +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 1 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + : Any + second: + enabled: 0 + settings: + Exclude Android: 0 + Exclude Editor: 0 + Exclude Linux64: 0 + Exclude OSXUniversal: 0 + Exclude WebGL: 0 + Exclude Win: 0 + Exclude Win64: 0 + Exclude iOS: 0 + - first: + Android: Android + second: + enabled: 1 + settings: + CPU: ARMv7 + - first: + Any: + second: + enabled: 1 + settings: {} + - first: + Editor: Editor + second: + enabled: 1 + settings: + CPU: AnyCPU + DefaultValueInitialized: true + OS: AnyOS + - first: + Standalone: Linux64 + second: + enabled: 1 + settings: + CPU: x86_64 + - first: + Standalone: OSXUniversal + second: + enabled: 1 + settings: + CPU: AnyCPU + - first: + Standalone: Win + second: + enabled: 1 + settings: + CPU: x86 + - first: + Standalone: Win64 + second: + enabled: 1 + settings: + CPU: x86_64 + - first: + WebGL: WebGL + second: + enabled: 1 + settings: {} + - first: + Windows Store Apps: WindowsStoreApps + second: + enabled: 0 + settings: + CPU: AnyCPU + - first: + iPhone: iOS + second: + enabled: 1 + settings: + AddToEmbeddedBinaries: false + CPU: AnyCPU + CompileFlags: + FrameworkDependencies: + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Other/System.IO.Pipelines.dll b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Other/System.IO.Pipelines.dll new file mode 100644 index 0000000..003bcd0 Binary files /dev/null and b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Other/System.IO.Pipelines.dll differ diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Other/System.IO.Pipelines.dll.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Other/System.IO.Pipelines.dll.meta new file mode 100644 index 0000000..7909033 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Other/System.IO.Pipelines.dll.meta @@ -0,0 +1,92 @@ +fileFormatVersion: 2 +guid: 5ea484bad04534c33b3b128ff1e85ed3 +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 1 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + : Any + second: + enabled: 0 + settings: + Exclude Android: 0 + Exclude Editor: 0 + Exclude Linux64: 0 + Exclude OSXUniversal: 0 + Exclude WebGL: 0 + Exclude Win: 0 + Exclude Win64: 0 + Exclude iOS: 0 + - first: + Android: Android + second: + enabled: 1 + settings: + CPU: ARMv7 + - first: + Any: + second: + enabled: 1 + settings: {} + - first: + Editor: Editor + second: + enabled: 1 + settings: + CPU: AnyCPU + DefaultValueInitialized: true + OS: AnyOS + - first: + Standalone: Linux64 + second: + enabled: 1 + settings: + CPU: AnyCPU + - first: + Standalone: OSXUniversal + second: + enabled: 1 + settings: + CPU: AnyCPU + - first: + Standalone: Win + second: + enabled: 1 + settings: + CPU: AnyCPU + - first: + Standalone: Win64 + second: + enabled: 1 + settings: + CPU: AnyCPU + - first: + WebGL: WebGL + second: + enabled: 1 + settings: {} + - first: + Windows Store Apps: WindowsStoreApps + second: + enabled: 0 + settings: + CPU: AnyCPU + - first: + iPhone: iOS + second: + enabled: 1 + settings: + AddToEmbeddedBinaries: false + CPU: AnyCPU + CompileFlags: + FrameworkDependencies: + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Other/System.Runtime.CompilerServices.Unsafe.dll b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Other/System.Runtime.CompilerServices.Unsafe.dll new file mode 100644 index 0000000..491a80a Binary files /dev/null and b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Other/System.Runtime.CompilerServices.Unsafe.dll differ diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Other/System.Runtime.CompilerServices.Unsafe.dll.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Other/System.Runtime.CompilerServices.Unsafe.dll.meta new file mode 100644 index 0000000..69e5f69 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Other/System.Runtime.CompilerServices.Unsafe.dll.meta @@ -0,0 +1,35 @@ +fileFormatVersion: 2 +guid: bd2b66cfee2b94dea92a1ff0385fa0cb +labels: +- NuGetForUnity +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 1 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + Any: + second: + enabled: 1 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + - first: + Windows Store Apps: WindowsStoreApps + second: + enabled: 0 + settings: + CPU: AnyCPU + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net.meta new file mode 100644 index 0000000..d7e5543 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: a612f894ce7024629851208a425b70cc +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/BclHelpers.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/BclHelpers.cs new file mode 100644 index 0000000..bcff9a4 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/BclHelpers.cs @@ -0,0 +1,712 @@ +using System; +using System.Reflection; +namespace ProtoBuf +{ + internal enum TimeSpanScale + { + Days = 0, + Hours = 1, + Minutes = 2, + Seconds = 3, + Milliseconds = 4, + Ticks = 5, + + MinMax = 15 + } + + /// + /// Provides support for common .NET types that do not have a direct representation + /// in protobuf, using the definitions from bcl.proto + /// + public static class BclHelpers + { + /// + /// Creates a new instance of the specified type, bypassing the constructor. + /// + /// The type to create + /// The new instance + /// If the platform does not support constructor-skipping + public static object GetUninitializedObject(Type type) + { +#if COREFX + object obj = TryGetUninitializedObjectWithFormatterServices(type); + if (obj != null) return obj; +#endif +#if PLAT_BINARYFORMATTER && !(COREFX || PROFILE259) + return System.Runtime.Serialization.FormatterServices.GetUninitializedObject(type); +#else + throw new NotSupportedException("Constructor-skipping is not supported on this platform"); +#endif + } + +#if COREFX // this is inspired by DCS: https://github.com/dotnet/corefx/blob/c02d33b18398199f6acc17d375dab154e9a1df66/src/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlFormatReaderGenerator.cs#L854-L894 + static Func getUninitializedObject; + static internal object TryGetUninitializedObjectWithFormatterServices(Type type) + { + if (getUninitializedObject == null) + { + try { + var formatterServiceType = typeof(string).GetTypeInfo().Assembly.GetType("System.Runtime.Serialization.FormatterServices"); + if (formatterServiceType == null) + { + // fallback for .Net Core 3.0 + var formatterAssembly = Assembly.Load(new AssemblyName("System.Runtime.Serialization.Formatters")); + formatterServiceType = formatterAssembly.GetType("System.Runtime.Serialization.FormatterServices"); + } + MethodInfo method = formatterServiceType?.GetMethod("GetUninitializedObject", BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static); + if (method != null) + { + getUninitializedObject = (Func)method.CreateDelegate(typeof(Func)); + } + } + catch { /* best efforts only */ } + if(getUninitializedObject == null) getUninitializedObject = x => null; + } + return getUninitializedObject(type); + } +#endif + + const int FieldTimeSpanValue = 0x01, FieldTimeSpanScale = 0x02, FieldTimeSpanKind = 0x03; + + internal static readonly DateTime[] EpochOrigin = { + new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), + new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc), + new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Local) + }; + + /// + /// The default value for dates that are following google.protobuf.Timestamp semantics + /// + private static readonly DateTime TimestampEpoch = EpochOrigin[(int)DateTimeKind.Utc]; + + /// + /// Writes a TimeSpan to a protobuf stream using protobuf-net's own representation, bcl.TimeSpan + /// + public static void WriteTimeSpan(TimeSpan timeSpan, ProtoWriter dest) + { + WriteTimeSpanImpl(timeSpan, dest, DateTimeKind.Unspecified); + } + + private static void WriteTimeSpanImpl(TimeSpan timeSpan, ProtoWriter dest, DateTimeKind kind) + { + if (dest == null) throw new ArgumentNullException(nameof(dest)); + long value; + switch (dest.WireType) + { + case WireType.String: + case WireType.StartGroup: + TimeSpanScale scale; + value = timeSpan.Ticks; + if (timeSpan == TimeSpan.MaxValue) + { + value = 1; + scale = TimeSpanScale.MinMax; + } + else if (timeSpan == TimeSpan.MinValue) + { + value = -1; + scale = TimeSpanScale.MinMax; + } + else if (value % TimeSpan.TicksPerDay == 0) + { + scale = TimeSpanScale.Days; + value /= TimeSpan.TicksPerDay; + } + else if (value % TimeSpan.TicksPerHour == 0) + { + scale = TimeSpanScale.Hours; + value /= TimeSpan.TicksPerHour; + } + else if (value % TimeSpan.TicksPerMinute == 0) + { + scale = TimeSpanScale.Minutes; + value /= TimeSpan.TicksPerMinute; + } + else if (value % TimeSpan.TicksPerSecond == 0) + { + scale = TimeSpanScale.Seconds; + value /= TimeSpan.TicksPerSecond; + } + else if (value % TimeSpan.TicksPerMillisecond == 0) + { + scale = TimeSpanScale.Milliseconds; + value /= TimeSpan.TicksPerMillisecond; + } + else + { + scale = TimeSpanScale.Ticks; + } + + SubItemToken token = ProtoWriter.StartSubItem(null, dest); + + if (value != 0) + { + ProtoWriter.WriteFieldHeader(FieldTimeSpanValue, WireType.SignedVariant, dest); + ProtoWriter.WriteInt64(value, dest); + } + if (scale != TimeSpanScale.Days) + { + ProtoWriter.WriteFieldHeader(FieldTimeSpanScale, WireType.Variant, dest); + ProtoWriter.WriteInt32((int)scale, dest); + } + if (kind != DateTimeKind.Unspecified) + { + ProtoWriter.WriteFieldHeader(FieldTimeSpanKind, WireType.Variant, dest); + ProtoWriter.WriteInt32((int)kind, dest); + } + ProtoWriter.EndSubItem(token, dest); + break; + case WireType.Fixed64: + ProtoWriter.WriteInt64(timeSpan.Ticks, dest); + break; + default: + throw new ProtoException("Unexpected wire-type: " + dest.WireType.ToString()); + } + } + + /// + /// Parses a TimeSpan from a protobuf stream using protobuf-net's own representation, bcl.TimeSpan + /// + public static TimeSpan ReadTimeSpan(ProtoReader source) + { + long ticks = ReadTimeSpanTicks(source, out DateTimeKind kind); + if (ticks == long.MinValue) return TimeSpan.MinValue; + if (ticks == long.MaxValue) return TimeSpan.MaxValue; + return TimeSpan.FromTicks(ticks); + } + + /// + /// Parses a TimeSpan from a protobuf stream using the standardized format, google.protobuf.Duration + /// + public static TimeSpan ReadDuration(ProtoReader source) + { + long seconds = 0; + int nanos = 0; + SubItemToken token = ProtoReader.StartSubItem(source); + int fieldNumber; + while ((fieldNumber = source.ReadFieldHeader()) > 0) + { + switch (fieldNumber) + { + case 1: + seconds = source.ReadInt64(); + break; + case 2: + nanos = source.ReadInt32(); + break; + default: + source.SkipField(); + break; + } + } + ProtoReader.EndSubItem(token, source); + return FromDurationSeconds(seconds, nanos); + } + + /// + /// Writes a TimeSpan to a protobuf stream using the standardized format, google.protobuf.Duration + /// + public static void WriteDuration(TimeSpan value, ProtoWriter dest) + { + var seconds = ToDurationSeconds(value, out int nanos); + WriteSecondsNanos(seconds, nanos, dest); + } + + private static void WriteSecondsNanos(long seconds, int nanos, ProtoWriter dest) + { + SubItemToken token = ProtoWriter.StartSubItem(null, dest); + if (seconds != 0) + { + ProtoWriter.WriteFieldHeader(1, WireType.Variant, dest); + ProtoWriter.WriteInt64(seconds, dest); + } + if (nanos != 0) + { + ProtoWriter.WriteFieldHeader(2, WireType.Variant, dest); + ProtoWriter.WriteInt32(nanos, dest); + } + ProtoWriter.EndSubItem(token, dest); + } + + /// + /// Parses a DateTime from a protobuf stream using the standardized format, google.protobuf.Timestamp + /// + public static DateTime ReadTimestamp(ProtoReader source) + { + // note: DateTime is only defined for just over 0000 to just below 10000; + // TimeSpan has a range of +/- 10,675,199 days === 29k years; + // so we can just use epoch time delta + return TimestampEpoch + ReadDuration(source); + } + + /// + /// Writes a DateTime to a protobuf stream using the standardized format, google.protobuf.Timestamp + /// + public static void WriteTimestamp(DateTime value, ProtoWriter dest) + { + var seconds = ToDurationSeconds(value - TimestampEpoch, out int nanos); + + if (nanos < 0) + { // from Timestamp.proto: + // "Negative second values with fractions must still have + // non -negative nanos values that count forward in time." + seconds--; + nanos += 1000000000; + } + WriteSecondsNanos(seconds, nanos, dest); + } + + static TimeSpan FromDurationSeconds(long seconds, int nanos) + { + + long ticks = checked((seconds * TimeSpan.TicksPerSecond) + + (nanos * TimeSpan.TicksPerMillisecond) / 1000000); + return TimeSpan.FromTicks(ticks); + } + + static long ToDurationSeconds(TimeSpan value, out int nanos) + { + nanos = (int)(((value.Ticks % TimeSpan.TicksPerSecond) * 1000000) + / TimeSpan.TicksPerMillisecond); + return value.Ticks / TimeSpan.TicksPerSecond; + } + + /// + /// Parses a DateTime from a protobuf stream + /// + public static DateTime ReadDateTime(ProtoReader source) + { + long ticks = ReadTimeSpanTicks(source, out DateTimeKind kind); + if (ticks == long.MinValue) return DateTime.MinValue; + if (ticks == long.MaxValue) return DateTime.MaxValue; + return EpochOrigin[(int)kind].AddTicks(ticks); + } + + /// + /// Writes a DateTime to a protobuf stream, excluding the Kind + /// + public static void WriteDateTime(DateTime value, ProtoWriter dest) + { + WriteDateTimeImpl(value, dest, false); + } + + /// + /// Writes a DateTime to a protobuf stream, including the Kind + /// + public static void WriteDateTimeWithKind(DateTime value, ProtoWriter dest) + { + WriteDateTimeImpl(value, dest, true); + } + + private static void WriteDateTimeImpl(DateTime value, ProtoWriter dest, bool includeKind) + { + if (dest == null) throw new ArgumentNullException(nameof(dest)); + TimeSpan delta; + switch (dest.WireType) + { + case WireType.StartGroup: + case WireType.String: + if (value == DateTime.MaxValue) + { + delta = TimeSpan.MaxValue; + includeKind = false; + } + else if (value == DateTime.MinValue) + { + delta = TimeSpan.MinValue; + includeKind = false; + } + else + { + delta = value - EpochOrigin[0]; + } + break; + default: + delta = value - EpochOrigin[0]; + break; + } + WriteTimeSpanImpl(delta, dest, includeKind ? value.Kind : DateTimeKind.Unspecified); + } + + private static long ReadTimeSpanTicks(ProtoReader source, out DateTimeKind kind) + { + kind = DateTimeKind.Unspecified; + switch (source.WireType) + { + case WireType.String: + case WireType.StartGroup: + SubItemToken token = ProtoReader.StartSubItem(source); + int fieldNumber; + TimeSpanScale scale = TimeSpanScale.Days; + long value = 0; + while ((fieldNumber = source.ReadFieldHeader()) > 0) + { + switch (fieldNumber) + { + case FieldTimeSpanScale: + scale = (TimeSpanScale)source.ReadInt32(); + break; + case FieldTimeSpanValue: + source.Assert(WireType.SignedVariant); + value = source.ReadInt64(); + break; + case FieldTimeSpanKind: + kind = (DateTimeKind)source.ReadInt32(); + switch (kind) + { + case DateTimeKind.Unspecified: + case DateTimeKind.Utc: + case DateTimeKind.Local: + break; // fine + default: + throw new ProtoException("Invalid date/time kind: " + kind.ToString()); + } + break; + default: + source.SkipField(); + break; + } + } + ProtoReader.EndSubItem(token, source); + switch (scale) + { + case TimeSpanScale.Days: + return value * TimeSpan.TicksPerDay; + case TimeSpanScale.Hours: + return value * TimeSpan.TicksPerHour; + case TimeSpanScale.Minutes: + return value * TimeSpan.TicksPerMinute; + case TimeSpanScale.Seconds: + return value * TimeSpan.TicksPerSecond; + case TimeSpanScale.Milliseconds: + return value * TimeSpan.TicksPerMillisecond; + case TimeSpanScale.Ticks: + return value; + case TimeSpanScale.MinMax: + switch (value) + { + case 1: return long.MaxValue; + case -1: return long.MinValue; + default: throw new ProtoException("Unknown min/max value: " + value.ToString()); + } + default: + throw new ProtoException("Unknown timescale: " + scale.ToString()); + } + case WireType.Fixed64: + return source.ReadInt64(); + default: + throw new ProtoException("Unexpected wire-type: " + source.WireType.ToString()); + } + } + + const int FieldDecimalLow = 0x01, FieldDecimalHigh = 0x02, FieldDecimalSignScale = 0x03; + + /// + /// Parses a decimal from a protobuf stream + /// + public static decimal ReadDecimal(ProtoReader reader) + { + ulong low = 0; + uint high = 0; + uint signScale = 0; + + int fieldNumber; + SubItemToken token = ProtoReader.StartSubItem(reader); + while ((fieldNumber = reader.ReadFieldHeader()) > 0) + { + switch (fieldNumber) + { + case FieldDecimalLow: low = reader.ReadUInt64(); break; + case FieldDecimalHigh: high = reader.ReadUInt32(); break; + case FieldDecimalSignScale: signScale = reader.ReadUInt32(); break; + default: reader.SkipField(); break; + } + + } + ProtoReader.EndSubItem(token, reader); + + int lo = (int)(low & 0xFFFFFFFFL), + mid = (int)((low >> 32) & 0xFFFFFFFFL), + hi = (int)high; + bool isNeg = (signScale & 0x0001) == 0x0001; + byte scale = (byte)((signScale & 0x01FE) >> 1); + return new decimal(lo, mid, hi, isNeg, scale); + } + + /// + /// Writes a decimal to a protobuf stream + /// + public static void WriteDecimal(decimal value, ProtoWriter writer) + { + int[] bits = decimal.GetBits(value); + ulong a = ((ulong)bits[1]) << 32, b = ((ulong)bits[0]) & 0xFFFFFFFFL; + ulong low = a | b; + uint high = (uint)bits[2]; + uint signScale = (uint)(((bits[3] >> 15) & 0x01FE) | ((bits[3] >> 31) & 0x0001)); + + SubItemToken token = ProtoWriter.StartSubItem(null, writer); + if (low != 0) + { + ProtoWriter.WriteFieldHeader(FieldDecimalLow, WireType.Variant, writer); + ProtoWriter.WriteUInt64(low, writer); + } + if (high != 0) + { + ProtoWriter.WriteFieldHeader(FieldDecimalHigh, WireType.Variant, writer); + ProtoWriter.WriteUInt32(high, writer); + } + if (signScale != 0) + { + ProtoWriter.WriteFieldHeader(FieldDecimalSignScale, WireType.Variant, writer); + ProtoWriter.WriteUInt32(signScale, writer); + } + ProtoWriter.EndSubItem(token, writer); + } + + const int FieldGuidLow = 1, FieldGuidHigh = 2; + /// + /// Writes a Guid to a protobuf stream + /// + public static void WriteGuid(Guid value, ProtoWriter dest) + { + byte[] blob = value.ToByteArray(); + + SubItemToken token = ProtoWriter.StartSubItem(null, dest); + if (value != Guid.Empty) + { + ProtoWriter.WriteFieldHeader(FieldGuidLow, WireType.Fixed64, dest); + ProtoWriter.WriteBytes(blob, 0, 8, dest); + ProtoWriter.WriteFieldHeader(FieldGuidHigh, WireType.Fixed64, dest); + ProtoWriter.WriteBytes(blob, 8, 8, dest); + } + ProtoWriter.EndSubItem(token, dest); + } + /// + /// Parses a Guid from a protobuf stream + /// + public static Guid ReadGuid(ProtoReader source) + { + ulong low = 0, high = 0; + int fieldNumber; + SubItemToken token = ProtoReader.StartSubItem(source); + while ((fieldNumber = source.ReadFieldHeader()) > 0) + { + switch (fieldNumber) + { + case FieldGuidLow: low = source.ReadUInt64(); break; + case FieldGuidHigh: high = source.ReadUInt64(); break; + default: source.SkipField(); break; + } + } + ProtoReader.EndSubItem(token, source); + if (low == 0 && high == 0) return Guid.Empty; + uint a = (uint)(low >> 32), b = (uint)low, c = (uint)(high >> 32), d = (uint)high; + return new Guid((int)b, (short)a, (short)(a >> 16), + (byte)d, (byte)(d >> 8), (byte)(d >> 16), (byte)(d >> 24), + (byte)c, (byte)(c >> 8), (byte)(c >> 16), (byte)(c >> 24)); + + } + + + private const int + FieldExistingObjectKey = 1, + FieldNewObjectKey = 2, + FieldExistingTypeKey = 3, + FieldNewTypeKey = 4, + FieldTypeName = 8, + FieldObject = 10; + + /// + /// Optional behaviours that introduce .NET-specific functionality + /// + [Flags] + public enum NetObjectOptions : byte + { + /// + /// No special behaviour + /// + None = 0, + /// + /// Enables full object-tracking/full-graph support. + /// + AsReference = 1, + /// + /// Embeds the type information into the stream, allowing usage with types not known in advance. + /// + DynamicType = 2, + /// + /// If false, the constructor for the type is bypassed during deserialization, meaning any field initializers + /// or other initialization code is skipped. + /// + UseConstructor = 4, + /// + /// Should the object index be reserved, rather than creating an object promptly + /// + LateSet = 8 + } + + /// + /// Reads an *implementation specific* bundled .NET object, including (as options) type-metadata, identity/re-use, etc. + /// + public static object ReadNetObject(object value, ProtoReader source, int key, Type type, NetObjectOptions options) + { + SubItemToken token = ProtoReader.StartSubItem(source); + int fieldNumber; + int newObjectKey = -1, newTypeKey = -1, tmp; + while ((fieldNumber = source.ReadFieldHeader()) > 0) + { + switch (fieldNumber) + { + case FieldExistingObjectKey: + tmp = source.ReadInt32(); + value = source.NetCache.GetKeyedObject(tmp); + break; + case FieldNewObjectKey: + newObjectKey = source.ReadInt32(); + break; + case FieldExistingTypeKey: + tmp = source.ReadInt32(); + type = (Type)source.NetCache.GetKeyedObject(tmp); + key = source.GetTypeKey(ref type); + break; + case FieldNewTypeKey: + newTypeKey = source.ReadInt32(); + break; + case FieldTypeName: + string typeName = source.ReadString(); + type = source.DeserializeType(typeName); + if (type == null) + { + throw new ProtoException("Unable to resolve type: " + typeName + " (you can use the TypeModel.DynamicTypeFormatting event to provide a custom mapping)"); + } + if (type == typeof(string)) + { + key = -1; + } + else + { + key = source.GetTypeKey(ref type); + if (key < 0) + throw new InvalidOperationException("Dynamic type is not a contract-type: " + type.Name); + } + break; + case FieldObject: + bool isString = type == typeof(string); + bool wasNull = value == null; + bool lateSet = wasNull && (isString || ((options & NetObjectOptions.LateSet) != 0)); + + if (newObjectKey >= 0 && !lateSet) + { + if (value == null) + { + source.TrapNextObject(newObjectKey); + } + else + { + source.NetCache.SetKeyedObject(newObjectKey, value); + } + if (newTypeKey >= 0) source.NetCache.SetKeyedObject(newTypeKey, type); + } + object oldValue = value; + if (isString) + { + value = source.ReadString(); + } + else + { + value = ProtoReader.ReadTypedObject(oldValue, key, source, type); + } + + if (newObjectKey >= 0) + { + if (wasNull && !lateSet) + { // this both ensures (via exception) that it *was* set, and makes sure we don't shout + // about changed references + oldValue = source.NetCache.GetKeyedObject(newObjectKey); + } + if (lateSet) + { + source.NetCache.SetKeyedObject(newObjectKey, value); + if (newTypeKey >= 0) source.NetCache.SetKeyedObject(newTypeKey, type); + } + } + if (newObjectKey >= 0 && !lateSet && !ReferenceEquals(oldValue, value)) + { + throw new ProtoException("A reference-tracked object changed reference during deserialization"); + } + if (newObjectKey < 0 && newTypeKey >= 0) + { // have a new type, but not a new object + source.NetCache.SetKeyedObject(newTypeKey, type); + } + break; + default: + source.SkipField(); + break; + } + } + if (newObjectKey >= 0 && (options & NetObjectOptions.AsReference) == 0) + { + throw new ProtoException("Object key in input stream, but reference-tracking was not expected"); + } + ProtoReader.EndSubItem(token, source); + + return value; + } + + /// + /// Writes an *implementation specific* bundled .NET object, including (as options) type-metadata, identity/re-use, etc. + /// + public static void WriteNetObject(object value, ProtoWriter dest, int key, NetObjectOptions options) + { + if (dest == null) throw new ArgumentNullException("dest"); + bool dynamicType = (options & NetObjectOptions.DynamicType) != 0, + asReference = (options & NetObjectOptions.AsReference) != 0; + WireType wireType = dest.WireType; + SubItemToken token = ProtoWriter.StartSubItem(null, dest); + bool writeObject = true; + if (asReference) + { + int objectKey = dest.NetCache.AddObjectKey(value, out bool existing); + ProtoWriter.WriteFieldHeader(existing ? FieldExistingObjectKey : FieldNewObjectKey, WireType.Variant, dest); + ProtoWriter.WriteInt32(objectKey, dest); + if (existing) + { + writeObject = false; + } + } + + if (writeObject) + { + if (dynamicType) + { + Type type = value.GetType(); + + if (!(value is string)) + { + key = dest.GetTypeKey(ref type); + if (key < 0) throw new InvalidOperationException("Dynamic type is not a contract-type: " + type.Name); + } + int typeKey = dest.NetCache.AddObjectKey(type, out bool existing); + ProtoWriter.WriteFieldHeader(existing ? FieldExistingTypeKey : FieldNewTypeKey, WireType.Variant, dest); + ProtoWriter.WriteInt32(typeKey, dest); + if (!existing) + { + ProtoWriter.WriteFieldHeader(FieldTypeName, WireType.String, dest); + ProtoWriter.WriteString(dest.SerializeType(type), dest); + } + + } + ProtoWriter.WriteFieldHeader(FieldObject, wireType, dest); + if (value is string) + { + ProtoWriter.WriteString((string)value, dest); + } + else + { + ProtoWriter.WriteObject(value, key, dest); + } + } + ProtoWriter.EndSubItem(token, dest); + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/BclHelpers.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/BclHelpers.cs.meta new file mode 100644 index 0000000..da3a37a --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/BclHelpers.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 5072fbed211eb9f43a3cd2805dd75ef7 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/BufferExtension.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/BufferExtension.cs new file mode 100644 index 0000000..ea428dd --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/BufferExtension.cs @@ -0,0 +1,78 @@ +using System; +using System.IO; + +namespace ProtoBuf +{ + /// + /// Provides a simple buffer-based implementation of an extension object. + /// + public sealed class BufferExtension : IExtension, IExtensionResettable + { + private byte[] buffer; + + void IExtensionResettable.Reset() + { + buffer = null; + } + + int IExtension.GetLength() + { + return buffer == null ? 0 : buffer.Length; + } + + Stream IExtension.BeginAppend() + { + return new MemoryStream(); + } + + void IExtension.EndAppend(Stream stream, bool commit) + { + using (stream) + { + int len; + if (commit && (len = (int)stream.Length) > 0) + { + MemoryStream ms = (MemoryStream)stream; + + if (buffer == null) + { // allocate new buffer + buffer = ms.ToArray(); + } + else + { // resize and copy the data + // note: Array.Resize not available on CF + int offset = buffer.Length; + byte[] tmp = new byte[offset + len]; + Buffer.BlockCopy(buffer, 0, tmp, 0, offset); + +#if PORTABLE // no GetBuffer() - fine, we'll use Read instead + int bytesRead; + long oldPos = ms.Position; + ms.Position = 0; + while (len > 0 && (bytesRead = ms.Read(tmp, offset, len)) > 0) + { + len -= bytesRead; + offset += bytesRead; + } + if(len != 0) throw new EndOfStreamException(); + ms.Position = oldPos; +#else + Buffer.BlockCopy(Helpers.GetBuffer(ms), 0, tmp, offset, len); +#endif + buffer = tmp; + } + } + } + } + + Stream IExtension.BeginQuery() + { + return buffer == null ? Stream.Null : new MemoryStream(buffer); + } + + void IExtension.EndQuery(Stream stream) + { + using (stream) { } // just clean up + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/BufferExtension.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/BufferExtension.cs.meta new file mode 100644 index 0000000..4a39591 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/BufferExtension.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a9cf66041a027e94892d5014c2b905b3 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/BufferPool.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/BufferPool.cs new file mode 100644 index 0000000..8ad3d1a --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/BufferPool.cs @@ -0,0 +1,149 @@ +using System; + +namespace ProtoBuf +{ + internal sealed class BufferPool + { + internal static void Flush() + { + lock (Pool) + { + for (var i = 0; i < Pool.Length; i++) + Pool[i] = null; + } + } + + private BufferPool() { } + private const int POOL_SIZE = 20; + internal const int BUFFER_LENGTH = 1024; + private static readonly CachedBuffer[] Pool = new CachedBuffer[POOL_SIZE]; + + internal static byte[] GetBuffer() => GetBuffer(BUFFER_LENGTH); + + internal static byte[] GetBuffer(int minSize) + { + byte[] cachedBuff = GetCachedBuffer(minSize); + return cachedBuff ?? new byte[minSize]; + } + + internal static byte[] GetCachedBuffer(int minSize) + { + lock (Pool) + { + var bestIndex = -1; + byte[] bestMatch = null; + for (var i = 0; i < Pool.Length; i++) + { + var buffer = Pool[i]; + if (buffer == null || buffer.Size < minSize) + { + continue; + } + if (bestMatch != null && bestMatch.Length < buffer.Size) + { + continue; + } + + var tmp = buffer.Buffer; + if (tmp == null) + { + Pool[i] = null; + } + else + { + bestMatch = tmp; + bestIndex = i; + } + } + + if (bestIndex >= 0) + { + Pool[bestIndex] = null; + } + + return bestMatch; + } + } + + /// + /// https://docs.microsoft.com/en-us/dotnet/framework/configure-apps/file-schema/runtime/gcallowverylargeobjects-element + /// + private const int MaxByteArraySize = int.MaxValue - 56; + + internal static void ResizeAndFlushLeft(ref byte[] buffer, int toFitAtLeastBytes, int copyFromIndex, int copyBytes) + { + Helpers.DebugAssert(buffer != null); + Helpers.DebugAssert(toFitAtLeastBytes > buffer.Length); + Helpers.DebugAssert(copyFromIndex >= 0); + Helpers.DebugAssert(copyBytes >= 0); + + int newLength = buffer.Length * 2; + if (newLength < 0) + { + newLength = MaxByteArraySize; + } + + if (newLength < toFitAtLeastBytes) newLength = toFitAtLeastBytes; + + if (copyBytes == 0) + { + ReleaseBufferToPool(ref buffer); + } + + var newBuffer = GetCachedBuffer(toFitAtLeastBytes) ?? new byte[newLength]; + + if (copyBytes > 0) + { + Buffer.BlockCopy(buffer, copyFromIndex, newBuffer, 0, copyBytes); + ReleaseBufferToPool(ref buffer); + } + + buffer = newBuffer; + } + + internal static void ReleaseBufferToPool(ref byte[] buffer) + { + if (buffer == null) return; + + lock (Pool) + { + var minIndex = 0; + var minSize = int.MaxValue; + for (var i = 0; i < Pool.Length; i++) + { + var tmp = Pool[i]; + if (tmp == null || !tmp.IsAlive) + { + minIndex = 0; + break; + } + if (tmp.Size < minSize) + { + minIndex = i; + minSize = tmp.Size; + } + } + + Pool[minIndex] = new CachedBuffer(buffer); + } + + buffer = null; + } + + private class CachedBuffer + { + private readonly WeakReference _reference; + + public int Size { get; } + + public bool IsAlive => _reference.IsAlive; + public byte[] Buffer => (byte[])_reference.Target; + + public CachedBuffer(byte[] buffer) + { + Size = buffer.Length; + _reference = new WeakReference(buffer); + } + } + } +} diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/BufferPool.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/BufferPool.cs.meta new file mode 100644 index 0000000..2870b8c --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/BufferPool.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 423b228ed060b91458bc6d4e6aa0f570 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/CallbackAttributes.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/CallbackAttributes.cs new file mode 100644 index 0000000..1adb8e5 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/CallbackAttributes.cs @@ -0,0 +1,33 @@ +using System; +using System.ComponentModel; + +namespace ProtoBuf +{ + /// Specifies a method on the root-contract in an hierarchy to be invoked before serialization. + [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)] +#if !CF && !PORTABLE && !COREFX && !PROFILE259 + [ImmutableObject(true)] +#endif + public sealed class ProtoBeforeSerializationAttribute : Attribute { } + + /// Specifies a method on the root-contract in an hierarchy to be invoked after serialization. + [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)] +#if !CF && !PORTABLE && !COREFX && !PROFILE259 + [ImmutableObject(true)] +#endif + public sealed class ProtoAfterSerializationAttribute : Attribute { } + + /// Specifies a method on the root-contract in an hierarchy to be invoked before deserialization. + [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)] +#if !CF && !PORTABLE && !COREFX && !PROFILE259 + [ImmutableObject(true)] +#endif + public sealed class ProtoBeforeDeserializationAttribute : Attribute { } + + /// Specifies a method on the root-contract in an hierarchy to be invoked after deserialization. + [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)] +#if !CF && !PORTABLE && !COREFX && !PROFILE259 + [ImmutableObject(true)] +#endif + public sealed class ProtoAfterDeserializationAttribute : Attribute { } +} diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/CallbackAttributes.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/CallbackAttributes.cs.meta new file mode 100644 index 0000000..7cf81a4 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/CallbackAttributes.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 53de2cb3784c9dd43aa6f30d7df072a4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Compiler.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Compiler.meta new file mode 100644 index 0000000..9de78a6 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Compiler.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 2cdd9eb2afa3ed24480a6035f507aad4 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Compiler/CompilerContext.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Compiler/CompilerContext.cs new file mode 100644 index 0000000..6100200 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Compiler/CompilerContext.cs @@ -0,0 +1,1435 @@ +#if FEAT_COMPILER +//#define DEBUG_COMPILE +using System; +using System.Threading; +using ProtoBuf.Meta; +using ProtoBuf.Serializers; +using System.Reflection; +using System.Reflection.Emit; + +namespace ProtoBuf.Compiler +{ + internal readonly struct CodeLabel + { + public readonly Label Value; + public readonly int Index; + public CodeLabel(Label value, int index) + { + this.Value = value; + this.Index = index; + } + } + internal sealed class CompilerContext + { + public TypeModel Model => model; + + readonly DynamicMethod method; + static int next; + + internal CodeLabel DefineLabel() + { + CodeLabel result = new CodeLabel(il.DefineLabel(), nextLabel++); + return result; + } +#if DEBUG_COMPILE + static readonly string traceCompilePath; + static CompilerContext() + { + traceCompilePath = System.IO.Path.Combine(System.IO.Directory.GetCurrentDirectory(), + "TraceCompile.txt"); + Console.WriteLine("DEBUG_COMPILE enabled; writing to " + traceCompilePath); + } +#endif + [System.Diagnostics.Conditional("DEBUG_COMPILE")] + private void TraceCompile(string value) + { +#if DEBUG_COMPILE + if (!string.IsNullOrWhiteSpace(value)) + { + using (System.IO.StreamWriter sw = System.IO.File.AppendText(traceCompilePath)) + { + sw.WriteLine(value); + } + } +#endif + } + internal void MarkLabel(CodeLabel label) + { + il.MarkLabel(label.Value); + TraceCompile("#: " + label.Index); + } + + public static ProtoSerializer BuildSerializer(IProtoSerializer head, TypeModel model) + { + Type type = head.ExpectedType; + try + { + CompilerContext ctx = new CompilerContext(type, true, true, model, typeof(object)); + ctx.LoadValue(ctx.InputValue); + ctx.CastFromObject(type); + ctx.WriteNullCheckedTail(type, head, null); + ctx.Emit(OpCodes.Ret); + return (ProtoSerializer)ctx.method.CreateDelegate( + typeof(ProtoSerializer)); + } + catch (Exception ex) + { + string name = type.FullName; + if (string.IsNullOrEmpty(name)) name = type.Name; + throw new InvalidOperationException("It was not possible to prepare a serializer for: " + name, ex); + } + } + /*public static ProtoCallback BuildCallback(IProtoTypeSerializer head) + { + Type type = head.ExpectedType; + CompilerContext ctx = new CompilerContext(type, true, true); + using (Local typedVal = new Local(ctx, type)) + { + ctx.LoadValue(Local.InputValue); + ctx.CastFromObject(type); + ctx.StoreValue(typedVal); + CodeLabel[] jumpTable = new CodeLabel[4]; + for(int i = 0 ; i < jumpTable.Length ; i++) { + jumpTable[i] = ctx.DefineLabel(); + } + ctx.LoadReaderWriter(); + ctx.Switch(jumpTable); + ctx.Return(); + for(int i = 0 ; i < jumpTable.Length ; i++) { + ctx.MarkLabel(jumpTable[i]); + if (head.HasCallbacks((TypeModel.CallbackType)i)) + { + head.EmitCallback(ctx, typedVal, (TypeModel.CallbackType)i); + } + ctx.Return(); + } + } + + ctx.Emit(OpCodes.Ret); + return (ProtoCallback)ctx.method.CreateDelegate( + typeof(ProtoCallback)); + }*/ + public static ProtoDeserializer BuildDeserializer(IProtoSerializer head, TypeModel model) + { + Type type = head.ExpectedType; + CompilerContext ctx = new CompilerContext(type, false, true, model, typeof(object)); + + using (Local typedVal = new Local(ctx, type)) + { + if (!Helpers.IsValueType(type)) + { + ctx.LoadValue(ctx.InputValue); + ctx.CastFromObject(type); + ctx.StoreValue(typedVal); + } + else + { + ctx.LoadValue(ctx.InputValue); + CodeLabel notNull = ctx.DefineLabel(), endNull = ctx.DefineLabel(); + ctx.BranchIfTrue(notNull, true); + + ctx.LoadAddress(typedVal, type); + ctx.EmitCtor(type); + ctx.Branch(endNull, true); + + ctx.MarkLabel(notNull); + ctx.LoadValue(ctx.InputValue); + ctx.CastFromObject(type); + ctx.StoreValue(typedVal); + + ctx.MarkLabel(endNull); + } + head.EmitRead(ctx, typedVal); + + if (head.ReturnsValue) + { + ctx.StoreValue(typedVal); + } + + ctx.LoadValue(typedVal); + ctx.CastToObject(type); + } + ctx.Emit(OpCodes.Ret); + return (ProtoDeserializer)ctx.method.CreateDelegate( + typeof(ProtoDeserializer)); + } + + internal void Return() + { + Emit(OpCodes.Ret); + } + + static bool IsObject(Type type) + { + return type == typeof(object); + } + + internal void CastToObject(Type type) + { + if (IsObject(type)) + { } + else if (Helpers.IsValueType(type)) + { + il.Emit(OpCodes.Box, type); + TraceCompile(OpCodes.Box + ": " + type); + } + else + { + il.Emit(OpCodes.Castclass, MapType(typeof(object))); + TraceCompile(OpCodes.Castclass + ": " + type); + } + } + + internal void CastFromObject(Type type) + { + if (IsObject(type)) + { } + else if (Helpers.IsValueType(type)) + { + switch (MetadataVersion) + { + case ILVersion.Net1: + il.Emit(OpCodes.Unbox, type); + il.Emit(OpCodes.Ldobj, type); + TraceCompile(OpCodes.Unbox + ": " + type); + TraceCompile(OpCodes.Ldobj + ": " + type); + break; + default: + + il.Emit(OpCodes.Unbox_Any, type); + TraceCompile(OpCodes.Unbox_Any + ": " + type); + break; + } + } + else + { + il.Emit(OpCodes.Castclass, type); + TraceCompile(OpCodes.Castclass + ": " + type); + } + } + private readonly bool isStatic; + private readonly RuntimeTypeModel.SerializerPair[] methodPairs; + + internal MethodBuilder GetDedicatedMethod(int metaKey, bool read) + { + if (methodPairs == null) return null; + // but if we *do* have pairs, we demand that we find a match... + for (int i = 0; i < methodPairs.Length; i++) + { + if (methodPairs[i].MetaKey == metaKey) { return read ? methodPairs[i].Deserialize : methodPairs[i].Serialize; } + } + throw new ArgumentException("Meta-key not found", "metaKey"); + } + + internal int MapMetaKeyToCompiledKey(int metaKey) + { + if (metaKey < 0 || methodPairs == null) return metaKey; // all meta, or a dummy/wildcard key + + for (int i = 0; i < methodPairs.Length; i++) + { + if (methodPairs[i].MetaKey == metaKey) return i; + } + throw new ArgumentException("Key could not be mapped: " + metaKey.ToString(), "metaKey"); + } + + + private readonly bool isWriter; + + private readonly bool nonPublic; + internal bool NonPublic { get { return nonPublic; } } + + private readonly Local inputValue; + public Local InputValue { get { return inputValue; } } + + private readonly string assemblyName; + internal CompilerContext(ILGenerator il, bool isStatic, bool isWriter, RuntimeTypeModel.SerializerPair[] methodPairs, TypeModel model, ILVersion metadataVersion, string assemblyName, Type inputType, string traceName) + { + if (string.IsNullOrEmpty(assemblyName)) throw new ArgumentNullException(nameof(assemblyName)); + this.assemblyName = assemblyName; + this.isStatic = isStatic; + this.methodPairs = methodPairs ?? throw new ArgumentNullException(nameof(methodPairs)); + this.il = il ?? throw new ArgumentNullException(nameof(il)); + // nonPublic = false; <== implicit + this.isWriter = isWriter; + this.model = model ?? throw new ArgumentNullException(nameof(model)); + this.metadataVersion = metadataVersion; + if (inputType != null) this.inputValue = new Local(null, inputType); + TraceCompile(">> " + traceName); + } + + private CompilerContext(Type associatedType, bool isWriter, bool isStatic, TypeModel model, Type inputType) + { + metadataVersion = ILVersion.Net2; + this.isStatic = isStatic; + this.isWriter = isWriter; + this.model = model ?? throw new ArgumentNullException(nameof(model)); + nonPublic = true; + Type[] paramTypes; + Type returnType; + if (isWriter) + { + returnType = typeof(void); + paramTypes = new Type[] { typeof(object), typeof(ProtoWriter) }; + } + else + { + returnType = typeof(object); + paramTypes = new Type[] { typeof(object), typeof(ProtoReader) }; + } + int uniqueIdentifier; +#if PLAT_NO_INTERLOCKED + uniqueIdentifier = ++next; +#else + uniqueIdentifier = Interlocked.Increment(ref next); +#endif + method = new DynamicMethod("proto_" + uniqueIdentifier.ToString(), returnType, paramTypes, associatedType +#if COREFX + .GetTypeInfo() +#endif + .IsInterface ? typeof(object) : associatedType, true); + this.il = method.GetILGenerator(); + if (inputType != null) this.inputValue = new Local(null, inputType); + TraceCompile(">> " + method.Name); + } + + private readonly ILGenerator il; + + private void Emit(OpCode opcode) + { + il.Emit(opcode); + TraceCompile(opcode.ToString()); + } + + public void LoadValue(string value) + { + if (value == null) + { + LoadNullRef(); + } + else + { + il.Emit(OpCodes.Ldstr, value); + TraceCompile(OpCodes.Ldstr + ": " + value); + } + } + + public void LoadValue(float value) + { + il.Emit(OpCodes.Ldc_R4, value); + TraceCompile(OpCodes.Ldc_R4 + ": " + value); + } + + public void LoadValue(double value) + { + il.Emit(OpCodes.Ldc_R8, value); + TraceCompile(OpCodes.Ldc_R8 + ": " + value); + } + + public void LoadValue(long value) + { + il.Emit(OpCodes.Ldc_I8, value); + TraceCompile(OpCodes.Ldc_I8 + ": " + value); + } + + public void LoadValue(int value) + { + switch (value) + { + case 0: Emit(OpCodes.Ldc_I4_0); break; + case 1: Emit(OpCodes.Ldc_I4_1); break; + case 2: Emit(OpCodes.Ldc_I4_2); break; + case 3: Emit(OpCodes.Ldc_I4_3); break; + case 4: Emit(OpCodes.Ldc_I4_4); break; + case 5: Emit(OpCodes.Ldc_I4_5); break; + case 6: Emit(OpCodes.Ldc_I4_6); break; + case 7: Emit(OpCodes.Ldc_I4_7); break; + case 8: Emit(OpCodes.Ldc_I4_8); break; + case -1: Emit(OpCodes.Ldc_I4_M1); break; + default: + if (value >= -128 && value <= 127) + { + il.Emit(OpCodes.Ldc_I4_S, (sbyte)value); + TraceCompile(OpCodes.Ldc_I4_S + ": " + value); + } + else + { + il.Emit(OpCodes.Ldc_I4, value); + TraceCompile(OpCodes.Ldc_I4 + ": " + value); + } + break; + + } + } + + MutableList locals = new MutableList(); + internal LocalBuilder GetFromPool(Type type) + { + int count = locals.Count; + for (int i = 0; i < count; i++) + { + LocalBuilder item = (LocalBuilder)locals[i]; + if (item != null && item.LocalType == type) + { + locals[i] = null; // remove from pool + return item; + } + } + LocalBuilder result = il.DeclareLocal(type); + TraceCompile("$ " + result + ": " + type); + return result; + } + + // + internal void ReleaseToPool(LocalBuilder value) + { + int count = locals.Count; + for (int i = 0; i < count; i++) + { + if (locals[i] == null) + { + locals[i] = value; // released into existing slot + return; + } + } + locals.Add(value); // create a new slot + } + + public void LoadReaderWriter() + { + Emit(isStatic ? OpCodes.Ldarg_1 : OpCodes.Ldarg_2); + } + + public void StoreValue(Local local) + { + if (local == this.InputValue) + { + byte b = isStatic ? (byte)0 : (byte)1; + il.Emit(OpCodes.Starg_S, b); + TraceCompile(OpCodes.Starg_S + ": $" + b); + } + else + { + + switch (local.Value.LocalIndex) + { + case 0: Emit(OpCodes.Stloc_0); break; + case 1: Emit(OpCodes.Stloc_1); break; + case 2: Emit(OpCodes.Stloc_2); break; + case 3: Emit(OpCodes.Stloc_3); break; + default: + + OpCode code = UseShortForm(local) ? OpCodes.Stloc_S : OpCodes.Stloc; + il.Emit(code, local.Value); + TraceCompile(code + ": $" + local.Value); + + break; + } + } + } + + public void LoadValue(Local local) + { + if (local == null) { /* nothing to do; top of stack */} + else if (local == this.InputValue) + { + Emit(isStatic ? OpCodes.Ldarg_0 : OpCodes.Ldarg_1); + } + else + { + + switch (local.Value.LocalIndex) + { + case 0: Emit(OpCodes.Ldloc_0); break; + case 1: Emit(OpCodes.Ldloc_1); break; + case 2: Emit(OpCodes.Ldloc_2); break; + case 3: Emit(OpCodes.Ldloc_3); break; + default: + + OpCode code = UseShortForm(local) ? OpCodes.Ldloc_S : OpCodes.Ldloc; + il.Emit(code, local.Value); + TraceCompile(code + ": $" + local.Value); + + break; + } + } + } + + public Local GetLocalWithValue(Type type, Compiler.Local fromValue) + { + if (fromValue != null) + { + if (fromValue.Type == type) return fromValue.AsCopy(); + // otherwise, load onto the stack and let the default handling (below) deal with it + LoadValue(fromValue); + if (!Helpers.IsValueType(type) && (fromValue.Type == null || !type.IsAssignableFrom(fromValue.Type))) + { // need to cast + Cast(type); + } + } + // need to store the value from the stack + Local result = new Local(this, type); + StoreValue(result); + return result; + } + + internal void EmitBasicRead(string methodName, Type expectedType) + { + MethodInfo method = MapType(typeof(ProtoReader)).GetMethod( + methodName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); + if (method == null || method.ReturnType != expectedType + || method.GetParameters().Length != 0) throw new ArgumentException("methodName"); + LoadReaderWriter(); + EmitCall(method); + } + + internal void EmitBasicRead(Type helperType, string methodName, Type expectedType) + { + MethodInfo method = helperType.GetMethod( + methodName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static); + if (method == null || method.ReturnType != expectedType + || method.GetParameters().Length != 1) throw new ArgumentException("methodName"); + LoadReaderWriter(); + EmitCall(method); + } + + internal void EmitBasicWrite(string methodName, Compiler.Local fromValue) + { + if (string.IsNullOrEmpty(methodName)) throw new ArgumentNullException("methodName"); + LoadValue(fromValue); + LoadReaderWriter(); + EmitCall(GetWriterMethod(methodName)); + } + + private MethodInfo GetWriterMethod(string methodName) + { + Type writerType = MapType(typeof(ProtoWriter)); + MethodInfo[] methods = writerType.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static); + foreach (MethodInfo method in methods) + { + if (method.Name != methodName) continue; + ParameterInfo[] pis = method.GetParameters(); + if (pis.Length == 2 && pis[1].ParameterType == writerType) return method; + } + throw new ArgumentException("No suitable method found for: " + methodName, "methodName"); + } + + internal void EmitWrite(Type helperType, string methodName, Compiler.Local valueFrom) + { + if (string.IsNullOrEmpty(methodName)) throw new ArgumentNullException("methodName"); + MethodInfo method = helperType.GetMethod( + methodName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static); + if (method == null || method.ReturnType != MapType(typeof(void))) throw new ArgumentException("methodName"); + LoadValue(valueFrom); + LoadReaderWriter(); + EmitCall(method); + } + + public void EmitCall(MethodInfo method) { EmitCall(method, null); } + + public void EmitCall(MethodInfo method, Type targetType) + { + Helpers.DebugAssert(method != null); + MemberInfo member = method; + CheckAccessibility(ref member); + OpCode opcode; + if (method.IsStatic || Helpers.IsValueType(method.DeclaringType)) + { + opcode = OpCodes.Call; + } + else + { + opcode = OpCodes.Callvirt; + if (targetType != null && Helpers.IsValueType(targetType) && !Helpers.IsValueType(method.DeclaringType)) + { + Constrain(targetType); + } + } + il.EmitCall(opcode, method, null); + TraceCompile(opcode + ": " + method + " on " + method.DeclaringType + (targetType == null ? "" : (" via " + targetType))); + } + + /// + /// Pushes a null reference onto the stack. Note that this should only + /// be used to return a null (or set a variable to null); for null-tests + /// use BranchIfTrue / BranchIfFalse. + /// + public void LoadNullRef() + { + Emit(OpCodes.Ldnull); + } + + private int nextLabel; + + internal void WriteNullCheckedTail(Type type, IProtoSerializer tail, Compiler.Local valueFrom) + { + if (Helpers.IsValueType(type)) + { + Type underlyingType = Helpers.GetUnderlyingType(type); + + if (underlyingType == null) + { // not a nullable T; can invoke directly + tail.EmitWrite(this, valueFrom); + } + else + { // nullable T; check HasValue + using (Compiler.Local valOrNull = GetLocalWithValue(type, valueFrom)) + { + LoadAddress(valOrNull, type); + LoadValue(type.GetProperty("HasValue")); + CodeLabel @end = DefineLabel(); + BranchIfFalse(@end, false); + LoadAddress(valOrNull, type); + EmitCall(type.GetMethod("GetValueOrDefault", Helpers.EmptyTypes)); + tail.EmitWrite(this, null); + MarkLabel(@end); + } + } + } + else + { // ref-type; do a null-check + LoadValue(valueFrom); + CopyValue(); + CodeLabel hasVal = DefineLabel(), @end = DefineLabel(); + BranchIfTrue(hasVal, true); + DiscardValue(); + Branch(@end, false); + MarkLabel(hasVal); + tail.EmitWrite(this, null); + MarkLabel(@end); + } + } + + internal void ReadNullCheckedTail(Type type, IProtoSerializer tail, Compiler.Local valueFrom) + { + + Type underlyingType; + + if (Helpers.IsValueType(type) && (underlyingType = Helpers.GetUnderlyingType(type)) != null) + { + if (tail.RequiresOldValue) + { + // we expect the input value to be in valueFrom; need to unpack it from T? + using (Local loc = GetLocalWithValue(type, valueFrom)) + { + LoadAddress(loc, type); + EmitCall(type.GetMethod("GetValueOrDefault", Helpers.EmptyTypes)); + } + } + else + { + Helpers.DebugAssert(valueFrom == null); // not expecting a valueFrom in this case + } + tail.EmitRead(this, null); // either unwrapped on the stack or not provided + if (tail.ReturnsValue) + { + // now re-wrap the value + EmitCtor(type, underlyingType); + } + return; + } + + // either a ref-type of a non-nullable struct; treat "as is", even if null + // (the type-serializer will handle the null case; it needs to allow null + // inputs to perform the correct type of subclass creation) + tail.EmitRead(this, valueFrom); + } + + public void EmitCtor(Type type) + { + EmitCtor(type, Helpers.EmptyTypes); + } + + public void EmitCtor(ConstructorInfo ctor) + { + if (ctor == null) throw new ArgumentNullException("ctor"); + MemberInfo ctorMember = ctor; + CheckAccessibility(ref ctorMember); + il.Emit(OpCodes.Newobj, ctor); + TraceCompile(OpCodes.Newobj + ": " + ctor.DeclaringType); + } + + public void InitLocal(Type type, Compiler.Local target) + { + LoadAddress(target, type, evenIfClass: true); // for class, initobj is a load-null, store-indirect + il.Emit(OpCodes.Initobj, type); + TraceCompile(OpCodes.Initobj + ": " + type); + } + + public void EmitCtor(Type type, params Type[] parameterTypes) + { + Helpers.DebugAssert(type != null); + Helpers.DebugAssert(parameterTypes != null); + if (Helpers.IsValueType(type) && parameterTypes.Length == 0) + { + il.Emit(OpCodes.Initobj, type); + TraceCompile(OpCodes.Initobj + ": " + type); + } + else + { + ConstructorInfo ctor = Helpers.GetConstructor(type +#if COREFX + .GetTypeInfo() +#endif + , parameterTypes, true); + if (ctor == null) throw new InvalidOperationException("No suitable constructor found for " + type.FullName); + EmitCtor(ctor); + } + } + + BasicList knownTrustedAssemblies, knownUntrustedAssemblies; + + bool InternalsVisible(Assembly assembly) + { + if (string.IsNullOrEmpty(assemblyName)) return false; + if (knownTrustedAssemblies != null) + { + if (knownTrustedAssemblies.IndexOfReference(assembly) >= 0) + { + return true; + } + } + if (knownUntrustedAssemblies != null) + { + if (knownUntrustedAssemblies.IndexOfReference(assembly) >= 0) + { + return false; + } + } + bool isTrusted = false; + Type attributeType = MapType(typeof(System.Runtime.CompilerServices.InternalsVisibleToAttribute)); + if (attributeType == null) return false; + +#if COREFX + foreach (System.Runtime.CompilerServices.InternalsVisibleToAttribute attrib in assembly.GetCustomAttributes(attributeType)) +#else + foreach (System.Runtime.CompilerServices.InternalsVisibleToAttribute attrib in assembly.GetCustomAttributes(attributeType, false)) +#endif + { + if (attrib.AssemblyName == assemblyName || attrib.AssemblyName.StartsWith(assemblyName + ",")) + { + isTrusted = true; + break; + } + } + + if (isTrusted) + { + if (knownTrustedAssemblies == null) knownTrustedAssemblies = new BasicList(); + knownTrustedAssemblies.Add(assembly); + } + else + { + if (knownUntrustedAssemblies == null) knownUntrustedAssemblies = new BasicList(); + knownUntrustedAssemblies.Add(assembly); + } + return isTrusted; + } + + internal void CheckAccessibility(ref MemberInfo member) + { + if (member == null) + { + throw new ArgumentNullException(nameof(member)); + } +#if !COREFX + Type type; +#endif + if (!NonPublic) + { + if (member is FieldInfo && member.Name.StartsWith("<") & member.Name.EndsWith(">k__BackingField")) + { + var propName = member.Name.Substring(1, member.Name.Length - 17); + var prop = member.DeclaringType.GetProperty(propName, BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static); + if (prop != null) member = prop; + } + bool isPublic; +#if COREFX + if (member is TypeInfo) + { + TypeInfo ti = (TypeInfo)member; + do + { + isPublic = ti.IsNestedPublic || ti.IsPublic || ((ti.IsNested || ti.IsNestedAssembly || ti.IsNestedFamORAssem) && InternalsVisible(ti.Assembly)); + } while (isPublic && ti.IsNested && (ti = ti.DeclaringType.GetTypeInfo()) != null); + } + else if (member is FieldInfo) + { + FieldInfo field = ((FieldInfo)member); + isPublic = field.IsPublic || ((field.IsAssembly || field.IsFamilyOrAssembly) && InternalsVisible(Helpers.GetAssembly(field.DeclaringType))); + } + else if (member is PropertyInfo) + { + isPublic = true; // defer to get/set + } + else if (member is ConstructorInfo) + { + ConstructorInfo ctor = ((ConstructorInfo)member); + isPublic = ctor.IsPublic || ((ctor.IsAssembly || ctor.IsFamilyOrAssembly) && InternalsVisible(Helpers.GetAssembly(ctor.DeclaringType))); + } + else if (member is MethodInfo) + { + MethodInfo method = ((MethodInfo)member); + isPublic = method.IsPublic || ((method.IsAssembly || method.IsFamilyOrAssembly) && InternalsVisible(Helpers.GetAssembly(method.DeclaringType))); + if (!isPublic) + { + // allow calls to TypeModel protected methods, and methods we are in the process of creating + if ( + member is MethodBuilder || + member.DeclaringType == MapType(typeof(TypeModel))) + isPublic = true; + } + } + else + { + throw new NotSupportedException(member.GetType().Name); + } +#else + MemberTypes memberType = member.MemberType; + switch (memberType) + { + case MemberTypes.TypeInfo: + // top-level type + type = (Type)member; + isPublic = type.IsPublic || InternalsVisible(type.Assembly); + break; + case MemberTypes.NestedType: + type = (Type)member; + do + { + isPublic = type.IsNestedPublic || type.IsPublic || ((type.DeclaringType == null || type.IsNestedAssembly || type.IsNestedFamORAssem) && InternalsVisible(type.Assembly)); + } while (isPublic && (type = type.DeclaringType) != null); // ^^^ !type.IsNested, but not all runtimes have that + break; + case MemberTypes.Field: + FieldInfo field = ((FieldInfo)member); + isPublic = field.IsPublic || ((field.IsAssembly || field.IsFamilyOrAssembly) && InternalsVisible(field.DeclaringType.Assembly)); + break; + case MemberTypes.Constructor: + ConstructorInfo ctor = ((ConstructorInfo)member); + isPublic = ctor.IsPublic || ((ctor.IsAssembly || ctor.IsFamilyOrAssembly) && InternalsVisible(ctor.DeclaringType.Assembly)); + break; + case MemberTypes.Method: + MethodInfo method = ((MethodInfo)member); + isPublic = method.IsPublic || ((method.IsAssembly || method.IsFamilyOrAssembly) && InternalsVisible(method.DeclaringType.Assembly)); + if (!isPublic) + { + // allow calls to TypeModel protected methods, and methods we are in the process of creating + if ( + member is MethodBuilder || + member.DeclaringType == MapType(typeof(TypeModel))) isPublic = true; + } + break; + case MemberTypes.Property: + isPublic = true; // defer to get/set + break; + default: + throw new NotSupportedException(memberType.ToString()); + } +#endif + if (!isPublic) + { +#if COREFX + if (member is TypeInfo) + { + throw new InvalidOperationException("Non-public type cannot be used with full dll compilation: " + + ((TypeInfo)member).FullName); + } + else + { + throw new InvalidOperationException("Non-public member cannot be used with full dll compilation: " + + member.DeclaringType.FullName + "." + member.Name); + } + +#else + switch (memberType) + { + case MemberTypes.TypeInfo: + case MemberTypes.NestedType: + throw new InvalidOperationException("Non-public type cannot be used with full dll compilation: " + + ((Type)member).FullName); + default: + throw new InvalidOperationException("Non-public member cannot be used with full dll compilation: " + + member.DeclaringType.FullName + "." + member.Name); + } +#endif + + } + } + } + + public void LoadValue(FieldInfo field) + { + MemberInfo member = field; + CheckAccessibility(ref member); + if (member is PropertyInfo) + { + LoadValue((PropertyInfo)member); + } + else + { + OpCode code = field.IsStatic ? OpCodes.Ldsfld : OpCodes.Ldfld; + il.Emit(code, field); + TraceCompile(code + ": " + field + " on " + field.DeclaringType); + } + } + + public void StoreValue(FieldInfo field) + { + MemberInfo member = field; + CheckAccessibility(ref member); + if (member is PropertyInfo) + { + StoreValue((PropertyInfo)member); + } + else + { + OpCode code = field.IsStatic ? OpCodes.Stsfld : OpCodes.Stfld; + il.Emit(code, field); + TraceCompile(code + ": " + field + " on " + field.DeclaringType); + } + } + + public void LoadValue(PropertyInfo property) + { + MemberInfo member = property; + CheckAccessibility(ref member); + EmitCall(Helpers.GetGetMethod(property, true, true)); + } + + public void StoreValue(PropertyInfo property) + { + MemberInfo member = property; + CheckAccessibility(ref member); + EmitCall(Helpers.GetSetMethod(property, true, true)); + } + + //internal void EmitInstance() + //{ + // if (isStatic) throw new InvalidOperationException(); + // Emit(OpCodes.Ldarg_0); + //} + + internal static void LoadValue(ILGenerator il, int value) + { + switch (value) + { + case 0: il.Emit(OpCodes.Ldc_I4_0); break; + case 1: il.Emit(OpCodes.Ldc_I4_1); break; + case 2: il.Emit(OpCodes.Ldc_I4_2); break; + case 3: il.Emit(OpCodes.Ldc_I4_3); break; + case 4: il.Emit(OpCodes.Ldc_I4_4); break; + case 5: il.Emit(OpCodes.Ldc_I4_5); break; + case 6: il.Emit(OpCodes.Ldc_I4_6); break; + case 7: il.Emit(OpCodes.Ldc_I4_7); break; + case 8: il.Emit(OpCodes.Ldc_I4_8); break; + case -1: il.Emit(OpCodes.Ldc_I4_M1); break; + default: il.Emit(OpCodes.Ldc_I4, value); break; + } + } + + private bool UseShortForm(Local local) + { + return local.Value.LocalIndex < 256; + } + + internal void LoadAddress(Local local, Type type, bool evenIfClass = false) + { + if (evenIfClass || Helpers.IsValueType(type)) + { + if (local == null) + { + throw new InvalidOperationException("Cannot load the address of the head of the stack"); + } + + if (local == this.InputValue) + { + il.Emit(OpCodes.Ldarga_S, (isStatic ? (byte)0 : (byte)1)); + TraceCompile(OpCodes.Ldarga_S + ": $" + (isStatic ? 0 : 1)); + } + else + { + OpCode code = UseShortForm(local) ? OpCodes.Ldloca_S : OpCodes.Ldloca; + il.Emit(code, local.Value); + TraceCompile(code + ": $" + local.Value); + } + + } + else + { // reference-type; already *is* the address; just load it + LoadValue(local); + } + } + + internal void Branch(CodeLabel label, bool @short) + { + OpCode code = @short ? OpCodes.Br_S : OpCodes.Br; + il.Emit(code, label.Value); + TraceCompile(code + ": " + label.Index); + } + + internal void BranchIfFalse(CodeLabel label, bool @short) + { + OpCode code = @short ? OpCodes.Brfalse_S : OpCodes.Brfalse; + il.Emit(code, label.Value); + TraceCompile(code + ": " + label.Index); + } + + internal void BranchIfTrue(CodeLabel label, bool @short) + { + OpCode code = @short ? OpCodes.Brtrue_S : OpCodes.Brtrue; + il.Emit(code, label.Value); + TraceCompile(code + ": " + label.Index); + } + + internal void BranchIfEqual(CodeLabel label, bool @short) + { + OpCode code = @short ? OpCodes.Beq_S : OpCodes.Beq; + il.Emit(code, label.Value); + TraceCompile(code + ": " + label.Index); + } + + //internal void TestEqual() + //{ + // Emit(OpCodes.Ceq); + //} + + internal void CopyValue() + { + Emit(OpCodes.Dup); + } + + internal void BranchIfGreater(CodeLabel label, bool @short) + { + OpCode code = @short ? OpCodes.Bgt_S : OpCodes.Bgt; + il.Emit(code, label.Value); + TraceCompile(code + ": " + label.Index); + } + + internal void BranchIfLess(CodeLabel label, bool @short) + { + OpCode code = @short ? OpCodes.Blt_S : OpCodes.Blt; + il.Emit(code, label.Value); + TraceCompile(code + ": " + label.Index); + } + + internal void DiscardValue() + { + Emit(OpCodes.Pop); + } + + public void Subtract() + { + Emit(OpCodes.Sub); + } + + public void Switch(CodeLabel[] jumpTable) + { + const int MAX_JUMPS = 128; + + if (jumpTable.Length <= MAX_JUMPS) + { + // simple case + Label[] labels = new Label[jumpTable.Length]; + for (int i = 0; i < labels.Length; i++) + { + labels[i] = jumpTable[i].Value; + } + TraceCompile(OpCodes.Switch.ToString()); + il.Emit(OpCodes.Switch, labels); + } + else + { + // too many to jump easily (especially on Android) - need to split up (note: uses a local pulled from the stack) + using (Local val = GetLocalWithValue(MapType(typeof(int)), null)) + { + int count = jumpTable.Length, offset = 0; + int blockCount = count / MAX_JUMPS; + if ((count % MAX_JUMPS) != 0) blockCount++; + + Label[] blockLabels = new Label[blockCount]; + for (int i = 0; i < blockCount; i++) + { + blockLabels[i] = il.DefineLabel(); + } + CodeLabel endOfSwitch = DefineLabel(); + + LoadValue(val); + LoadValue(MAX_JUMPS); + Emit(OpCodes.Div); + TraceCompile(OpCodes.Switch.ToString()); + il.Emit(OpCodes.Switch, blockLabels); + Branch(endOfSwitch, false); + + Label[] innerLabels = new Label[MAX_JUMPS]; + for (int blockIndex = 0; blockIndex < blockCount; blockIndex++) + { + il.MarkLabel(blockLabels[blockIndex]); + + int itemsThisBlock = Math.Min(MAX_JUMPS, count); + count -= itemsThisBlock; + if (innerLabels.Length != itemsThisBlock) innerLabels = new Label[itemsThisBlock]; + + int subtract = offset; + for (int j = 0; j < itemsThisBlock; j++) + { + innerLabels[j] = jumpTable[offset++].Value; + } + LoadValue(val); + if (subtract != 0) // switches are always zero-based + { + LoadValue(subtract); + Emit(OpCodes.Sub); + } + TraceCompile(OpCodes.Switch.ToString()); + il.Emit(OpCodes.Switch, innerLabels); + if (count != 0) + { // force default to the very bottom + Branch(endOfSwitch, false); + } + } + Helpers.DebugAssert(count == 0, "Should use exactly all switch items"); + MarkLabel(endOfSwitch); + } + } + } + + internal void EndFinally() + { + il.EndExceptionBlock(); + TraceCompile("EndExceptionBlock"); + } + + internal void BeginFinally() + { + il.BeginFinallyBlock(); + TraceCompile("BeginFinallyBlock"); + } + + internal void EndTry(CodeLabel label, bool @short) + { + OpCode code = @short ? OpCodes.Leave_S : OpCodes.Leave; + il.Emit(code, label.Value); + TraceCompile(code + ": " + label.Index); + } + + internal CodeLabel BeginTry() + { + CodeLabel label = new CodeLabel(il.BeginExceptionBlock(), nextLabel++); + TraceCompile("BeginExceptionBlock: " + label.Index); + return label; + } + + internal void Constrain(Type type) + { + il.Emit(OpCodes.Constrained, type); + TraceCompile(OpCodes.Constrained + ": " + type); + } + + internal void TryCast(Type type) + { + il.Emit(OpCodes.Isinst, type); + TraceCompile(OpCodes.Isinst + ": " + type); + } + + internal void Cast(Type type) + { + il.Emit(OpCodes.Castclass, type); + TraceCompile(OpCodes.Castclass + ": " + type); + } + + public IDisposable Using(Local local) + { + return new UsingBlock(this, local); + } + + private sealed class UsingBlock : IDisposable + { + private Local local; + CompilerContext ctx; + CodeLabel label; + /// + /// Creates a new "using" block (equivalent) around a variable; + /// the variable must exist, and note that (unlike in C#) it is + /// the variables *final* value that gets disposed. If you need + /// *original* disposal, copy your variable first. + /// + /// It is the callers responsibility to ensure that the variable's + /// scope fully-encapsulates the "using"; if not, the variable + /// may be re-used (and thus re-assigned) unexpectedly. + /// + public UsingBlock(CompilerContext ctx, Local local) + { + if (ctx == null) throw new ArgumentNullException("ctx"); + if (local == null) throw new ArgumentNullException("local"); + + Type type = local.Type; + // check if **never** disposable + if ((Helpers.IsValueType(type) || Helpers.IsSealed(type)) && + !ctx.MapType(typeof(IDisposable)).IsAssignableFrom(type)) + { + return; // nothing to do! easiest "using" block ever + // (note that C# wouldn't allow this as a "using" block, + // but we'll be generous and simply not do anything) + } + this.local = local; + this.ctx = ctx; + label = ctx.BeginTry(); + + } + public void Dispose() + { + if (local == null || ctx == null) return; + + ctx.EndTry(label, false); + ctx.BeginFinally(); + Type disposableType = ctx.MapType(typeof(IDisposable)); + MethodInfo dispose = disposableType.GetMethod("Dispose"); + Type type = local.Type; + // remember that we've already (in the .ctor) excluded the case + // where it *cannot* be disposable + if (Helpers.IsValueType(type)) + { + ctx.LoadAddress(local, type); + switch (ctx.MetadataVersion) + { + case ILVersion.Net1: + ctx.LoadValue(local); + ctx.CastToObject(type); + break; + default: + ctx.Constrain(type); + break; + } + ctx.EmitCall(dispose); + } + else + { + Compiler.CodeLabel @null = ctx.DefineLabel(); + if (disposableType.IsAssignableFrom(type)) + { // *known* to be IDisposable; just needs a null-check + ctx.LoadValue(local); + ctx.BranchIfFalse(@null, true); + ctx.LoadAddress(local, type); + } + else + { // *could* be IDisposable; test via "as" + using (Compiler.Local disp = new Compiler.Local(ctx, disposableType)) + { + ctx.LoadValue(local); + ctx.TryCast(disposableType); + ctx.CopyValue(); + ctx.StoreValue(disp); + ctx.BranchIfFalse(@null, true); + ctx.LoadAddress(disp, disposableType); + } + } + ctx.EmitCall(dispose); + ctx.MarkLabel(@null); + } + ctx.EndFinally(); + this.local = null; + this.ctx = null; + label = new CodeLabel(); // default + } + } + + internal void Add() + { + Emit(OpCodes.Add); + } + + internal void LoadLength(Local arr, bool zeroIfNull) + { + Helpers.DebugAssert(arr.Type.IsArray && arr.Type.GetArrayRank() == 1); + + if (zeroIfNull) + { + Compiler.CodeLabel notNull = DefineLabel(), done = DefineLabel(); + LoadValue(arr); + CopyValue(); // optimised for non-null case + BranchIfTrue(notNull, true); + DiscardValue(); + LoadValue(0); + Branch(done, true); + MarkLabel(notNull); + Emit(OpCodes.Ldlen); + Emit(OpCodes.Conv_I4); + MarkLabel(done); + } + else + { + LoadValue(arr); + Emit(OpCodes.Ldlen); + Emit(OpCodes.Conv_I4); + } + } + + internal void CreateArray(Type elementType, Local length) + { + LoadValue(length); + il.Emit(OpCodes.Newarr, elementType); + TraceCompile(OpCodes.Newarr + ": " + elementType); + } + + internal void LoadArrayValue(Local arr, Local i) + { + Type type = arr.Type; + Helpers.DebugAssert(type.IsArray && arr.Type.GetArrayRank() == 1); + type = type.GetElementType(); + Helpers.DebugAssert(type != null, "Not an array: " + arr.Type.FullName); + LoadValue(arr); + LoadValue(i); + switch (Helpers.GetTypeCode(type)) + { + case ProtoTypeCode.SByte: Emit(OpCodes.Ldelem_I1); break; + case ProtoTypeCode.Int16: Emit(OpCodes.Ldelem_I2); break; + case ProtoTypeCode.Int32: Emit(OpCodes.Ldelem_I4); break; + case ProtoTypeCode.Int64: Emit(OpCodes.Ldelem_I8); break; + + case ProtoTypeCode.Byte: Emit(OpCodes.Ldelem_U1); break; + case ProtoTypeCode.UInt16: Emit(OpCodes.Ldelem_U2); break; + case ProtoTypeCode.UInt32: Emit(OpCodes.Ldelem_U4); break; + case ProtoTypeCode.UInt64: Emit(OpCodes.Ldelem_I8); break; // odd, but this is what C# does... + + case ProtoTypeCode.Single: Emit(OpCodes.Ldelem_R4); break; + case ProtoTypeCode.Double: Emit(OpCodes.Ldelem_R8); break; + default: + if (Helpers.IsValueType(type)) + { + il.Emit(OpCodes.Ldelema, type); + il.Emit(OpCodes.Ldobj, type); + TraceCompile(OpCodes.Ldelema + ": " + type); + TraceCompile(OpCodes.Ldobj + ": " + type); + } + else + { + Emit(OpCodes.Ldelem_Ref); + } + + break; + } + } + + internal void LoadValue(Type type) + { + il.Emit(OpCodes.Ldtoken, type); + TraceCompile(OpCodes.Ldtoken + ": " + type); + EmitCall(MapType(typeof(System.Type)).GetMethod("GetTypeFromHandle")); + } + + internal void ConvertToInt32(ProtoTypeCode typeCode, bool uint32Overflow) + { + switch (typeCode) + { + case ProtoTypeCode.Byte: + case ProtoTypeCode.SByte: + case ProtoTypeCode.Int16: + case ProtoTypeCode.UInt16: + Emit(OpCodes.Conv_I4); + break; + case ProtoTypeCode.Int32: + break; + case ProtoTypeCode.Int64: + Emit(OpCodes.Conv_Ovf_I4); + break; + case ProtoTypeCode.UInt32: + Emit(uint32Overflow ? OpCodes.Conv_Ovf_I4_Un : OpCodes.Conv_Ovf_I4); + break; + case ProtoTypeCode.UInt64: + Emit(OpCodes.Conv_Ovf_I4_Un); + break; + default: + throw new InvalidOperationException("ConvertToInt32 not implemented for: " + typeCode.ToString()); + } + } + + internal void ConvertFromInt32(ProtoTypeCode typeCode, bool uint32Overflow) + { + switch (typeCode) + { + case ProtoTypeCode.SByte: Emit(OpCodes.Conv_Ovf_I1); break; + case ProtoTypeCode.Byte: Emit(OpCodes.Conv_Ovf_U1); break; + case ProtoTypeCode.Int16: Emit(OpCodes.Conv_Ovf_I2); break; + case ProtoTypeCode.UInt16: Emit(OpCodes.Conv_Ovf_U2); break; + case ProtoTypeCode.Int32: break; + case ProtoTypeCode.UInt32: Emit(uint32Overflow ? OpCodes.Conv_Ovf_U4 : OpCodes.Conv_U4); break; + case ProtoTypeCode.Int64: Emit(OpCodes.Conv_I8); break; + case ProtoTypeCode.UInt64: Emit(OpCodes.Conv_U8); break; + default: throw new InvalidOperationException(); + } + } + + internal void LoadValue(decimal value) + { + if (value == 0M) + { + LoadValue(typeof(decimal).GetField("Zero")); + } + else + { + int[] bits = decimal.GetBits(value); + LoadValue(bits[0]); // lo + LoadValue(bits[1]); // mid + LoadValue(bits[2]); // hi + LoadValue((int)(((uint)bits[3]) >> 31)); // isNegative (bool, but int for CLI purposes) + LoadValue((bits[3] >> 16) & 0xFF); // scale (byte, but int for CLI purposes) + + EmitCtor(MapType(typeof(decimal)), new Type[] { MapType(typeof(int)), MapType(typeof(int)), MapType(typeof(int)), MapType(typeof(bool)), MapType(typeof(byte)) }); + } + } + + internal void LoadValue(Guid value) + { + if (value == Guid.Empty) + { + LoadValue(typeof(Guid).GetField("Empty")); + } + else + { // note we're adding lots of shorts/bytes here - but at the IL level they are I4, not I1/I2 (which barely exist) + byte[] bytes = value.ToByteArray(); + int i = (bytes[0]) | (bytes[1] << 8) | (bytes[2] << 16) | (bytes[3] << 24); + LoadValue(i); + short s = (short)((bytes[4]) | (bytes[5] << 8)); + LoadValue(s); + s = (short)((bytes[6]) | (bytes[7] << 8)); + LoadValue(s); + for (i = 8; i <= 15; i++) + { + LoadValue(bytes[i]); + } + EmitCtor(MapType(typeof(Guid)), new Type[] { MapType(typeof(int)), MapType(typeof(short)), MapType(typeof(short)), + MapType(typeof(byte)), MapType(typeof(byte)), MapType(typeof(byte)), MapType(typeof(byte)), MapType(typeof(byte)), MapType(typeof(byte)), MapType(typeof(byte)), MapType(typeof(byte)) }); + } + } + + //internal void LoadValue(bool value) + //{ + // Emit(value ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0); + //} + + internal void LoadSerializationContext() + { + LoadReaderWriter(); + LoadValue((isWriter ? typeof(ProtoWriter) : typeof(ProtoReader)).GetProperty("Context")); + } + + private readonly TypeModel model; + + internal Type MapType(Type type) + { + return model.MapType(type); + } + + private readonly ILVersion metadataVersion; + public ILVersion MetadataVersion { get { return metadataVersion; } } + public enum ILVersion + { + Net1, Net2 + } + + internal bool AllowInternal(PropertyInfo property) + { + return NonPublic ? true : InternalsVisible(Helpers.GetAssembly(property.DeclaringType)); + } + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Compiler/CompilerContext.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Compiler/CompilerContext.cs.meta new file mode 100644 index 0000000..b40174b --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Compiler/CompilerContext.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a58d20a1d8c7730499ef29a11532d07e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Compiler/CompilerDelegates.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Compiler/CompilerDelegates.cs new file mode 100644 index 0000000..e7f0508 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Compiler/CompilerDelegates.cs @@ -0,0 +1,7 @@ +#if FEAT_COMPILER +namespace ProtoBuf.Compiler +{ + internal delegate void ProtoSerializer(object value, ProtoWriter dest); + internal delegate object ProtoDeserializer(object value, ProtoReader source); +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Compiler/CompilerDelegates.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Compiler/CompilerDelegates.cs.meta new file mode 100644 index 0000000..c9fedb0 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Compiler/CompilerDelegates.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3b923d7ab8e95f740b059ca797596261 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Compiler/Local.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Compiler/Local.cs new file mode 100644 index 0000000..fd3dfa9 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Compiler/Local.cs @@ -0,0 +1,58 @@ +#if FEAT_COMPILER +using System; +using System.Reflection.Emit; + +namespace ProtoBuf.Compiler +{ + internal sealed class Local : IDisposable + { + // public static readonly Local InputValue = new Local(null, null); + private LocalBuilder value; + private readonly Type type; + private CompilerContext ctx; + + private Local(LocalBuilder value, Type type) + { + this.value = value; + this.type = type; + } + + internal Local(CompilerContext ctx, Type type) + { + this.ctx = ctx; + if (ctx != null) { value = ctx.GetFromPool(type); } + this.type = type; + } + + internal LocalBuilder Value => value ?? throw new ObjectDisposedException(GetType().Name); + + public Type Type => type; + + public Local AsCopy() + { + if (ctx == null) return this; // can re-use if context-free + return new Local(value, this.type); + } + + public void Dispose() + { + if (ctx != null) + { + // only *actually* dispose if this is context-bound; note that non-bound + // objects are cheekily re-used, and *must* be left intact agter a "using" etc + ctx.ReleaseToPool(value); + value = null; + ctx = null; + } + } + + internal bool IsSame(Local other) + { + if((object)this == (object)other) return true; + + object ourVal = value; // use prop to ensure obj-disposed etc + return other != null && ourVal == (object)(other.value); + } + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Compiler/Local.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Compiler/Local.cs.meta new file mode 100644 index 0000000..2767c29 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Compiler/Local.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 07d12d9a9b7d45b498e28b7c39bdca01 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/DataFormat.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/DataFormat.cs new file mode 100644 index 0000000..4d97b4f --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/DataFormat.cs @@ -0,0 +1,49 @@ + +namespace ProtoBuf +{ + /// + /// Sub-format to use when serializing/deserializing data + /// + public enum DataFormat + { + /// + /// Uses the default encoding for the data-type. + /// + Default, + + /// + /// When applied to signed integer-based data (including Decimal), this + /// indicates that zigzag variant encoding will be used. This means that values + /// with small magnitude (regardless of sign) take a small amount + /// of space to encode. + /// + ZigZag, + + /// + /// When applied to signed integer-based data (including Decimal), this + /// indicates that two's-complement variant encoding will be used. + /// This means that any -ve number will take 10 bytes (even for 32-bit), + /// so should only be used for compatibility. + /// + TwosComplement, + + /// + /// When applied to signed integer-based data (including Decimal), this + /// indicates that a fixed amount of space will be used. + /// + FixedSize, + + /// + /// When applied to a sub-message, indicates that the value should be treated + /// as group-delimited. + /// + Group, + + /// + /// When applied to members of types such as DateTime or TimeSpan, specifies + /// that the "well known" standardized representation should be use; DateTime uses Timestamp, + /// + /// + WellKnown + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/DataFormat.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/DataFormat.cs.meta new file mode 100644 index 0000000..644abad --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/DataFormat.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 875f2f7de4b03ff409de70d226359e8f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/DiscriminatedUnion.Serializable.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/DiscriminatedUnion.Serializable.cs new file mode 100644 index 0000000..0fd671f --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/DiscriminatedUnion.Serializable.cs @@ -0,0 +1,176 @@ +#if PLAT_BINARYFORMATTER +using System; +using System.Runtime.InteropServices; +using System.Runtime.Serialization; + +namespace ProtoBuf +{ + [Serializable] + public readonly partial struct DiscriminatedUnionObject : ISerializable + { + void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context) + { + if (Discriminator != default) info.AddValue("d", Discriminator); + if (Object is object) info.AddValue("o", Object); + } + private DiscriminatedUnionObject(SerializationInfo info, StreamingContext context) + { + this = default; + foreach (var field in info) + { + switch (field.Name) + { + case "d": Discriminator = (int)field.Value; break; + case "o": Object = field.Value; break; + } + } + } + } + + [Serializable] + public readonly partial struct DiscriminatedUnion128Object : ISerializable + { + [FieldOffset(8)] private readonly long _lo; + [FieldOffset(16)] private readonly long _hi; + void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context) + { + if (_discriminator != default) info.AddValue("d", _discriminator); + if (_lo != default) info.AddValue("l", _lo); + if (_hi != default) info.AddValue("h", _hi); + if (Object != null) info.AddValue("o", Object); + } + private DiscriminatedUnion128Object(SerializationInfo info, StreamingContext context) + { + this = default; + foreach (var field in info) + { + switch (field.Name) + { + case "d": _discriminator = (int)field.Value; break; + case "l": _lo = (long)field.Value; break; + case "h": _hi = (long)field.Value; break; + case "o": Object = field.Value; break; + } + } + } + } + + [Serializable] + public readonly partial struct DiscriminatedUnion128 : ISerializable + { + [FieldOffset(8)] private readonly long _lo; + [FieldOffset(16)] private readonly long _hi; + void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context) + { + if (_discriminator != default) info.AddValue("d", _discriminator); + if (_lo != default) info.AddValue("l", _lo); + if (_hi != default) info.AddValue("h", _hi); + } + private DiscriminatedUnion128(SerializationInfo info, StreamingContext context) + { + this = default; + foreach (var field in info) + { + switch (field.Name) + { + case "d": _discriminator = (int)field.Value; break; + case "l": _lo = (long)field.Value; break; + case "h": _hi = (long)field.Value; break; + } + } + } + } + + [Serializable] + public readonly partial struct DiscriminatedUnion64 : ISerializable + { + void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context) + { + if (_discriminator != default) info.AddValue("d", _discriminator); + if (Int64 != default) info.AddValue("i", Int64); + } + private DiscriminatedUnion64(SerializationInfo info, StreamingContext context) + { + this = default; + foreach (var field in info) + { + switch (field.Name) + { + case "d": _discriminator = (int)field.Value; break; + case "i": Int64 = (long)field.Value; break; + } + } + } + } + + [Serializable] + public readonly partial struct DiscriminatedUnion64Object : ISerializable + { + void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context) + { + if (_discriminator != default) info.AddValue("d", _discriminator); + if (Int64 != default) info.AddValue("i", Int64); + if (Object is object) info.AddValue("o", Object); + } + private DiscriminatedUnion64Object(SerializationInfo info, StreamingContext context) + { + this = default; + foreach (var field in info) + { + switch (field.Name) + { + case "d": _discriminator = (int)field.Value; break; + case "i": Int64 = (long)field.Value; break; + case "o": Object = field.Value; break; + } + } + } + } + + [Serializable] + public readonly partial struct DiscriminatedUnion32 : ISerializable + { + void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context) + { + if (_discriminator != default) info.AddValue("d", _discriminator); + if (Int32 != default) info.AddValue("i", Int32); + } + private DiscriminatedUnion32(SerializationInfo info, StreamingContext context) + { + this = default; + foreach (var field in info) + { + switch (field.Name) + { + case "d": _discriminator = (int)field.Value; break; + case "i": Int32 = (int)field.Value; break; + } + } + } + } + + [Serializable] + public readonly partial struct DiscriminatedUnion32Object : ISerializable + { + void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context) + { + if (_discriminator != default) info.AddValue("d", _discriminator); + if (Int32 != default) info.AddValue("i", Int32); + if (Object is object) info.AddValue("o", Object); + } + private DiscriminatedUnion32Object(SerializationInfo info, StreamingContext context) + { + this = default; + foreach (var field in info) + { + switch (field.Name) + { + case "d": _discriminator = (int)field.Value; break; + case "i": Int32 = (int)field.Value; break; + case "o": Object = field.Value; break; + } + } + } + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/DiscriminatedUnion.Serializable.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/DiscriminatedUnion.Serializable.cs.meta new file mode 100644 index 0000000..f616331 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/DiscriminatedUnion.Serializable.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7a3aeec9c8a4c734e9ad022627502d1d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/DiscriminatedUnion.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/DiscriminatedUnion.cs new file mode 100644 index 0000000..7cc8cf8 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/DiscriminatedUnion.cs @@ -0,0 +1,416 @@ +using System; +using System.Runtime.InteropServices; + +namespace ProtoBuf +{ + /// Represent multiple types as a union; this is used as part of OneOf - + /// note that it is the caller's responsbility to only read/write the value as the same type + public readonly partial struct DiscriminatedUnionObject + { + + /// The value typed as Object + public readonly object Object; + + /// Indicates whether the specified discriminator is assigned + public bool Is(int discriminator) => Discriminator == discriminator; + + /// Create a new discriminated union value + public DiscriminatedUnionObject(int discriminator, object value) + { + Discriminator = discriminator; + Object = value; + } + + /// Reset a value if the specified discriminator is assigned + public static void Reset(ref DiscriminatedUnionObject value, int discriminator) + { + if (value.Discriminator == discriminator) value = default; + } + + /// The discriminator value + public int Discriminator { get; } + } + + /// Represent multiple types as a union; this is used as part of OneOf - + /// note that it is the caller's responsbility to only read/write the value as the same type + [StructLayout(LayoutKind.Explicit)] + public readonly partial struct DiscriminatedUnion64 + { +#if !FEAT_SAFE + unsafe static DiscriminatedUnion64() + { + if (sizeof(DateTime) > 8) throw new InvalidOperationException(nameof(DateTime) + " was unexpectedly too big for " + nameof(DiscriminatedUnion64)); + if (sizeof(TimeSpan) > 8) throw new InvalidOperationException(nameof(TimeSpan) + " was unexpectedly too big for " + nameof(DiscriminatedUnion64)); + } +#endif + [FieldOffset(0)] private readonly int _discriminator; // note that we can't pack further because Object needs x8 alignment/padding on x64 + + /// The value typed as Int64 + [FieldOffset(8)] public readonly long Int64; + /// The value typed as UInt64 + [FieldOffset(8)] public readonly ulong UInt64; + /// The value typed as Int32 + [FieldOffset(8)] public readonly int Int32; + /// The value typed as UInt32 + [FieldOffset(8)] public readonly uint UInt32; + /// The value typed as Boolean + [FieldOffset(8)] public readonly bool Boolean; + /// The value typed as Single + [FieldOffset(8)] public readonly float Single; + /// The value typed as Double + [FieldOffset(8)] public readonly double Double; + /// The value typed as DateTime + [FieldOffset(8)] public readonly DateTime DateTime; + /// The value typed as TimeSpan + [FieldOffset(8)] public readonly TimeSpan TimeSpan; + + private DiscriminatedUnion64(int discriminator) : this() + { + _discriminator = discriminator; + } + + /// Indicates whether the specified discriminator is assigned + public bool Is(int discriminator) => _discriminator == discriminator; + + /// Create a new discriminated union value + public DiscriminatedUnion64(int discriminator, long value) : this(discriminator) { Int64 = value; } + /// Create a new discriminated union value + public DiscriminatedUnion64(int discriminator, int value) : this(discriminator) { Int32 = value; } + /// Create a new discriminated union value + public DiscriminatedUnion64(int discriminator, ulong value) : this(discriminator) { UInt64 = value; } + /// Create a new discriminated union value + public DiscriminatedUnion64(int discriminator, uint value) : this(discriminator) { UInt32 = value; } + /// Create a new discriminated union value + public DiscriminatedUnion64(int discriminator, float value) : this(discriminator) { Single = value; } + /// Create a new discriminated union value + public DiscriminatedUnion64(int discriminator, double value) : this(discriminator) { Double = value; } + /// Create a new discriminated union value + public DiscriminatedUnion64(int discriminator, bool value) : this(discriminator) { Boolean = value; } + /// Create a new discriminated union value + public DiscriminatedUnion64(int discriminator, DateTime? value) : this(value.HasValue ? discriminator: 0) { DateTime = value.GetValueOrDefault(); } + /// Create a new discriminated union value + public DiscriminatedUnion64(int discriminator, TimeSpan? value) : this(value.HasValue ? discriminator : 0) { TimeSpan = value.GetValueOrDefault(); } + + /// Reset a value if the specified discriminator is assigned + public static void Reset(ref DiscriminatedUnion64 value, int discriminator) + { + if (value.Discriminator == discriminator) value = default; + } + /// The discriminator value + public int Discriminator => _discriminator; + } + + /// Represent multiple types as a union; this is used as part of OneOf - + /// note that it is the caller's responsbility to only read/write the value as the same type + [StructLayout(LayoutKind.Explicit)] + public readonly partial struct DiscriminatedUnion128Object + { +#if !FEAT_SAFE + unsafe static DiscriminatedUnion128Object() + { + if (sizeof(DateTime) > 16) throw new InvalidOperationException(nameof(DateTime) + " was unexpectedly too big for " + nameof(DiscriminatedUnion128Object)); + if (sizeof(TimeSpan) > 16) throw new InvalidOperationException(nameof(TimeSpan) + " was unexpectedly too big for " + nameof(DiscriminatedUnion128Object)); + if (sizeof(Guid) > 16) throw new InvalidOperationException(nameof(Guid) + " was unexpectedly too big for " + nameof(DiscriminatedUnion128Object)); + } +#endif + + [FieldOffset(0)] private readonly int _discriminator; // note that we can't pack further because Object needs x8 alignment/padding on x64 + + /// The value typed as Int64 + [FieldOffset(8)] public readonly long Int64; + /// The value typed as UInt64 + [FieldOffset(8)] public readonly ulong UInt64; + /// The value typed as Int32 + [FieldOffset(8)] public readonly int Int32; + /// The value typed as UInt32 + [FieldOffset(8)] public readonly uint UInt32; + /// The value typed as Boolean + [FieldOffset(8)] public readonly bool Boolean; + /// The value typed as Single + [FieldOffset(8)] public readonly float Single; + /// The value typed as Double + [FieldOffset(8)] public readonly double Double; + /// The value typed as DateTime + [FieldOffset(8)] public readonly DateTime DateTime; + /// The value typed as TimeSpan + [FieldOffset(8)] public readonly TimeSpan TimeSpan; + /// The value typed as Guid + [FieldOffset(8)] public readonly Guid Guid; + /// The value typed as Object + [FieldOffset(24)] public readonly object Object; + + private DiscriminatedUnion128Object(int discriminator) : this() + { + _discriminator = discriminator; + } + + /// Indicates whether the specified discriminator is assigned + public bool Is(int discriminator) => _discriminator == discriminator; + + /// Create a new discriminated union value + public DiscriminatedUnion128Object(int discriminator, long value) : this(discriminator) { Int64 = value; } + /// Create a new discriminated union value + public DiscriminatedUnion128Object(int discriminator, int value) : this(discriminator) { Int32 = value; } + /// Create a new discriminated union value + public DiscriminatedUnion128Object(int discriminator, ulong value) : this(discriminator) { UInt64 = value; } + /// Create a new discriminated union value + public DiscriminatedUnion128Object(int discriminator, uint value) : this(discriminator) { UInt32 = value; } + /// Create a new discriminated union value + public DiscriminatedUnion128Object(int discriminator, float value) : this(discriminator) { Single = value; } + /// Create a new discriminated union value + public DiscriminatedUnion128Object(int discriminator, double value) : this(discriminator) { Double = value; } + /// Create a new discriminated union value + public DiscriminatedUnion128Object(int discriminator, bool value) : this(discriminator) { Boolean = value; } + /// Create a new discriminated union value + public DiscriminatedUnion128Object(int discriminator, object value) : this(value != null ? discriminator : 0) { Object = value; } + /// Create a new discriminated union value + public DiscriminatedUnion128Object(int discriminator, DateTime? value) : this(value.HasValue ? discriminator: 0) { DateTime = value.GetValueOrDefault(); } + /// Create a new discriminated union value + public DiscriminatedUnion128Object(int discriminator, TimeSpan? value) : this(value.HasValue ? discriminator : 0) { TimeSpan = value.GetValueOrDefault(); } + /// Create a new discriminated union value + public DiscriminatedUnion128Object(int discriminator, Guid? value) : this(value.HasValue ? discriminator : 0) { Guid = value.GetValueOrDefault(); } + + /// Reset a value if the specified discriminator is assigned + public static void Reset(ref DiscriminatedUnion128Object value, int discriminator) + { + if (value.Discriminator == discriminator) value = default; + } + /// The discriminator value + public int Discriminator => _discriminator; + } + + /// Represent multiple types as a union; this is used as part of OneOf - + /// note that it is the caller's responsbility to only read/write the value as the same type + [StructLayout(LayoutKind.Explicit)] + public readonly partial struct DiscriminatedUnion128 + { +#if !FEAT_SAFE + unsafe static DiscriminatedUnion128() + { + if (sizeof(DateTime) > 16) throw new InvalidOperationException(nameof(DateTime) + " was unexpectedly too big for " + nameof(DiscriminatedUnion128)); + if (sizeof(TimeSpan) > 16) throw new InvalidOperationException(nameof(TimeSpan) + " was unexpectedly too big for " + nameof(DiscriminatedUnion128)); + if (sizeof(Guid) > 16) throw new InvalidOperationException(nameof(Guid) + " was unexpectedly too big for " + nameof(DiscriminatedUnion128)); + } +#endif + [FieldOffset(0)] private readonly int _discriminator; // note that we can't pack further because Object needs x8 alignment/padding on x64 + + /// The value typed as Int64 + [FieldOffset(8)] public readonly long Int64; + /// The value typed as UInt64 + [FieldOffset(8)] public readonly ulong UInt64; + /// The value typed as Int32 + [FieldOffset(8)] public readonly int Int32; + /// The value typed as UInt32 + [FieldOffset(8)] public readonly uint UInt32; + /// The value typed as Boolean + [FieldOffset(8)] public readonly bool Boolean; + /// The value typed as Single + [FieldOffset(8)] public readonly float Single; + /// The value typed as Double + [FieldOffset(8)] public readonly double Double; + /// The value typed as DateTime + [FieldOffset(8)] public readonly DateTime DateTime; + /// The value typed as TimeSpan + [FieldOffset(8)] public readonly TimeSpan TimeSpan; + /// The value typed as Guid + [FieldOffset(8)] public readonly Guid Guid; + + private DiscriminatedUnion128(int discriminator) : this() + { + _discriminator = discriminator; + } + + /// Indicates whether the specified discriminator is assigned + public bool Is(int discriminator) => _discriminator == discriminator; + + /// Create a new discriminated union value + public DiscriminatedUnion128(int discriminator, long value) : this(discriminator) { Int64 = value; } + /// Create a new discriminated union value + public DiscriminatedUnion128(int discriminator, int value) : this(discriminator) { Int32 = value; } + /// Create a new discriminated union value + public DiscriminatedUnion128(int discriminator, ulong value) : this(discriminator) { UInt64 = value; } + /// Create a new discriminated union value + public DiscriminatedUnion128(int discriminator, uint value) : this(discriminator) { UInt32 = value; } + /// Create a new discriminated union value + public DiscriminatedUnion128(int discriminator, float value) : this(discriminator) { Single = value; } + /// Create a new discriminated union value + public DiscriminatedUnion128(int discriminator, double value) : this(discriminator) { Double = value; } + /// Create a new discriminated union value + public DiscriminatedUnion128(int discriminator, bool value) : this(discriminator) { Boolean = value; } + /// Create a new discriminated union value + public DiscriminatedUnion128(int discriminator, DateTime? value) : this(value.HasValue ? discriminator: 0) { DateTime = value.GetValueOrDefault(); } + /// Create a new discriminated union value + public DiscriminatedUnion128(int discriminator, TimeSpan? value) : this(value.HasValue ? discriminator : 0) { TimeSpan = value.GetValueOrDefault(); } + /// Create a new discriminated union value + public DiscriminatedUnion128(int discriminator, Guid? value) : this(value.HasValue ? discriminator : 0) { Guid = value.GetValueOrDefault(); } + + /// Reset a value if the specified discriminator is assigned + public static void Reset(ref DiscriminatedUnion128 value, int discriminator) + { + if (value.Discriminator == discriminator) value = default; + } + /// The discriminator value + public int Discriminator => _discriminator; + } + + /// Represent multiple types as a union; this is used as part of OneOf - + /// note that it is the caller's responsbility to only read/write the value as the same type + [StructLayout(LayoutKind.Explicit)] + public readonly partial struct DiscriminatedUnion64Object + { +#if !FEAT_SAFE + unsafe static DiscriminatedUnion64Object() + { + if (sizeof(DateTime) > 8) throw new InvalidOperationException(nameof(DateTime) + " was unexpectedly too big for " + nameof(DiscriminatedUnion64Object)); + if (sizeof(TimeSpan) > 8) throw new InvalidOperationException(nameof(TimeSpan) + " was unexpectedly too big for " + nameof(DiscriminatedUnion64Object)); + } +#endif + [FieldOffset(0)] private readonly int _discriminator; // note that we can't pack further because Object needs x8 alignment/padding on x64 + + /// The value typed as Int64 + [FieldOffset(8)] public readonly long Int64; + /// The value typed as UInt64 + [FieldOffset(8)] public readonly ulong UInt64; + /// The value typed as Int32 + [FieldOffset(8)] public readonly int Int32; + /// The value typed as UInt32 + [FieldOffset(8)] public readonly uint UInt32; + /// The value typed as Boolean + [FieldOffset(8)] public readonly bool Boolean; + /// The value typed as Single + [FieldOffset(8)] public readonly float Single; + /// The value typed as Double + [FieldOffset(8)] public readonly double Double; + /// The value typed as DateTime + [FieldOffset(8)] public readonly DateTime DateTime; + /// The value typed as TimeSpan + [FieldOffset(8)] public readonly TimeSpan TimeSpan; + /// The value typed as Object + [FieldOffset(16)] public readonly object Object; + + private DiscriminatedUnion64Object(int discriminator) : this() + { + _discriminator = discriminator; + } + + /// Indicates whether the specified discriminator is assigned + public bool Is(int discriminator) => _discriminator == discriminator; + + /// Create a new discriminated union value + public DiscriminatedUnion64Object(int discriminator, long value) : this(discriminator) { Int64 = value; } + /// Create a new discriminated union value + public DiscriminatedUnion64Object(int discriminator, int value) : this(discriminator) { Int32 = value; } + /// Create a new discriminated union value + public DiscriminatedUnion64Object(int discriminator, ulong value) : this(discriminator) { UInt64 = value; } + /// Create a new discriminated union value + public DiscriminatedUnion64Object(int discriminator, uint value) : this(discriminator) { UInt32 = value; } + /// Create a new discriminated union value + public DiscriminatedUnion64Object(int discriminator, float value) : this(discriminator) { Single = value; } + /// Create a new discriminated union value + public DiscriminatedUnion64Object(int discriminator, double value) : this(discriminator) { Double = value; } + /// Create a new discriminated union value + public DiscriminatedUnion64Object(int discriminator, bool value) : this(discriminator) { Boolean = value; } + /// Create a new discriminated union value + public DiscriminatedUnion64Object(int discriminator, object value) : this(value != null ? discriminator : 0) { Object = value; } + /// Create a new discriminated union value + public DiscriminatedUnion64Object(int discriminator, DateTime? value) : this(value.HasValue ? discriminator: 0) { DateTime = value.GetValueOrDefault(); } + /// Create a new discriminated union value + public DiscriminatedUnion64Object(int discriminator, TimeSpan? value) : this(value.HasValue ? discriminator : 0) { TimeSpan = value.GetValueOrDefault(); } + + /// Reset a value if the specified discriminator is assigned + public static void Reset(ref DiscriminatedUnion64Object value, int discriminator) + { + if (value.Discriminator == discriminator) value = default; + } + /// The discriminator value + public int Discriminator => _discriminator; + } + + /// Represent multiple types as a union; this is used as part of OneOf - + /// note that it is the caller's responsbility to only read/write the value as the same type + [StructLayout(LayoutKind.Explicit)] + public readonly partial struct DiscriminatedUnion32 + { + [FieldOffset(0)] private readonly int _discriminator; + + /// The value typed as Int32 + [FieldOffset(4)] public readonly int Int32; + /// The value typed as UInt32 + [FieldOffset(4)] public readonly uint UInt32; + /// The value typed as Boolean + [FieldOffset(4)] public readonly bool Boolean; + /// The value typed as Single + [FieldOffset(4)] public readonly float Single; + + private DiscriminatedUnion32(int discriminator) : this() + { + _discriminator = discriminator; + } + + /// Indicates whether the specified discriminator is assigned + public bool Is(int discriminator) => _discriminator == discriminator; + + /// Create a new discriminated union value + public DiscriminatedUnion32(int discriminator, int value) : this(discriminator) { Int32 = value; } + /// Create a new discriminated union value + public DiscriminatedUnion32(int discriminator, uint value) : this(discriminator) { UInt32 = value; } + /// Create a new discriminated union value + public DiscriminatedUnion32(int discriminator, float value) : this(discriminator) { Single = value; } + /// Create a new discriminated union value + public DiscriminatedUnion32(int discriminator, bool value) : this(discriminator) { Boolean = value; } + + /// Reset a value if the specified discriminator is assigned + public static void Reset(ref DiscriminatedUnion32 value, int discriminator) + { + if (value.Discriminator == discriminator) value = default; + } + /// The discriminator value + public int Discriminator => _discriminator; + } + + /// Represent multiple types as a union; this is used as part of OneOf - + /// note that it is the caller's responsbility to only read/write the value as the same type + [StructLayout(LayoutKind.Explicit)] + public readonly partial struct DiscriminatedUnion32Object + { + [FieldOffset(0)] private readonly int _discriminator; + + /// The value typed as Int32 + [FieldOffset(4)] public readonly int Int32; + /// The value typed as UInt32 + [FieldOffset(4)] public readonly uint UInt32; + /// The value typed as Boolean + [FieldOffset(4)] public readonly bool Boolean; + /// The value typed as Single + [FieldOffset(4)] public readonly float Single; + /// The value typed as Object + [FieldOffset(8)] public readonly object Object; + + private DiscriminatedUnion32Object(int discriminator) : this() + { + _discriminator = discriminator; + } + + /// Indicates whether the specified discriminator is assigned + public bool Is(int discriminator) => _discriminator == discriminator; + + /// Create a new discriminated union value + public DiscriminatedUnion32Object(int discriminator, int value) : this(discriminator) { Int32 = value; } + /// Create a new discriminated union value + public DiscriminatedUnion32Object(int discriminator, uint value) : this(discriminator) { UInt32 = value; } + /// Create a new discriminated union value + public DiscriminatedUnion32Object(int discriminator, float value) : this(discriminator) { Single = value; } + /// Create a new discriminated union value + public DiscriminatedUnion32Object(int discriminator, bool value) : this(discriminator) { Boolean = value; } + /// Create a new discriminated union value + public DiscriminatedUnion32Object(int discriminator, object value) : this(value != null ? discriminator : 0) { Object = value; } + + /// Reset a value if the specified discriminator is assigned + public static void Reset(ref DiscriminatedUnion32Object value, int discriminator) + { + if (value.Discriminator == discriminator) value = default; + } + /// The discriminator value + public int Discriminator => _discriminator; + } +} diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/DiscriminatedUnion.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/DiscriminatedUnion.cs.meta new file mode 100644 index 0000000..3268148 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/DiscriminatedUnion.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ab51817e163a1144bb8518368ba0a465 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Extensible.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Extensible.cs new file mode 100644 index 0000000..6bd528b --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Extensible.cs @@ -0,0 +1,284 @@ +using System; +using System.Collections.Generic; +using ProtoBuf.Meta; +using System.Collections; + +namespace ProtoBuf +{ + /// + /// Simple base class for supporting unexpected fields allowing + /// for loss-less round-tips/merge, even if the data is not understod. + /// The additional fields are (by default) stored in-memory in a buffer. + /// + /// As an example of an alternative implementation, you might + /// choose to use the file system (temporary files) as the back-end, tracking + /// only the paths [such an object would ideally be IDisposable and use + /// a finalizer to ensure that the files are removed]. + /// + public abstract class Extensible : IExtensible + { + // note: not marked ProtoContract - no local state, and can't + // predict sub-classes + + private IExtension extensionObject; + + IExtension IExtensible.GetExtensionObject(bool createIfMissing) + { + return GetExtensionObject(createIfMissing); + } + + /// + /// Retrieves the extension object for the current + /// instance, optionally creating it if it does not already exist. + /// + /// Should a new extension object be + /// created if it does not already exist? + /// The extension object if it exists (or was created), or null + /// if the extension object does not exist or is not available. + /// The createIfMissing argument is false during serialization, + /// and true during deserialization upon encountering unexpected fields. + protected virtual IExtension GetExtensionObject(bool createIfMissing) + { + return GetExtensionObject(ref extensionObject, createIfMissing); + } + + /// + /// Provides a simple, default implementation for extension support, + /// optionally creating it if it does not already exist. Designed to be called by + /// classes implementing . + /// + /// Should a new extension object be + /// created if it does not already exist? + /// The extension field to check (and possibly update). + /// The extension object if it exists (or was created), or null + /// if the extension object does not exist or is not available. + /// The createIfMissing argument is false during serialization, + /// and true during deserialization upon encountering unexpected fields. + public static IExtension GetExtensionObject(ref IExtension extensionObject, bool createIfMissing) + { + if (createIfMissing && extensionObject == null) + { + extensionObject = new BufferExtension(); + } + return extensionObject; + } + +#if !NO_RUNTIME + /// + /// Appends the value as an additional (unexpected) data-field for the instance. + /// Note that for non-repeated sub-objects, this equates to a merge operation; + /// for repeated sub-objects this adds a new instance to the set; for simple + /// values the new value supercedes the old value. + /// + /// Note that appending a value does not remove the old value from + /// the stream; avoid repeatedly appending values for the same field. + /// The type of the value to append. + /// The extensible object to append the value to. + /// The field identifier; the tag should not be defined as a known data-field for the instance. + /// The value to append. + public static void AppendValue(IExtensible instance, int tag, TValue value) + { + AppendValue(instance, tag, DataFormat.Default, value); + } + + /// + /// Appends the value as an additional (unexpected) data-field for the instance. + /// Note that for non-repeated sub-objects, this equates to a merge operation; + /// for repeated sub-objects this adds a new instance to the set; for simple + /// values the new value supercedes the old value. + /// + /// Note that appending a value does not remove the old value from + /// the stream; avoid repeatedly appending values for the same field. + /// The data-type of the field. + /// The data-format to use when encoding the value. + /// The extensible object to append the value to. + /// The field identifier; the tag should not be defined as a known data-field for the instance. + /// The value to append. + public static void AppendValue(IExtensible instance, int tag, DataFormat format, TValue value) + { + ExtensibleUtil.AppendExtendValue(RuntimeTypeModel.Default, instance, tag, format, value); + } + /// + /// Queries an extensible object for an additional (unexpected) data-field for the instance. + /// The value returned is the composed value after merging any duplicated content; if the + /// value is "repeated" (a list), then use GetValues instead. + /// + /// The data-type of the field. + /// The extensible object to obtain the value from. + /// The field identifier; the tag should not be defined as a known data-field for the instance. + /// The effective value of the field, or the default value if not found. + public static TValue GetValue(IExtensible instance, int tag) + { + return GetValue(instance, tag, DataFormat.Default); + } + + /// + /// Queries an extensible object for an additional (unexpected) data-field for the instance. + /// The value returned is the composed value after merging any duplicated content; if the + /// value is "repeated" (a list), then use GetValues instead. + /// + /// The data-type of the field. + /// The extensible object to obtain the value from. + /// The field identifier; the tag should not be defined as a known data-field for the instance. + /// The data-format to use when decoding the value. + /// The effective value of the field, or the default value if not found. + public static TValue GetValue(IExtensible instance, int tag, DataFormat format) + { + TryGetValue(instance, tag, format, out TValue value); + return value; + } + + /// + /// Queries an extensible object for an additional (unexpected) data-field for the instance. + /// The value returned (in "value") is the composed value after merging any duplicated content; + /// if the value is "repeated" (a list), then use GetValues instead. + /// + /// The data-type of the field. + /// The effective value of the field, or the default value if not found. + /// The extensible object to obtain the value from. + /// The field identifier; the tag should not be defined as a known data-field for the instance. + /// True if data for the field was present, false otherwise. + public static bool TryGetValue(IExtensible instance, int tag, out TValue value) + { + return TryGetValue(instance, tag, DataFormat.Default, out value); + } + + /// + /// Queries an extensible object for an additional (unexpected) data-field for the instance. + /// The value returned (in "value") is the composed value after merging any duplicated content; + /// if the value is "repeated" (a list), then use GetValues instead. + /// + /// The data-type of the field. + /// The effective value of the field, or the default value if not found. + /// The extensible object to obtain the value from. + /// The field identifier; the tag should not be defined as a known data-field for the instance. + /// The data-format to use when decoding the value. + /// True if data for the field was present, false otherwise. + public static bool TryGetValue(IExtensible instance, int tag, DataFormat format, out TValue value) + { + return TryGetValue(instance, tag, format, false, out value); + } + + /// + /// Queries an extensible object for an additional (unexpected) data-field for the instance. + /// The value returned (in "value") is the composed value after merging any duplicated content; + /// if the value is "repeated" (a list), then use GetValues instead. + /// + /// The data-type of the field. + /// The effective value of the field, or the default value if not found. + /// The extensible object to obtain the value from. + /// The field identifier; the tag should not be defined as a known data-field for the instance. + /// The data-format to use when decoding the value. + /// Allow tags that are present as part of the definition; for example, to query unknown enum values. + /// True if data for the field was present, false otherwise. + public static bool TryGetValue(IExtensible instance, int tag, DataFormat format, bool allowDefinedTag, out TValue value) + { + value = default; + bool set = false; + foreach (TValue val in ExtensibleUtil.GetExtendedValues(instance, tag, format, true, allowDefinedTag)) + { + // expecting at most one yield... + // but don't break; need to read entire stream + value = val; + set = true; + } + + return set; + } + + /// + /// Queries an extensible object for an additional (unexpected) data-field for the instance. + /// Each occurrence of the field is yielded separately, making this usage suitable for "repeated" + /// (list) fields. + /// + /// The extended data is processed lazily as the enumerator is iterated. + /// The data-type of the field. + /// The extensible object to obtain the value from. + /// The field identifier; the tag should not be defined as a known data-field for the instance. + /// An enumerator that yields each occurrence of the field. + public static IEnumerable GetValues(IExtensible instance, int tag) + { + return ExtensibleUtil.GetExtendedValues(instance, tag, DataFormat.Default, false, false); + } + + /// + /// Queries an extensible object for an additional (unexpected) data-field for the instance. + /// Each occurrence of the field is yielded separately, making this usage suitable for "repeated" + /// (list) fields. + /// + /// The extended data is processed lazily as the enumerator is iterated. + /// The data-type of the field. + /// The extensible object to obtain the value from. + /// The field identifier; the tag should not be defined as a known data-field for the instance. + /// The data-format to use when decoding the value. + /// An enumerator that yields each occurrence of the field. + public static IEnumerable GetValues(IExtensible instance, int tag, DataFormat format) + { + return ExtensibleUtil.GetExtendedValues(instance, tag, format, false, false); + } +#endif + + /// + /// Queries an extensible object for an additional (unexpected) data-field for the instance. + /// The value returned (in "value") is the composed value after merging any duplicated content; + /// if the value is "repeated" (a list), then use GetValues instead. + /// + /// The data-type of the field. + /// The model to use for configuration. + /// The effective value of the field, or the default value if not found. + /// The extensible object to obtain the value from. + /// The field identifier; the tag should not be defined as a known data-field for the instance. + /// The data-format to use when decoding the value. + /// Allow tags that are present as part of the definition; for example, to query unknown enum values. + /// True if data for the field was present, false otherwise. + public static bool TryGetValue(TypeModel model, Type type, IExtensible instance, int tag, DataFormat format, bool allowDefinedTag, out object value) + { + value = null; + bool set = false; + foreach (object val in ExtensibleUtil.GetExtendedValues(model, type, instance, tag, format, true, allowDefinedTag)) + { + // expecting at most one yield... + // but don't break; need to read entire stream + value = val; + set = true; + } + + return set; + } + + /// + /// Queries an extensible object for an additional (unexpected) data-field for the instance. + /// Each occurrence of the field is yielded separately, making this usage suitable for "repeated" + /// (list) fields. + /// + /// The extended data is processed lazily as the enumerator is iterated. + /// The model to use for configuration. + /// The data-type of the field. + /// The extensible object to obtain the value from. + /// The field identifier; the tag should not be defined as a known data-field for the instance. + /// The data-format to use when decoding the value. + /// An enumerator that yields each occurrence of the field. + public static IEnumerable GetValues(TypeModel model, Type type, IExtensible instance, int tag, DataFormat format) + { + return ExtensibleUtil.GetExtendedValues(model, type, instance, tag, format, false, false); + } + + /// + /// Appends the value as an additional (unexpected) data-field for the instance. + /// Note that for non-repeated sub-objects, this equates to a merge operation; + /// for repeated sub-objects this adds a new instance to the set; for simple + /// values the new value supercedes the old value. + /// + /// Note that appending a value does not remove the old value from + /// the stream; avoid repeatedly appending values for the same field. + /// The model to use for configuration. + /// The data-format to use when encoding the value. + /// The extensible object to append the value to. + /// The field identifier; the tag should not be defined as a known data-field for the instance. + /// The value to append. + public static void AppendValue(TypeModel model, IExtensible instance, int tag, DataFormat format, object value) + { + ExtensibleUtil.AppendExtendValue(model, instance, tag, format, value); + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Extensible.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Extensible.cs.meta new file mode 100644 index 0000000..ac4ec36 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Extensible.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: fc24b62dbd0b19642bce397e2b061aa0 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/ExtensibleUtil.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/ExtensibleUtil.cs new file mode 100644 index 0000000..9cc1613 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/ExtensibleUtil.cs @@ -0,0 +1,118 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using ProtoBuf.Meta; + +namespace ProtoBuf +{ + /// + /// This class acts as an internal wrapper allowing us to do a dynamic + /// methodinfo invoke; an't put into Serializer as don't want on public + /// API; can't put into Serializer<T> since we need to invoke + /// across classes + /// + internal static class ExtensibleUtil + { + +#if !NO_RUNTIME + /// + /// All this does is call GetExtendedValuesTyped with the correct type for "instance"; + /// this ensures that we don't get issues with subclasses declaring conflicting types - + /// the caller must respect the fields defined for the type they pass in. + /// + internal static IEnumerable GetExtendedValues(IExtensible instance, int tag, DataFormat format, bool singleton, bool allowDefinedTag) + { + foreach (TValue value in GetExtendedValues(RuntimeTypeModel.Default, typeof(TValue), instance, tag, format, singleton, allowDefinedTag)) + { + yield return value; + } + } +#endif + /// + /// All this does is call GetExtendedValuesTyped with the correct type for "instance"; + /// this ensures that we don't get issues with subclasses declaring conflicting types - + /// the caller must respect the fields defined for the type they pass in. + /// + internal static IEnumerable GetExtendedValues(TypeModel model, Type type, IExtensible instance, int tag, DataFormat format, bool singleton, bool allowDefinedTag) + { + if (instance == null) throw new ArgumentNullException(nameof(instance)); + if (tag <= 0) throw new ArgumentOutOfRangeException(nameof(tag)); + IExtension extn = instance.GetExtensionObject(false); + + if (extn == null) + { + yield break; + } + + Stream stream = extn.BeginQuery(); + object value = null; + ProtoReader reader = null; + try + { + SerializationContext ctx = new SerializationContext(); + reader = ProtoReader.Create(stream, model, ctx, ProtoReader.TO_EOF); + while (model.TryDeserializeAuxiliaryType(reader, format, tag, type, ref value, true, true, false, false, null) && value != null) + { + if (!singleton) + { + yield return value; + + value = null; // fresh item each time + } + } + if (singleton && value != null) + { + yield return value; + } + } + finally + { + ProtoReader.Recycle(reader); + extn.EndQuery(stream); + } + } + + internal static void AppendExtendValue(TypeModel model, IExtensible instance, int tag, DataFormat format, object value) + { + if (instance == null) throw new ArgumentNullException(nameof(instance)); + if (value == null) throw new ArgumentNullException(nameof(value)); + + // TODO + //model.CheckTagNotInUse(tag); + + // obtain the extension object and prepare to write + IExtension extn = instance.GetExtensionObject(true); + if (extn == null) throw new InvalidOperationException("No extension object available; appended data would be lost."); + bool commit = false; + Stream stream = extn.BeginAppend(); + try + { + using (ProtoWriter writer = ProtoWriter.Create(stream, model, null)) + { + model.TrySerializeAuxiliaryType(writer, null, format, tag, value, false, null); + writer.Close(); + } + commit = true; + } + finally + { + extn.EndAppend(stream, commit); + } + } + + // /// + // /// Stores the given value into the instance's stream; the serializer + // /// is inferred from TValue and format. + // /// + // /// Needs to be public to be callable thru reflection in Silverlight + // public static void AppendExtendValueTyped( + // TypeModel model, TSource instance, int tag, DataFormat format, TValue value) + // where TSource : class, IExtensible + // { + // AppendExtendValue(model, instance, tag, format, value); + // } + + } + +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/ExtensibleUtil.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/ExtensibleUtil.cs.meta new file mode 100644 index 0000000..ea420c6 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/ExtensibleUtil.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: dc71d3f5e8f25ad41bb04ea933cee56e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/GlobalSuppressions.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/GlobalSuppressions.cs new file mode 100644 index 0000000..48b9190 Binary files /dev/null and b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/GlobalSuppressions.cs differ diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/GlobalSuppressions.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/GlobalSuppressions.cs.meta new file mode 100644 index 0000000..14ab4e3 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/GlobalSuppressions.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c110f96e5d6da4f498bcb6d5fa673be7 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Helpers.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Helpers.cs new file mode 100644 index 0000000..1a0491d --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Helpers.cs @@ -0,0 +1,638 @@ + +using System; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Text; +#if COREFX +using System.Linq; +#endif +#if PROFILE259 +using System.Reflection; +using System.Linq; +#else +using System.Reflection; +#endif + +namespace ProtoBuf +{ + /// + /// Not all frameworks are created equal (fx1.1 vs fx2.0, + /// micro-framework, compact-framework, + /// silverlight, etc). This class simply wraps up a few things that would + /// otherwise make the real code unnecessarily messy, providing fallback + /// implementations if necessary. + /// + internal sealed class Helpers + { + private Helpers() { } + + public static StringBuilder AppendLine(StringBuilder builder) + { + return builder.AppendLine(); + } + + [System.Diagnostics.Conditional("DEBUG")] + public static void DebugWriteLine(string message, object obj) + { +#if DEBUG + string suffix; + try + { + suffix = obj == null ? "(null)" : obj.ToString(); + } + catch + { + suffix = "(exception)"; + } + DebugWriteLine(message + ": " + suffix); +#endif + } + [System.Diagnostics.Conditional("DEBUG")] + public static void DebugWriteLine(string message) + { +#if DEBUG + System.Diagnostics.Debug.WriteLine(message); +#endif + } + [System.Diagnostics.Conditional("TRACE")] + public static void TraceWriteLine(string message) + { +#if TRACE +#if CF2 || PORTABLE || COREFX || PROFILE259 + System.Diagnostics.Debug.WriteLine(message); +#else + System.Diagnostics.Trace.WriteLine(message); +#endif +#endif + } + + [System.Diagnostics.Conditional("DEBUG")] + public static void DebugAssert(bool condition, string message) + { +#if DEBUG + if (!condition) + { + System.Diagnostics.Debug.Assert(false, message); + } +#endif + } + [System.Diagnostics.Conditional("DEBUG")] + public static void DebugAssert(bool condition, string message, params object[] args) + { +#if DEBUG + if (!condition) DebugAssert(false, string.Format(message, args)); +#endif + } + [System.Diagnostics.Conditional("DEBUG")] + public static void DebugAssert(bool condition) + { +#if DEBUG + if (!condition && System.Diagnostics.Debugger.IsAttached) System.Diagnostics.Debugger.Break(); + System.Diagnostics.Debug.Assert(condition); +#endif + } +#if !NO_RUNTIME + public static void Sort(int[] keys, object[] values) + { + // bubble-sort; it'll work on MF, has small code, + // and works well-enough for our sizes. This approach + // also allows us to do `int` compares without having + // to go via IComparable etc, so win:win + bool swapped; + do + { + swapped = false; + for (int i = 1; i < keys.Length; i++) + { + if (keys[i - 1] > keys[i]) + { + int tmpKey = keys[i]; + keys[i] = keys[i - 1]; + keys[i - 1] = tmpKey; + object tmpValue = values[i]; + values[i] = values[i - 1]; + values[i - 1] = tmpValue; + swapped = true; + } + } + } while (swapped); + } +#endif + +#if COREFX + internal static MemberInfo GetInstanceMember(TypeInfo declaringType, string name) + { + var members = declaringType.AsType().GetMember(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); + switch(members.Length) + { + case 0: return null; + case 1: return members[0]; + default: throw new AmbiguousMatchException(name); + } + } + internal static MethodInfo GetInstanceMethod(Type declaringType, string name) + { + foreach (MethodInfo method in declaringType.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)) + { + if (method.Name == name) return method; + } + return null; + } + internal static MethodInfo GetInstanceMethod(TypeInfo declaringType, string name) + { + return GetInstanceMethod(declaringType.AsType(), name); ; + } + internal static MethodInfo GetStaticMethod(Type declaringType, string name) + { + foreach (MethodInfo method in declaringType.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)) + { + if (method.Name == name) return method; + } + return null; + } + + internal static MethodInfo GetStaticMethod(TypeInfo declaringType, string name) + { + return GetStaticMethod(declaringType.AsType(), name); + } + internal static MethodInfo GetStaticMethod(Type declaringType, string name, Type[] parameterTypes) + { + foreach(MethodInfo method in declaringType.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)) + { + if (method.Name == name && IsMatch(method.GetParameters(), parameterTypes)) return method; + } + return null; + } + internal static MethodInfo GetInstanceMethod(Type declaringType, string name, Type[] parameterTypes) + { + foreach (MethodInfo method in declaringType.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)) + { + if (method.Name == name && IsMatch(method.GetParameters(), parameterTypes)) return method; + } + return null; + } + internal static MethodInfo GetInstanceMethod(TypeInfo declaringType, string name, Type[] types) + { + return GetInstanceMethod(declaringType.AsType(), name, types); + } +#elif PROFILE259 + internal static MemberInfo GetInstanceMember(TypeInfo declaringType, string name) + { + IEnumerable members = declaringType.DeclaredMembers; + IList found = new List(); + foreach (MemberInfo member in members) + { + if (member.Name.Equals(name)) + { + found.Add(member); + } + } + switch (found.Count) + { + case 0: return null; + case 1: return found.First(); + default: throw new AmbiguousMatchException(name); + } + } + internal static MethodInfo GetInstanceMethod(Type declaringType, string name) + { + var methods = declaringType.GetRuntimeMethods(); + foreach (MethodInfo method in methods) + { + if (method.Name == name) + { + return method; + } + } + return null; + } + internal static MethodInfo GetInstanceMethod(TypeInfo declaringType, string name) + { + return GetInstanceMethod(declaringType.AsType(), name); ; + } + internal static MethodInfo GetStaticMethod(Type declaringType, string name) + { + var methods = declaringType.GetRuntimeMethods(); + foreach (MethodInfo method in methods) + { + if (method.Name == name) + { + return method; + } + } + return null; + } + + internal static MethodInfo GetStaticMethod(TypeInfo declaringType, string name) + { + return GetStaticMethod(declaringType.AsType(), name); + } + internal static MethodInfo GetStaticMethod(Type declaringType, string name, Type[] parameterTypes) + { + var methods = declaringType.GetRuntimeMethods(); + foreach (MethodInfo method in methods) + { + if (method.Name == name && + IsMatch(method.GetParameters(), parameterTypes)) + { + return method; + } + } + return null; + } + internal static MethodInfo GetInstanceMethod(Type declaringType, string name, Type[] parameterTypes) + { + var methods = declaringType.GetRuntimeMethods(); + foreach (MethodInfo method in methods) + { + if (method.Name == name && + IsMatch(method.GetParameters(), parameterTypes)) + { + return method; + } + } + return null; + } + internal static MethodInfo GetInstanceMethod(TypeInfo declaringType, string name, Type[] types) + { + return GetInstanceMethod(declaringType.AsType(), name, types); + } +#else + internal static MethodInfo GetInstanceMethod(Type declaringType, string name) + { + return declaringType.GetMethod(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); + } + internal static MethodInfo GetStaticMethod(Type declaringType, string name) + { + return declaringType.GetMethod(name, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); + } + internal static MethodInfo GetStaticMethod(Type declaringType, string name, Type[] parameterTypes) + { +#if PORTABLE + foreach (MethodInfo method in declaringType.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)) + { + if (method.Name == name && IsMatch(method.GetParameters(), parameterTypes)) return method; + } + return null; +#else + return declaringType.GetMethod(name, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null, parameterTypes, null); +#endif + } + internal static MethodInfo GetInstanceMethod(Type declaringType, string name, Type[] types) + { + if (types == null) types = EmptyTypes; +#if PORTABLE || COREFX + MethodInfo method = declaringType.GetMethod(name, types); + if (method != null && method.IsStatic) method = null; + return method; +#else + return declaringType.GetMethod(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, + null, types, null); +#endif + } +#endif + + internal static bool IsSubclassOf(Type type, Type baseClass) + { +#if COREFX || PROFILE259 + return type.GetTypeInfo().IsSubclassOf(baseClass); +#else + return type.IsSubclassOf(baseClass); +#endif + } + + public readonly static Type[] EmptyTypes = +#if PORTABLE || CF2 || CF35 || PROFILE259 + new Type[0]; +#else + Type.EmptyTypes; +#endif + +#if COREFX || PROFILE259 + private static readonly Type[] knownTypes = new Type[] { + typeof(bool), typeof(char), typeof(sbyte), typeof(byte), + typeof(short), typeof(ushort), typeof(int), typeof(uint), + typeof(long), typeof(ulong), typeof(float), typeof(double), + typeof(decimal), typeof(string), + typeof(DateTime), typeof(TimeSpan), typeof(Guid), typeof(Uri), + typeof(byte[]), typeof(Type)}; + private static readonly ProtoTypeCode[] knownCodes = new ProtoTypeCode[] { + ProtoTypeCode.Boolean, ProtoTypeCode.Char, ProtoTypeCode.SByte, ProtoTypeCode.Byte, + ProtoTypeCode.Int16, ProtoTypeCode.UInt16, ProtoTypeCode.Int32, ProtoTypeCode.UInt32, + ProtoTypeCode.Int64, ProtoTypeCode.UInt64, ProtoTypeCode.Single, ProtoTypeCode.Double, + ProtoTypeCode.Decimal, ProtoTypeCode.String, + ProtoTypeCode.DateTime, ProtoTypeCode.TimeSpan, ProtoTypeCode.Guid, ProtoTypeCode.Uri, + ProtoTypeCode.ByteArray, ProtoTypeCode.Type + }; + +#endif + + public static ProtoTypeCode GetTypeCode(Type type) + { +#if COREFX || PROFILE259 + if (IsEnum(type)) + { + type = Enum.GetUnderlyingType(type); + } + int idx = Array.IndexOf(knownTypes, type); + if (idx >= 0) return knownCodes[idx]; + return type == null ? ProtoTypeCode.Empty : ProtoTypeCode.Unknown; +#else + TypeCode code = Type.GetTypeCode(type); + switch (code) + { + case TypeCode.Empty: + case TypeCode.Boolean: + case TypeCode.Char: + case TypeCode.SByte: + case TypeCode.Byte: + case TypeCode.Int16: + case TypeCode.UInt16: + case TypeCode.Int32: + case TypeCode.UInt32: + case TypeCode.Int64: + case TypeCode.UInt64: + case TypeCode.Single: + case TypeCode.Double: + case TypeCode.Decimal: + case TypeCode.DateTime: + case TypeCode.String: + return (ProtoTypeCode)code; + } + if (type == typeof(TimeSpan)) return ProtoTypeCode.TimeSpan; + if (type == typeof(Guid)) return ProtoTypeCode.Guid; + if (type == typeof(Uri)) return ProtoTypeCode.Uri; +#if PORTABLE + // In PCLs, the Uri type may not match (WinRT uses Internal/Uri, .Net uses System/Uri), so match on the full name instead + if (type.FullName == typeof(Uri).FullName) return ProtoTypeCode.Uri; +#endif + if (type == typeof(byte[])) return ProtoTypeCode.ByteArray; + if (type == typeof(Type)) return ProtoTypeCode.Type; + + return ProtoTypeCode.Unknown; +#endif + } + + internal static Type GetUnderlyingType(Type type) + { + return Nullable.GetUnderlyingType(type); + } + + internal static bool IsValueType(Type type) + { +#if COREFX || PROFILE259 + return type.GetTypeInfo().IsValueType; +#else + return type.IsValueType; +#endif + } + internal static bool IsSealed(Type type) + { +#if COREFX || PROFILE259 + return type.GetTypeInfo().IsSealed; +#else + return type.IsSealed; +#endif + } + internal static bool IsClass(Type type) + { +#if COREFX || PROFILE259 + return type.GetTypeInfo().IsClass; +#else + return type.IsClass; +#endif + } + + internal static bool IsEnum(Type type) + { +#if COREFX || PROFILE259 + return type.GetTypeInfo().IsEnum; +#else + return type.IsEnum; +#endif + } + + internal static MethodInfo GetGetMethod(PropertyInfo property, bool nonPublic, bool allowInternal) + { + if (property == null) return null; +#if COREFX || PROFILE259 + MethodInfo method = property.GetMethod; + if (!nonPublic && method != null && !method.IsPublic) method = null; + return method; +#else + MethodInfo method = property.GetGetMethod(nonPublic); + if (method == null && !nonPublic && allowInternal) + { // could be "internal" or "protected internal"; look for a non-public, then back-check + method = property.GetGetMethod(true); + if (method == null && !(method.IsAssembly || method.IsFamilyOrAssembly)) + { + method = null; + } + } + return method; +#endif + } + internal static MethodInfo GetSetMethod(PropertyInfo property, bool nonPublic, bool allowInternal) + { + if (property == null) return null; +#if COREFX || PROFILE259 + MethodInfo method = property.SetMethod; + if (!nonPublic && method != null && !method.IsPublic) method = null; + return method; +#else + MethodInfo method = property.GetSetMethod(nonPublic); + if (method == null && !nonPublic && allowInternal) + { // could be "internal" or "protected internal"; look for a non-public, then back-check + method = property.GetGetMethod(true); + if (method == null && !(method.IsAssembly || method.IsFamilyOrAssembly)) + { + method = null; + } + } + return method; +#endif + } + +#if COREFX || PORTABLE || PROFILE259 + private static bool IsMatch(ParameterInfo[] parameters, Type[] parameterTypes) + { + if (parameterTypes == null) parameterTypes = EmptyTypes; + if (parameters.Length != parameterTypes.Length) return false; + for (int i = 0; i < parameters.Length; i++) + { + if (parameters[i].ParameterType != parameterTypes[i]) return false; + } + return true; + } +#endif +#if COREFX || PROFILE259 + internal static ConstructorInfo GetConstructor(Type type, Type[] parameterTypes, bool nonPublic) + { + return GetConstructor(type.GetTypeInfo(), parameterTypes, nonPublic); + } + internal static ConstructorInfo GetConstructor(TypeInfo type, Type[] parameterTypes, bool nonPublic) + { + return GetConstructors(type, nonPublic).SingleOrDefault(ctor => IsMatch(ctor.GetParameters(), parameterTypes)); + } + internal static ConstructorInfo[] GetConstructors(TypeInfo typeInfo, bool nonPublic) + { + return typeInfo.DeclaredConstructors.Where(c => !c.IsStatic && ((!nonPublic && c.IsPublic) || nonPublic)).ToArray(); + } + internal static PropertyInfo GetProperty(Type type, string name, bool nonPublic) + { + return GetProperty(type.GetTypeInfo(), name, nonPublic); + } + internal static PropertyInfo GetProperty(TypeInfo type, string name, bool nonPublic) + { + return type.GetDeclaredProperty(name); + } +#else + + internal static ConstructorInfo GetConstructor(Type type, Type[] parameterTypes, bool nonPublic) + { +#if PORTABLE || COREFX + // pretty sure this will only ever return public, but... + ConstructorInfo ctor = type.GetConstructor(parameterTypes); + return (ctor != null && (nonPublic || ctor.IsPublic)) ? ctor : null; +#else + return type.GetConstructor( + nonPublic ? BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic + : BindingFlags.Instance | BindingFlags.Public, + null, parameterTypes, null); +#endif + + } + internal static ConstructorInfo[] GetConstructors(Type type, bool nonPublic) + { + return type.GetConstructors( + nonPublic ? BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic + : BindingFlags.Instance | BindingFlags.Public); + } + internal static PropertyInfo GetProperty(Type type, string name, bool nonPublic) + { + return type.GetProperty(name, + nonPublic ? BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic + : BindingFlags.Instance | BindingFlags.Public); + } +#endif + + + internal static object ParseEnum(Type type, string value) + { + return Enum.Parse(type, value, true); + } + + + internal static MemberInfo[] GetInstanceFieldsAndProperties(Type type, bool publicOnly) + { +#if PROFILE259 + var members = new List(); + foreach (FieldInfo field in type.GetRuntimeFields()) + { + if (field.IsStatic) continue; + if (field.IsPublic || !publicOnly) members.Add(field); + } + foreach (PropertyInfo prop in type.GetRuntimeProperties()) + { + MethodInfo getter = Helpers.GetGetMethod(prop, true, true); + if (getter == null || getter.IsStatic) continue; + if (getter.IsPublic || !publicOnly) members.Add(prop); + } + return members.ToArray(); +#else + BindingFlags flags = publicOnly ? BindingFlags.Public | BindingFlags.Instance : BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic; + PropertyInfo[] props = type.GetProperties(flags); + FieldInfo[] fields = type.GetFields(flags); + MemberInfo[] members = new MemberInfo[fields.Length + props.Length]; + props.CopyTo(members, 0); + fields.CopyTo(members, props.Length); + return members; +#endif + } + + internal static Type GetMemberType(MemberInfo member) + { +#if PORTABLE || COREFX || PROFILE259 + if (member is PropertyInfo prop) return prop.PropertyType; + FieldInfo fld = member as FieldInfo; + return fld?.FieldType; +#else + switch (member.MemberType) + { + case MemberTypes.Field: return ((FieldInfo)member).FieldType; + case MemberTypes.Property: return ((PropertyInfo)member).PropertyType; + default: return null; + } +#endif + } + + internal static bool IsAssignableFrom(Type target, Type type) + { +#if PROFILE259 + return target.GetTypeInfo().IsAssignableFrom(type.GetTypeInfo()); +#else + return target.IsAssignableFrom(type); +#endif + } + internal static Assembly GetAssembly(Type type) + { +#if COREFX || PROFILE259 + return type.GetTypeInfo().Assembly; +#else + return type.Assembly; +#endif + } + internal static byte[] GetBuffer(MemoryStream ms) + { +#if COREFX + if(!ms.TryGetBuffer(out var segment)) + { + throw new InvalidOperationException("Unable to obtain underlying MemoryStream buffer"); + } else if(segment.Offset != 0) + { + throw new InvalidOperationException("Underlying MemoryStream buffer was not zero-offset"); + } else + { + return segment.Array; + } +#elif PORTABLE || PROFILE259 + return ms.ToArray(); +#else + return ms.GetBuffer(); +#endif + } + } + /// + /// Intended to be a direct map to regular TypeCode, but: + /// - with missing types + /// - existing on WinRT + /// + internal enum ProtoTypeCode + { + Empty = 0, + Unknown = 1, // maps to TypeCode.Object + Boolean = 3, + Char = 4, + SByte = 5, + Byte = 6, + Int16 = 7, + UInt16 = 8, + Int32 = 9, + UInt32 = 10, + Int64 = 11, + UInt64 = 12, + Single = 13, + Double = 14, + Decimal = 15, + DateTime = 16, + String = 18, + + // additions + TimeSpan = 100, + ByteArray = 101, + Guid = 102, + Uri = 103, + Type = 104 + } +} diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Helpers.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Helpers.cs.meta new file mode 100644 index 0000000..d67edef --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Helpers.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 227f762ea287cdf42a9293ea6c481ff8 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/IExtensible.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/IExtensible.cs new file mode 100644 index 0000000..b7c0b57 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/IExtensible.cs @@ -0,0 +1,23 @@ + +namespace ProtoBuf +{ + /// + /// Indicates that the implementing type has support for protocol-buffer + /// extensions. + /// + /// Can be implemented by deriving from Extensible. + public interface IExtensible + { + /// + /// Retrieves the extension object for the current + /// instance, optionally creating it if it does not already exist. + /// + /// Should a new extension object be + /// created if it does not already exist? + /// The extension object if it exists (or was created), or null + /// if the extension object does not exist or is not available. + /// The createIfMissing argument is false during serialization, + /// and true during deserialization upon encountering unexpected fields. + IExtension GetExtensionObject(bool createIfMissing); + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/IExtensible.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/IExtensible.cs.meta new file mode 100644 index 0000000..3c8f29a --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/IExtensible.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b9cd5092c5d6d9d4299fc0c88ebb9390 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/IExtension.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/IExtension.cs new file mode 100644 index 0000000..0a137ac --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/IExtension.cs @@ -0,0 +1,58 @@ + +using System.IO; +namespace ProtoBuf +{ + /// + /// Provides addition capability for supporting unexpected fields during + /// protocol-buffer serialization/deserialization. This allows for loss-less + /// round-trip/merge, even when the data is not fully understood. + /// + public interface IExtension + { + /// + /// Requests a stream into which any unexpected fields can be persisted. + /// + /// A new stream suitable for storing data. + Stream BeginAppend(); + + /// + /// Indicates that all unexpected fields have now been stored. The + /// implementing class is responsible for closing the stream. If + /// "commit" is not true the data may be discarded. + /// + /// The stream originally obtained by BeginAppend. + /// True if the append operation completed successfully. + void EndAppend(Stream stream, bool commit); + + /// + /// Requests a stream of the unexpected fields previously stored. + /// + /// A prepared stream of the unexpected fields. + Stream BeginQuery(); + + /// + /// Indicates that all unexpected fields have now been read. The + /// implementing class is responsible for closing the stream. + /// + /// The stream originally obtained by BeginQuery. + void EndQuery(Stream stream); + + /// + /// Requests the length of the raw binary stream; this is used + /// when serializing sub-entities to indicate the expected size. + /// + /// The length of the binary stream representing unexpected data. + int GetLength(); + } + + /// + /// Provides the ability to remove all existing extension data + /// + public interface IExtensionResettable : IExtension + { + /// + /// Remove all existing extension data + /// + void Reset(); + } +} diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/IExtension.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/IExtension.cs.meta new file mode 100644 index 0000000..d5da340 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/IExtension.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8018fb363175787478148842225e7d16 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/IProtoInputT.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/IProtoInputT.cs new file mode 100644 index 0000000..6eaa0ce --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/IProtoInputT.cs @@ -0,0 +1,13 @@ +namespace ProtoBuf +{ + /// + /// Represents the ability to deserialize values from an input of type + /// + public interface IProtoInput + { + /// + /// Deserialize a value from the input + /// + T Deserialize(TInput source, T value = default, object userState = null); + } +} diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/IProtoInputT.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/IProtoInputT.cs.meta new file mode 100644 index 0000000..a80bc62 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/IProtoInputT.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a6514bacfd3143a49a027f15434586f7 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/IProtoOutputT.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/IProtoOutputT.cs new file mode 100644 index 0000000..1c7dd42 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/IProtoOutputT.cs @@ -0,0 +1,55 @@ +using System; + +namespace ProtoBuf +{ + /// + /// Represents the ability to serialize values to an output of type + /// + public interface IProtoOutput + { + /// + /// Serialize the provided value + /// + void Serialize(TOutput destination, T value, object userState = null); + } + + /// + /// Represents the ability to serialize values to an output of type + /// with pre-computation of the length + /// + public interface IMeasuredProtoOutput : IProtoOutput + { + /// + /// Measure the length of a value in advance of serialization + /// + MeasureState Measure(T value, object userState = null); + + /// + /// Serialize the previously measured value + /// + void Serialize(MeasureState measured, TOutput destination); + } + + /// + /// Represents the outcome of computing the length of an object; since this may have required computing lengths + /// for multiple objects, some metadata is retained so that a subsequent serialize operation using + /// this instance can re-use the previously calculated lengths. If the object state changes between the + /// measure and serialize operations, the behavior is undefined. + /// + public struct MeasureState : IDisposable + // note: 2.4.* does not actually implement this API; + // it only advertises it for 3.* capability/feature-testing, i.e. + // callers can check whether a model implements + // IMeasuredProtoOutput, and *work from that* + { + /// + /// Releases all resources associated with this value + /// + public void Dispose() => throw new NotImplementedException(); + + /// + /// Gets the calculated length of this serialize operation, in bytes + /// + public long Length => throw new NotImplementedException(); + } +} diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/IProtoOutputT.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/IProtoOutputT.cs.meta new file mode 100644 index 0000000..a6e7d86 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/IProtoOutputT.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 17c52d90924d69d4aaf31925ea2c90bf +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/ImplicitFields.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/ImplicitFields.cs new file mode 100644 index 0000000..211abdd --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/ImplicitFields.cs @@ -0,0 +1,29 @@ +namespace ProtoBuf +{ + /// + /// Specifies the method used to infer field tags for members of the type + /// under consideration. Tags are deduced using the invariant alphabetic + /// sequence of the members' names; this makes implicit field tags very brittle, + /// and susceptible to changes such as field names (normally an isolated + /// change). + /// + public enum ImplicitFields + { + /// + /// No members are serialized implicitly; all members require a suitable + /// attribute such as [ProtoMember]. This is the recmomended mode for + /// most scenarios. + /// + None = 0, + /// + /// Public properties and fields are eligible for implicit serialization; + /// this treats the public API as a contract. Ordering beings from ImplicitFirstTag. + /// + AllPublic = 1, + /// + /// Public and non-public fields are eligible for implicit serialization; + /// this acts as a state/implementation serializer. Ordering beings from ImplicitFirstTag. + /// + AllFields = 2 + } +} diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/ImplicitFields.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/ImplicitFields.cs.meta new file mode 100644 index 0000000..6da3bef --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/ImplicitFields.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b838f9e3c6536bc438e7c31f73c49160 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/KeyValuePairProxy.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/KeyValuePairProxy.cs new file mode 100644 index 0000000..0da5761 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/KeyValuePairProxy.cs @@ -0,0 +1,44 @@ +//using System.Collections.Generic; + +//namespace ProtoBuf +//{ +// /// +// /// Mutable version of the common key/value pair struct; used during serialization. This type is intended for internal use only and should not +// /// be used by calling code; it is required to be public for implementation reasons. +// /// +// [ProtoContract] +// public struct KeyValuePairSurrogate +// { +// private TKey key; +// private TValue value; +// /// +// /// The key of the pair. +// /// +// [ProtoMember(1, IsRequired = true)] +// public TKey Key { get { return key; } set { key = value; } } +// /// +// /// The value of the pair. +// /// +// [ProtoMember(2)] +// public TValue Value{ get { return value; } set { this.value = value; } } +// private KeyValuePairSurrogate(TKey key, TValue value) +// { +// this.key = key; +// this.value = value; +// } +// /// +// /// Convert a surrogate instance to a standard pair instance. +// /// +// public static implicit operator KeyValuePair (KeyValuePairSurrogate value) +// { +// return new KeyValuePair(value.key, value.value); +// } +// /// +// /// Convert a standard pair instance to a surrogate instance. +// /// +// public static implicit operator KeyValuePairSurrogate(KeyValuePair value) +// { +// return new KeyValuePairSurrogate(value.Key, value.Value); +// } +// } +//} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/KeyValuePairProxy.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/KeyValuePairProxy.cs.meta new file mode 100644 index 0000000..c74b284 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/KeyValuePairProxy.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b6221476e2339494cb5ee2bdc10ffd81 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Meta.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Meta.meta new file mode 100644 index 0000000..5f17bdd --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Meta.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: a70a85c13dddce74d9a6395c440c9156 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Meta/AttributeMap.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Meta/AttributeMap.cs new file mode 100644 index 0000000..5bab942 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Meta/AttributeMap.cs @@ -0,0 +1,108 @@ +#if !NO_RUNTIME +using System; +using System.Reflection; + +namespace ProtoBuf.Meta +{ + internal abstract class AttributeMap + { +#if DEBUG + [Obsolete("Please use AttributeType instead")] + new public Type GetType() => AttributeType; +#endif + public override string ToString() => AttributeType?.FullName ?? ""; + public abstract bool TryGet(string key, bool publicOnly, out object value); + public bool TryGet(string key, out object value) + { + return TryGet(key, true, out value); + } + public abstract Type AttributeType { get; } + public static AttributeMap[] Create(TypeModel model, Type type, bool inherit) + { + +#if COREFX || PROFILE259 + Attribute[] all = System.Linq.Enumerable.ToArray(System.Linq.Enumerable.OfType(type.GetTypeInfo().GetCustomAttributes(inherit))); +#else + object[] all = type.GetCustomAttributes(inherit); +#endif + AttributeMap[] result = new AttributeMap[all.Length]; + for(int i = 0 ; i < all.Length ; i++) + { + result[i] = new ReflectionAttributeMap((Attribute)all[i]); + } + return result; + } + + public static AttributeMap[] Create(TypeModel model, MemberInfo member, bool inherit) + { + +#if COREFX || PROFILE259 + Attribute[] all = System.Linq.Enumerable.ToArray(System.Linq.Enumerable.OfType(member.GetCustomAttributes(inherit))); +#else + object[] all = member.GetCustomAttributes(inherit); +#endif + AttributeMap[] result = new AttributeMap[all.Length]; + for(int i = 0 ; i < all.Length ; i++) + { + result[i] = new ReflectionAttributeMap((Attribute)all[i]); + } + return result; + } + public static AttributeMap[] Create(TypeModel model, Assembly assembly) + { +#if COREFX || PROFILE259 + Attribute[] all = System.Linq.Enumerable.ToArray(assembly.GetCustomAttributes()); +#else + const bool inherit = false; + object[] all = assembly.GetCustomAttributes(inherit); +#endif + AttributeMap[] result = new AttributeMap[all.Length]; + for(int i = 0 ; i < all.Length ; i++) + { + result[i] = new ReflectionAttributeMap((Attribute)all[i]); + } + return result; + + } + + public abstract object Target { get; } + + private sealed class ReflectionAttributeMap : AttributeMap + { + private readonly Attribute attribute; + + public ReflectionAttributeMap(Attribute attribute) + { + this.attribute = attribute; + } + + public override object Target => attribute; + + public override Type AttributeType => attribute.GetType(); + + public override bool TryGet(string key, bool publicOnly, out object value) + { + MemberInfo[] members = Helpers.GetInstanceFieldsAndProperties(attribute.GetType(), publicOnly); + foreach (MemberInfo member in members) + { + if (string.Equals(member.Name, key, StringComparison.OrdinalIgnoreCase)) + { + if (member is PropertyInfo prop) { + value = prop.GetValue(attribute, null); + return true; + } + if (member is FieldInfo field) { + value = field.GetValue(attribute); + return true; + } + + throw new NotSupportedException(member.GetType().Name); + } + } + value = null; + return false; + } + } + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Meta/AttributeMap.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Meta/AttributeMap.cs.meta new file mode 100644 index 0000000..d92ef3a --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Meta/AttributeMap.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a3e64de7ef1358447843db562f78060f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Meta/BasicList.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Meta/BasicList.cs new file mode 100644 index 0000000..d1308f3 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Meta/BasicList.cs @@ -0,0 +1,267 @@ +using System; +using System.Collections; + +namespace ProtoBuf.Meta +{ + internal sealed class MutableList : BasicList + { + /* Like BasicList, but allows existing values to be changed + */ + public new object this[int index] + { + get { return head[index]; } + set { head[index] = value; } + } + public void RemoveLast() + { + head.RemoveLastWithMutate(); + } + + public void Clear() + { + head.Clear(); + } + } + + internal class BasicList : IEnumerable + { + /* Requirements: + * - Fast access by index + * - Immutable in the tail, so a node can be read (iterated) without locking + * - Lock-free tail handling must match the memory mode; struct for Node + * wouldn't work as "read" would not be atomic + * - Only operation required is append, but this shouldn't go out of its + * way to be inefficient + * - Assume that the caller is handling thread-safety (to co-ordinate with + * other code); no attempt to be thread-safe + * - Assume that the data is private; internal data structure is allowed to + * be mutable (i.e. array is fine as long as we don't screw it up) + */ + private static readonly Node nil = new Node(null, 0); + + public void CopyTo(Array array, int offset) + { + head.CopyTo(array, offset); + } + + protected Node head = nil; + + public int Add(object value) + { + return (head = head.Append(value)).Length - 1; + } + + public object this[int index] => head[index]; + + //public object TryGet(int index) + //{ + // return head.TryGet(index); + //} + + public void Trim() { head = head.Trim(); } + + public int Count => head.Length; + + IEnumerator IEnumerable.GetEnumerator() => new NodeEnumerator(head); + + public NodeEnumerator GetEnumerator() => new NodeEnumerator(head); + + public struct NodeEnumerator : IEnumerator + { + private int position; + private readonly Node node; + internal NodeEnumerator(Node node) + { + this.position = -1; + this.node = node; + } + void IEnumerator.Reset() { position = -1; } + public object Current { get { return node[position]; } } + public bool MoveNext() + { + int len = node.Length; + return (position <= len) && (++position < len); + } + } + + internal sealed class Node + { + public object this[int index] + { + get + { + if (index >= 0 && index < length) + { + return data[index]; + } + throw new ArgumentOutOfRangeException(nameof(index)); + } + set + { + if (index >= 0 && index < length) + { + data[index] = value; + } + else + { + throw new ArgumentOutOfRangeException(nameof(index)); + } + } + } + //public object TryGet(int index) + //{ + // return (index >= 0 && index < length) ? data[index] : null; + //} + private readonly object[] data; + + private int length; + public int Length => length; + + internal Node(object[] data, int length) + { + Helpers.DebugAssert((data == null && length == 0) || + (data != null && length > 0 && length <= data.Length)); + this.data = data; + + this.length = length; + } + + public void RemoveLastWithMutate() + { + if (length == 0) throw new InvalidOperationException(); + length -= 1; + } + + public Node Append(object value) + { + object[] newData; + int newLength = length + 1; + if (data == null) + { + newData = new object[10]; + } + else if (length == data.Length) + { + newData = new object[data.Length * 2]; + Array.Copy(data, newData, length); + } + else + { + newData = data; + } + newData[length] = value; + return new Node(newData, newLength); + } + + public Node Trim() + { + if (length == 0 || length == data.Length) return this; + object[] newData = new object[length]; + Array.Copy(data, newData, length); + return new Node(newData, length); + } + + internal int IndexOfString(string value) + { + for (int i = 0; i < length; i++) + { + if ((string)value == (string)data[i]) return i; + } + return -1; + } + + internal int IndexOfReference(object instance) + { + for (int i = 0; i < length; i++) + { + if ((object)instance == (object)data[i]) return i; + } // ^^^ (object) above should be preserved, even if this was typed; needs + // to be a reference check + return -1; + } + + internal int IndexOf(MatchPredicate predicate, object ctx) + { + for (int i = 0; i < length; i++) + { + if (predicate(data[i], ctx)) return i; + } + return -1; + } + + internal void CopyTo(Array array, int offset) + { + if (length > 0) + { + Array.Copy(data, 0, array, offset, length); + } + } + + internal void Clear() + { + if (data != null) + { + Array.Clear(data, 0, data.Length); + } + length = 0; + } + } + + internal int IndexOf(MatchPredicate predicate, object ctx) + { + return head.IndexOf(predicate, ctx); + } + + internal int IndexOfString(string value) + { + return head.IndexOfString(value); + } + + internal int IndexOfReference(object instance) + { + return head.IndexOfReference(instance); + } + + internal delegate bool MatchPredicate(object value, object ctx); + + internal bool Contains(object value) + { + foreach (object obj in this) + { + if (object.Equals(obj, value)) return true; + } + return false; + } + + internal sealed class Group + { + public readonly int First; + public readonly BasicList Items; + public Group(int first) + { + this.First = first; + this.Items = new BasicList(); + } + } + + internal static BasicList GetContiguousGroups(int[] keys, object[] values) + { + if (keys == null) throw new ArgumentNullException(nameof(keys)); + if (values == null) throw new ArgumentNullException(nameof(values)); + if (values.Length < keys.Length) throw new ArgumentException("Not all keys are covered by values", nameof(values)); + BasicList outer = new BasicList(); + Group group = null; + for (int i = 0; i < keys.Length; i++) + { + if (i == 0 || keys[i] != keys[i - 1]) { group = null; } + if (group == null) + { + group = new Group(keys[i]); + outer.Add(group); + } + group.Items.Add(values[i]); + } + return outer; + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Meta/BasicList.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Meta/BasicList.cs.meta new file mode 100644 index 0000000..3304e30 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Meta/BasicList.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: be5fc2a1ac0731a44b0365987d942485 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Meta/CallbackSet.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Meta/CallbackSet.cs new file mode 100644 index 0000000..8b08585 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Meta/CallbackSet.cs @@ -0,0 +1,110 @@ +#if !NO_RUNTIME +using System; +using System.Reflection; + +namespace ProtoBuf.Meta +{ + /// + /// Represents the set of serialization callbacks to be used when serializing/deserializing a type. + /// + public class CallbackSet + { + private readonly MetaType metaType; + internal CallbackSet(MetaType metaType) + { + this.metaType = metaType ?? throw new ArgumentNullException(nameof(metaType)); + } + + internal MethodInfo this[TypeModel.CallbackType callbackType] + { + get + { + switch (callbackType) + { + case TypeModel.CallbackType.BeforeSerialize: return beforeSerialize; + case TypeModel.CallbackType.AfterSerialize: return afterSerialize; + case TypeModel.CallbackType.BeforeDeserialize: return beforeDeserialize; + case TypeModel.CallbackType.AfterDeserialize: return afterDeserialize; + default: throw new ArgumentException("Callback type not supported: " + callbackType.ToString(), "callbackType"); + } + } + } + + internal static bool CheckCallbackParameters(TypeModel model, MethodInfo method) + { + ParameterInfo[] args = method.GetParameters(); + for (int i = 0; i < args.Length; i++) + { + Type paramType = args[i].ParameterType; + if (paramType == model.MapType(typeof(SerializationContext))) { } + else if (paramType == model.MapType(typeof(System.Type))) { } +#if PLAT_BINARYFORMATTER + else if (paramType == model.MapType(typeof(System.Runtime.Serialization.StreamingContext))) { } +#endif + else return false; + } + return true; + } + + private MethodInfo SanityCheckCallback(TypeModel model, MethodInfo callback) + { + metaType.ThrowIfFrozen(); + if (callback == null) return callback; // fine + if (callback.IsStatic) throw new ArgumentException("Callbacks cannot be static", nameof(callback)); + if (callback.ReturnType != model.MapType(typeof(void)) + || !CheckCallbackParameters(model, callback)) + { + throw CreateInvalidCallbackSignature(callback); + } + return callback; + } + + internal static Exception CreateInvalidCallbackSignature(MethodInfo method) + { + return new NotSupportedException("Invalid callback signature in " + method.DeclaringType.FullName + "." + method.Name); + } + + private MethodInfo beforeSerialize, afterSerialize, beforeDeserialize, afterDeserialize; + + /// Called before serializing an instance + public MethodInfo BeforeSerialize + { + get { return beforeSerialize; } + set { beforeSerialize = SanityCheckCallback(metaType.Model, value); } + } + + /// Called before deserializing an instance + public MethodInfo BeforeDeserialize + { + get { return beforeDeserialize; } + set { beforeDeserialize = SanityCheckCallback(metaType.Model, value); } + } + + /// Called after serializing an instance + public MethodInfo AfterSerialize + { + get { return afterSerialize; } + set { afterSerialize = SanityCheckCallback(metaType.Model, value); } + } + + /// Called after deserializing an instance + public MethodInfo AfterDeserialize + { + get { return afterDeserialize; } + set { afterDeserialize = SanityCheckCallback(metaType.Model, value); } + } + + /// + /// True if any callback is set, else False + /// + public bool NonTrivial + { + get + { + return beforeSerialize != null || beforeDeserialize != null + || afterSerialize != null || afterDeserialize != null; + } + } + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Meta/CallbackSet.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Meta/CallbackSet.cs.meta new file mode 100644 index 0000000..0c6da40 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Meta/CallbackSet.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: de0e7cb7bfcf4904aa31e910f241a8aa +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Meta/MetaType.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Meta/MetaType.cs new file mode 100644 index 0000000..8d9bed6 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Meta/MetaType.cs @@ -0,0 +1,2171 @@ +#if !NO_RUNTIME +using System; +using System.Collections; +using System.Text; +using ProtoBuf.Serializers; +using System.Reflection; +using System.Collections.Generic; + +#if PROFILE259 +using System.Linq; +#endif + +namespace ProtoBuf.Meta +{ + /// + /// Represents a type at runtime for use with protobuf, allowing the field mappings (etc) to be defined + /// + public class MetaType : ISerializerProxy + { + internal sealed class Comparer : IComparer, IComparer + { + public static readonly Comparer Default = new Comparer(); + public int Compare(object x, object y) + { + return Compare(x as MetaType, y as MetaType); + } + public int Compare(MetaType x, MetaType y) + { + if (ReferenceEquals(x, y)) return 0; + if (x == null) return -1; + if (y == null) return 1; + + return string.Compare(x.GetSchemaTypeName(), y.GetSchemaTypeName(), StringComparison.Ordinal); + } + } + /// + /// Get the name of the type being represented + /// + public override string ToString() + { + return type.ToString(); + } + + IProtoSerializer ISerializerProxy.Serializer => Serializer; + private MetaType baseType; + + /// + /// Gets the base-type for this type + /// + public MetaType BaseType => baseType; + + internal TypeModel Model => model; + + /// + /// When used to compile a model, should public serialization/deserialzation methods + /// be included for this type? + /// + public bool IncludeSerializerMethod + { // negated to minimize common-case / initializer + get { return !HasFlag(OPTIONS_PrivateOnApi); } + set { SetFlag(OPTIONS_PrivateOnApi, !value, true); } + } + + /// + /// Should this type be treated as a reference by default? + /// + public bool AsReferenceDefault + { + get { return HasFlag(OPTIONS_AsReferenceDefault); } + set { SetFlag(OPTIONS_AsReferenceDefault, value, true); } + } + + private BasicList subTypes; + private bool IsValidSubType(Type subType) + { +#if COREFX || PROFILE259 + return typeInfo.IsAssignableFrom(subType.GetTypeInfo()); +#else + return type.IsAssignableFrom(subType); +#endif + } + /// + /// Adds a known sub-type to the inheritance model + /// + public MetaType AddSubType(int fieldNumber, Type derivedType) + { + return AddSubType(fieldNumber, derivedType, DataFormat.Default); + } + /// + /// Adds a known sub-type to the inheritance model + /// + public MetaType AddSubType(int fieldNumber, Type derivedType, DataFormat dataFormat) + { + if (derivedType == null) throw new ArgumentNullException("derivedType"); + if (fieldNumber < 1) throw new ArgumentOutOfRangeException("fieldNumber"); +#if COREFX || COREFX || PROFILE259 + if (!(typeInfo.IsClass || typeInfo.IsInterface) || typeInfo.IsSealed) { +#else + if (!(type.IsClass || type.IsInterface) || type.IsSealed) + { +#endif + throw new InvalidOperationException("Sub-types can only be added to non-sealed classes"); + } + if (!IsValidSubType(derivedType)) + { + throw new ArgumentException(derivedType.Name + " is not a valid sub-type of " + type.Name, "derivedType"); + } + MetaType derivedMeta = model[derivedType]; + ThrowIfFrozen(); + derivedMeta.ThrowIfFrozen(); + SubType subType = new SubType(fieldNumber, derivedMeta, dataFormat); + ThrowIfFrozen(); + + derivedMeta.SetBaseType(this); // includes ThrowIfFrozen + if (subTypes == null) subTypes = new BasicList(); + subTypes.Add(subType); + model.ResetKeyCache(); + return this; + } +#if COREFX || PROFILE259 + internal static readonly TypeInfo ienumerable = typeof(IEnumerable).GetTypeInfo(); +#else + internal static readonly Type ienumerable = typeof(IEnumerable); +#endif + private void SetBaseType(MetaType baseType) + { + if (baseType == null) throw new ArgumentNullException("baseType"); + if (this.baseType == baseType) return; + if (this.baseType != null) throw new InvalidOperationException($"Type '{this.baseType.Type.FullName}' can only participate in one inheritance hierarchy"); + + MetaType type = baseType; + while (type != null) + { + if (ReferenceEquals(type, this)) throw new InvalidOperationException($"Cyclic inheritance of '{this.baseType.Type.FullName}' is not allowed"); + type = type.baseType; + } + this.baseType = baseType; + } + + private CallbackSet callbacks; + + /// + /// Indicates whether the current type has defined callbacks + /// + public bool HasCallbacks => callbacks != null && callbacks.NonTrivial; + + /// + /// Indicates whether the current type has defined subtypes + /// + public bool HasSubtypes => subTypes != null && subTypes.Count != 0; + + /// + /// Returns the set of callbacks defined for this type + /// + public CallbackSet Callbacks + { + get + { + if (callbacks == null) callbacks = new CallbackSet(this); + return callbacks; + } + } + + private bool IsValueType + { + get + { +#if COREFX || PROFILE259 + return typeInfo.IsValueType; +#else + return type.IsValueType; +#endif + } + } + /// + /// Assigns the callbacks to use during serialiation/deserialization. + /// + /// The method (or null) called before serialization begins. + /// The method (or null) called when serialization is complete. + /// The method (or null) called before deserialization begins (or when a new instance is created during deserialization). + /// The method (or null) called when deserialization is complete. + /// The set of callbacks. + public MetaType SetCallbacks(MethodInfo beforeSerialize, MethodInfo afterSerialize, MethodInfo beforeDeserialize, MethodInfo afterDeserialize) + { + CallbackSet callbacks = Callbacks; + callbacks.BeforeSerialize = beforeSerialize; + callbacks.AfterSerialize = afterSerialize; + callbacks.BeforeDeserialize = beforeDeserialize; + callbacks.AfterDeserialize = afterDeserialize; + return this; + } + /// + /// Assigns the callbacks to use during serialiation/deserialization. + /// + /// The name of the method (or null) called before serialization begins. + /// The name of the method (or null) called when serialization is complete. + /// The name of the method (or null) called before deserialization begins (or when a new instance is created during deserialization). + /// The name of the method (or null) called when deserialization is complete. + /// The set of callbacks. + public MetaType SetCallbacks(string beforeSerialize, string afterSerialize, string beforeDeserialize, string afterDeserialize) + { + if (IsValueType) throw new InvalidOperationException(); + CallbackSet callbacks = Callbacks; + callbacks.BeforeSerialize = ResolveMethod(beforeSerialize, true); + callbacks.AfterSerialize = ResolveMethod(afterSerialize, true); + callbacks.BeforeDeserialize = ResolveMethod(beforeDeserialize, true); + callbacks.AfterDeserialize = ResolveMethod(afterDeserialize, true); + return this; + } + + /// + /// Returns the public Type name of this Type used in serialization + /// + public string GetSchemaTypeName() + { + if (surrogate != null) return model[surrogate].GetSchemaTypeName(); + + if (!string.IsNullOrEmpty(name)) return name; + + string typeName = type.Name; + if (type +#if COREFX || PROFILE259 + .GetTypeInfo() +#endif + .IsGenericType) + { + var sb = new StringBuilder(typeName); + int split = typeName.IndexOf('`'); + if (split >= 0) sb.Length = split; + foreach (Type arg in type +#if COREFX || PROFILE259 + .GetTypeInfo().GenericTypeArguments +#else + .GetGenericArguments() +#endif + ) + { + sb.Append('_'); + Type tmp = arg; + int key = model.GetKey(ref tmp); + MetaType mt; + if (key >= 0 && (mt = model[tmp]) != null && mt.surrogate == null) // <=== need to exclude surrogate to avoid chance of infinite loop + { + + sb.Append(mt.GetSchemaTypeName()); + } + else + { + sb.Append(tmp.Name); + } + } + return sb.ToString(); + } + + return typeName; + } + + private string name; + + /// + /// Gets or sets the name of this contract. + /// + public string Name + { + get + { + return name; + } + set + { + ThrowIfFrozen(); + name = value; + } + } + + private MethodInfo factory; + /// + /// Designate a factory-method to use to create instances of this type + /// + public MetaType SetFactory(MethodInfo factory) + { + model.VerifyFactory(factory, type); + ThrowIfFrozen(); + this.factory = factory; + return this; + } + + /// + /// Designate a factory-method to use to create instances of this type + /// + public MetaType SetFactory(string factory) + { + return SetFactory(ResolveMethod(factory, false)); + } + + private MethodInfo ResolveMethod(string name, bool instance) + { + if (string.IsNullOrEmpty(name)) return null; +#if COREFX + return instance ? Helpers.GetInstanceMethod(typeInfo, name) : Helpers.GetStaticMethod(typeInfo, name); +#else + return instance ? Helpers.GetInstanceMethod(type, name) : Helpers.GetStaticMethod(type, name); +#endif + } + + private readonly RuntimeTypeModel model; + + internal static Exception InbuiltType(Type type) + { + return new ArgumentException("Data of this type has inbuilt behaviour, and cannot be added to a model in this way: " + type.FullName); + } + + internal MetaType(RuntimeTypeModel model, Type type, MethodInfo factory) + { + this.factory = factory; + if (model == null) throw new ArgumentNullException("model"); + if (type == null) throw new ArgumentNullException("type"); + + if (type.IsArray) throw InbuiltType(type); + IProtoSerializer coreSerializer = model.TryGetBasicTypeSerializer(type); + if (coreSerializer != null) + { + throw InbuiltType(type); + } + + this.type = type; +#if COREFX || PROFILE259 + this.typeInfo = type.GetTypeInfo(); +#endif + this.model = model; + + if (Helpers.IsEnum(type)) + { +#if COREFX || PROFILE259 + EnumPassthru = typeInfo.IsDefined(typeof(FlagsAttribute), false); +#else + EnumPassthru = type.IsDefined(model.MapType(typeof(FlagsAttribute)), false); +#endif + } + } +#if COREFX || PROFILE259 + private readonly TypeInfo typeInfo; +#endif + /// + /// Throws an exception if the type has been made immutable + /// + protected internal void ThrowIfFrozen() + { + if ((flags & OPTIONS_Frozen) != 0) throw new InvalidOperationException("The type cannot be changed once a serializer has been generated for " + type.FullName); + } + + // internal void Freeze() { flags |= OPTIONS_Frozen; } + + private readonly Type type; + /// + /// The runtime type that the meta-type represents + /// + public Type Type => type; + + private IProtoTypeSerializer serializer; + internal IProtoTypeSerializer Serializer + { + get + { + if (serializer == null) + { + int opaqueToken = 0; + try + { + model.TakeLock(ref opaqueToken); + if (serializer == null) + { // double-check, but our main purpse with this lock is to ensure thread-safety with + // serializers needing to wait until another thread has finished adding the properties + SetFlag(OPTIONS_Frozen, true, false); + serializer = BuildSerializer(); +#if FEAT_COMPILER + if (model.AutoCompile) CompileInPlace(); +#endif + } + } + finally + { + model.ReleaseLock(opaqueToken); + } + } + return serializer; + } + } + internal bool IsList + { + get + { + Type itemType = IgnoreListHandling ? null : TypeModel.GetListItemType(model, type); + return itemType != null; + } + } + private IProtoTypeSerializer BuildSerializer() + { + if (Helpers.IsEnum(type)) + { + return new TagDecorator(ProtoBuf.Serializer.ListItemTag, WireType.Variant, false, new EnumSerializer(type, GetEnumMap())); + } + Type itemType = IgnoreListHandling ? null : TypeModel.GetListItemType(model, type); + if (itemType != null) + { + if (surrogate != null) + { + throw new ArgumentException("Repeated data (a list, collection, etc) has inbuilt behaviour and cannot use a surrogate"); + } + if (subTypes != null && subTypes.Count != 0) + { + throw new ArgumentException("Repeated data (a list, collection, etc) has inbuilt behaviour and cannot be subclassed"); + } + Type defaultType = null; + ResolveListTypes(model, type, ref itemType, ref defaultType); + ValueMember fakeMember = new ValueMember(model, ProtoBuf.Serializer.ListItemTag, type, itemType, defaultType, DataFormat.Default); + return new TypeSerializer(model, type, new int[] { ProtoBuf.Serializer.ListItemTag }, new IProtoSerializer[] { fakeMember.Serializer }, null, true, true, null, constructType, factory); + } + if (surrogate != null) + { + MetaType mt = model[surrogate], mtBase; + while ((mtBase = mt.baseType) != null) { mt = mtBase; } + return new SurrogateSerializer(model, type, surrogate, mt.Serializer); + } + if (IsAutoTuple) + { + ConstructorInfo ctor = ResolveTupleConstructor(type, out MemberInfo[] mapping); + if (ctor == null) throw new InvalidOperationException(); + return new TupleSerializer(model, ctor, mapping); + } + + fields.Trim(); + int fieldCount = fields.Count; + int subTypeCount = subTypes == null ? 0 : subTypes.Count; + int[] fieldNumbers = new int[fieldCount + subTypeCount]; + IProtoSerializer[] serializers = new IProtoSerializer[fieldCount + subTypeCount]; + int i = 0; + if (subTypeCount != 0) + { + foreach (SubType subType in subTypes) + { +#if COREFX || PROFILE259 + if (!subType.DerivedType.IgnoreListHandling && ienumerable.IsAssignableFrom(subType.DerivedType.Type.GetTypeInfo())) +#else + if (!subType.DerivedType.IgnoreListHandling && model.MapType(ienumerable).IsAssignableFrom(subType.DerivedType.Type)) +#endif + { + throw new ArgumentException("Repeated data (a list, collection, etc) has inbuilt behaviour and cannot be used as a subclass"); + } + fieldNumbers[i] = subType.FieldNumber; + serializers[i++] = subType.Serializer; + } + } + if (fieldCount != 0) + { + foreach (ValueMember member in fields) + { + fieldNumbers[i] = member.FieldNumber; + serializers[i++] = member.Serializer; + } + } + + BasicList baseCtorCallbacks = null; + MetaType tmp = BaseType; + + while (tmp != null) + { + MethodInfo method = tmp.HasCallbacks ? tmp.Callbacks.BeforeDeserialize : null; + if (method != null) + { + if (baseCtorCallbacks == null) baseCtorCallbacks = new BasicList(); + baseCtorCallbacks.Add(method); + } + tmp = tmp.BaseType; + } + MethodInfo[] arr = null; + if (baseCtorCallbacks != null) + { + arr = new MethodInfo[baseCtorCallbacks.Count]; + baseCtorCallbacks.CopyTo(arr, 0); + Array.Reverse(arr); + } + return new TypeSerializer(model, type, fieldNumbers, serializers, arr, baseType == null, UseConstructor, callbacks, constructType, factory); + } + + [Flags] + internal enum AttributeFamily + { + None = 0, ProtoBuf = 1, DataContractSerialier = 2, XmlSerializer = 4, AutoTuple = 8 + } + static Type GetBaseType(MetaType type) + { +#if COREFX || PROFILE259 + return type.typeInfo.BaseType; +#else + return type.type.BaseType; +#endif + } + internal static bool GetAsReferenceDefault(RuntimeTypeModel model, Type type) + { + if (type == null) throw new ArgumentNullException(nameof(type)); + if (Helpers.IsEnum(type)) return false; // never as-ref + AttributeMap[] typeAttribs = AttributeMap.Create(model, type, false); + for (int i = 0; i < typeAttribs.Length; i++) + { + if (typeAttribs[i].AttributeType.FullName == "ProtoBuf.ProtoContractAttribute") + { + if (typeAttribs[i].TryGet("AsReferenceDefault", out object tmp)) return (bool)tmp; + } + } + return false; + } + + internal void ApplyDefaultBehaviour() + { + TypeAddedEventArgs args = null; // allows us to share the event-args between events + RuntimeTypeModel.OnBeforeApplyDefaultBehaviour(this, ref args); + if (args == null || args.ApplyDefaultBehaviour) ApplyDefaultBehaviourImpl(); + RuntimeTypeModel.OnAfterApplyDefaultBehaviour(this, ref args); + } + + internal void ApplyDefaultBehaviourImpl() + { + Type baseType = GetBaseType(this); + if (baseType != null && model.FindWithoutAdd(baseType) == null + && GetContractFamily(model, baseType, null) != MetaType.AttributeFamily.None) + { + model.FindOrAddAuto(baseType, true, false, false); + } + + AttributeMap[] typeAttribs = AttributeMap.Create(model, type, false); + AttributeFamily family = GetContractFamily(model, type, typeAttribs); + if (family == AttributeFamily.AutoTuple) + { + SetFlag(OPTIONS_AutoTuple, true, true); + } + bool isEnum = !EnumPassthru && Helpers.IsEnum(type); + if (family == AttributeFamily.None && !isEnum) return; // and you'd like me to do what, exactly? + + bool enumShouldUseImplicitPassThru = isEnum; + BasicList partialIgnores = null, partialMembers = null; + int dataMemberOffset = 0, implicitFirstTag = 1; + bool inferTagByName = model.InferTagFromNameDefault; + ImplicitFields implicitMode = ImplicitFields.None; + string name = null; + for (int i = 0; i < typeAttribs.Length; i++) + { + AttributeMap item = (AttributeMap)typeAttribs[i]; + object tmp; + string fullAttributeTypeName = item.AttributeType.FullName; + if (!isEnum && fullAttributeTypeName == "ProtoBuf.ProtoIncludeAttribute") + { + int tag = 0; + if (item.TryGet("tag", out tmp)) tag = (int)tmp; + DataFormat dataFormat = DataFormat.Default; + if (item.TryGet("DataFormat", out tmp)) + { + dataFormat = (DataFormat)(int)tmp; + } + Type knownType = null; + try + { + if (item.TryGet("knownTypeName", out tmp)) knownType = model.GetType((string)tmp, type +#if COREFX || PROFILE259 + .GetTypeInfo() +#endif + .Assembly); + else if (item.TryGet("knownType", out tmp)) knownType = (Type)tmp; + } + catch (Exception ex) + { + throw new InvalidOperationException("Unable to resolve sub-type of: " + type.FullName, ex); + } + if (knownType == null) + { + throw new InvalidOperationException("Unable to resolve sub-type of: " + type.FullName); + } + if (IsValidSubType(knownType)) AddSubType(tag, knownType, dataFormat); + } + + if (fullAttributeTypeName == "ProtoBuf.ProtoPartialIgnoreAttribute") + { + if (item.TryGet(nameof(ProtoPartialIgnoreAttribute.MemberName), out tmp) && tmp != null) + { + if (partialIgnores == null) partialIgnores = new BasicList(); + partialIgnores.Add((string)tmp); + } + } + if (!isEnum && fullAttributeTypeName == "ProtoBuf.ProtoPartialMemberAttribute") + { + if (partialMembers == null) partialMembers = new BasicList(); + partialMembers.Add(item); + } + + if (fullAttributeTypeName == "ProtoBuf.ProtoContractAttribute") + { + if (item.TryGet(nameof(ProtoContractAttribute.Name), out tmp)) name = (string)tmp; + if (Helpers.IsEnum(type)) // note this is subtly different to isEnum; want to do this even if [Flags] + { + if (item.TryGet(nameof(ProtoContractAttribute.EnumPassthruHasValue), false, out tmp) && (bool)tmp) + { + if (item.TryGet(nameof(ProtoContractAttribute.EnumPassthru), out tmp)) + { + EnumPassthru = (bool)tmp; + enumShouldUseImplicitPassThru = false; + if (EnumPassthru) isEnum = false; // no longer treated as an enum + } + } + } + else + { + if (item.TryGet(nameof(ProtoContractAttribute.DataMemberOffset), out tmp)) dataMemberOffset = (int)tmp; + + if (item.TryGet(nameof(ProtoContractAttribute.InferTagFromNameHasValue), false, out tmp) && (bool)tmp) + { + if (item.TryGet(nameof(ProtoContractAttribute.InferTagFromName), out tmp)) inferTagByName = (bool)tmp; + } + + if (item.TryGet(nameof(ProtoContractAttribute.ImplicitFields), out tmp) && tmp != null) + { + implicitMode = (ImplicitFields)(int)tmp; // note that this uses the bizarre unboxing rules of enums/underlying-types + } + + if (item.TryGet(nameof(ProtoContractAttribute.SkipConstructor), out tmp)) UseConstructor = !(bool)tmp; + if (item.TryGet(nameof(ProtoContractAttribute.IgnoreListHandling), out tmp)) IgnoreListHandling = (bool)tmp; + if (item.TryGet(nameof(ProtoContractAttribute.AsReferenceDefault), out tmp)) AsReferenceDefault = (bool)tmp; + if (item.TryGet(nameof(ProtoContractAttribute.ImplicitFirstTag), out tmp) && (int)tmp > 0) implicitFirstTag = (int)tmp; + if (item.TryGet(nameof(ProtoContractAttribute.IsGroup), out tmp)) IsGroup = (bool)tmp; + + if (item.TryGet(nameof(ProtoContractAttribute.Surrogate), out tmp)) + { + SetSurrogate((Type)tmp); + } + } + } + + if (fullAttributeTypeName == "System.Runtime.Serialization.DataContractAttribute") + { + if (name == null && item.TryGet("Name", out tmp)) name = (string)tmp; + } + if (fullAttributeTypeName == "System.Xml.Serialization.XmlTypeAttribute") + { + if (name == null && item.TryGet("TypeName", out tmp)) name = (string)tmp; + } + } + if (!string.IsNullOrEmpty(name)) Name = name; + if (implicitMode != ImplicitFields.None) + { + family &= AttributeFamily.ProtoBuf; // with implicit fields, **only** proto attributes are important + } + MethodInfo[] callbacks = null; + + BasicList members = new BasicList(); + +#if PROFILE259 + IEnumerable foundList; + if(isEnum) { + foundList = type.GetRuntimeFields(); + } + else + { + List list = new List(); + foreach(PropertyInfo prop in type.GetRuntimeProperties()) { + MethodInfo getter = Helpers.GetGetMethod(prop, false, false); + if(getter != null && !getter.IsStatic) list.Add(prop); + } + foreach(FieldInfo fld in type.GetRuntimeFields()) if(fld.IsPublic && !fld.IsStatic) list.Add(fld); + foreach(MethodInfo mthd in type.GetRuntimeMethods()) if(mthd.IsPublic && !mthd.IsStatic) list.Add(mthd); + foundList = list; + } +#else + MemberInfo[] foundList = type.GetMembers(isEnum ? BindingFlags.Public | BindingFlags.Static + : BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); +#endif + bool hasConflictingEnumValue = false; + foreach (MemberInfo member in foundList) + { + if (member.DeclaringType != type) continue; + if (member.IsDefined(model.MapType(typeof(ProtoIgnoreAttribute)), true)) continue; + if (partialIgnores != null && partialIgnores.Contains(member.Name)) continue; + + bool forced = false, isPublic, isField; + Type effectiveType; + + if (member is PropertyInfo property) + { + if (isEnum) continue; // wasn't expecting any props! + MemberInfo backingField = null; + if (!property.CanWrite) + { + // roslyn automatically implemented properties, in particular for get-only properties: <{Name}>k__BackingField; + var backingFieldName = $"<{property.Name}>k__BackingField"; + foreach (var fieldMemeber in foundList) + { + if ((fieldMemeber as FieldInfo != null) && fieldMemeber.Name == backingFieldName) + { + backingField = fieldMemeber; + break; + } + } + } + effectiveType = property.PropertyType; + isPublic = Helpers.GetGetMethod(property, false, false) != null; + isField = false; + ApplyDefaultBehaviour_AddMembers(model, family, isEnum, partialMembers, dataMemberOffset, inferTagByName, implicitMode, members, member, ref forced, isPublic, isField, ref effectiveType, ref hasConflictingEnumValue, backingField); + } + else if (member is FieldInfo field) + { + effectiveType = field.FieldType; + isPublic = field.IsPublic; + isField = true; + if (isEnum && !field.IsStatic) + { // only care about static things on enums; WinRT has a __value instance field! + continue; + } + ApplyDefaultBehaviour_AddMembers(model, family, isEnum, partialMembers, dataMemberOffset, inferTagByName, implicitMode, members, member, ref forced, isPublic, isField, ref effectiveType, ref hasConflictingEnumValue); + } + else if (member is MethodInfo method) + { + if (isEnum) continue; + AttributeMap[] memberAttribs = AttributeMap.Create(model, method, false); + if (memberAttribs != null && memberAttribs.Length > 0) + { + CheckForCallback(method, memberAttribs, "ProtoBuf.ProtoBeforeSerializationAttribute", ref callbacks, 0); + CheckForCallback(method, memberAttribs, "ProtoBuf.ProtoAfterSerializationAttribute", ref callbacks, 1); + CheckForCallback(method, memberAttribs, "ProtoBuf.ProtoBeforeDeserializationAttribute", ref callbacks, 2); + CheckForCallback(method, memberAttribs, "ProtoBuf.ProtoAfterDeserializationAttribute", ref callbacks, 3); + CheckForCallback(method, memberAttribs, "System.Runtime.Serialization.OnSerializingAttribute", ref callbacks, 4); + CheckForCallback(method, memberAttribs, "System.Runtime.Serialization.OnSerializedAttribute", ref callbacks, 5); + CheckForCallback(method, memberAttribs, "System.Runtime.Serialization.OnDeserializingAttribute", ref callbacks, 6); + CheckForCallback(method, memberAttribs, "System.Runtime.Serialization.OnDeserializedAttribute", ref callbacks, 7); + } + } + } + + if (isEnum && enumShouldUseImplicitPassThru && !hasConflictingEnumValue) + { + EnumPassthru = true; + // but leave isEnum alone + } + var arr = new ProtoMemberAttribute[members.Count]; + members.CopyTo(arr, 0); + + if (inferTagByName || implicitMode != ImplicitFields.None) + { + Array.Sort(arr); + int nextTag = implicitFirstTag; + foreach (ProtoMemberAttribute normalizedAttribute in arr) + { + if (!normalizedAttribute.TagIsPinned) // if ProtoMember etc sets a tag, we'll trust it + { + normalizedAttribute.Rebase(nextTag++); + } + } + } + + foreach (ProtoMemberAttribute normalizedAttribute in arr) + { + ValueMember vm = ApplyDefaultBehaviour(isEnum, normalizedAttribute); + if (vm != null) + { + Add(vm); + } + } + + if (callbacks != null) + { + SetCallbacks(Coalesce(callbacks, 0, 4), Coalesce(callbacks, 1, 5), + Coalesce(callbacks, 2, 6), Coalesce(callbacks, 3, 7)); + } + } + + private static void ApplyDefaultBehaviour_AddMembers(TypeModel model, AttributeFamily family, bool isEnum, BasicList partialMembers, int dataMemberOffset, bool inferTagByName, ImplicitFields implicitMode, BasicList members, MemberInfo member, ref bool forced, bool isPublic, bool isField, ref Type effectiveType, ref bool hasConflictingEnumValue, MemberInfo backingMember = null) + { + switch (implicitMode) + { + case ImplicitFields.AllFields: + if (isField) forced = true; + break; + case ImplicitFields.AllPublic: + if (isPublic) forced = true; + break; + } + + // we just don't like delegate types ;p +#if COREFX || PROFILE259 + if (effectiveType.GetTypeInfo().IsSubclassOf(typeof(Delegate))) effectiveType = null; +#else + if (effectiveType.IsSubclassOf(model.MapType(typeof(Delegate)))) effectiveType = null; +#endif + if (effectiveType != null) + { + ProtoMemberAttribute normalizedAttribute = NormalizeProtoMember(model, member, family, forced, isEnum, partialMembers, dataMemberOffset, inferTagByName, ref hasConflictingEnumValue, backingMember); + if (normalizedAttribute != null) members.Add(normalizedAttribute); + } + } + + static MethodInfo Coalesce(MethodInfo[] arr, int x, int y) + { + MethodInfo mi = arr[x]; + if (mi == null) mi = arr[y]; + return mi; + } + + internal static AttributeFamily GetContractFamily(RuntimeTypeModel model, Type type, AttributeMap[] attributes) + { + AttributeFamily family = AttributeFamily.None; + + if (attributes == null) attributes = AttributeMap.Create(model, type, false); + + for (int i = 0; i < attributes.Length; i++) + { + switch (attributes[i].AttributeType.FullName) + { + case "ProtoBuf.ProtoContractAttribute": + bool tmp = false; + GetFieldBoolean(ref tmp, attributes[i], "UseProtoMembersOnly"); + if (tmp) return AttributeFamily.ProtoBuf; + family |= AttributeFamily.ProtoBuf; + break; + case "System.Xml.Serialization.XmlTypeAttribute": + if (!model.AutoAddProtoContractTypesOnly) + { + family |= AttributeFamily.XmlSerializer; + } + break; + case "System.Runtime.Serialization.DataContractAttribute": + if (!model.AutoAddProtoContractTypesOnly) + { + family |= AttributeFamily.DataContractSerialier; + } + break; + } + } + if (family == AttributeFamily.None) + { // check for obvious tuples + if (ResolveTupleConstructor(type, out MemberInfo[] mapping) != null) + { + family |= AttributeFamily.AutoTuple; + } + } + return family; + } + internal static ConstructorInfo ResolveTupleConstructor(Type type, out MemberInfo[] mappedMembers) + { + mappedMembers = null; + if (type == null) throw new ArgumentNullException(nameof(type)); +#if COREFX || PROFILE259 + TypeInfo typeInfo = type.GetTypeInfo(); + if (typeInfo.IsAbstract) return null; // as if! + ConstructorInfo[] ctors = Helpers.GetConstructors(typeInfo, false); +#else + if (type.IsAbstract) return null; // as if! + ConstructorInfo[] ctors = Helpers.GetConstructors(type, false); +#endif + // need to have an interesting constructor to bother even checking this stuff + if (ctors.Length == 0 || (ctors.Length == 1 && ctors[0].GetParameters().Length == 0)) return null; + + MemberInfo[] fieldsPropsUnfiltered = Helpers.GetInstanceFieldsAndProperties(type, true); + BasicList memberList = new BasicList(); + // for most types we'll enforce that you need readonly, because that is what protobuf-net + // always did historically; but: if you smell so much like a Tuple that it is *in your name*, + // we'll let you past that + bool demandReadOnly = type.Name.IndexOf("Tuple", StringComparison.OrdinalIgnoreCase) < 0; + for (int i = 0; i < fieldsPropsUnfiltered.Length; i++) + { + if (fieldsPropsUnfiltered[i] is PropertyInfo prop) + { + if (!prop.CanRead) return null; // no use if can't read + if (demandReadOnly && prop.CanWrite && Helpers.GetSetMethod(prop, false, false) != null) return null; // don't allow a public set (need to allow non-public to handle Mono's KeyValuePair<,>) + memberList.Add(prop); + } + else + { + if (fieldsPropsUnfiltered[i] is FieldInfo field) + { + if (demandReadOnly && !field.IsInitOnly) return null; // all public fields must be readonly to be counted a tuple + memberList.Add(field); + } + } + } + if (memberList.Count == 0) + { + return null; + } + + MemberInfo[] members = new MemberInfo[memberList.Count]; + memberList.CopyTo(members, 0); + + int[] mapping = new int[members.Length]; + int found = 0; + ConstructorInfo result = null; + mappedMembers = new MemberInfo[mapping.Length]; + for (int i = 0; i < ctors.Length; i++) + { + ParameterInfo[] parameters = ctors[i].GetParameters(); + + if (parameters.Length != members.Length) continue; + + // reset the mappings to test + for (int j = 0; j < mapping.Length; j++) mapping[j] = -1; + + for (int j = 0; j < parameters.Length; j++) + { + for (int k = 0; k < members.Length; k++) + { + if (string.Compare(parameters[j].Name, members[k].Name, StringComparison.OrdinalIgnoreCase) != 0) continue; + Type memberType = Helpers.GetMemberType(members[k]); + if (memberType != parameters[j].ParameterType) continue; + + mapping[j] = k; + } + } + // did we map all? + bool notMapped = false; + for (int j = 0; j < mapping.Length; j++) + { + if (mapping[j] < 0) + { + notMapped = true; + break; + } + mappedMembers[j] = members[mapping[j]]; + } + + if (notMapped) continue; + found++; + result = ctors[i]; + + } + return found == 1 ? result : null; + } + + private static void CheckForCallback(MethodInfo method, AttributeMap[] attributes, string callbackTypeName, ref MethodInfo[] callbacks, int index) + { + for (int i = 0; i < attributes.Length; i++) + { + if (attributes[i].AttributeType.FullName == callbackTypeName) + { + if (callbacks == null) { callbacks = new MethodInfo[8]; } + else if (callbacks[index] != null) + { +#if COREFX || PROFILE259 + Type reflected = method.DeclaringType; +#else + Type reflected = method.ReflectedType; +#endif + throw new ProtoException("Duplicate " + callbackTypeName + " callbacks on " + reflected.FullName); + } + callbacks[index] = method; + } + } + } + private static bool HasFamily(AttributeFamily value, AttributeFamily required) + { + return (value & required) == required; + } + + private static ProtoMemberAttribute NormalizeProtoMember(TypeModel model, MemberInfo member, AttributeFamily family, bool forced, bool isEnum, BasicList partialMembers, int dataMemberOffset, bool inferByTagName, ref bool hasConflictingEnumValue, MemberInfo backingMember = null) + { + if (member == null || (family == AttributeFamily.None && !isEnum)) return null; // nix + int fieldNumber = int.MinValue, minAcceptFieldNumber = inferByTagName ? -1 : 1; + string name = null; + bool isPacked = false, ignore = false, done = false, isRequired = false, asReference = false, asReferenceHasValue = false, dynamicType = false, tagIsPinned = false, overwriteList = false; + DataFormat dataFormat = DataFormat.Default; + if (isEnum) forced = true; + AttributeMap[] attribs = AttributeMap.Create(model, member, true); + AttributeMap attrib; + + if (isEnum) + { + attrib = GetAttribute(attribs, "ProtoBuf.ProtoIgnoreAttribute"); + if (attrib != null) + { + ignore = true; + } + else + { + attrib = GetAttribute(attribs, "ProtoBuf.ProtoEnumAttribute"); +#if PORTABLE || CF || COREFX || PROFILE259 + fieldNumber = Convert.ToInt32(((FieldInfo)member).GetValue(null)); +#else + fieldNumber = Convert.ToInt32(((FieldInfo)member).GetRawConstantValue()); +#endif + if (attrib != null) + { + GetFieldName(ref name, attrib, nameof(ProtoEnumAttribute.Name)); + + if ((bool)Helpers.GetInstanceMethod(attrib.AttributeType +#if COREFX || PROFILE259 + .GetTypeInfo() +#endif + , nameof(ProtoEnumAttribute.HasValue)).Invoke(attrib.Target, null)) + { + if (attrib.TryGet(nameof(ProtoEnumAttribute.Value), out object tmp)) + { + if (fieldNumber != (int)tmp) + { + hasConflictingEnumValue = true; + } + fieldNumber = (int)tmp; + } + } + } + + } + done = true; + } + + if (!ignore && !done) // always consider ProtoMember + { + attrib = GetAttribute(attribs, "ProtoBuf.ProtoMemberAttribute"); + GetIgnore(ref ignore, attrib, attribs, "ProtoBuf.ProtoIgnoreAttribute"); + + if (!ignore && attrib != null) + { + GetFieldNumber(ref fieldNumber, attrib, "Tag"); + GetFieldName(ref name, attrib, "Name"); + GetFieldBoolean(ref isRequired, attrib, "IsRequired"); + GetFieldBoolean(ref isPacked, attrib, "IsPacked"); + GetFieldBoolean(ref overwriteList, attrib, "OverwriteList"); + GetDataFormat(ref dataFormat, attrib, "DataFormat"); + GetFieldBoolean(ref asReferenceHasValue, attrib, "AsReferenceHasValue", false); + + if (asReferenceHasValue) + { + asReferenceHasValue = GetFieldBoolean(ref asReference, attrib, "AsReference", true); + } + GetFieldBoolean(ref dynamicType, attrib, "DynamicType"); + done = tagIsPinned = fieldNumber > 0; // note minAcceptFieldNumber only applies to non-proto + } + + if (!done && partialMembers != null) + { + foreach (AttributeMap ppma in partialMembers) + { + if (ppma.TryGet("MemberName", out object tmp) && (string)tmp == member.Name) + { + GetFieldNumber(ref fieldNumber, ppma, "Tag"); + GetFieldName(ref name, ppma, "Name"); + GetFieldBoolean(ref isRequired, ppma, "IsRequired"); + GetFieldBoolean(ref isPacked, ppma, "IsPacked"); + GetFieldBoolean(ref overwriteList, attrib, "OverwriteList"); + GetDataFormat(ref dataFormat, ppma, "DataFormat"); + GetFieldBoolean(ref asReferenceHasValue, attrib, "AsReferenceHasValue", false); + + if (asReferenceHasValue) + { + asReferenceHasValue = GetFieldBoolean(ref asReference, ppma, "AsReference", true); + } + GetFieldBoolean(ref dynamicType, ppma, "DynamicType"); + if (done = tagIsPinned = fieldNumber > 0) break; // note minAcceptFieldNumber only applies to non-proto + } + } + } + } + + if (!ignore && !done && HasFamily(family, AttributeFamily.DataContractSerialier)) + { + attrib = GetAttribute(attribs, "System.Runtime.Serialization.DataMemberAttribute"); + if (attrib != null) + { + GetFieldNumber(ref fieldNumber, attrib, "Order"); + GetFieldName(ref name, attrib, "Name"); + GetFieldBoolean(ref isRequired, attrib, "IsRequired"); + done = fieldNumber >= minAcceptFieldNumber; + if (done) fieldNumber += dataMemberOffset; // dataMemberOffset only applies to DCS flags, to allow us to "bump" WCF by a notch + } + } + if (!ignore && !done && HasFamily(family, AttributeFamily.XmlSerializer)) + { + attrib = GetAttribute(attribs, "System.Xml.Serialization.XmlElementAttribute"); + if (attrib == null) attrib = GetAttribute(attribs, "System.Xml.Serialization.XmlArrayAttribute"); + GetIgnore(ref ignore, attrib, attribs, "System.Xml.Serialization.XmlIgnoreAttribute"); + if (attrib != null && !ignore) + { + GetFieldNumber(ref fieldNumber, attrib, "Order"); + GetFieldName(ref name, attrib, "ElementName"); + done = fieldNumber >= minAcceptFieldNumber; + } + } + if (!ignore && !done) + { + if (GetAttribute(attribs, "System.NonSerializedAttribute") != null) ignore = true; + } + if (ignore || (fieldNumber < minAcceptFieldNumber && !forced)) return null; + ProtoMemberAttribute result = new ProtoMemberAttribute(fieldNumber, forced || inferByTagName) + { + AsReference = asReference, + AsReferenceHasValue = asReferenceHasValue, + DataFormat = dataFormat, + DynamicType = dynamicType, + IsPacked = isPacked, + OverwriteList = overwriteList, + IsRequired = isRequired, + Name = string.IsNullOrEmpty(name) ? member.Name : name, + Member = member, + BackingMember = backingMember, + TagIsPinned = tagIsPinned + }; + return result; + } + + private ValueMember ApplyDefaultBehaviour(bool isEnum, ProtoMemberAttribute normalizedAttribute) + { + MemberInfo member; + if (normalizedAttribute == null || (member = normalizedAttribute.Member) == null) return null; // nix + + Type effectiveType = Helpers.GetMemberType(member); + + + Type itemType = null; + Type defaultType = null; + + // check for list types + ResolveListTypes(model, effectiveType, ref itemType, ref defaultType); + bool ignoreListHandling = false; + // but take it back if it is explicitly excluded + if (itemType != null) + { // looks like a list, but double check for IgnoreListHandling + int idx = model.FindOrAddAuto(effectiveType, false, true, false); + if (idx >= 0 && (ignoreListHandling = model[effectiveType].IgnoreListHandling)) + { + itemType = null; + defaultType = null; + } + } + AttributeMap[] attribs = AttributeMap.Create(model, member, true); + AttributeMap attrib; + + object defaultValue = null; + // implicit zero default + if (model.UseImplicitZeroDefaults) + { + switch (Helpers.GetTypeCode(effectiveType)) + { + case ProtoTypeCode.Boolean: defaultValue = false; break; + case ProtoTypeCode.Decimal: defaultValue = (decimal)0; break; + case ProtoTypeCode.Single: defaultValue = (float)0; break; + case ProtoTypeCode.Double: defaultValue = (double)0; break; + case ProtoTypeCode.Byte: defaultValue = (byte)0; break; + case ProtoTypeCode.Char: defaultValue = (char)0; break; + case ProtoTypeCode.Int16: defaultValue = (short)0; break; + case ProtoTypeCode.Int32: defaultValue = (int)0; break; + case ProtoTypeCode.Int64: defaultValue = (long)0; break; + case ProtoTypeCode.SByte: defaultValue = (sbyte)0; break; + case ProtoTypeCode.UInt16: defaultValue = (ushort)0; break; + case ProtoTypeCode.UInt32: defaultValue = (uint)0; break; + case ProtoTypeCode.UInt64: defaultValue = (ulong)0; break; + case ProtoTypeCode.TimeSpan: defaultValue = TimeSpan.Zero; break; + case ProtoTypeCode.Guid: defaultValue = Guid.Empty; break; + } + } + if ((attrib = GetAttribute(attribs, "System.ComponentModel.DefaultValueAttribute")) != null) + { + if (attrib.TryGet("Value", out object tmp)) defaultValue = tmp; + } + ValueMember vm = ((isEnum || normalizedAttribute.Tag > 0)) + ? new ValueMember(model, type, normalizedAttribute.Tag, member, effectiveType, itemType, defaultType, normalizedAttribute.DataFormat, defaultValue) + : null; + if (vm != null) + { + vm.BackingMember = normalizedAttribute.BackingMember; +#if COREFX || PROFILE259 + TypeInfo finalType = typeInfo; +#else + Type finalType = type; +#endif + PropertyInfo prop = Helpers.GetProperty(finalType, member.Name + "Specified", true); + MethodInfo getMethod = Helpers.GetGetMethod(prop, true, true); + if (getMethod == null || getMethod.IsStatic) prop = null; + if (prop != null) + { + vm.SetSpecified(getMethod, Helpers.GetSetMethod(prop, true, true)); + } + else + { + MethodInfo method = Helpers.GetInstanceMethod(finalType, "ShouldSerialize" + member.Name, Helpers.EmptyTypes); + if (method != null && method.ReturnType == model.MapType(typeof(bool))) + { + vm.SetSpecified(method, null); + } + } + if (!string.IsNullOrEmpty(normalizedAttribute.Name)) vm.SetName(normalizedAttribute.Name); + vm.IsPacked = normalizedAttribute.IsPacked; + vm.IsRequired = normalizedAttribute.IsRequired; + vm.OverwriteList = normalizedAttribute.OverwriteList; + if (normalizedAttribute.AsReferenceHasValue) + { + vm.AsReference = normalizedAttribute.AsReference; + } + vm.DynamicType = normalizedAttribute.DynamicType; + + vm.IsMap = ignoreListHandling ? false : vm.ResolveMapTypes(out var _, out var _, out var _); + if (vm.IsMap) // is it even *allowed* to be a map? + { + if ((attrib = GetAttribute(attribs, "ProtoBuf.ProtoMapAttribute")) != null) + { + if (attrib.TryGet(nameof(ProtoMapAttribute.DisableMap), out object tmp) && (bool)tmp) + { + vm.IsMap = false; + } + else + { + if (attrib.TryGet(nameof(ProtoMapAttribute.KeyFormat), out tmp)) vm.MapKeyFormat = (DataFormat)tmp; + if (attrib.TryGet(nameof(ProtoMapAttribute.ValueFormat), out tmp)) vm.MapValueFormat = (DataFormat)tmp; + } + } + } + + } + return vm; + } + + private static void GetDataFormat(ref DataFormat value, AttributeMap attrib, string memberName) + { + if ((attrib == null) || (value != DataFormat.Default)) return; + if (attrib.TryGet(memberName, out object obj) && obj != null) value = (DataFormat)obj; + } + + private static void GetIgnore(ref bool ignore, AttributeMap attrib, AttributeMap[] attribs, string fullName) + { + if (ignore || attrib == null) return; + ignore = GetAttribute(attribs, fullName) != null; + return; + } + + private static void GetFieldBoolean(ref bool value, AttributeMap attrib, string memberName) + { + GetFieldBoolean(ref value, attrib, memberName, true); + } + private static bool GetFieldBoolean(ref bool value, AttributeMap attrib, string memberName, bool publicOnly) + { + if (attrib == null) return false; + if (value) return true; + if (attrib.TryGet(memberName, publicOnly, out object obj) && obj != null) + { + value = (bool)obj; + return true; + } + return false; + } + + private static void GetFieldNumber(ref int value, AttributeMap attrib, string memberName) + { + if (attrib == null || value > 0) return; + if (attrib.TryGet(memberName, out object obj) && obj != null) value = (int)obj; + } + + private static void GetFieldName(ref string name, AttributeMap attrib, string memberName) + { + if (attrib == null || !string.IsNullOrEmpty(name)) return; + if (attrib.TryGet(memberName, out object obj) && obj != null) name = (string)obj; + } + + private static AttributeMap GetAttribute(AttributeMap[] attribs, string fullName) + { + for (int i = 0; i < attribs.Length; i++) + { + AttributeMap attrib = attribs[i]; + if (attrib != null && attrib.AttributeType.FullName == fullName) return attrib; + } + return null; + } + + /// + /// Adds a member (by name) to the MetaType + /// + public MetaType Add(int fieldNumber, string memberName) + { + AddField(fieldNumber, memberName, null, null, null); + return this; + } + + /// + /// Adds a member (by name) to the MetaType, returning the ValueMember rather than the fluent API. + /// This is otherwise identical to Add. + /// + public ValueMember AddField(int fieldNumber, string memberName) + { + return AddField(fieldNumber, memberName, null, null, null); + } + + /// + /// Gets or sets whether the type should use a parameterless constructor (the default), + /// or whether the type should skip the constructor completely. This option is not supported + /// on compact-framework. + /// + public bool UseConstructor + { // negated to have defaults as flat zero + get { return !HasFlag(OPTIONS_SkipConstructor); } + set { SetFlag(OPTIONS_SkipConstructor, !value, true); } + } + + /// + /// The concrete type to create when a new instance of this type is needed; this may be useful when dealing + /// with dynamic proxies, or with interface-based APIs + /// + public Type ConstructType + { + get { return constructType; } + set + { + ThrowIfFrozen(); + constructType = value; + } + } + + private Type constructType; + /// + /// Adds a member (by name) to the MetaType + /// + public MetaType Add(string memberName) + { + Add(GetNextFieldNumber(), memberName); + return this; + } + + Type surrogate; + /// + /// Performs serialization of this type via a surrogate; all + /// other serialization options are ignored and handled + /// by the surrogate's configuration. + /// + public void SetSurrogate(Type surrogateType) + { + if (surrogateType == type) surrogateType = null; + if (surrogateType != null) + { + // note that BuildSerializer checks the **CURRENT TYPE** is OK to be surrogated + if (surrogateType != null && Helpers.IsAssignableFrom(model.MapType(typeof(IEnumerable)), surrogateType)) + { + throw new ArgumentException("Repeated data (a list, collection, etc) has inbuilt behaviour and cannot be used as a surrogate"); + } + } + ThrowIfFrozen(); + this.surrogate = surrogateType; + // no point in offering chaining; no options are respected + } + + internal MetaType GetSurrogateOrSelf() + { + if (surrogate != null) return model[surrogate]; + return this; + } + + internal MetaType GetSurrogateOrBaseOrSelf(bool deep) + { + if (surrogate != null) return model[surrogate]; + MetaType snapshot = this.baseType; + if (snapshot != null) + { + if (deep) + { + MetaType tmp; + do + { + tmp = snapshot; + snapshot = snapshot.baseType; + } while (snapshot != null); + return tmp; + } + return snapshot; + } + return this; + } + + private int GetNextFieldNumber() + { + int maxField = 0; + foreach (ValueMember member in fields) + { + if (member.FieldNumber > maxField) maxField = member.FieldNumber; + } + if (subTypes != null) + { + foreach (SubType subType in subTypes) + { + if (subType.FieldNumber > maxField) maxField = subType.FieldNumber; + } + } + return maxField + 1; + } + + /// + /// Adds a set of members (by name) to the MetaType + /// + public MetaType Add(params string[] memberNames) + { + if (memberNames == null) throw new ArgumentNullException("memberNames"); + int next = GetNextFieldNumber(); + for (int i = 0; i < memberNames.Length; i++) + { + Add(next++, memberNames[i]); + } + return this; + } + + /// + /// Adds a member (by name) to the MetaType + /// + public MetaType Add(int fieldNumber, string memberName, object defaultValue) + { + AddField(fieldNumber, memberName, null, null, defaultValue); + return this; + } + + /// + /// Adds a member (by name) to the MetaType, including an itemType and defaultType for representing lists + /// + public MetaType Add(int fieldNumber, string memberName, Type itemType, Type defaultType) + { + AddField(fieldNumber, memberName, itemType, defaultType, null); + return this; + } + + /// + /// Adds a member (by name) to the MetaType, including an itemType and defaultType for representing lists, returning the ValueMember rather than the fluent API. + /// This is otherwise identical to Add. + /// + public ValueMember AddField(int fieldNumber, string memberName, Type itemType, Type defaultType) + { + return AddField(fieldNumber, memberName, itemType, defaultType, null); + } + + private ValueMember AddField(int fieldNumber, string memberName, Type itemType, Type defaultType, object defaultValue) + { + MemberInfo mi = null; +#if PROFILE259 + mi = Helpers.IsEnum(type) ? type.GetTypeInfo().GetDeclaredField(memberName) : Helpers.GetInstanceMember(type.GetTypeInfo(), memberName); + +#else + MemberInfo[] members = type.GetMember(memberName, Helpers.IsEnum(type) ? BindingFlags.Static | BindingFlags.Public : BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); + if (members != null && members.Length == 1) mi = members[0]; +#endif + if (mi == null) throw new ArgumentException("Unable to determine member: " + memberName, "memberName"); + + Type miType; + PropertyInfo pi = null; + FieldInfo fi = null; +#if PORTABLE || COREFX || PROFILE259 + pi = mi as PropertyInfo; + if (pi == null) + { + fi = mi as FieldInfo; + if (fi == null) + { + throw new NotSupportedException(mi.GetType().Name); + } + else + { + miType = fi.FieldType; + } + } + else + { + miType = pi.PropertyType; + } +#else + switch (mi.MemberType) + { + case MemberTypes.Field: + fi = (FieldInfo)mi; + miType = fi.FieldType; break; + case MemberTypes.Property: + pi = (PropertyInfo)mi; + miType = pi.PropertyType; break; + default: + throw new NotSupportedException(mi.MemberType.ToString()); + } +#endif + ResolveListTypes(model, miType, ref itemType, ref defaultType); + + MemberInfo backingField = null; + if (pi?.CanWrite == false) + { + string name = $"<{((PropertyInfo)mi).Name}>k__BackingField"; +#if PROFILE259 + var backingMembers = type.GetTypeInfo().DeclaredMembers; + var memberInfos = backingMembers as MemberInfo[] ?? backingMembers.ToArray(); + if (memberInfos.Count() == 1) + { + MemberInfo first = memberInfos.FirstOrDefault(); + if (first is FieldInfo) + { + backingField = first; + } + } +#else + var backingMembers = type.GetMember($"<{((PropertyInfo)mi).Name}>k__BackingField", Helpers.IsEnum(type) ? BindingFlags.Static | BindingFlags.Public : BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); + if (backingMembers != null && backingMembers.Length == 1 && (backingMembers[0] as FieldInfo) != null) + backingField = backingMembers[0]; +#endif + } + ValueMember newField = new ValueMember(model, type, fieldNumber, backingField ?? mi, miType, itemType, defaultType, DataFormat.Default, defaultValue); + if (backingField != null) + newField.SetName(mi.Name); + Add(newField); + return newField; + } + + internal static void ResolveListTypes(TypeModel model, Type type, ref Type itemType, ref Type defaultType) + { + if (type == null) return; + // handle arrays + if (type.IsArray) + { + if (type.GetArrayRank() != 1) + { + throw new NotSupportedException("Multi-dimensional arrays are not supported"); + } + itemType = type.GetElementType(); + if (itemType == model.MapType(typeof(byte))) + { + defaultType = itemType = null; + } + else + { + defaultType = type; + } + } + // handle lists + if (itemType == null) { itemType = TypeModel.GetListItemType(model, type); } + + // check for nested data (not allowed) + if (itemType != null) + { + Type nestedItemType = null, nestedDefaultType = null; + ResolveListTypes(model, itemType, ref nestedItemType, ref nestedDefaultType); + if (nestedItemType != null) + { + throw TypeModel.CreateNestedListsNotSupported(type); + } + } + + if (itemType != null && defaultType == null) + { +#if COREFX || PROFILE259 + TypeInfo typeInfo = type.GetTypeInfo(); + if (typeInfo.IsClass && !typeInfo.IsAbstract && Helpers.GetConstructor(typeInfo, Helpers.EmptyTypes, true) != null) +#else + if (type.IsClass && !type.IsAbstract && Helpers.GetConstructor(type, Helpers.EmptyTypes, true) != null) +#endif + { + defaultType = type; + } + if (defaultType == null) + { +#if COREFX || PROFILE259 + if (typeInfo.IsInterface) +#else + if (type.IsInterface) +#endif + { + + Type[] genArgs; +#if COREFX || PROFILE259 + if (typeInfo.IsGenericType && type.GetGenericTypeDefinition() == typeof(System.Collections.Generic.IDictionary<,>) + && itemType == typeof(System.Collections.Generic.KeyValuePair<,>).MakeGenericType(genArgs = typeInfo.GenericTypeArguments)) +#else + if (type.IsGenericType && type.GetGenericTypeDefinition() == model.MapType(typeof(System.Collections.Generic.IDictionary<,>)) + && itemType == model.MapType(typeof(System.Collections.Generic.KeyValuePair<,>)).MakeGenericType(genArgs = type.GetGenericArguments())) +#endif + { + defaultType = model.MapType(typeof(System.Collections.Generic.Dictionary<,>)).MakeGenericType(genArgs); + } + else + { + defaultType = model.MapType(typeof(System.Collections.Generic.List<>)).MakeGenericType(itemType); + } + } + } + // verify that the default type is appropriate + if (defaultType != null && !Helpers.IsAssignableFrom(type, defaultType)) { defaultType = null; } + } + } + + private void Add(ValueMember member) + { + int opaqueToken = 0; + try + { + model.TakeLock(ref opaqueToken); + ThrowIfFrozen(); + fields.Add(member); + } + finally + { + model.ReleaseLock(opaqueToken); + } + } + + /// + /// Returns the ValueMember that matchs a given field number, or null if not found + /// + public ValueMember this[int fieldNumber] + { + get + { + foreach (ValueMember member in fields) + { + if (member.FieldNumber == fieldNumber) return member; + } + return null; + } + } + /// + /// Returns the ValueMember that matchs a given member (property/field), or null if not found + /// + public ValueMember this[MemberInfo member] + { + get + { + if (member == null) return null; + foreach (ValueMember x in fields) + { + if (x.Member == member || x.BackingMember == member) return x; + } + return null; + } + } + private readonly BasicList fields = new BasicList(); + + /// + /// Returns the ValueMember instances associated with this type + /// + public ValueMember[] GetFields() + { + ValueMember[] arr = new ValueMember[fields.Count]; + fields.CopyTo(arr, 0); + Array.Sort(arr, ValueMember.Comparer.Default); + return arr; + } + + /// + /// Returns the SubType instances associated with this type + /// + public SubType[] GetSubtypes() + { + if (subTypes == null || subTypes.Count == 0) return new SubType[0]; + SubType[] arr = new SubType[subTypes.Count]; + subTypes.CopyTo(arr, 0); + Array.Sort(arr, SubType.Comparer.Default); + return arr; + } + + internal IEnumerable GetAllGenericArguments() + { + return GetAllGenericArguments(type); + } + + private static IEnumerable GetAllGenericArguments(Type type) + { + +#if PROFILE259 + var genericArguments = type.GetGenericTypeDefinition().GenericTypeArguments; +#else + var genericArguments = type.GetGenericArguments(); +#endif + foreach (var arg in genericArguments) + { + yield return arg; + foreach (var inner in GetAllGenericArguments(arg)) + { + yield return inner; + } + } + } + +#if FEAT_COMPILER + /// + /// Compiles the serializer for this type; this is *not* a full + /// standalone compile, but can significantly boost performance + /// while allowing additional types to be added. + /// + /// An in-place compile can access non-public types / members + public void CompileInPlace() + { + serializer = CompiledSerializer.Wrap(Serializer, model); + } +#endif + + internal bool IsDefined(int fieldNumber) + { + foreach (ValueMember field in fields) + { + if (field.FieldNumber == fieldNumber) return true; + } + return false; + } + + internal int GetKey(bool demand, bool getBaseKey) + { + return model.GetKey(type, demand, getBaseKey); + } + + internal EnumSerializer.EnumPair[] GetEnumMap() + { + if (HasFlag(OPTIONS_EnumPassThru)) return null; + EnumSerializer.EnumPair[] result = new EnumSerializer.EnumPair[fields.Count]; + for (int i = 0; i < result.Length; i++) + { + ValueMember member = (ValueMember)fields[i]; + int wireValue = member.FieldNumber; + object value = member.GetRawEnumValue(); + result[i] = new EnumSerializer.EnumPair(wireValue, value, member.MemberType); + } + return result; + } + + /// + /// Gets or sets a value indicating that an enum should be treated directly as an int/short/etc, rather + /// than enforcing .proto enum rules. This is useful *in particul* for [Flags] enums. + /// + public bool EnumPassthru + { + get { return HasFlag(OPTIONS_EnumPassThru); } + set { SetFlag(OPTIONS_EnumPassThru, value, true); } + } + + /// + /// Gets or sets a value indicating that this type should NOT be treated as a list, even if it has + /// familiar list-like characteristics (enumerable, add, etc) + /// + public bool IgnoreListHandling + { + get { return HasFlag(OPTIONS_IgnoreListHandling); } + set { SetFlag(OPTIONS_IgnoreListHandling, value, true); } + } + + internal bool Pending + { + get { return HasFlag(OPTIONS_Pending); } + set { SetFlag(OPTIONS_Pending, value, false); } + } + + private const ushort + OPTIONS_Pending = 1, + OPTIONS_EnumPassThru = 2, + OPTIONS_Frozen = 4, + OPTIONS_PrivateOnApi = 8, + OPTIONS_SkipConstructor = 16, + OPTIONS_AsReferenceDefault = 32, + OPTIONS_AutoTuple = 64, + OPTIONS_IgnoreListHandling = 128, + OPTIONS_IsGroup = 256; + + private volatile ushort flags; + private bool HasFlag(ushort flag) { return (flags & flag) == flag; } + private void SetFlag(ushort flag, bool value, bool throwIfFrozen) + { + if (throwIfFrozen && HasFlag(flag) != value) + { + ThrowIfFrozen(); + } + if (value) + flags |= flag; + else + flags = (ushort)(flags & ~flag); + } + + internal static MetaType GetRootType(MetaType source) + { + while (source.serializer != null) + { + MetaType tmp = source.baseType; + if (tmp == null) return source; + source = tmp; // else loop until we reach something that isn't generated, or is the root + } + + // now we get into uncertain territory + RuntimeTypeModel model = source.model; + int opaqueToken = 0; + try + { + model.TakeLock(ref opaqueToken); + + MetaType tmp; + while ((tmp = source.baseType) != null) source = tmp; + return source; + + } + finally + { + model.ReleaseLock(opaqueToken); + } + } + + internal bool IsPrepared() + { +#if FEAT_COMPILER + return serializer is CompiledSerializer; +#else + return false; +#endif + } + + internal IEnumerable Fields => this.fields; + + internal static StringBuilder NewLine(StringBuilder builder, int indent) + { + return Helpers.AppendLine(builder).Append(' ', indent * 3); + } + + internal bool IsAutoTuple => HasFlag(OPTIONS_AutoTuple); + + /// + /// Indicates whether this type should always be treated as a "group" (rather than a string-prefixed sub-message) + /// + public bool IsGroup + { + get { return HasFlag(OPTIONS_IsGroup); } + set { SetFlag(OPTIONS_IsGroup, value, true); } + } + + internal void WriteSchema(StringBuilder builder, int indent, ref RuntimeTypeModel.CommonImports imports, ProtoSyntax syntax) + { + if (surrogate != null) return; // nothing to write + + ValueMember[] fieldsArr = new ValueMember[fields.Count]; + fields.CopyTo(fieldsArr, 0); + Array.Sort(fieldsArr, ValueMember.Comparer.Default); + + if (IsList) + { + string itemTypeName = model.GetSchemaTypeName(TypeModel.GetListItemType(model, type), DataFormat.Default, false, false, ref imports); + NewLine(builder, indent).Append("message ").Append(GetSchemaTypeName()).Append(" {"); + NewLine(builder, indent + 1).Append("repeated ").Append(itemTypeName).Append(" items = 1;"); + NewLine(builder, indent).Append('}'); + } + else if (IsAutoTuple) + { // key-value-pair etc + + if (ResolveTupleConstructor(type, out MemberInfo[] mapping) != null) + { + NewLine(builder, indent).Append("message ").Append(GetSchemaTypeName()).Append(" {"); + for (int i = 0; i < mapping.Length; i++) + { + Type effectiveType; + if (mapping[i] is PropertyInfo property) + { + effectiveType = property.PropertyType; + } + else if (mapping[i] is FieldInfo field) + { + effectiveType = field.FieldType; + } + else + { + throw new NotSupportedException("Unknown member type: " + mapping[i].GetType().Name); + } + NewLine(builder, indent + 1).Append(syntax == ProtoSyntax.Proto2 ? "optional " : "").Append(model.GetSchemaTypeName(effectiveType, DataFormat.Default, false, false, ref imports).Replace('.', '_')) + .Append(' ').Append(mapping[i].Name).Append(" = ").Append(i + 1).Append(';'); + } + NewLine(builder, indent).Append('}'); + } + } + else if (Helpers.IsEnum(type)) + { + NewLine(builder, indent).Append("enum ").Append(GetSchemaTypeName()).Append(" {"); + if (fieldsArr.Length == 0 && EnumPassthru) + { + if (type +#if COREFX || PROFILE259 + .GetTypeInfo() +#endif +.IsDefined(model.MapType(typeof(FlagsAttribute)), false)) + { + NewLine(builder, indent + 1).Append("// this is a composite/flags enumeration"); + } + else + { + NewLine(builder, indent + 1).Append("// this enumeration will be passed as a raw value"); + } + foreach (FieldInfo field in +#if PROFILE259 + type.GetRuntimeFields() +#else + type.GetFields() +#endif + + ) + { + if (field.IsStatic && field.IsLiteral) + { + object enumVal; +#if PORTABLE || CF || NETSTANDARD1_3 || NETSTANDARD1_4 || PROFILE259 || UAP + enumVal = Convert.ChangeType(field.GetValue(null), Enum.GetUnderlyingType(field.FieldType), System.Globalization.CultureInfo.InvariantCulture); +#else + enumVal = field.GetRawConstantValue(); +#endif + NewLine(builder, indent + 1).Append(field.Name).Append(" = ").Append(enumVal).Append(";"); + } + } + + } + else + { + Dictionary countByField = new Dictionary(fieldsArr.Length); + bool needsAlias = false; + foreach (var field in fieldsArr) + { + if (countByField.ContainsKey(field.FieldNumber)) + { // no point actually counting; that's enough to know we have a problem + needsAlias = true; + break; + } + countByField.Add(field.FieldNumber, 1); + } + if (needsAlias) + { // duplicated value requires allow_alias + NewLine(builder, indent + 1).Append("option allow_alias = true;"); + } + + bool haveWrittenZero = false; + // write zero values **first** + foreach (ValueMember member in fieldsArr) + { + if (member.FieldNumber == 0) + { + NewLine(builder, indent + 1).Append(member.Name).Append(" = ").Append(member.FieldNumber).Append(';'); + haveWrittenZero = true; + } + } + if (syntax == ProtoSyntax.Proto3 && !haveWrittenZero) + { + NewLine(builder, indent + 1).Append("ZERO = 0; // proto3 requires a zero value as the first item (it can be named anything)"); + } + // note array is already sorted, so zero would already be first + foreach (ValueMember member in fieldsArr) + { + if (member.FieldNumber == 0) continue; + NewLine(builder, indent + 1).Append(member.Name).Append(" = ").Append(member.FieldNumber).Append(';'); + } + } + NewLine(builder, indent).Append('}'); + } + else + { + NewLine(builder, indent).Append("message ").Append(GetSchemaTypeName()).Append(" {"); + foreach (ValueMember member in fieldsArr) + { + string schemaTypeName; + bool hasOption = false; + if (member.IsMap) + { + member.ResolveMapTypes(out var _, out var keyType, out var valueType); + + var keyTypeName = model.GetSchemaTypeName(keyType, member.MapKeyFormat, false, false, ref imports); + schemaTypeName = model.GetSchemaTypeName(valueType, member.MapKeyFormat, member.AsReference, member.DynamicType, ref imports); + NewLine(builder, indent + 1).Append("map<").Append(keyTypeName).Append(",").Append(schemaTypeName).Append("> ") + .Append(member.Name).Append(" = ").Append(member.FieldNumber).Append(";"); + } + else + { + string ordinality = member.ItemType != null ? "repeated " : (syntax == ProtoSyntax.Proto2 ? (member.IsRequired ? "required " : "optional ") : ""); + NewLine(builder, indent + 1).Append(ordinality); + if (member.DataFormat == DataFormat.Group) builder.Append("group "); + schemaTypeName = member.GetSchemaTypeName(true, ref imports); + builder.Append(schemaTypeName).Append(" ") + .Append(member.Name).Append(" = ").Append(member.FieldNumber); + + if (syntax == ProtoSyntax.Proto2 && member.DefaultValue != null && member.IsRequired == false) + { + if (member.DefaultValue is string) + { + AddOption(builder, ref hasOption).Append("default = \"").Append(member.DefaultValue).Append("\""); + } + else if (member.DefaultValue is TimeSpan) + { + // ignore + } + else if (member.DefaultValue is bool) + { // need to be lower case (issue 304) + AddOption(builder, ref hasOption).Append((bool)member.DefaultValue ? "default = true" : "default = false"); + } + else + { + AddOption(builder, ref hasOption).Append("default = ").Append(member.DefaultValue); + } + } + if (CanPack(member.ItemType)) + { + if (syntax == ProtoSyntax.Proto2) + { + if (member.IsPacked) AddOption(builder, ref hasOption).Append("packed = true"); // disabled by default + } + else + { + if (!member.IsPacked) AddOption(builder, ref hasOption).Append("packed = false"); // enabled by default + } + } + if (member.AsReference) + { + imports |= RuntimeTypeModel.CommonImports.Protogen; + AddOption(builder, ref hasOption).Append("(.protobuf_net.fieldopt).asRef = true"); + } + if (member.DynamicType) + { + imports |= RuntimeTypeModel.CommonImports.Protogen; + AddOption(builder, ref hasOption).Append("(.protobuf_net.fieldopt).dynamicType = true"); + } + CloseOption(builder, ref hasOption).Append(';'); + if (syntax != ProtoSyntax.Proto2 && member.DefaultValue != null && !member.IsRequired) + { + if (IsImplicitDefault(member.DefaultValue)) + { + // don't emit; we're good + } + else + { + builder.Append(" // default value could not be applied: ").Append(member.DefaultValue); + } + } + } + if (schemaTypeName == ".bcl.NetObjectProxy" && member.AsReference && !member.DynamicType) // we know what it is; tell the user + { + builder.Append(" // reference-tracked ").Append(member.GetSchemaTypeName(false, ref imports)); + } + } + if (subTypes != null && subTypes.Count != 0) + { + SubType[] subTypeArr = new SubType[subTypes.Count]; + subTypes.CopyTo(subTypeArr, 0); + Array.Sort(subTypeArr, SubType.Comparer.Default); + string[] fieldNames = new string[subTypeArr.Length]; + for(int i = 0; i < subTypeArr.Length;i++) + fieldNames[i] = subTypeArr[i].DerivedType.GetSchemaTypeName(); + + string fieldName = "subtype"; + while (Array.IndexOf(fieldNames, fieldName) >= 0) + fieldName = "_" + fieldName; + + NewLine(builder, indent + 1).Append("oneof ").Append(fieldName).Append(" {"); + for(int i = 0; i < subTypeArr.Length; i++) + { + var subTypeName = fieldNames[i]; + NewLine(builder, indent + 2).Append(subTypeName) + .Append(" ").Append(subTypeName).Append(" = ").Append(subTypeArr[i].FieldNumber).Append(';'); + } + NewLine(builder, indent + 1).Append("}"); + } + NewLine(builder, indent).Append('}'); + } + } + + private static StringBuilder AddOption(StringBuilder builder, ref bool hasOption) + { + if (hasOption) + return builder.Append(", "); + hasOption = true; + return builder.Append(" ["); + } + + private static StringBuilder CloseOption(StringBuilder builder, ref bool hasOption) + { + if (hasOption) + { + hasOption = false; + return builder.Append("]"); + } + return builder; + } + + private static bool IsImplicitDefault(object value) + { + try + { + if (value == null) return false; + switch (Helpers.GetTypeCode(value.GetType())) + { + case ProtoTypeCode.Boolean: return ((bool)value) == false; + case ProtoTypeCode.Byte: return ((byte)value) == (byte)0; + case ProtoTypeCode.Char: return ((char)value) == (char)0; + case ProtoTypeCode.DateTime: return ((DateTime)value) == default; + case ProtoTypeCode.Decimal: return ((decimal)value) == 0M; + case ProtoTypeCode.Double: return ((double)value) == (double)0; + case ProtoTypeCode.Int16: return ((short)value) == (short)0; + case ProtoTypeCode.Int32: return ((int)value) == (int)0; + case ProtoTypeCode.Int64: return ((long)value) == (long)0; + case ProtoTypeCode.SByte: return ((sbyte)value) == (sbyte)0; + case ProtoTypeCode.Single: return ((float)value) == (float)0; + case ProtoTypeCode.String: return ((string)value) == ""; + case ProtoTypeCode.TimeSpan: return ((TimeSpan)value) == TimeSpan.Zero; + case ProtoTypeCode.UInt16: return ((ushort)value) == (ushort)0; + case ProtoTypeCode.UInt32: return ((uint)value) == (uint)0; + case ProtoTypeCode.UInt64: return ((ulong)value) == (ulong)0; + } + } + catch { } + return false; + } + + private static bool CanPack(Type type) + { + if (type == null) return false; + switch (Helpers.GetTypeCode(type)) + { + case ProtoTypeCode.Boolean: + case ProtoTypeCode.Byte: + case ProtoTypeCode.Char: + case ProtoTypeCode.Double: + case ProtoTypeCode.Int16: + case ProtoTypeCode.Int32: + case ProtoTypeCode.Int64: + case ProtoTypeCode.SByte: + case ProtoTypeCode.Single: + case ProtoTypeCode.UInt16: + case ProtoTypeCode.UInt32: + case ProtoTypeCode.UInt64: + return true; + } + return false; + } + + /// + /// Apply a shift to all fields (and sub-types) on this type + /// + /// The change in field number to apply + /// The resultant field numbers must still all be considered valid +#if !(NETSTANDARD1_0 || NETSTANDARD1_3 || UAP) + [System.ComponentModel.Browsable(false)] +#endif + [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Advanced)] + public void ApplyFieldOffset(int offset) + { + if (Helpers.IsEnum(type)) throw new InvalidOperationException("Cannot apply field-offset to an enum"); + if (offset == 0) return; // nothing to do + int opaqueToken = 0; + try + { + model.TakeLock(ref opaqueToken); + ThrowIfFrozen(); + + if (fields != null) + { + foreach(ValueMember field in fields) + AssertValidFieldNumber(field.FieldNumber + offset); + } + if (subTypes != null) + { + foreach (SubType subType in subTypes) + AssertValidFieldNumber(subType.FieldNumber + offset); + } + + // we've checked the ranges are all OK; since we're moving everything, we can't overlap ourselves + // so: we can just move + if (fields != null) + { + foreach (ValueMember field in fields) + field.FieldNumber += offset; + } + if (subTypes != null) + { + foreach (SubType subType in subTypes) + subType.FieldNumber += offset; + } + } + finally + { + model.ReleaseLock(opaqueToken); + } + } + + internal static void AssertValidFieldNumber(int fieldNumber) + { + if (fieldNumber < 1) throw new ArgumentOutOfRangeException(nameof(fieldNumber)); + } + } +} +#endif diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Meta/MetaType.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Meta/MetaType.cs.meta new file mode 100644 index 0000000..edc2cad --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Meta/MetaType.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 170c607ac9d3b9346a8f4197e9e4d86a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Meta/ProtoSyntax.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Meta/ProtoSyntax.cs new file mode 100644 index 0000000..ab90d5b --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Meta/ProtoSyntax.cs @@ -0,0 +1,17 @@ +namespace ProtoBuf.Meta +{ + /// + /// Indiate the variant of the protobuf .proto DSL syntax to use + /// + public enum ProtoSyntax + { + /// + /// https://developers.google.com/protocol-buffers/docs/proto + /// + Proto2 = 0, + /// + /// https://developers.google.com/protocol-buffers/docs/proto3 + /// + Proto3 = 1, + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Meta/ProtoSyntax.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Meta/ProtoSyntax.cs.meta new file mode 100644 index 0000000..2320025 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Meta/ProtoSyntax.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8df2b30e0bc1f274a8170e86c9d08f96 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Meta/RuntimeTypeModel.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Meta/RuntimeTypeModel.cs new file mode 100644 index 0000000..05dfcf1 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Meta/RuntimeTypeModel.cs @@ -0,0 +1,2036 @@ +#if !NO_RUNTIME +using System; +using System.Collections; +using System.Text; +using System.Reflection; +#if FEAT_COMPILER +using System.Reflection.Emit; +#endif + +using ProtoBuf.Serializers; +using System.Threading; +using System.IO; +using System.Diagnostics; +using System.Runtime.CompilerServices; + +namespace ProtoBuf.Meta +{ + /// + /// Provides protobuf serialization support for a number of types that can be defined at runtime + /// + public sealed class RuntimeTypeModel : TypeModel + { + private ushort options; + private const ushort + OPTIONS_InferTagFromNameDefault = 1, + OPTIONS_IsDefaultModel = 2, + OPTIONS_Frozen = 4, + OPTIONS_AutoAddMissingTypes = 8, +#if FEAT_COMPILER + OPTIONS_AutoCompile = 16, +#endif + OPTIONS_UseImplicitZeroDefaults = 32, + OPTIONS_AllowParseableTypes = 64, + OPTIONS_AutoAddProtoContractTypesOnly = 128, + OPTIONS_IncludeDateTimeKind = 256, + OPTIONS_DoNotInternStrings = 512; + + private bool GetOption(ushort option) + { + return (options & option) == option; + } + + private void SetOption(ushort option, bool value) + { + if (value) options |= option; + else options &= (ushort)~option; + } + + /// + /// Global default that + /// enables/disables automatic tag generation based on the existing name / order + /// of the defined members. See + /// for usage and important warning / explanation. + /// You must set the global default before attempting to serialize/deserialize any + /// impacted type. + /// + public bool InferTagFromNameDefault + { + get { return GetOption(OPTIONS_InferTagFromNameDefault); } + set { SetOption(OPTIONS_InferTagFromNameDefault, value); } + } + + /// + /// Global default that determines whether types are considered serializable + /// if they have [DataContract] / [XmlType]. With this enabled, ONLY + /// types marked as [ProtoContract] are added automatically. + /// + public bool AutoAddProtoContractTypesOnly + { + get { return GetOption(OPTIONS_AutoAddProtoContractTypesOnly); } + set { SetOption(OPTIONS_AutoAddProtoContractTypesOnly, value); } + } + + /// + /// Global switch that enables or disables the implicit + /// handling of "zero defaults"; meanning: if no other default is specified, + /// it assumes bools always default to false, integers to zero, etc. + /// + /// If this is disabled, no such assumptions are made and only *explicit* + /// default values are processed. This is enabled by default to + /// preserve similar logic to v1. + /// + public bool UseImplicitZeroDefaults + { + get { return GetOption(OPTIONS_UseImplicitZeroDefaults); } + set + { + if (!value && GetOption(OPTIONS_IsDefaultModel)) + { + throw new InvalidOperationException("UseImplicitZeroDefaults cannot be disabled on the default model"); + } + SetOption(OPTIONS_UseImplicitZeroDefaults, value); + } + } + + /// + /// Global switch that determines whether types with a .ToString() and a Parse(string) + /// should be serialized as strings. + /// + public bool AllowParseableTypes + { + get { return GetOption(OPTIONS_AllowParseableTypes); } + set { SetOption(OPTIONS_AllowParseableTypes, value); } + } + + /// + /// Global switch that determines whether DateTime serialization should include the Kind of the date/time. + /// + public bool IncludeDateTimeKind + { + get { return GetOption(OPTIONS_IncludeDateTimeKind); } + set { SetOption(OPTIONS_IncludeDateTimeKind, value); } + } + + /// + /// Global switch that determines whether a single instance of the same string should be used during deserialization. + /// + /// Note this does not use the global .NET string interner + public bool InternStrings + { + get { return !GetOption(OPTIONS_DoNotInternStrings); } + set { SetOption(OPTIONS_DoNotInternStrings, !value); } + } + + /// + /// Should the Kind be included on date/time values? + /// + protected internal override bool SerializeDateTimeKind() + { + return GetOption(OPTIONS_IncludeDateTimeKind); + } + + private sealed class Singleton + { + private Singleton() { } + internal static readonly RuntimeTypeModel Value = new RuntimeTypeModel(true); + } + + /// + /// The default model, used to support ProtoBuf.Serializer + /// + public static RuntimeTypeModel Default => Singleton.Value; + + /// + /// Returns a sequence of the Type instances that can be + /// processed by this model. + /// + public IEnumerable GetTypes() => types; + + /// + /// Suggest a .proto definition for the given type + /// + /// The type to generate a .proto definition for, or null to generate a .proto that represents the entire model + /// The .proto definition as a string + /// The .proto syntax to use + public override string GetSchema(Type type, ProtoSyntax syntax) + { + BasicList requiredTypes = new BasicList(); + MetaType primaryType = null; + bool isInbuiltType = false; + if (type == null) + { // generate for the entire model + foreach (MetaType meta in types) + { + MetaType tmp = meta.GetSurrogateOrBaseOrSelf(false); + if (!requiredTypes.Contains(tmp)) + { // ^^^ note that the type might have been added as a descendent + requiredTypes.Add(tmp); + CascadeDependents(requiredTypes, tmp); + } + } + } + else + { + Type tmp = Helpers.GetUnderlyingType(type); + if (tmp != null) type = tmp; + + WireType defaultWireType; + isInbuiltType = (ValueMember.TryGetCoreSerializer(this, DataFormat.Default, type, out defaultWireType, false, false, false, false) != null); + if (!isInbuiltType) + { + //Agenerate just relative to the supplied type + int index = FindOrAddAuto(type, false, false, false); + if (index < 0) throw new ArgumentException("The type specified is not a contract-type", "type"); + + // get the required types + primaryType = ((MetaType)types[index]).GetSurrogateOrBaseOrSelf(false); + requiredTypes.Add(primaryType); + CascadeDependents(requiredTypes, primaryType); + } + } + + // use the provided type's namespace for the "package" + StringBuilder headerBuilder = new StringBuilder(); + string package = null; + + if (!isInbuiltType) + { + IEnumerable typesForNamespace = primaryType == null ? types : requiredTypes; + foreach (MetaType meta in typesForNamespace) + { + if (meta.IsList) continue; + string tmp = meta.Type.Namespace; + if (!string.IsNullOrEmpty(tmp)) + { + if (tmp.StartsWith("System.")) continue; + if (package == null) + { // haven't seen any suggestions yet + package = tmp; + } + else if (package == tmp) + { // that's fine; a repeat of the one we already saw + } + else + { // something else; have confliucting suggestions; abort + package = null; + break; + } + } + } + } + switch (syntax) + { + case ProtoSyntax.Proto2: + headerBuilder.AppendLine(@"syntax = ""proto2"";"); + break; + case ProtoSyntax.Proto3: + headerBuilder.AppendLine(@"syntax = ""proto3"";"); + break; + default: + throw new ArgumentOutOfRangeException(nameof(syntax)); + } + + if (!string.IsNullOrEmpty(package)) + { + headerBuilder.Append("package ").Append(package).Append(';'); + Helpers.AppendLine(headerBuilder); + } + + var imports = CommonImports.None; + StringBuilder bodyBuilder = new StringBuilder(); + // sort them by schema-name + MetaType[] metaTypesArr = new MetaType[requiredTypes.Count]; + requiredTypes.CopyTo(metaTypesArr, 0); + Array.Sort(metaTypesArr, MetaType.Comparer.Default); + + // write the messages + if (isInbuiltType) + { + Helpers.AppendLine(bodyBuilder).Append("message ").Append(type.Name).Append(" {"); + MetaType.NewLine(bodyBuilder, 1).Append(syntax == ProtoSyntax.Proto2 ? "optional " : "").Append(GetSchemaTypeName(type, DataFormat.Default, false, false, ref imports)) + .Append(" value = 1;"); + Helpers.AppendLine(bodyBuilder).Append('}'); + } + else + { + for (int i = 0; i < metaTypesArr.Length; i++) + { + MetaType tmp = metaTypesArr[i]; + if (tmp.IsList && tmp != primaryType) continue; + tmp.WriteSchema(bodyBuilder, 0, ref imports, syntax); + } + } + if ((imports & CommonImports.Bcl) != 0) + { + headerBuilder.Append("import \"protobuf-net/bcl.proto\"; // schema for protobuf-net's handling of core .NET types"); + Helpers.AppendLine(headerBuilder); + } + if ((imports & CommonImports.Protogen) != 0) + { + headerBuilder.Append("import \"protobuf-net/protogen.proto\"; // custom protobuf-net options"); + Helpers.AppendLine(headerBuilder); + } + if ((imports & CommonImports.Timestamp) != 0) + { + headerBuilder.Append("import \"google/protobuf/timestamp.proto\";"); + Helpers.AppendLine(headerBuilder); + } + if ((imports & CommonImports.Duration) != 0) + { + headerBuilder.Append("import \"google/protobuf/duration.proto\";"); + Helpers.AppendLine(headerBuilder); + } + return Helpers.AppendLine(headerBuilder.Append(bodyBuilder)).ToString(); + } + [Flags] + internal enum CommonImports + { + None = 0, + Bcl = 1, + Timestamp = 2, + Duration = 4, + Protogen = 8 + } + private void CascadeDependents(BasicList list, MetaType metaType) + { + MetaType tmp; + if (metaType.IsList) + { + Type itemType = TypeModel.GetListItemType(this, metaType.Type); + TryGetCoreSerializer(list, itemType); + } + else + { + if (metaType.IsAutoTuple) + { + MemberInfo[] mapping; + if (MetaType.ResolveTupleConstructor(metaType.Type, out mapping) != null) + { + for (int i = 0; i < mapping.Length; i++) + { + Type type = null; + if (mapping[i] is PropertyInfo) type = ((PropertyInfo)mapping[i]).PropertyType; + else if (mapping[i] is FieldInfo) type = ((FieldInfo)mapping[i]).FieldType; + TryGetCoreSerializer(list, type); + } + } + } + else + { + foreach (ValueMember member in metaType.Fields) + { + Type type = member.ItemType; + if (member.IsMap) + { + member.ResolveMapTypes(out _, out _, out type); // don't need key-type + } + if (type == null) type = member.MemberType; + TryGetCoreSerializer(list, type); + } + } + foreach (var genericArgument in metaType.GetAllGenericArguments()) + { + TryGetCoreSerializer(list, genericArgument); + } + if (metaType.HasSubtypes) + { + foreach (SubType subType in metaType.GetSubtypes()) + { + tmp = subType.DerivedType.GetSurrogateOrSelf(); // note: exclude base-types! + if (!list.Contains(tmp)) + { + list.Add(tmp); + CascadeDependents(list, tmp); + } + } + } + tmp = metaType.BaseType; + if (tmp != null) tmp = tmp.GetSurrogateOrSelf(); // note: already walking base-types; exclude base + if (tmp != null && !list.Contains(tmp)) + { + list.Add(tmp); + CascadeDependents(list, tmp); + } + } + } + + private void TryGetCoreSerializer(BasicList list, Type itemType) + { + var coreSerializer = ValueMember.TryGetCoreSerializer(this, DataFormat.Default, itemType, out _, false, false, false, false); + if (coreSerializer != null) + { + return; + } + int index = FindOrAddAuto(itemType, false, false, false); + if (index < 0) + { + return; + } + var temp = ((MetaType)types[index]).GetSurrogateOrBaseOrSelf(false); + if (list.Contains(temp)) + { + return; + } + // could perhaps also implement as a queue, but this should work OK for sane models + list.Add(temp); + CascadeDependents(list, temp); + } + +#if !NO_RUNTIME + /// + /// Creates a new runtime model, to which the caller + /// can add support for a range of types. A model + /// can be used "as is", or can be compiled for + /// optimal performance. + /// + /// not used currently; this is for compatibility with v3 +#pragma warning disable IDE0060 // Remove unused parameter + public static RuntimeTypeModel Create(string name = null) +#pragma warning restore IDE0060 // Remove unused parameter + { + return new RuntimeTypeModel(false); + } +#endif + + private RuntimeTypeModel(bool isDefault) + { + AutoAddMissingTypes = true; + UseImplicitZeroDefaults = true; + SetOption(OPTIONS_IsDefaultModel, isDefault); +#if FEAT_COMPILER && !DEBUG + try + { + AutoCompile = EnableAutoCompile(); + } + catch { } // this is all kinds of brittle on things like UWP +#endif + } + +#if FEAT_COMPILER + [MethodImpl(MethodImplOptions.NoInlining)] + internal static bool EnableAutoCompile() + { + try + { + var dm = new DynamicMethod("CheckCompilerAvailable", typeof(bool), new Type[] { typeof(int) }); + var il = dm.GetILGenerator(); + il.Emit(OpCodes.Ldarg_0); + il.Emit(OpCodes.Ldc_I4, 42); + il.Emit(OpCodes.Ceq); + il.Emit(OpCodes.Ret); + var func = (Predicate)dm.CreateDelegate(typeof(Predicate)); + return func(42); + } + catch (Exception ex) + { + Debug.WriteLine(ex); + return false; + } + } +#endif + + /// + /// Obtains the MetaType associated with a given Type for the current model, + /// allowing additional configuration. + /// + public MetaType this[Type type] { get { return (MetaType)types[FindOrAddAuto(type, true, false, false)]; } } + + internal MetaType FindWithoutAdd(Type type) + { + // this list is thread-safe for reading + foreach (MetaType metaType in types) + { + if (metaType.Type == type) + { + if (metaType.Pending) WaitOnLock(metaType); + return metaType; + } + } + // if that failed, check for a proxy + Type underlyingType = ResolveProxies(type); + return underlyingType == null ? null : FindWithoutAdd(underlyingType); + } + + static readonly BasicList.MatchPredicate + MetaTypeFinder = new BasicList.MatchPredicate(MetaTypeFinderImpl), + BasicTypeFinder = new BasicList.MatchPredicate(BasicTypeFinderImpl); + + static bool MetaTypeFinderImpl(object value, object ctx) + { + return ((MetaType)value).Type == (Type)ctx; + } + + static bool BasicTypeFinderImpl(object value, object ctx) + { + return ((BasicType)value).Type == (Type)ctx; + } + + private void WaitOnLock(MetaType type) + { + int opaqueToken = 0; + try + { + TakeLock(ref opaqueToken); + } + finally + { + ReleaseLock(opaqueToken); + } + } + + BasicList basicTypes = new BasicList(); + + sealed class BasicType + { + private readonly Type type; + public Type Type => type; + private readonly IProtoSerializer serializer; + public IProtoSerializer Serializer => serializer; + + public BasicType(Type type, IProtoSerializer serializer) + { + this.type = type; + this.serializer = serializer; + } + } + internal IProtoSerializer TryGetBasicTypeSerializer(Type type) + { + int idx = basicTypes.IndexOf(BasicTypeFinder, type); + + if (idx >= 0) return ((BasicType)basicTypes[idx]).Serializer; + + lock (basicTypes) + { // don't need a full model lock for this + + // double-checked + idx = basicTypes.IndexOf(BasicTypeFinder, type); + if (idx >= 0) return ((BasicType)basicTypes[idx]).Serializer; + + MetaType.AttributeFamily family = MetaType.GetContractFamily(this, type, null); + IProtoSerializer ser = family == MetaType.AttributeFamily.None + ? ValueMember.TryGetCoreSerializer(this, DataFormat.Default, type, out WireType defaultWireType, false, false, false, false) + : null; + + if (ser != null) basicTypes.Add(new BasicType(type, ser)); + return ser; + } + } + + internal int FindOrAddAuto(Type type, bool demand, bool addWithContractOnly, bool addEvenIfAutoDisabled) + { + int key = types.IndexOf(MetaTypeFinder, type); + MetaType metaType; + + // the fast happy path: meta-types we've already seen + if (key >= 0) + { + metaType = (MetaType)types[key]; + if (metaType.Pending) + { + WaitOnLock(metaType); + } + return key; + } + + // the fast fail path: types that will never have a meta-type + bool shouldAdd = AutoAddMissingTypes || addEvenIfAutoDisabled; + + if (!Helpers.IsEnum(type) && TryGetBasicTypeSerializer(type) != null) + { + if (shouldAdd && !addWithContractOnly) throw MetaType.InbuiltType(type); + return -1; // this will never be a meta-type + } + + // otherwise: we don't yet know + + // check for proxy types + Type underlyingType = ResolveProxies(type); + if (underlyingType != null && underlyingType != type) + { + key = types.IndexOf(MetaTypeFinder, underlyingType); + type = underlyingType; // if new added, make it reflect the underlying type + } + + if (key < 0) + { + int opaqueToken = 0; + Type origType = type; + bool weAdded = false; + try + { + TakeLock(ref opaqueToken); + // try to recognise a few familiar patterns... + if ((metaType = RecogniseCommonTypes(type)) == null) + { // otherwise, check if it is a contract + MetaType.AttributeFamily family = MetaType.GetContractFamily(this, type, null); + if (family == MetaType.AttributeFamily.AutoTuple) + { + shouldAdd = addEvenIfAutoDisabled = true; // always add basic tuples, such as KeyValuePair + } + + if (!shouldAdd || ( + !Helpers.IsEnum(type) && addWithContractOnly && family == MetaType.AttributeFamily.None) + ) + { + if (demand) ThrowUnexpectedType(type); + return key; + } + metaType = Create(type); + } + + metaType.Pending = true; + + // double-checked + int winner = types.IndexOf(MetaTypeFinder, type); + if (winner < 0) + { + ThrowIfFrozen(); + key = types.Add(metaType); + weAdded = true; + } + else + { + key = winner; + } + if (weAdded) + { + metaType.ApplyDefaultBehaviour(); + metaType.Pending = false; + } + } + finally + { + ReleaseLock(opaqueToken); + if (weAdded) + { + ResetKeyCache(); + } + } + } + return key; + } + + private MetaType RecogniseCommonTypes(Type type) + { + // if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(System.Collections.Generic.KeyValuePair<,>)) + // { + // MetaType mt = new MetaType(this, type); + + // Type surrogate = typeof (KeyValuePairSurrogate<,>).MakeGenericType(type.GetGenericArguments()); + + // mt.SetSurrogate(surrogate); + // mt.IncludeSerializerMethod = false; + // mt.Freeze(); + + // MetaType surrogateMeta = (MetaType)types[FindOrAddAuto(surrogate, true, true, true)]; // this forcibly adds it if needed + // if(surrogateMeta.IncludeSerializerMethod) + // { // don't blindly set - it might be frozen + // surrogateMeta.IncludeSerializerMethod = false; + // } + // surrogateMeta.Freeze(); + // return mt; + // } + return null; + } + private MetaType Create(Type type) + { + ThrowIfFrozen(); + return new MetaType(this, type, defaultFactory); + } + + /// + /// Adds support for an additional type in this model, optionally + /// applying inbuilt patterns. If the type is already known to the + /// model, the existing type is returned **without** applying + /// any additional behaviour. + /// + /// Inbuilt patterns include: + /// [ProtoContract]/[ProtoMember(n)] + /// [DataContract]/[DataMember(Order=n)] + /// [XmlType]/[XmlElement(Order=n)] + /// [On{Des|S}erializ{ing|ed}] + /// ShouldSerialize*/*Specified + /// + /// The type to be supported + /// Whether to apply the inbuilt configuration patterns (via attributes etc), or + /// just add the type with no additional configuration (the type must then be manually configured). + /// The MetaType representing this type, allowing + /// further configuration. + public MetaType Add(Type type, bool applyDefaultBehaviour) + { + if (type == null) throw new ArgumentNullException("type"); + MetaType newType = FindWithoutAdd(type); + if (newType != null) return newType; // return existing + int opaqueToken = 0; + +#if COREFX || PROFILE259 + TypeInfo typeInfo = IntrospectionExtensions.GetTypeInfo(type); + if (typeInfo.IsInterface && MetaType.ienumerable.IsAssignableFrom(typeInfo) +#else + if (type.IsInterface && MapType(MetaType.ienumerable).IsAssignableFrom(type) +#endif + && GetListItemType(this, type) == null) + { + throw new ArgumentException("IEnumerable[] data cannot be used as a meta-type unless an Add method can be resolved"); + } + try + { + newType = RecogniseCommonTypes(type); + if (newType != null) + { + if (!applyDefaultBehaviour) + { + throw new ArgumentException( + "Default behaviour must be observed for certain types with special handling; " + type.FullName, + "applyDefaultBehaviour"); + } + // we should assume that type is fully configured, though; no need to re-run: + applyDefaultBehaviour = false; + } + if (newType == null) newType = Create(type); + newType.Pending = true; + TakeLock(ref opaqueToken); + // double checked + if (FindWithoutAdd(type) != null) throw new ArgumentException("Duplicate type", "type"); + ThrowIfFrozen(); + types.Add(newType); + if (applyDefaultBehaviour) { newType.ApplyDefaultBehaviour(); } + newType.Pending = false; + } + finally + { + ReleaseLock(opaqueToken); + ResetKeyCache(); + } + + return newType; + } + +#if FEAT_COMPILER + /// + /// Should serializers be compiled on demand? It may be useful + /// to disable this for debugging purposes. + /// + public bool AutoCompile + { + get { return GetOption(OPTIONS_AutoCompile); } + set { SetOption(OPTIONS_AutoCompile, value); } + } +#endif + /// + /// Should support for unexpected types be added automatically? + /// If false, an exception is thrown when unexpected types + /// are encountered. + /// + public bool AutoAddMissingTypes + { + get { return GetOption(OPTIONS_AutoAddMissingTypes); } + set + { + if (!value && GetOption(OPTIONS_IsDefaultModel)) + { + throw new InvalidOperationException("The default model must allow missing types"); + } + ThrowIfFrozen(); + SetOption(OPTIONS_AutoAddMissingTypes, value); + } + } + /// + /// Verifies that the model is still open to changes; if not, an exception is thrown + /// + private void ThrowIfFrozen() + { + if (GetOption(OPTIONS_Frozen)) throw new InvalidOperationException("The model cannot be changed once frozen"); + } + + /// + /// Prevents further changes to this model + /// + public void Freeze() + { + if (GetOption(OPTIONS_IsDefaultModel)) throw new InvalidOperationException("The default model cannot be frozen"); + SetOption(OPTIONS_Frozen, true); + } + + private readonly BasicList types = new BasicList(); + + /// + /// Provides the key that represents a given type in the current model. + /// + protected override int GetKeyImpl(Type type) + { + return GetKey(type, false, true); + } + + internal int GetKey(Type type, bool demand, bool getBaseKey) + { + Helpers.DebugAssert(type != null); + try + { + int typeIndex = FindOrAddAuto(type, demand, true, false); + if (typeIndex >= 0) + { + MetaType mt = (MetaType)types[typeIndex]; + if (getBaseKey) + { + mt = MetaType.GetRootType(mt); + typeIndex = FindOrAddAuto(mt.Type, true, true, false); + } + } + return typeIndex; + } + catch (NotSupportedException) + { + throw; // re-surface "as-is" + } + catch (Exception ex) + { + if (ex.Message.IndexOf(type.FullName) >= 0) throw; // already enough info + throw new ProtoException(ex.Message + " (" + type.FullName + ")", ex); + } + } + + /// + /// Writes a protocol-buffer representation of the given instance to the supplied stream. + /// + /// Represents the type (including inheritance) to consider. + /// The existing instance to be serialized (cannot be null). + /// The destination stream to write to. + protected internal override void Serialize(int key, object value, ProtoWriter dest) + { + //Helpers.DebugWriteLine("Serialize", value); + ((MetaType)types[key]).Serializer.Write(value, dest); + } + + /// + /// Applies a protocol-buffer stream to an existing instance (which may be null). + /// + /// Represents the type (including inheritance) to consider. + /// The existing instance to be modified (can be null). + /// The binary stream to apply to the instance (cannot be null). + /// The updated instance; this may be different to the instance argument if + /// either the original instance was null, or the stream defines a known sub-type of the + /// original instance. + protected internal override object Deserialize(int key, object value, ProtoReader source) + { + //Helpers.DebugWriteLine("Deserialize", value); + IProtoSerializer ser = ((MetaType)types[key]).Serializer; + if (value == null && Helpers.IsValueType(ser.ExpectedType)) + { + if (ser.RequiresOldValue) value = Activator.CreateInstance(ser.ExpectedType); + return ser.Read(value, source); + } + else + { + return ser.Read(value, source); + } + } + +#if FEAT_COMPILER + // this is used by some unit-tests; do not remove + internal Compiler.ProtoSerializer GetSerializer(IProtoSerializer serializer, bool compiled) + { + if (serializer == null) throw new ArgumentNullException("serializer"); +#if FEAT_COMPILER + if (compiled) return Compiler.CompilerContext.BuildSerializer(serializer, this); +#endif + return new Compiler.ProtoSerializer(serializer.Write); + } + + /// + /// Compiles the serializers individually; this is *not* a full + /// standalone compile, but can significantly boost performance + /// while allowing additional types to be added. + /// + /// An in-place compile can access non-public types / members + public void CompileInPlace() + { + foreach (MetaType type in types) + { + type.CompileInPlace(); + } + } + +#endif + //internal override IProtoSerializer GetTypeSerializer(Type type) + //{ // this list is thread-safe for reading + // .Serializer; + //} + //internal override IProtoSerializer GetTypeSerializer(int key) + //{ // this list is thread-safe for reading + // MetaType type = (MetaType)types.TryGet(key); + // if (type != null) return type.Serializer; + // throw new KeyNotFoundException(); + + //} + +#if FEAT_COMPILER + private void BuildAllSerializers() + { + // note that types.Count may increase during this operation, as some serializers + // bring other types into play + for (int i = 0; i < types.Count; i++) + { + // the primary purpose of this is to force the creation of the Serializer + MetaType mt = (MetaType)types[i]; + if (mt.Serializer == null) + throw new InvalidOperationException("No serializer available for " + mt.Type.Name); + } + } + + internal sealed class SerializerPair : IComparable + { + int IComparable.CompareTo(object obj) + { + if (obj == null) throw new ArgumentException("obj"); + SerializerPair other = (SerializerPair)obj; + + // we want to bunch all the items with the same base-type together, but we need the items with a + // different base **first**. + if (this.BaseKey == this.MetaKey) + { + if (other.BaseKey == other.MetaKey) + { // neither is a subclass + return this.MetaKey.CompareTo(other.MetaKey); + } + else + { // "other" (only) is involved in inheritance; "other" should be first + return 1; + } + } + else + { + if (other.BaseKey == other.MetaKey) + { // "this" (only) is involved in inheritance; "this" should be first + return -1; + } + else + { // both are involved in inheritance + int result = this.BaseKey.CompareTo(other.BaseKey); + if (result == 0) result = this.MetaKey.CompareTo(other.MetaKey); + return result; + } + } + } + public readonly int MetaKey, BaseKey; + public readonly MetaType Type; + public readonly MethodBuilder Serialize, Deserialize; + public readonly ILGenerator SerializeBody, DeserializeBody; + public SerializerPair(int metaKey, int baseKey, MetaType type, MethodBuilder serialize, MethodBuilder deserialize, + ILGenerator serializeBody, ILGenerator deserializeBody) + { + this.MetaKey = metaKey; + this.BaseKey = baseKey; + this.Serialize = serialize; + this.Deserialize = deserialize; + this.SerializeBody = serializeBody; + this.DeserializeBody = deserializeBody; + this.Type = type; + } + } + + /// + /// Fully compiles the current model into a static-compiled model instance + /// + /// A full compilation is restricted to accessing public types / members + /// An instance of the newly created compiled type-model + public TypeModel Compile() + { + CompilerOptions options = new CompilerOptions(); + return Compile(options); + } + + static ILGenerator Override(TypeBuilder type, string name) + { + MethodInfo baseMethod = type.BaseType.GetMethod(name, BindingFlags.NonPublic | BindingFlags.Instance); + + ParameterInfo[] parameters = baseMethod.GetParameters(); + Type[] paramTypes = new Type[parameters.Length]; + for (int i = 0; i < paramTypes.Length; i++) + { + paramTypes[i] = parameters[i].ParameterType; + } + MethodBuilder newMethod = type.DefineMethod(baseMethod.Name, + (baseMethod.Attributes & ~MethodAttributes.Abstract) | MethodAttributes.Final, baseMethod.CallingConvention, baseMethod.ReturnType, paramTypes); + ILGenerator il = newMethod.GetILGenerator(); + type.DefineMethodOverride(newMethod, baseMethod); + return il; + } + + /// + /// Represents configuration options for compiling a model to + /// a standalone assembly. + /// + public sealed class CompilerOptions + { + /// + /// Import framework options from an existing type + /// + public void SetFrameworkOptions(MetaType from) + { + if (from == null) throw new ArgumentNullException("from"); + AttributeMap[] attribs = AttributeMap.Create(from.Model, Helpers.GetAssembly(from.Type)); + foreach (AttributeMap attrib in attribs) + { + if (attrib.AttributeType.FullName == "System.Runtime.Versioning.TargetFrameworkAttribute") + { + object tmp; + if (attrib.TryGet("FrameworkName", out tmp)) TargetFrameworkName = (string)tmp; + if (attrib.TryGet("FrameworkDisplayName", out tmp)) TargetFrameworkDisplayName = (string)tmp; + break; + } + } + } + + private string targetFrameworkName, targetFrameworkDisplayName, typeName, outputPath, imageRuntimeVersion; + private int metaDataVersion; + /// + /// The TargetFrameworkAttribute FrameworkName value to burn into the generated assembly + /// + public string TargetFrameworkName { get { return targetFrameworkName; } set { targetFrameworkName = value; } } + + /// + /// The TargetFrameworkAttribute FrameworkDisplayName value to burn into the generated assembly + /// + public string TargetFrameworkDisplayName { get { return targetFrameworkDisplayName; } set { targetFrameworkDisplayName = value; } } + /// + /// The name of the TypeModel class to create + /// + public string TypeName { get { return typeName; } set { typeName = value; } } + +#if COREFX + internal const string NoPersistence = "Assembly persistence not supported on this runtime"; +#endif + /// + /// The path for the new dll + /// +#if COREFX + [Obsolete(NoPersistence)] +#endif + public string OutputPath { get { return outputPath; } set { outputPath = value; } } + /// + /// The runtime version for the generated assembly + /// + public string ImageRuntimeVersion { get { return imageRuntimeVersion; } set { imageRuntimeVersion = value; } } + /// + /// The runtime version for the generated assembly + /// + public int MetaDataVersion { get { return metaDataVersion; } set { metaDataVersion = value; } } + + + private Accessibility accessibility = Accessibility.Public; + /// + /// The acecssibility of the generated serializer + /// + public Accessibility Accessibility { get { return accessibility; } set { accessibility = value; } } + } + + /// + /// Type accessibility + /// + public enum Accessibility + { + /// + /// Available to all callers + /// + Public, + /// + /// Available to all callers in the same assembly, or assemblies specified via [InternalsVisibleTo(...)] + /// + Internal + } + +#if !COREFX + /// + /// Fully compiles the current model into a static-compiled serialization dll + /// (the serialization dll still requires protobuf-net for support services). + /// + /// A full compilation is restricted to accessing public types / members + /// The name of the TypeModel class to create + /// The path for the new dll + /// An instance of the newly created compiled type-model + public TypeModel Compile(string name, string path) + { + CompilerOptions options = new CompilerOptions(); + options.TypeName = name; + options.OutputPath = path; + return Compile(options); + } +#endif + /// + /// Fully compiles the current model into a static-compiled serialization dll + /// (the serialization dll still requires protobuf-net for support services). + /// + /// A full compilation is restricted to accessing public types / members + /// An instance of the newly created compiled type-model + public TypeModel Compile(CompilerOptions options) + { + if (options == null) throw new ArgumentNullException("options"); + string typeName = options.TypeName; +#pragma warning disable 0618 + string path = options.OutputPath; +#pragma warning restore 0618 + BuildAllSerializers(); + Freeze(); + bool save = !string.IsNullOrEmpty(path); + if (string.IsNullOrEmpty(typeName)) + { + if (save) throw new ArgumentNullException("typeName"); + typeName = Guid.NewGuid().ToString(); + } + + + string assemblyName, moduleName; + if (path == null) + { + assemblyName = typeName; + moduleName = assemblyName + ".dll"; + } + else + { + assemblyName = new System.IO.FileInfo(System.IO.Path.GetFileNameWithoutExtension(path)).Name; + moduleName = assemblyName + System.IO.Path.GetExtension(path); + } + +#if COREFX + AssemblyName an = new AssemblyName(); + an.Name = assemblyName; + AssemblyBuilder asm = AssemblyBuilder.DefineDynamicAssembly(an, + AssemblyBuilderAccess.Run); + ModuleBuilder module = asm.DefineDynamicModule(moduleName); +#else + AssemblyName an = new AssemblyName(); + an.Name = assemblyName; + AssemblyBuilder asm = AppDomain.CurrentDomain.DefineDynamicAssembly(an, + (save ? AssemblyBuilderAccess.RunAndSave : AssemblyBuilderAccess.Run) + ); + ModuleBuilder module = save ? asm.DefineDynamicModule(moduleName, path) + : asm.DefineDynamicModule(moduleName); +#endif + + WriteAssemblyAttributes(options, assemblyName, asm); + + TypeBuilder type = WriteBasicTypeModel(options, typeName, module); + + int index; + bool hasInheritance; + SerializerPair[] methodPairs; + Compiler.CompilerContext.ILVersion ilVersion; + WriteSerializers(options, assemblyName, type, out index, out hasInheritance, out methodPairs, out ilVersion); + + ILGenerator il; + int knownTypesCategory; + FieldBuilder knownTypes; + Type knownTypesLookupType; + WriteGetKeyImpl(type, hasInheritance, methodPairs, ilVersion, assemblyName, out il, out knownTypesCategory, out knownTypes, out knownTypesLookupType); + + // trivial flags + il = Override(type, "SerializeDateTimeKind"); + il.Emit(IncludeDateTimeKind ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0); + il.Emit(OpCodes.Ret); + // end: trivial flags + + Compiler.CompilerContext ctx = WriteSerializeDeserialize(assemblyName, type, methodPairs, ilVersion, ref il); + + WriteConstructors(type, ref index, methodPairs, ref il, knownTypesCategory, knownTypes, knownTypesLookupType, ctx); + + +#if COREFX + Type finalType = type.CreateTypeInfo().AsType(); +#else + Type finalType = type.CreateType(); +#endif + if (!string.IsNullOrEmpty(path)) + { +#if COREFX + throw new NotSupportedException(CompilerOptions.NoPersistence); +#else + try + { + asm.Save(path); + } + catch (IOException ex) + { + // advertise the file info + throw new IOException(path + ", " + ex.Message, ex); + } + Helpers.DebugWriteLine("Wrote dll:" + path); +#endif + } + return (TypeModel)Activator.CreateInstance(finalType); + } + + private void WriteConstructors(TypeBuilder type, ref int index, SerializerPair[] methodPairs, ref ILGenerator il, int knownTypesCategory, FieldBuilder knownTypes, Type knownTypesLookupType, Compiler.CompilerContext ctx) + { + type.DefineDefaultConstructor(MethodAttributes.Public); + il = type.DefineTypeInitializer().GetILGenerator(); + switch (knownTypesCategory) + { + case KnownTypes_Array: + { + Compiler.CompilerContext.LoadValue(il, types.Count); + il.Emit(OpCodes.Newarr, ctx.MapType(typeof(System.Type))); + index = 0; + foreach (SerializerPair pair in methodPairs) + { + il.Emit(OpCodes.Dup); + Compiler.CompilerContext.LoadValue(il, index); + il.Emit(OpCodes.Ldtoken, pair.Type.Type); + il.EmitCall(OpCodes.Call, ctx.MapType(typeof(System.Type)).GetMethod("GetTypeFromHandle"), null); + il.Emit(OpCodes.Stelem_Ref); + index++; + } + il.Emit(OpCodes.Stsfld, knownTypes); + il.Emit(OpCodes.Ret); + } + break; + case KnownTypes_Dictionary: + { + Compiler.CompilerContext.LoadValue(il, types.Count); + //LocalBuilder loc = il.DeclareLocal(knownTypesLookupType); + il.Emit(OpCodes.Newobj, knownTypesLookupType.GetConstructor(new Type[] { MapType(typeof(int)) })); + il.Emit(OpCodes.Stsfld, knownTypes); + int typeIndex = 0; + foreach (SerializerPair pair in methodPairs) + { + il.Emit(OpCodes.Ldsfld, knownTypes); + il.Emit(OpCodes.Ldtoken, pair.Type.Type); + il.EmitCall(OpCodes.Call, ctx.MapType(typeof(System.Type)).GetMethod("GetTypeFromHandle"), null); + int keyIndex = typeIndex++, lastKey = pair.BaseKey; + if (lastKey != pair.MetaKey) // not a base-type; need to give the index of the base-type + { + keyIndex = -1; // assume epic fail + for (int j = 0; j < methodPairs.Length; j++) + { + if (methodPairs[j].BaseKey == lastKey && methodPairs[j].MetaKey == lastKey) + { + keyIndex = j; + break; + } + } + } + Compiler.CompilerContext.LoadValue(il, keyIndex); + il.EmitCall(OpCodes.Callvirt, knownTypesLookupType.GetMethod("Add", new Type[] { MapType(typeof(System.Type)), MapType(typeof(int)) }), null); + } + il.Emit(OpCodes.Ret); + } + break; + case KnownTypes_Hashtable: + { + Compiler.CompilerContext.LoadValue(il, types.Count); + il.Emit(OpCodes.Newobj, knownTypesLookupType.GetConstructor(new Type[] { MapType(typeof(int)) })); + il.Emit(OpCodes.Stsfld, knownTypes); + int typeIndex = 0; + foreach (SerializerPair pair in methodPairs) + { + il.Emit(OpCodes.Ldsfld, knownTypes); + il.Emit(OpCodes.Ldtoken, pair.Type.Type); + il.EmitCall(OpCodes.Call, ctx.MapType(typeof(System.Type)).GetMethod("GetTypeFromHandle"), null); + int keyIndex = typeIndex++, lastKey = pair.BaseKey; + if (lastKey != pair.MetaKey) // not a base-type; need to give the index of the base-type + { + keyIndex = -1; // assume epic fail + for (int j = 0; j < methodPairs.Length; j++) + { + if (methodPairs[j].BaseKey == lastKey && methodPairs[j].MetaKey == lastKey) + { + keyIndex = j; + break; + } + } + } + Compiler.CompilerContext.LoadValue(il, keyIndex); + il.Emit(OpCodes.Box, MapType(typeof(int))); + il.EmitCall(OpCodes.Callvirt, knownTypesLookupType.GetMethod("Add", new Type[] { MapType(typeof(object)), MapType(typeof(object)) }), null); + } + il.Emit(OpCodes.Ret); + } + break; + default: + throw new InvalidOperationException(); + } + } + + private Compiler.CompilerContext WriteSerializeDeserialize(string assemblyName, TypeBuilder type, SerializerPair[] methodPairs, Compiler.CompilerContext.ILVersion ilVersion, ref ILGenerator il) + { + il = Override(type, "Serialize"); + Compiler.CompilerContext ctx = new Compiler.CompilerContext(il, false, true, methodPairs, this, ilVersion, assemblyName, MapType(typeof(object)), "Serialize " + type.Name); + // arg0 = this, arg1 = key, arg2=obj, arg3=dest + Compiler.CodeLabel[] jumpTable = new Compiler.CodeLabel[types.Count]; + for (int i = 0; i < jumpTable.Length; i++) + { + jumpTable[i] = ctx.DefineLabel(); + } + il.Emit(OpCodes.Ldarg_1); + ctx.Switch(jumpTable); + ctx.Return(); + for (int i = 0; i < jumpTable.Length; i++) + { + SerializerPair pair = methodPairs[i]; + ctx.MarkLabel(jumpTable[i]); + il.Emit(OpCodes.Ldarg_2); + ctx.CastFromObject(pair.Type.Type); + il.Emit(OpCodes.Ldarg_3); + il.EmitCall(OpCodes.Call, pair.Serialize, null); + ctx.Return(); + } + + il = Override(type, "Deserialize"); + ctx = new Compiler.CompilerContext(il, false, false, methodPairs, this, ilVersion, assemblyName, MapType(typeof(object)), "Deserialize " + type.Name); + // arg0 = this, arg1 = key, arg2=obj, arg3=source + for (int i = 0; i < jumpTable.Length; i++) + { + jumpTable[i] = ctx.DefineLabel(); + } + il.Emit(OpCodes.Ldarg_1); + ctx.Switch(jumpTable); + ctx.LoadNullRef(); + ctx.Return(); + for (int i = 0; i < jumpTable.Length; i++) + { + SerializerPair pair = methodPairs[i]; + ctx.MarkLabel(jumpTable[i]); + Type keyType = pair.Type.Type; + if (Helpers.IsValueType(keyType)) + { + il.Emit(OpCodes.Ldarg_2); + il.Emit(OpCodes.Ldarg_3); + il.EmitCall(OpCodes.Call, EmitBoxedSerializer(type, i, keyType, methodPairs, this, ilVersion, assemblyName), null); + ctx.Return(); + } + else + { + il.Emit(OpCodes.Ldarg_2); + ctx.CastFromObject(keyType); + il.Emit(OpCodes.Ldarg_3); + il.EmitCall(OpCodes.Call, pair.Deserialize, null); + ctx.Return(); + } + } + return ctx; + } + + private const int KnownTypes_Array = 1, KnownTypes_Dictionary = 2, KnownTypes_Hashtable = 3, KnownTypes_ArrayCutoff = 20; + private void WriteGetKeyImpl(TypeBuilder type, bool hasInheritance, SerializerPair[] methodPairs, Compiler.CompilerContext.ILVersion ilVersion, string assemblyName, out ILGenerator il, out int knownTypesCategory, out FieldBuilder knownTypes, out Type knownTypesLookupType) + { + + il = Override(type, "GetKeyImpl"); + Compiler.CompilerContext ctx = new Compiler.CompilerContext(il, false, false, methodPairs, this, ilVersion, assemblyName, MapType(typeof(System.Type), true), "GetKeyImpl"); + + + if (types.Count <= KnownTypes_ArrayCutoff) + { + knownTypesCategory = KnownTypes_Array; + knownTypesLookupType = MapType(typeof(System.Type[]), true); + } + else + { + knownTypesLookupType = MapType(typeof(System.Collections.Generic.Dictionary), false); + +#if !COREFX + if (knownTypesLookupType == null) + { + knownTypesLookupType = MapType(typeof(Hashtable), true); + knownTypesCategory = KnownTypes_Hashtable; + } + else +#endif + { + knownTypesCategory = KnownTypes_Dictionary; + } + } + knownTypes = type.DefineField("knownTypes", knownTypesLookupType, FieldAttributes.Private | FieldAttributes.InitOnly | FieldAttributes.Static); + + switch (knownTypesCategory) + { + case KnownTypes_Array: + { + il.Emit(OpCodes.Ldsfld, knownTypes); + il.Emit(OpCodes.Ldarg_1); + // note that Array.IndexOf is not supported under CF + il.EmitCall(OpCodes.Callvirt, MapType(typeof(IList)).GetMethod( + "IndexOf", new Type[] { MapType(typeof(object)) }), null); + if (hasInheritance) + { + il.DeclareLocal(MapType(typeof(int))); // loc-0 + il.Emit(OpCodes.Dup); + il.Emit(OpCodes.Stloc_0); + + BasicList getKeyLabels = new BasicList(); + int lastKey = -1; + for (int i = 0; i < methodPairs.Length; i++) + { + if (methodPairs[i].MetaKey == methodPairs[i].BaseKey) break; + if (lastKey == methodPairs[i].BaseKey) + { // add the last label again + getKeyLabels.Add(getKeyLabels[getKeyLabels.Count - 1]); + } + else + { // add a new unique label + getKeyLabels.Add(ctx.DefineLabel()); + lastKey = methodPairs[i].BaseKey; + } + } + Compiler.CodeLabel[] subtypeLabels = new Compiler.CodeLabel[getKeyLabels.Count]; + getKeyLabels.CopyTo(subtypeLabels, 0); + + ctx.Switch(subtypeLabels); + il.Emit(OpCodes.Ldloc_0); // not a sub-type; use the original value + il.Emit(OpCodes.Ret); + + lastKey = -1; + // now output the different branches per sub-type (not derived type) + for (int i = subtypeLabels.Length - 1; i >= 0; i--) + { + if (lastKey != methodPairs[i].BaseKey) + { + lastKey = methodPairs[i].BaseKey; + // find the actual base-index for this base-key (i.e. the index of + // the base-type) + int keyIndex = -1; + for (int j = subtypeLabels.Length; j < methodPairs.Length; j++) + { + if (methodPairs[j].BaseKey == lastKey && methodPairs[j].MetaKey == lastKey) + { + keyIndex = j; + break; + } + } + ctx.MarkLabel(subtypeLabels[i]); + Compiler.CompilerContext.LoadValue(il, keyIndex); + il.Emit(OpCodes.Ret); + } + } + } + else + { + il.Emit(OpCodes.Ret); + } + } + break; + case KnownTypes_Dictionary: + { + LocalBuilder result = il.DeclareLocal(MapType(typeof(int))); + Label otherwise = il.DefineLabel(); + il.Emit(OpCodes.Ldsfld, knownTypes); + il.Emit(OpCodes.Ldarg_1); + il.Emit(OpCodes.Ldloca_S, result); + il.EmitCall(OpCodes.Callvirt, knownTypesLookupType.GetMethod("TryGetValue", BindingFlags.Instance | BindingFlags.Public), null); + il.Emit(OpCodes.Brfalse_S, otherwise); + il.Emit(OpCodes.Ldloc_S, result); + il.Emit(OpCodes.Ret); + il.MarkLabel(otherwise); + il.Emit(OpCodes.Ldc_I4_M1); + il.Emit(OpCodes.Ret); + } + break; + case KnownTypes_Hashtable: + { + Label otherwise = il.DefineLabel(); + il.Emit(OpCodes.Ldsfld, knownTypes); + il.Emit(OpCodes.Ldarg_1); + il.EmitCall(OpCodes.Callvirt, knownTypesLookupType.GetProperty("Item").GetGetMethod(), null); + il.Emit(OpCodes.Dup); + il.Emit(OpCodes.Brfalse_S, otherwise); + if (ilVersion == Compiler.CompilerContext.ILVersion.Net1) + { + il.Emit(OpCodes.Unbox, MapType(typeof(int))); + il.Emit(OpCodes.Ldobj, MapType(typeof(int))); + } + else + { + il.Emit(OpCodes.Unbox_Any, MapType(typeof(int))); + } + il.Emit(OpCodes.Ret); + il.MarkLabel(otherwise); + il.Emit(OpCodes.Pop); + il.Emit(OpCodes.Ldc_I4_M1); + il.Emit(OpCodes.Ret); + } + break; + default: + throw new InvalidOperationException(); + } + } + + private void WriteSerializers(CompilerOptions options, string assemblyName, TypeBuilder type, out int index, out bool hasInheritance, out SerializerPair[] methodPairs, out Compiler.CompilerContext.ILVersion ilVersion) + { + Compiler.CompilerContext ctx; + + index = 0; + hasInheritance = false; + methodPairs = new SerializerPair[types.Count]; + foreach (MetaType metaType in types) + { + MethodBuilder writeMethod = type.DefineMethod("Write" +#if DEBUG + + metaType.Type.Name +#endif +, + MethodAttributes.Private | MethodAttributes.Static, CallingConventions.Standard, + MapType(typeof(void)), new Type[] { metaType.Type, MapType(typeof(ProtoWriter)) }); + + MethodBuilder readMethod = type.DefineMethod("Read" +#if DEBUG + + metaType.Type.Name +#endif +, + MethodAttributes.Private | MethodAttributes.Static, CallingConventions.Standard, + metaType.Type, new Type[] { metaType.Type, MapType(typeof(ProtoReader)) }); + + SerializerPair pair = new SerializerPair( + GetKey(metaType.Type, true, false), GetKey(metaType.Type, true, true), metaType, + writeMethod, readMethod, writeMethod.GetILGenerator(), readMethod.GetILGenerator()); + methodPairs[index++] = pair; + if (pair.MetaKey != pair.BaseKey) hasInheritance = true; + } + + if (hasInheritance) + { + Array.Sort(methodPairs); + } + + ilVersion = Compiler.CompilerContext.ILVersion.Net2; + if (options.MetaDataVersion == 0x10000) + { + ilVersion = Compiler.CompilerContext.ILVersion.Net1; // old-school! + } + for (index = 0; index < methodPairs.Length; index++) + { + SerializerPair pair = methodPairs[index]; + ctx = new Compiler.CompilerContext(pair.SerializeBody, true, true, methodPairs, this, ilVersion, assemblyName, pair.Type.Type, "SerializeImpl " + pair.Type.Type.Name); + MemberInfo returnType = pair.Deserialize.ReturnType +#if COREFX + .GetTypeInfo() +#endif + ; + ctx.CheckAccessibility(ref returnType); + pair.Type.Serializer.EmitWrite(ctx, ctx.InputValue); + ctx.Return(); + + ctx = new Compiler.CompilerContext(pair.DeserializeBody, true, false, methodPairs, this, ilVersion, assemblyName, pair.Type.Type, "DeserializeImpl " + pair.Type.Type.Name); + pair.Type.Serializer.EmitRead(ctx, ctx.InputValue); + if (!pair.Type.Serializer.ReturnsValue) + { + ctx.LoadValue(ctx.InputValue); + } + ctx.Return(); + } + } + + private TypeBuilder WriteBasicTypeModel(CompilerOptions options, string typeName, ModuleBuilder module) + { + Type baseType = MapType(typeof(TypeModel)); +#if COREFX + TypeAttributes typeAttributes = (baseType.GetTypeInfo().Attributes & ~TypeAttributes.Abstract) | TypeAttributes.Sealed; +#else + TypeAttributes typeAttributes = (baseType.Attributes & ~TypeAttributes.Abstract) | TypeAttributes.Sealed; +#endif + if (options.Accessibility == Accessibility.Internal) + { + typeAttributes &= ~TypeAttributes.Public; + } + + TypeBuilder type = module.DefineType(typeName, typeAttributes, baseType); + return type; + } + + private void WriteAssemblyAttributes(CompilerOptions options, string assemblyName, AssemblyBuilder asm) + { + if (!string.IsNullOrEmpty(options.TargetFrameworkName)) + { + // get [TargetFramework] from mscorlib/equivalent and burn into the new assembly + Type versionAttribType = null; + try + { // this is best-endeavours only + versionAttribType = GetType("System.Runtime.Versioning.TargetFrameworkAttribute", Helpers.GetAssembly(MapType(typeof(string)))); + } + catch { /* don't stress */ } + if (versionAttribType != null) + { + PropertyInfo[] props; + object[] propValues; + if (string.IsNullOrEmpty(options.TargetFrameworkDisplayName)) + { + props = new PropertyInfo[0]; + propValues = new object[0]; + } + else + { + props = new PropertyInfo[1] { versionAttribType.GetProperty("FrameworkDisplayName") }; + propValues = new object[1] { options.TargetFrameworkDisplayName }; + } + CustomAttributeBuilder builder = new CustomAttributeBuilder( + versionAttribType.GetConstructor(new Type[] { MapType(typeof(string)) }), + new object[] { options.TargetFrameworkName }, + props, + propValues); + asm.SetCustomAttribute(builder); + } + } + + // copy assembly:InternalsVisibleTo + Type internalsVisibleToAttribType = null; + + try + { + internalsVisibleToAttribType = MapType(typeof(System.Runtime.CompilerServices.InternalsVisibleToAttribute)); + } + catch { /* best endeavors only */ } + + if (internalsVisibleToAttribType != null) + { + BasicList internalAssemblies = new BasicList(), consideredAssemblies = new BasicList(); + foreach (MetaType metaType in types) + { + Assembly assembly = Helpers.GetAssembly(metaType.Type); + if (consideredAssemblies.IndexOfReference(assembly) >= 0) continue; + consideredAssemblies.Add(assembly); + + AttributeMap[] assemblyAttribsMap = AttributeMap.Create(this, assembly); + for (int i = 0; i < assemblyAttribsMap.Length; i++) + { + + if (assemblyAttribsMap[i].AttributeType != internalsVisibleToAttribType) continue; + + object privelegedAssemblyObj; + assemblyAttribsMap[i].TryGet("AssemblyName", out privelegedAssemblyObj); + string privelegedAssemblyName = privelegedAssemblyObj as string; + if (privelegedAssemblyName == assemblyName || string.IsNullOrEmpty(privelegedAssemblyName)) continue; // ignore + + if (internalAssemblies.IndexOfString(privelegedAssemblyName) >= 0) continue; // seen it before + internalAssemblies.Add(privelegedAssemblyName); + + CustomAttributeBuilder builder = new CustomAttributeBuilder( + internalsVisibleToAttribType.GetConstructor(new Type[] { MapType(typeof(string)) }), + new object[] { privelegedAssemblyName }); + asm.SetCustomAttribute(builder); + } + } + } + } + + private static MethodBuilder EmitBoxedSerializer(TypeBuilder type, int i, Type valueType, SerializerPair[] methodPairs, TypeModel model, Compiler.CompilerContext.ILVersion ilVersion, string assemblyName) + { + MethodInfo dedicated = methodPairs[i].Deserialize; + MethodBuilder boxedSerializer = type.DefineMethod("_" + i.ToString(), MethodAttributes.Static, CallingConventions.Standard, + model.MapType(typeof(object)), new Type[] { model.MapType(typeof(object)), model.MapType(typeof(ProtoReader)) }); + Compiler.CompilerContext ctx = new Compiler.CompilerContext(boxedSerializer.GetILGenerator(), true, false, methodPairs, model, ilVersion, assemblyName, model.MapType(typeof(object)), "BoxedSerializer " + valueType.Name); + ctx.LoadValue(ctx.InputValue); + Compiler.CodeLabel @null = ctx.DefineLabel(); + ctx.BranchIfFalse(@null, true); + + Type mappedValueType = valueType; + ctx.LoadValue(ctx.InputValue); + ctx.CastFromObject(mappedValueType); + ctx.LoadReaderWriter(); + ctx.EmitCall(dedicated); + ctx.CastToObject(mappedValueType); + ctx.Return(); + + ctx.MarkLabel(@null); + using (Compiler.Local typedVal = new Compiler.Local(ctx, mappedValueType)) + { + // create a new valueType + ctx.LoadAddress(typedVal, mappedValueType); + ctx.EmitCtor(mappedValueType); + ctx.LoadValue(typedVal); + ctx.LoadReaderWriter(); + ctx.EmitCall(dedicated); + ctx.CastToObject(mappedValueType); + ctx.Return(); + } + return boxedSerializer; + } + +#endif + //internal bool IsDefined(Type type, int fieldNumber) + //{ + // return FindWithoutAdd(type).IsDefined(fieldNumber); + //} + + // note that this is used by some of the unit tests + internal bool IsPrepared(Type type) + { + MetaType meta = FindWithoutAdd(type); + return meta != null && meta.IsPrepared(); + } + + internal EnumSerializer.EnumPair[] GetEnumMap(Type type) + { + int index = FindOrAddAuto(type, false, false, false); + return index < 0 ? null : ((MetaType)types[index]).GetEnumMap(); + } + + private int metadataTimeoutMilliseconds = 5000; + /// + /// The amount of time to wait if there are concurrent metadata access operations + /// + public int MetadataTimeoutMilliseconds + { + get { return metadataTimeoutMilliseconds; } + set + { + if (value <= 0) throw new ArgumentOutOfRangeException("MetadataTimeoutMilliseconds"); + metadataTimeoutMilliseconds = value; + } + } + +#if DEBUG + int lockCount; + /// + /// Gets how many times a model lock was taken + /// + public int LockCount { get { return lockCount; } } +#endif + internal void TakeLock(ref int opaqueToken) + { + const string message = "Timeout while inspecting metadata; this may indicate a deadlock. This can often be avoided by preparing necessary serializers during application initialization, rather than allowing multiple threads to perform the initial metadata inspection; please also see the LockContended event"; + opaqueToken = 0; +#if PORTABLE + if(!Monitor.TryEnter(types, metadataTimeoutMilliseconds)) throw new TimeoutException(message); + opaqueToken = Interlocked.CompareExchange(ref contentionCounter, 0, 0); // just fetch current value (starts at 1) +#elif CF2 || CF35 + int remaining = metadataTimeoutMilliseconds; + bool lockTaken; + do { + lockTaken = Monitor.TryEnter(types); + if(!lockTaken) + { + if(remaining <= 0) throw new TimeoutException(message); + remaining -= 50; + Thread.Sleep(50); + } + } while(!lockTaken); + opaqueToken = Interlocked.CompareExchange(ref contentionCounter, 0, 0); // just fetch current value (starts at 1) +#else + if (Monitor.TryEnter(types, metadataTimeoutMilliseconds)) + { + opaqueToken = GetContention(); // just fetch current value (starts at 1) + } + else + { + AddContention(); + + throw new TimeoutException(message); + } +#endif + +#if DEBUG // note that here, through all code-paths: we have the lock + lockCount++; +#endif + } + + private int contentionCounter = 1; +#if PLAT_NO_INTERLOCKED + private readonly object contentionLock = new object(); +#endif + private int GetContention() + { +#if PLAT_NO_INTERLOCKED + lock(contentionLock) + { + return contentionCounter; + } +#else + return Interlocked.CompareExchange(ref contentionCounter, 0, 0); +#endif + } + private void AddContention() + { +#if PLAT_NO_INTERLOCKED + lock(contentionLock) + { + contentionCounter++; + } +#else + Interlocked.Increment(ref contentionCounter); +#endif + } + + internal void ReleaseLock(int opaqueToken) + { + if (opaqueToken != 0) + { + Monitor.Exit(types); + if (opaqueToken != GetContention()) // contention-count changes since we looked! + { + LockContentedEventHandler handler = LockContended; + if (handler != null) + { + // not hugely elegant, but this is such a far-corner-case that it doesn't need to be slick - I'll settle for cross-platform + string stackTrace; + try + { + throw new ProtoException(); + } + catch (Exception ex) + { + stackTrace = ex.StackTrace; + } + + handler(this, new LockContentedEventArgs(stackTrace)); + } + } + } + } + /// + /// If a lock-contention is detected, this event signals the *owner* of the lock responsible for the blockage, indicating + /// what caused the problem; this is only raised if the lock-owning code successfully completes. + /// + public event LockContentedEventHandler LockContended; + + internal void ResolveListTypes(Type type, ref Type itemType, ref Type defaultType) + { + if (type == null) return; + if (Helpers.GetTypeCode(type) != ProtoTypeCode.Unknown) return; // don't try this[type] for inbuilts + + // handle arrays + if (type.IsArray) + { + if (type.GetArrayRank() != 1) + { + throw new NotSupportedException("Multi-dimension arrays are supported"); + } + itemType = type.GetElementType(); + if (itemType == MapType(typeof(byte))) + { + defaultType = itemType = null; + } + else + { + defaultType = type; + } + } + else + { + // if not an array, first check it isn't explicitly opted out + if (this[type].IgnoreListHandling) return; + } + + // handle lists + if (itemType == null) { itemType = TypeModel.GetListItemType(this, type); } + + // check for nested data (not allowed) + if (itemType != null) + { + Type nestedItemType = null, nestedDefaultType = null; + ResolveListTypes(itemType, ref nestedItemType, ref nestedDefaultType); + if (nestedItemType != null) + { + throw TypeModel.CreateNestedListsNotSupported(type); + } + } + + if (itemType != null && defaultType == null) + { +#if COREFX || PROFILE259 + TypeInfo typeInfo = IntrospectionExtensions.GetTypeInfo(type); + if (typeInfo.IsClass && !typeInfo.IsAbstract && Helpers.GetConstructor(typeInfo, Helpers.EmptyTypes, true) != null) +#else + if (type.IsClass && !type.IsAbstract && Helpers.GetConstructor(type, Helpers.EmptyTypes, true) != null) +#endif + { + defaultType = type; + } + if (defaultType == null) + { +#if COREFX || PROFILE259 + if (typeInfo.IsInterface) +#else + if (type.IsInterface) +#endif + { + + Type[] genArgs; +#if COREFX || PROFILE259 + if (typeInfo.IsGenericType && typeInfo.GetGenericTypeDefinition() == typeof(System.Collections.Generic.IDictionary<,>) + && itemType == typeof(System.Collections.Generic.KeyValuePair<,>).MakeGenericType(genArgs = typeInfo.GenericTypeArguments)) +#else + if (type.IsGenericType && type.GetGenericTypeDefinition() == MapType(typeof(System.Collections.Generic.IDictionary<,>)) + && itemType == MapType(typeof(System.Collections.Generic.KeyValuePair<,>)).MakeGenericType(genArgs = type.GetGenericArguments())) +#endif + { + defaultType = MapType(typeof(System.Collections.Generic.Dictionary<,>)).MakeGenericType(genArgs); + } + else + { + defaultType = MapType(typeof(System.Collections.Generic.List<>)).MakeGenericType(itemType); + } + } + } + // verify that the default type is appropriate + if (defaultType != null && !Helpers.IsAssignableFrom(type, defaultType)) { defaultType = null; } + } + } + + internal string GetSchemaTypeName(Type effectiveType, DataFormat dataFormat, bool asReference, bool dynamicType, ref CommonImports imports) + { + Type tmp = Helpers.GetUnderlyingType(effectiveType); + if (tmp != null) effectiveType = tmp; + + if (effectiveType == this.MapType(typeof(byte[]))) return "bytes"; + + WireType wireType; + IProtoSerializer ser = ValueMember.TryGetCoreSerializer(this, dataFormat, effectiveType, out wireType, false, false, false, false); + if (ser == null) + { // model type + if (asReference || dynamicType) + { + imports |= CommonImports.Bcl; + return ".bcl.NetObjectProxy"; + } + return this[effectiveType].GetSurrogateOrBaseOrSelf(true).GetSchemaTypeName(); + } + else + { + if (ser is ParseableSerializer) + { + if (asReference) imports |= CommonImports.Bcl; + return asReference ? ".bcl.NetObjectProxy" : "string"; + } + + switch (Helpers.GetTypeCode(effectiveType)) + { + case ProtoTypeCode.Boolean: return "bool"; + case ProtoTypeCode.Single: return "float"; + case ProtoTypeCode.Double: return "double"; + case ProtoTypeCode.String: + if (asReference) imports |= CommonImports.Bcl; + return asReference ? ".bcl.NetObjectProxy" : "string"; + case ProtoTypeCode.Byte: + case ProtoTypeCode.Char: + case ProtoTypeCode.UInt16: + case ProtoTypeCode.UInt32: + switch (dataFormat) + { + case DataFormat.FixedSize: return "fixed32"; + default: return "uint32"; + } + case ProtoTypeCode.SByte: + case ProtoTypeCode.Int16: + case ProtoTypeCode.Int32: + switch (dataFormat) + { + case DataFormat.ZigZag: return "sint32"; + case DataFormat.FixedSize: return "sfixed32"; + default: return "int32"; + } + case ProtoTypeCode.UInt64: + switch (dataFormat) + { + case DataFormat.FixedSize: return "fixed64"; + default: return "uint64"; + } + case ProtoTypeCode.Int64: + switch (dataFormat) + { + case DataFormat.ZigZag: return "sint64"; + case DataFormat.FixedSize: return "sfixed64"; + default: return "int64"; + } + case ProtoTypeCode.DateTime: + switch (dataFormat) + { + case DataFormat.FixedSize: return "sint64"; + case DataFormat.WellKnown: + imports |= CommonImports.Timestamp; + return ".google.protobuf.Timestamp"; + default: + imports |= CommonImports.Bcl; + return ".bcl.DateTime"; + } + case ProtoTypeCode.TimeSpan: + switch (dataFormat) + { + case DataFormat.FixedSize: return "sint64"; + case DataFormat.WellKnown: + imports |= CommonImports.Duration; + return ".google.protobuf.Duration"; + default: + imports |= CommonImports.Bcl; + return ".bcl.TimeSpan"; + } + case ProtoTypeCode.Decimal: imports |= CommonImports.Bcl; return ".bcl.Decimal"; + case ProtoTypeCode.Guid: imports |= CommonImports.Bcl; return ".bcl.Guid"; + case ProtoTypeCode.Type: return "string"; + default: throw new NotSupportedException("No .proto map found for: " + effectiveType.FullName); + } + } + + } + + /// + /// Designate a factory-method to use to create instances of any type; note that this only affect types seen by the serializer *after* setting the factory. + /// + public void SetDefaultFactory(MethodInfo methodInfo) + { + VerifyFactory(methodInfo, null); + defaultFactory = methodInfo; + } + private MethodInfo defaultFactory; + + internal void VerifyFactory(MethodInfo factory, Type type) + { + if (factory != null) + { + if (type != null && Helpers.IsValueType(type)) throw new InvalidOperationException(); + if (!factory.IsStatic) throw new ArgumentException("A factory-method must be static", "factory"); + if ((type != null && factory.ReturnType != type) && factory.ReturnType != MapType(typeof(object))) throw new ArgumentException("The factory-method must return object" + (type == null ? "" : (" or " + type.FullName)), "factory"); + + if (!CallbackSet.CheckCallbackParameters(this, factory)) throw new ArgumentException("Invalid factory signature in " + factory.DeclaringType.FullName + "." + factory.Name, "factory"); + } + } + + /// + /// Raised before a type is auto-configured; this allows the auto-configuration to be electively suppressed + /// + /// This callback should be fast and not involve complex external calls, as it may block the model + public event EventHandler BeforeApplyDefaultBehaviour; + + /// + /// Raised after a type is auto-configured; this allows additional external customizations + /// + /// This callback should be fast and not involve complex external calls, as it may block the model + public event EventHandler AfterApplyDefaultBehaviour; + + internal static void OnBeforeApplyDefaultBehaviour(MetaType metaType, ref TypeAddedEventArgs args) + => OnApplyDefaultBehaviour((metaType?.Model as RuntimeTypeModel)?.BeforeApplyDefaultBehaviour, metaType, ref args); + + internal static void OnAfterApplyDefaultBehaviour(MetaType metaType, ref TypeAddedEventArgs args) + => OnApplyDefaultBehaviour((metaType?.Model as RuntimeTypeModel)?.AfterApplyDefaultBehaviour, metaType, ref args); + + private static void OnApplyDefaultBehaviour( + EventHandler handler, MetaType metaType, ref TypeAddedEventArgs args) + { + if (handler != null) + { + if (args == null) args = new TypeAddedEventArgs(metaType); + handler(metaType.Model, args); + } + } + } + + /// + /// Contains the stack-trace of the owning code when a lock-contention scenario is detected + /// + public sealed class LockContentedEventArgs : EventArgs + { + private readonly string ownerStackTrace; + internal LockContentedEventArgs(string ownerStackTrace) + { + this.ownerStackTrace = ownerStackTrace; + } + + /// + /// The stack-trace of the code that owned the lock when a lock-contention scenario occurred + /// + public string OwnerStackTrace => ownerStackTrace; + } + /// + /// Event-type that is raised when a lock-contention scenario is detected + /// + public delegate void LockContentedEventHandler(object sender, LockContentedEventArgs args); +} +#endif diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Meta/RuntimeTypeModel.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Meta/RuntimeTypeModel.cs.meta new file mode 100644 index 0000000..231a028 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Meta/RuntimeTypeModel.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0e4440bfa9e92f84d81d48e6c5b0022e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Meta/SubType.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Meta/SubType.cs new file mode 100644 index 0000000..72c8126 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Meta/SubType.cs @@ -0,0 +1,97 @@ +#if !NO_RUNTIME +using System; +using System.Collections.Generic; +using ProtoBuf.Serializers; + +namespace ProtoBuf.Meta +{ + /// + /// Represents an inherited type in a type hierarchy. + /// + public sealed class SubType + { + internal sealed class Comparer : System.Collections.IComparer, IComparer + { + public static readonly Comparer Default = new Comparer(); + + public int Compare(object x, object y) + { + return Compare(x as SubType, y as SubType); + } + + public int Compare(SubType x, SubType y) + { + if (ReferenceEquals(x, y)) return 0; + if (x == null) return -1; + if (y == null) return 1; + + return x.FieldNumber.CompareTo(y.FieldNumber); + } + } + + private int _fieldNumber; + + /// + /// The field-number that is used to encapsulate the data (as a nested + /// message) for the derived dype. + /// + public int FieldNumber + { + get => _fieldNumber; + internal set + { + if (_fieldNumber != value) + { + MetaType.AssertValidFieldNumber(value); + ThrowIfFrozen(); + _fieldNumber = value; + } + } + } + + private void ThrowIfFrozen() + { + if (serializer != null) throw new InvalidOperationException("The type cannot be changed once a serializer has been generated"); + } + + + /// + /// The sub-type to be considered. + /// + public MetaType DerivedType => derivedType; + private readonly MetaType derivedType; + + /// + /// Creates a new SubType instance. + /// + /// The field-number that is used to encapsulate the data (as a nested + /// message) for the derived dype. + /// The sub-type to be considered. + /// Specific encoding style to use; in particular, Grouped can be used to avoid buffering, but is not the default. + public SubType(int fieldNumber, MetaType derivedType, DataFormat format) + { + if (derivedType == null) throw new ArgumentNullException(nameof(derivedType)); + if (fieldNumber <= 0) throw new ArgumentOutOfRangeException(nameof(fieldNumber)); + _fieldNumber = fieldNumber; + this.derivedType = derivedType; + this.dataFormat = format; + } + + private readonly DataFormat dataFormat; + + private IProtoSerializer serializer; + + internal IProtoSerializer Serializer => serializer ?? (serializer = BuildSerializer()); + + private IProtoSerializer BuildSerializer() + { + // note the caller here is MetaType.BuildSerializer, which already has the sync-lock + WireType wireType = WireType.String; + if(dataFormat == DataFormat.Group) wireType = WireType.StartGroup; // only one exception + + IProtoSerializer ser = new SubItemSerializer(derivedType.Type, derivedType.GetKey(false, false), derivedType, false); + return new TagDecorator(_fieldNumber, wireType, false, ser); + } + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Meta/SubType.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Meta/SubType.cs.meta new file mode 100644 index 0000000..fb7fe45 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Meta/SubType.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a2912d37917b74846bdcffe3daa174d2 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Meta/TypeAddedEventArgs.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Meta/TypeAddedEventArgs.cs new file mode 100644 index 0000000..399c638 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Meta/TypeAddedEventArgs.cs @@ -0,0 +1,33 @@ +using System; + +namespace ProtoBuf.Meta +{ + /// + /// Event data associated with new types being added to a model + /// + public sealed class TypeAddedEventArgs : EventArgs + { + internal TypeAddedEventArgs(MetaType metaType) + { + MetaType = metaType; + ApplyDefaultBehaviour = true; + } + + /// + /// Whether or not to apply the default mapping behavior + /// + public bool ApplyDefaultBehaviour { get; set; } + /// + /// The configuration of the type being added + /// + public MetaType MetaType { get; } + /// + /// The type that was added to the model + /// + public Type Type => MetaType.Type; + /// + /// The model that is being changed + /// + public RuntimeTypeModel Model => MetaType.Model as RuntimeTypeModel; + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Meta/TypeAddedEventArgs.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Meta/TypeAddedEventArgs.cs.meta new file mode 100644 index 0000000..8ac9b8f --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Meta/TypeAddedEventArgs.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1500030a10d2168408f75fe907ce0568 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Meta/TypeFormatEventArgs.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Meta/TypeFormatEventArgs.cs new file mode 100644 index 0000000..3db0999 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Meta/TypeFormatEventArgs.cs @@ -0,0 +1,64 @@ +using System; + +namespace ProtoBuf.Meta +{ + /// + /// Event arguments needed to perform type-formatting functions; this could be resolving a Type to a string suitable for serialization, or could + /// be requesting a Type from a string. If no changes are made, a default implementation will be used (from the assembly-qualified names). + /// + public class TypeFormatEventArgs : EventArgs + { + private Type type; + private string formattedName; + private readonly bool typeFixed; + /// + /// The type involved in this map; if this is initially null, a Type is expected to be provided for the string in FormattedName. + /// + public Type Type + { + get { return type; } + set + { + if (type != value) + { + if (typeFixed) throw new InvalidOperationException("The type is fixed and cannot be changed"); + type = value; + } + } + } + + /// + /// The formatted-name involved in this map; if this is initially null, a formatted-name is expected from the type in Type. + /// + public string FormattedName + { + get { return formattedName; } + set + { + if (formattedName != value) + { + if (!typeFixed) throw new InvalidOperationException("The formatted-name is fixed and cannot be changed"); + formattedName = value; + } + } + } + + internal TypeFormatEventArgs(string formattedName) + { + if (string.IsNullOrEmpty(formattedName)) throw new ArgumentNullException("formattedName"); + this.formattedName = formattedName; + // typeFixed = false; <== implicit + } + + internal TypeFormatEventArgs(Type type) + { + this.type = type ?? throw new ArgumentNullException(nameof(type)); + typeFixed = true; + } + } + + /// + /// Delegate type used to perform type-formatting functions; the sender originates as the type-model. + /// + public delegate void TypeFormatEventHandler(object sender, TypeFormatEventArgs args); +} diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Meta/TypeFormatEventArgs.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Meta/TypeFormatEventArgs.cs.meta new file mode 100644 index 0000000..a21c2ab --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Meta/TypeFormatEventArgs.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d27afe6e96660d1418a49cf374e84ad0 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Meta/TypeModel.InputOutput.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Meta/TypeModel.InputOutput.cs new file mode 100644 index 0000000..9b023a6 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Meta/TypeModel.InputOutput.cs @@ -0,0 +1,45 @@ +using System; +using System.IO; + +namespace ProtoBuf.Meta +{ + partial class TypeModel : + IProtoInput, + IProtoInput>, + IProtoInput, + IProtoOutput + { + static SerializationContext CreateContext(object userState) + { + if (userState == null) + return SerializationContext.Default; + if (userState is SerializationContext ctx) + return ctx; + + var obj = new SerializationContext { Context = userState }; + obj.Freeze(); + return obj; + } + T IProtoInput.Deserialize(Stream source, T value, object userState) + => (T)Deserialize(source, value, typeof(T), CreateContext(userState)); + + T IProtoInput>.Deserialize(ArraySegment source, T value, object userState) + { + using (var ms = new MemoryStream(source.Array, source.Offset, source.Count)) + { + return (T)Deserialize(ms, value, typeof(T), CreateContext(userState)); + } + } + + T IProtoInput.Deserialize(byte[] source, T value, object userState) + { + using (var ms = new MemoryStream(source)) + { + return (T)Deserialize(ms, value, typeof(T), CreateContext(userState)); + } + } + + void IProtoOutput.Serialize(Stream destination, T value, object userState) + => Serialize(destination, value, CreateContext(userState)); + } +} diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Meta/TypeModel.InputOutput.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Meta/TypeModel.InputOutput.cs.meta new file mode 100644 index 0000000..80015e5 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Meta/TypeModel.InputOutput.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d683bc55be70e8e46824012108beb15f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Meta/TypeModel.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Meta/TypeModel.cs new file mode 100644 index 0000000..1867cf2 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Meta/TypeModel.cs @@ -0,0 +1,1696 @@ +using System; +using System.IO; + +using System.Collections; +using System.Collections.Generic; +using System.Reflection; + +namespace ProtoBuf.Meta +{ + /// + /// Provides protobuf serialization support for a number of types + /// + public abstract partial class TypeModel + { +#if COREFX + internal TypeInfo MapType(TypeInfo type) + { + return type; + } +#endif + + /// + /// Should the Kind be included on date/time values? + /// + protected internal virtual bool SerializeDateTimeKind() { return false; } + + /// + /// Resolve a System.Type to the compiler-specific type + /// + protected internal Type MapType(Type type) + { + return MapType(type, true); + } + /// + /// Resolve a System.Type to the compiler-specific type + /// + protected internal virtual Type MapType(Type type, bool demand) + { + return type; + } + + private WireType GetWireType(ProtoTypeCode code, DataFormat format, ref Type type, out int modelKey) + { + modelKey = -1; + if (Helpers.IsEnum(type)) + { + modelKey = GetKey(ref type); + return WireType.Variant; + } + switch (code) + { + case ProtoTypeCode.Int64: + case ProtoTypeCode.UInt64: + return format == DataFormat.FixedSize ? WireType.Fixed64 : WireType.Variant; + case ProtoTypeCode.Int16: + case ProtoTypeCode.Int32: + case ProtoTypeCode.UInt16: + case ProtoTypeCode.UInt32: + case ProtoTypeCode.Boolean: + case ProtoTypeCode.SByte: + case ProtoTypeCode.Byte: + case ProtoTypeCode.Char: + return format == DataFormat.FixedSize ? WireType.Fixed32 : WireType.Variant; + case ProtoTypeCode.Double: + return WireType.Fixed64; + case ProtoTypeCode.Single: + return WireType.Fixed32; + case ProtoTypeCode.String: + case ProtoTypeCode.DateTime: + case ProtoTypeCode.Decimal: + case ProtoTypeCode.ByteArray: + case ProtoTypeCode.TimeSpan: + case ProtoTypeCode.Guid: + case ProtoTypeCode.Uri: + return WireType.String; + } + + if ((modelKey = GetKey(ref type)) >= 0) + { + return WireType.String; + } + return WireType.None; + } + + + /// + /// This is the more "complete" version of Serialize, which handles single instances of mapped types. + /// The value is written as a complete field, including field-header and (for sub-objects) a + /// length-prefix + /// In addition to that, this provides support for: + /// - basic values; individual int / string / Guid / etc + /// - IEnumerable sequences of any type handled by TrySerializeAuxiliaryType + /// + /// + internal bool TrySerializeAuxiliaryType(ProtoWriter writer, Type type, DataFormat format, int tag, object value, bool isInsideList, object parentList) + { + if (type == null) { type = value.GetType(); } + + ProtoTypeCode typecode = Helpers.GetTypeCode(type); + // note the "ref type" here normalizes against proxies + WireType wireType = GetWireType(typecode, format, ref type, out int modelKey); + + + if (modelKey >= 0) + { // write the header, but defer to the model + if (Helpers.IsEnum(type)) + { // no header + Serialize(modelKey, value, writer); + return true; + } + else + { + ProtoWriter.WriteFieldHeader(tag, wireType, writer); + switch (wireType) + { + case WireType.None: + throw ProtoWriter.CreateException(writer); + case WireType.StartGroup: + case WireType.String: + // needs a wrapping length etc + SubItemToken token = ProtoWriter.StartSubItem(value, writer); + Serialize(modelKey, value, writer); + ProtoWriter.EndSubItem(token, writer); + return true; + default: + Serialize(modelKey, value, writer); + return true; + } + } + } + + if (wireType != WireType.None) + { + ProtoWriter.WriteFieldHeader(tag, wireType, writer); + } + switch (typecode) + { + case ProtoTypeCode.Int16: ProtoWriter.WriteInt16((short)value, writer); return true; + case ProtoTypeCode.Int32: ProtoWriter.WriteInt32((int)value, writer); return true; + case ProtoTypeCode.Int64: ProtoWriter.WriteInt64((long)value, writer); return true; + case ProtoTypeCode.UInt16: ProtoWriter.WriteUInt16((ushort)value, writer); return true; + case ProtoTypeCode.UInt32: ProtoWriter.WriteUInt32((uint)value, writer); return true; + case ProtoTypeCode.UInt64: ProtoWriter.WriteUInt64((ulong)value, writer); return true; + case ProtoTypeCode.Boolean: ProtoWriter.WriteBoolean((bool)value, writer); return true; + case ProtoTypeCode.SByte: ProtoWriter.WriteSByte((sbyte)value, writer); return true; + case ProtoTypeCode.Byte: ProtoWriter.WriteByte((byte)value, writer); return true; + case ProtoTypeCode.Char: ProtoWriter.WriteUInt16((ushort)(char)value, writer); return true; + case ProtoTypeCode.Double: ProtoWriter.WriteDouble((double)value, writer); return true; + case ProtoTypeCode.Single: ProtoWriter.WriteSingle((float)value, writer); return true; + case ProtoTypeCode.DateTime: + if (SerializeDateTimeKind()) + BclHelpers.WriteDateTimeWithKind((DateTime)value, writer); + else + BclHelpers.WriteDateTime((DateTime)value, writer); + return true; + case ProtoTypeCode.Decimal: BclHelpers.WriteDecimal((decimal)value, writer); return true; + case ProtoTypeCode.String: ProtoWriter.WriteString((string)value, writer); return true; + case ProtoTypeCode.ByteArray: ProtoWriter.WriteBytes((byte[])value, writer); return true; + case ProtoTypeCode.TimeSpan: BclHelpers.WriteTimeSpan((TimeSpan)value, writer); return true; + case ProtoTypeCode.Guid: BclHelpers.WriteGuid((Guid)value, writer); return true; + case ProtoTypeCode.Uri: ProtoWriter.WriteString(((Uri)value).OriginalString, writer); return true; + } + + // by now, we should have covered all the simple cases; if we wrote a field-header, we have + // forgotten something! + Helpers.DebugAssert(wireType == WireType.None); + + // now attempt to handle sequences (including arrays and lists) + if (value is IEnumerable sequence) + { + if (isInsideList) throw CreateNestedListsNotSupported(parentList?.GetType()); + foreach (object item in sequence) + { + if (item == null) { throw new NullReferenceException(); } + if (!TrySerializeAuxiliaryType(writer, null, format, tag, item, true, sequence)) + { + ThrowUnexpectedType(item.GetType()); + } + } + return true; + } + return false; + } + + private void SerializeCore(ProtoWriter writer, object value) + { + if (value == null) throw new ArgumentNullException(nameof(value)); + Type type = value.GetType(); + int key = GetKey(ref type); + if (key >= 0) + { + Serialize(key, value, writer); + } + else if (!TrySerializeAuxiliaryType(writer, type, DataFormat.Default, Serializer.ListItemTag, value, false, null)) + { + ThrowUnexpectedType(type); + } + } + + /// + /// Writes a protocol-buffer representation of the given instance to the supplied stream. + /// + /// The existing instance to be serialized (cannot be null). + /// The destination stream to write to. + public void Serialize(Stream dest, object value) + { + Serialize(dest, value, null); + } + + /// + /// Writes a protocol-buffer representation of the given instance to the supplied stream. + /// + /// The existing instance to be serialized (cannot be null). + /// The destination stream to write to. + /// Additional information about this serialization operation. + public void Serialize(Stream dest, object value, SerializationContext context) + { + using (ProtoWriter writer = ProtoWriter.Create(dest, this, context)) + { + writer.SetRootObject(value); + SerializeCore(writer, value); + writer.Close(); + } + } + + /// + /// Writes a protocol-buffer representation of the given instance to the supplied writer. + /// + /// The existing instance to be serialized (cannot be null). + /// The destination writer to write to. + public void Serialize(ProtoWriter dest, object value) + { + if (dest == null) throw new ArgumentNullException(nameof(dest)); + dest.CheckDepthFlushlock(); + dest.SetRootObject(value); + SerializeCore(dest, value); + dest.CheckDepthFlushlock(); + ProtoWriter.Flush(dest); + } + + /// + /// Applies a protocol-buffer stream to an existing instance (or null), using length-prefixed + /// data - useful with network IO. + /// + /// The type being merged. + /// The existing instance to be modified (can be null). + /// The binary stream to apply to the instance (cannot be null). + /// How to encode the length prefix. + /// The tag used as a prefix to each record (only used with base-128 style prefixes). + /// The updated instance; this may be different to the instance argument if + /// either the original instance was null, or the stream defines a known sub-type of the + /// original instance. + public object DeserializeWithLengthPrefix(Stream source, object value, Type type, PrefixStyle style, int fieldNumber) + => DeserializeWithLengthPrefix(source, value, type, style, fieldNumber, null, out long bytesRead); + + /// + /// Applies a protocol-buffer stream to an existing instance (or null), using length-prefixed + /// data - useful with network IO. + /// + /// The type being merged. + /// The existing instance to be modified (can be null). + /// The binary stream to apply to the instance (cannot be null). + /// How to encode the length prefix. + /// The tag used as a prefix to each record (only used with base-128 style prefixes). + /// Used to resolve types on a per-field basis. + /// The updated instance; this may be different to the instance argument if + /// either the original instance was null, or the stream defines a known sub-type of the + /// original instance. + public object DeserializeWithLengthPrefix(Stream source, object value, Type type, PrefixStyle style, int expectedField, Serializer.TypeResolver resolver) + => DeserializeWithLengthPrefix(source, value, type, style, expectedField, resolver, out long bytesRead); + + /// + /// Applies a protocol-buffer stream to an existing instance (or null), using length-prefixed + /// data - useful with network IO. + /// + /// The type being merged. + /// The existing instance to be modified (can be null). + /// The binary stream to apply to the instance (cannot be null). + /// How to encode the length prefix. + /// The tag used as a prefix to each record (only used with base-128 style prefixes). + /// Used to resolve types on a per-field basis. + /// Returns the number of bytes consumed by this operation (includes length-prefix overheads and any skipped data). + /// The updated instance; this may be different to the instance argument if + /// either the original instance was null, or the stream defines a known sub-type of the + /// original instance. + public object DeserializeWithLengthPrefix(Stream source, object value, Type type, PrefixStyle style, int expectedField, Serializer.TypeResolver resolver, out int bytesRead) + { + object result = DeserializeWithLengthPrefix(source, value, type, style, expectedField, resolver, out long bytesRead64, out bool haveObject, null); + bytesRead = checked((int)bytesRead64); + return result; + } + + /// + /// Applies a protocol-buffer stream to an existing instance (or null), using length-prefixed + /// data - useful with network IO. + /// + /// The type being merged. + /// The existing instance to be modified (can be null). + /// The binary stream to apply to the instance (cannot be null). + /// How to encode the length prefix. + /// The tag used as a prefix to each record (only used with base-128 style prefixes). + /// Used to resolve types on a per-field basis. + /// Returns the number of bytes consumed by this operation (includes length-prefix overheads and any skipped data). + /// The updated instance; this may be different to the instance argument if + /// either the original instance was null, or the stream defines a known sub-type of the + /// original instance. + public object DeserializeWithLengthPrefix(Stream source, object value, Type type, PrefixStyle style, int expectedField, Serializer.TypeResolver resolver, out long bytesRead) => DeserializeWithLengthPrefix(source, value, type, style, expectedField, resolver, out bytesRead, out bool haveObject, null); + + private object DeserializeWithLengthPrefix(Stream source, object value, Type type, PrefixStyle style, int expectedField, Serializer.TypeResolver resolver, out long bytesRead, out bool haveObject, SerializationContext context) + { + haveObject = false; + bool skip; + long len; + bytesRead = 0; + if (type == null && (style != PrefixStyle.Base128 || resolver == null)) + { + throw new InvalidOperationException("A type must be provided unless base-128 prefixing is being used in combination with a resolver"); + } + do + { + + bool expectPrefix = expectedField > 0 || resolver != null; + len = ProtoReader.ReadLongLengthPrefix(source, expectPrefix, style, out int actualField, out int tmpBytesRead); + if (tmpBytesRead == 0) return value; + bytesRead += tmpBytesRead; + if (len < 0) return value; + + switch (style) + { + case PrefixStyle.Base128: + if (expectPrefix && expectedField == 0 && type == null && resolver != null) + { + type = resolver(actualField); + skip = type == null; + } + else { skip = expectedField != actualField; } + break; + default: + skip = false; + break; + } + + if (skip) + { + if (len == long.MaxValue) throw new InvalidOperationException(); + ProtoReader.Seek(source, len, null); + bytesRead += len; + } + } while (skip); + + ProtoReader reader = null; + try + { + reader = ProtoReader.Create(source, this, context, len); + int key = GetKey(ref type); + if (key >= 0 && !Helpers.IsEnum(type)) + { + value = Deserialize(key, value, reader); + } + else + { + if (!(TryDeserializeAuxiliaryType(reader, DataFormat.Default, Serializer.ListItemTag, type, ref value, true, false, true, false, null) || len == 0)) + { + TypeModel.ThrowUnexpectedType(type); // throws + } + } + bytesRead += reader.LongPosition; + haveObject = true; + return value; + } + finally + { + ProtoReader.Recycle(reader); + } + } + + /// + /// Reads a sequence of consecutive length-prefixed items from a stream, using + /// either base-128 or fixed-length prefixes. Base-128 prefixes with a tag + /// are directly comparable to serializing multiple items in succession + /// (use the tag to emulate the implicit behavior + /// when serializing a list/array). When a tag is + /// specified, any records with different tags are silently omitted. The + /// tag is ignored. The tag is ignores for fixed-length prefixes. + /// + /// The binary stream containing the serialized records. + /// The prefix style used in the data. + /// The tag of records to return (if non-positive, then no tag is + /// expected and all records are returned). + /// On a field-by-field basis, the type of object to deserialize (can be null if "type" is specified). + /// The type of object to deserialize (can be null if "resolver" is specified). + /// The sequence of deserialized objects. + public IEnumerable DeserializeItems(System.IO.Stream source, Type type, PrefixStyle style, int expectedField, Serializer.TypeResolver resolver) + { + return DeserializeItems(source, type, style, expectedField, resolver, null); + } + /// + /// Reads a sequence of consecutive length-prefixed items from a stream, using + /// either base-128 or fixed-length prefixes. Base-128 prefixes with a tag + /// are directly comparable to serializing multiple items in succession + /// (use the tag to emulate the implicit behavior + /// when serializing a list/array). When a tag is + /// specified, any records with different tags are silently omitted. The + /// tag is ignored. The tag is ignores for fixed-length prefixes. + /// + /// The binary stream containing the serialized records. + /// The prefix style used in the data. + /// The tag of records to return (if non-positive, then no tag is + /// expected and all records are returned). + /// On a field-by-field basis, the type of object to deserialize (can be null if "type" is specified). + /// The type of object to deserialize (can be null if "resolver" is specified). + /// The sequence of deserialized objects. + /// Additional information about this serialization operation. + public IEnumerable DeserializeItems(System.IO.Stream source, Type type, PrefixStyle style, int expectedField, Serializer.TypeResolver resolver, SerializationContext context) + { + return new DeserializeItemsIterator(this, source, type, style, expectedField, resolver, context); + } + + /// + /// Reads a sequence of consecutive length-prefixed items from a stream, using + /// either base-128 or fixed-length prefixes. Base-128 prefixes with a tag + /// are directly comparable to serializing multiple items in succession + /// (use the tag to emulate the implicit behavior + /// when serializing a list/array). When a tag is + /// specified, any records with different tags are silently omitted. The + /// tag is ignored. The tag is ignores for fixed-length prefixes. + /// + /// The type of object to deserialize. + /// The binary stream containing the serialized records. + /// The prefix style used in the data. + /// The tag of records to return (if non-positive, then no tag is + /// expected and all records are returned). + /// The sequence of deserialized objects. + public IEnumerable DeserializeItems(Stream source, PrefixStyle style, int expectedField) + { + return DeserializeItems(source, style, expectedField, null); + } + /// + /// Reads a sequence of consecutive length-prefixed items from a stream, using + /// either base-128 or fixed-length prefixes. Base-128 prefixes with a tag + /// are directly comparable to serializing multiple items in succession + /// (use the tag to emulate the implicit behavior + /// when serializing a list/array). When a tag is + /// specified, any records with different tags are silently omitted. The + /// tag is ignored. The tag is ignores for fixed-length prefixes. + /// + /// The type of object to deserialize. + /// The binary stream containing the serialized records. + /// The prefix style used in the data. + /// The tag of records to return (if non-positive, then no tag is + /// expected and all records are returned). + /// The sequence of deserialized objects. + /// Additional information about this serialization operation. + public IEnumerable DeserializeItems(Stream source, PrefixStyle style, int expectedField, SerializationContext context) + { + return new DeserializeItemsIterator(this, source, style, expectedField, context); + } + + private sealed class DeserializeItemsIterator : DeserializeItemsIterator, + IEnumerator, + IEnumerable + { + IEnumerator IEnumerable.GetEnumerator() { return this; } + public new T Current { get { return (T)base.Current; } } + void IDisposable.Dispose() { } + public DeserializeItemsIterator(TypeModel model, Stream source, PrefixStyle style, int expectedField, SerializationContext context) + : base(model, source, model.MapType(typeof(T)), style, expectedField, null, context) { } + } + + private class DeserializeItemsIterator : IEnumerator, IEnumerable + { + IEnumerator IEnumerable.GetEnumerator() { return this; } + private bool haveObject; + private object current; + public bool MoveNext() + { + if (haveObject) + { + current = model.DeserializeWithLengthPrefix(source, null, type, style, expectedField, resolver, out long bytesRead, out haveObject, context); + } + return haveObject; + } + void IEnumerator.Reset() { throw new NotSupportedException(); } + public object Current { get { return current; } } + private readonly Stream source; + private readonly Type type; + private readonly PrefixStyle style; + private readonly int expectedField; + private readonly Serializer.TypeResolver resolver; + private readonly TypeModel model; + private readonly SerializationContext context; + public DeserializeItemsIterator(TypeModel model, Stream source, Type type, PrefixStyle style, int expectedField, Serializer.TypeResolver resolver, SerializationContext context) + { + haveObject = true; + this.source = source; + this.type = type; + this.style = style; + this.expectedField = expectedField; + this.resolver = resolver; + this.model = model; + this.context = context; + } + } + + /// + /// Writes a protocol-buffer representation of the given instance to the supplied stream, + /// with a length-prefix. This is useful for socket programming, + /// as DeserializeWithLengthPrefix can be used to read the single object back + /// from an ongoing stream. + /// + /// The type being serialized. + /// The existing instance to be serialized (cannot be null). + /// How to encode the length prefix. + /// The destination stream to write to. + /// The tag used as a prefix to each record (only used with base-128 style prefixes). + public void SerializeWithLengthPrefix(Stream dest, object value, Type type, PrefixStyle style, int fieldNumber) + { + SerializeWithLengthPrefix(dest, value, type, style, fieldNumber, null); + } + + /// + /// Writes a protocol-buffer representation of the given instance to the supplied stream, + /// with a length-prefix. This is useful for socket programming, + /// as DeserializeWithLengthPrefix can be used to read the single object back + /// from an ongoing stream. + /// + /// The type being serialized. + /// The existing instance to be serialized (cannot be null). + /// How to encode the length prefix. + /// The destination stream to write to. + /// The tag used as a prefix to each record (only used with base-128 style prefixes). + /// Additional information about this serialization operation. + public void SerializeWithLengthPrefix(Stream dest, object value, Type type, PrefixStyle style, int fieldNumber, SerializationContext context) + { + if (type == null) + { + if (value == null) throw new ArgumentNullException(nameof(value)); + type = MapType(value.GetType()); + } + int key = GetKey(ref type); + using (ProtoWriter writer = ProtoWriter.Create(dest, this, context)) + { + switch (style) + { + case PrefixStyle.None: + Serialize(key, value, writer); + break; + case PrefixStyle.Base128: + case PrefixStyle.Fixed32: + case PrefixStyle.Fixed32BigEndian: + ProtoWriter.WriteObject(value, key, writer, style, fieldNumber); + break; + default: + throw new ArgumentOutOfRangeException("style"); + } + writer.Close(); + } + } + /// + /// Applies a protocol-buffer stream to an existing instance (which may be null). + /// + /// The type (including inheritance) to consider. + /// The existing instance to be modified (can be null). + /// The binary stream to apply to the instance (cannot be null). + /// The updated instance; this may be different to the instance argument if + /// either the original instance was null, or the stream defines a known sub-type of the + /// original instance. + public object Deserialize(Stream source, object value, Type type) + { + return Deserialize(source, value, type, null); + } + + /// + /// Applies a protocol-buffer stream to an existing instance (which may be null). + /// + /// The type (including inheritance) to consider. + /// The existing instance to be modified (can be null). + /// The binary stream to apply to the instance (cannot be null). + /// The updated instance; this may be different to the instance argument if + /// either the original instance was null, or the stream defines a known sub-type of the + /// original instance. + /// Additional information about this serialization operation. + public object Deserialize(Stream source, object value, Type type, SerializationContext context) + { + bool autoCreate = PrepareDeserialize(value, ref type); + ProtoReader reader = null; + try + { + reader = ProtoReader.Create(source, this, context, ProtoReader.TO_EOF); + if (value != null) reader.SetRootObject(value); + object obj = DeserializeCore(reader, type, value, autoCreate); + reader.CheckFullyConsumed(); + return obj; + } + finally + { + ProtoReader.Recycle(reader); + } + } + + private bool PrepareDeserialize(object value, ref Type type) + { + if (type == null) + { + if (value == null) + { + throw new ArgumentNullException(nameof(type)); + } + else + { + type = MapType(value.GetType()); + } + } + + bool autoCreate = true; + Type underlyingType = Helpers.GetUnderlyingType(type); + if (underlyingType != null) + { + type = underlyingType; + autoCreate = false; + } + return autoCreate; + } + + /// + /// Applies a protocol-buffer stream to an existing instance (which may be null). + /// + /// The type (including inheritance) to consider. + /// The existing instance to be modified (can be null). + /// The binary stream to apply to the instance (cannot be null). + /// The number of bytes to consume. + /// The updated instance; this may be different to the instance argument if + /// either the original instance was null, or the stream defines a known sub-type of the + /// original instance. + public object Deserialize(Stream source, object value, System.Type type, int length) + => Deserialize(source, value, type, length, null); + + /// + /// Applies a protocol-buffer stream to an existing instance (which may be null). + /// + /// The type (including inheritance) to consider. + /// The existing instance to be modified (can be null). + /// The binary stream to apply to the instance (cannot be null). + /// The number of bytes to consume. + /// The updated instance; this may be different to the instance argument if + /// either the original instance was null, or the stream defines a known sub-type of the + /// original instance. + public object Deserialize(Stream source, object value, System.Type type, long length) + => Deserialize(source, value, type, length, null); + + /// + /// Applies a protocol-buffer stream to an existing instance (which may be null). + /// + /// The type (including inheritance) to consider. + /// The existing instance to be modified (can be null). + /// The binary stream to apply to the instance (cannot be null). + /// The number of bytes to consume (or -1 to read to the end of the stream). + /// The updated instance; this may be different to the instance argument if + /// either the original instance was null, or the stream defines a known sub-type of the + /// original instance. + /// Additional information about this serialization operation. + public object Deserialize(Stream source, object value, System.Type type, int length, SerializationContext context) + => Deserialize(source, value, type, length == int.MaxValue ? long.MaxValue : (long)length, context); + + /// + /// Applies a protocol-buffer stream to an existing instance (which may be null). + /// + /// The type (including inheritance) to consider. + /// The existing instance to be modified (can be null). + /// The binary stream to apply to the instance (cannot be null). + /// The number of bytes to consume (or -1 to read to the end of the stream). + /// The updated instance; this may be different to the instance argument if + /// either the original instance was null, or the stream defines a known sub-type of the + /// original instance. + /// Additional information about this serialization operation. + public object Deserialize(Stream source, object value, System.Type type, long length, SerializationContext context) + { + bool autoCreate = PrepareDeserialize(value, ref type); + ProtoReader reader = null; + try + { + reader = ProtoReader.Create(source, this, context, length); + if (value != null) reader.SetRootObject(value); + object obj = DeserializeCore(reader, type, value, autoCreate); + reader.CheckFullyConsumed(); + return obj; + } + finally + { + ProtoReader.Recycle(reader); + } + } + + /// + /// Applies a protocol-buffer reader to an existing instance (which may be null). + /// + /// The type (including inheritance) to consider. + /// The existing instance to be modified (can be null). + /// The reader to apply to the instance (cannot be null). + /// The updated instance; this may be different to the instance argument if + /// either the original instance was null, or the stream defines a known sub-type of the + /// original instance. + public object Deserialize(ProtoReader source, object value, System.Type type) + { + if (source == null) throw new ArgumentNullException("source"); + bool autoCreate = PrepareDeserialize(value, ref type); + if (value != null) source.SetRootObject(value); + object obj = DeserializeCore(source, type, value, autoCreate); + source.CheckFullyConsumed(); + return obj; + } + + private object DeserializeCore(ProtoReader reader, Type type, object value, bool noAutoCreate) + { + int key = GetKey(ref type); + if (key >= 0 && !Helpers.IsEnum(type)) + { + return Deserialize(key, value, reader); + } + // this returns true to say we actively found something, but a value is assigned either way (or throws) + TryDeserializeAuxiliaryType(reader, DataFormat.Default, Serializer.ListItemTag, type, ref value, true, false, noAutoCreate, false, null); + return value; + } + +#if COREFX + private static readonly System.Reflection.TypeInfo ilist = typeof(IList).GetTypeInfo(); +#else + private static readonly System.Type ilist = typeof(IList); +#endif + internal static MethodInfo ResolveListAdd(TypeModel model, Type listType, Type itemType, out bool isList) + { +#if COREFX || PROFILE259 + TypeInfo listTypeInfo = listType.GetTypeInfo(); +#else + Type listTypeInfo = listType; +#endif +#if PROFILE259 + isList = model.MapType(ilist).GetTypeInfo().IsAssignableFrom(listTypeInfo); +#else + isList = model.MapType(ilist).IsAssignableFrom(listTypeInfo); +#endif + Type[] types = { itemType }; + MethodInfo add = Helpers.GetInstanceMethod(listTypeInfo, "Add", types); + +#if !NO_GENERICS + if (add == null) + { // fallback: look for ICollection's Add(typedObject) method + + bool forceList = listTypeInfo.IsInterface && + model.MapType(typeof(System.Collections.Generic.IEnumerable<>)).MakeGenericType(types) +#if COREFX || PROFILE259 + .GetTypeInfo() +#endif + .IsAssignableFrom(listTypeInfo); + +#if COREFX || PROFILE259 + TypeInfo constuctedListType = typeof(System.Collections.Generic.ICollection<>).MakeGenericType(types).GetTypeInfo(); +#else + Type constuctedListType = model.MapType(typeof(System.Collections.Generic.ICollection<>)).MakeGenericType(types); +#endif + if (forceList || constuctedListType.IsAssignableFrom(listTypeInfo)) + { + add = Helpers.GetInstanceMethod(constuctedListType, "Add", types); + } + } + + if (add == null) + { + +#if COREFX || PROFILE259 + foreach (Type tmpType in listTypeInfo.ImplementedInterfaces) +#else + foreach (Type interfaceType in listTypeInfo.GetInterfaces()) +#endif + { +#if COREFX || PROFILE259 + TypeInfo interfaceType = tmpType.GetTypeInfo(); +#endif + if (interfaceType.Name == "IProducerConsumerCollection`1" && interfaceType.IsGenericType && interfaceType.GetGenericTypeDefinition().FullName == "System.Collections.Concurrent.IProducerConsumerCollection`1") + { + add = Helpers.GetInstanceMethod(interfaceType, "TryAdd", types); + if (add != null) break; + } + } + } +#endif + + if (add == null) + { // fallback: look for a public list.Add(object) method + types[0] = model.MapType(typeof(object)); + add = Helpers.GetInstanceMethod(listTypeInfo, "Add", types); + } + if (add == null && isList) + { // fallback: look for IList's Add(object) method + add = Helpers.GetInstanceMethod(model.MapType(ilist), "Add", types); + } + return add; + } + internal static Type GetListItemType(TypeModel model, Type listType) + { + Helpers.DebugAssert(listType != null); + +#if PROFILE259 + TypeInfo listTypeInfo = listType.GetTypeInfo(); + if (listType == typeof(string) || listType.IsArray + || !typeof(IEnumerable).GetTypeInfo().IsAssignableFrom(listTypeInfo)) return null; +#else + if (listType == model.MapType(typeof(string)) || listType.IsArray + || !model.MapType(typeof(IEnumerable)).IsAssignableFrom(listType)) return null; +#endif + + BasicList candidates = new BasicList(); +#if PROFILE259 + foreach (MethodInfo method in listType.GetRuntimeMethods()) +#else + foreach (MethodInfo method in listType.GetMethods()) +#endif + { + if (method.IsStatic || method.Name != "Add") continue; + ParameterInfo[] parameters = method.GetParameters(); + Type paramType; + if (parameters.Length == 1 && !candidates.Contains(paramType = parameters[0].ParameterType)) + { + candidates.Add(paramType); + } + } + + string name = listType.Name; + bool isQueueStack = name != null && (name.IndexOf("Queue") >= 0 || name.IndexOf("Stack") >= 0); + + if (!isQueueStack) + { + TestEnumerableListPatterns(model, candidates, listType); +#if PROFILE259 + foreach (Type iType in listTypeInfo.ImplementedInterfaces) + { + TestEnumerableListPatterns(model, candidates, iType); + } +#else + foreach (Type iType in listType.GetInterfaces()) + { + TestEnumerableListPatterns(model, candidates, iType); + } +#endif + } + +#if PROFILE259 + // more convenient GetProperty overload not supported on all platforms + foreach (PropertyInfo indexer in listType.GetRuntimeProperties()) + { + if (indexer.Name != "Item" || candidates.Contains(indexer.PropertyType)) continue; + ParameterInfo[] args = indexer.GetIndexParameters(); + if (args.Length != 1 || args[0].ParameterType != typeof(int)) continue; + MethodInfo getter = indexer.GetMethod; + if (getter == null || getter.IsStatic) continue; + candidates.Add(indexer.PropertyType); + } +#else + // more convenient GetProperty overload not supported on all platforms + foreach (PropertyInfo indexer in listType.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)) + { + if (indexer.Name != "Item" || candidates.Contains(indexer.PropertyType)) continue; + ParameterInfo[] args = indexer.GetIndexParameters(); + if (args.Length != 1 || args[0].ParameterType != model.MapType(typeof(int))) continue; + candidates.Add(indexer.PropertyType); + } +#endif + + switch (candidates.Count) + { + case 0: + return null; + case 1: + if ((Type)candidates[0] == listType) return null; // recursive + return (Type)candidates[0]; + case 2: + if ((Type)candidates[0] != listType && CheckDictionaryAccessors(model, (Type)candidates[0], (Type)candidates[1])) return (Type)candidates[0]; + if ((Type)candidates[1] != listType && CheckDictionaryAccessors(model, (Type)candidates[1], (Type)candidates[0])) return (Type)candidates[1]; + break; + } + + return null; + } + + private static void TestEnumerableListPatterns(TypeModel model, BasicList candidates, Type iType) + { + +#if COREFX || PROFILE259 + TypeInfo iTypeInfo = iType.GetTypeInfo(); + if (iTypeInfo.IsGenericType) + { + Type typeDef = iTypeInfo.GetGenericTypeDefinition(); + if( + typeDef == model.MapType(typeof(System.Collections.Generic.IEnumerable<>)) + || typeDef == model.MapType(typeof(System.Collections.Generic.ICollection<>)) + || typeDef.GetTypeInfo().FullName == "System.Collections.Concurrent.IProducerConsumerCollection`1") + { + + Type[] iTypeArgs = iTypeInfo.GenericTypeArguments; + if (!candidates.Contains(iTypeArgs[0])) + { + candidates.Add(iTypeArgs[0]); + } + } + } +#else + if (iType.IsGenericType) + { + Type typeDef = iType.GetGenericTypeDefinition(); + if (typeDef == model.MapType(typeof(System.Collections.Generic.IEnumerable<>)) + || typeDef == model.MapType(typeof(System.Collections.Generic.ICollection<>)) + || typeDef.FullName == "System.Collections.Concurrent.IProducerConsumerCollection`1") + { + Type[] iTypeArgs = iType.GetGenericArguments(); + if (!candidates.Contains(iTypeArgs[0])) + { + candidates.Add(iTypeArgs[0]); + } + } + } +#endif + } + + private static bool CheckDictionaryAccessors(TypeModel model, Type pair, Type value) + { +#if COREFX || PROFILE259 + TypeInfo finalType = pair.GetTypeInfo(); + return finalType.IsGenericType && finalType.GetGenericTypeDefinition() == typeof(System.Collections.Generic.KeyValuePair<,>) + && finalType.GenericTypeArguments[1] == value; +#else + return pair.IsGenericType && pair.GetGenericTypeDefinition() == model.MapType(typeof(System.Collections.Generic.KeyValuePair<,>)) + && pair.GetGenericArguments()[1] == value; +#endif + } + + private bool TryDeserializeList(TypeModel model, ProtoReader reader, DataFormat format, int tag, Type listType, Type itemType, ref object value) + { + MethodInfo addMethod = TypeModel.ResolveListAdd(model, listType, itemType, out bool isList); + if (addMethod == null) throw new NotSupportedException("Unknown list variant: " + listType.FullName); + bool found = false; + object nextItem = null; + IList list = value as IList; + object[] args = isList ? null : new object[1]; + BasicList arraySurrogate = listType.IsArray ? new BasicList() : null; + + while (TryDeserializeAuxiliaryType(reader, format, tag, itemType, ref nextItem, true, true, true, true, value ?? listType)) + { + found = true; + if (value == null && arraySurrogate == null) + { + value = CreateListInstance(listType, itemType); + list = value as IList; + } + if (list != null) + { + list.Add(nextItem); + } + else if (arraySurrogate != null) + { + arraySurrogate.Add(nextItem); + } + else + { + args[0] = nextItem; + addMethod.Invoke(value, args); + } + nextItem = null; + } + if (arraySurrogate != null) + { + Array newArray; + if (value != null) + { + if (arraySurrogate.Count == 0) + { // we'll stay with what we had, thanks + } + else + { + Array existing = (Array)value; + newArray = Array.CreateInstance(itemType, existing.Length + arraySurrogate.Count); + Array.Copy(existing, newArray, existing.Length); + arraySurrogate.CopyTo(newArray, existing.Length); + value = newArray; + } + } + else + { + newArray = Array.CreateInstance(itemType, arraySurrogate.Count); + arraySurrogate.CopyTo(newArray, 0); + value = newArray; + } + } + return found; + } + + private static object CreateListInstance(Type listType, Type itemType) + { + Type concreteListType = listType; + + if (listType.IsArray) + { + return Array.CreateInstance(itemType, 0); + } + +#if COREFX || PROFILE259 + TypeInfo listTypeInfo = listType.GetTypeInfo(); + if (!listTypeInfo.IsClass || listTypeInfo.IsAbstract || + Helpers.GetConstructor(listTypeInfo, Helpers.EmptyTypes, true) == null) +#else + if (!listType.IsClass || listType.IsAbstract || + Helpers.GetConstructor(listType, Helpers.EmptyTypes, true) == null) +#endif + { + string fullName; + bool handled = false; +#if COREFX || PROFILE259 + if (listTypeInfo.IsInterface && +#else + if (listType.IsInterface && +#endif + (fullName = listType.FullName) != null && fullName.IndexOf("Dictionary") >= 0) // have to try to be frugal here... + { +#if COREFX || PROFILE259 + TypeInfo finalType = listType.GetTypeInfo(); + if (finalType.IsGenericType && finalType.GetGenericTypeDefinition() == typeof(System.Collections.Generic.IDictionary<,>)) + { + Type[] genericTypes = listType.GenericTypeArguments; + concreteListType = typeof(System.Collections.Generic.Dictionary<,>).MakeGenericType(genericTypes); + handled = true; + } +#else + if (listType.IsGenericType && listType.GetGenericTypeDefinition() == typeof(System.Collections.Generic.IDictionary<,>)) + { + Type[] genericTypes = listType.GetGenericArguments(); + concreteListType = typeof(System.Collections.Generic.Dictionary<,>).MakeGenericType(genericTypes); + handled = true; + } +#endif + +#if !PORTABLE && !COREFX && !PROFILE259 + if (!handled && listType == typeof(IDictionary)) + { + concreteListType = typeof(Hashtable); + handled = true; + } +#endif + } + + if (!handled) + { + concreteListType = typeof(System.Collections.Generic.List<>).MakeGenericType(itemType); + handled = true; + } + +#if !PORTABLE && !COREFX && !PROFILE259 + if (!handled) + { + concreteListType = typeof(ArrayList); + handled = true; + } +#endif + } + return Activator.CreateInstance(concreteListType); + } + + /// + /// This is the more "complete" version of Deserialize, which handles single instances of mapped types. + /// The value is read as a complete field, including field-header and (for sub-objects) a + /// length-prefix..kmc + /// + /// In addition to that, this provides support for: + /// - basic values; individual int / string / Guid / etc + /// - IList sets of any type handled by TryDeserializeAuxiliaryType + /// + internal bool TryDeserializeAuxiliaryType(ProtoReader reader, DataFormat format, int tag, Type type, ref object value, bool skipOtherFields, bool asListItem, bool autoCreate, bool insideList, object parentListOrType) + { + if (type == null) throw new ArgumentNullException(nameof(type)); + Type itemType = null; + ProtoTypeCode typecode = Helpers.GetTypeCode(type); + WireType wiretype = GetWireType(typecode, format, ref type, out int modelKey); + + bool found = false; + if (wiretype == WireType.None) + { + itemType = GetListItemType(this, type); + if (itemType == null && type.IsArray && type.GetArrayRank() == 1 && type != typeof(byte[])) + { + itemType = type.GetElementType(); + } + if (itemType != null) + { + if (insideList) throw TypeModel.CreateNestedListsNotSupported((parentListOrType as Type) ?? (parentListOrType?.GetType())); + found = TryDeserializeList(this, reader, format, tag, type, itemType, ref value); + if (!found && autoCreate) + { + value = CreateListInstance(type, itemType); + } + return found; + } + + // otherwise, not a happy bunny... + ThrowUnexpectedType(type); + } + + // to treat correctly, should read all values + + while (true) + { + // for convenience (re complex exit conditions), additional exit test here: + // if we've got the value, are only looking for one, and we aren't a list - then exit + if (found && asListItem) break; + + + // read the next item + int fieldNumber = reader.ReadFieldHeader(); + if (fieldNumber <= 0) break; + if (fieldNumber != tag) + { + if (skipOtherFields) + { + reader.SkipField(); + continue; + } + throw ProtoReader.AddErrorData(new InvalidOperationException( + "Expected field " + tag.ToString() + ", but found " + fieldNumber.ToString()), reader); + } + found = true; + reader.Hint(wiretype); // handle signed data etc + + if (modelKey >= 0) + { + switch (wiretype) + { + case WireType.String: + case WireType.StartGroup: + SubItemToken token = ProtoReader.StartSubItem(reader); + value = Deserialize(modelKey, value, reader); + ProtoReader.EndSubItem(token, reader); + continue; + default: + value = Deserialize(modelKey, value, reader); + continue; + } + } + switch (typecode) + { + case ProtoTypeCode.Int16: value = reader.ReadInt16(); continue; + case ProtoTypeCode.Int32: value = reader.ReadInt32(); continue; + case ProtoTypeCode.Int64: value = reader.ReadInt64(); continue; + case ProtoTypeCode.UInt16: value = reader.ReadUInt16(); continue; + case ProtoTypeCode.UInt32: value = reader.ReadUInt32(); continue; + case ProtoTypeCode.UInt64: value = reader.ReadUInt64(); continue; + case ProtoTypeCode.Boolean: value = reader.ReadBoolean(); continue; + case ProtoTypeCode.SByte: value = reader.ReadSByte(); continue; + case ProtoTypeCode.Byte: value = reader.ReadByte(); continue; + case ProtoTypeCode.Char: value = (char)reader.ReadUInt16(); continue; + case ProtoTypeCode.Double: value = reader.ReadDouble(); continue; + case ProtoTypeCode.Single: value = reader.ReadSingle(); continue; + case ProtoTypeCode.DateTime: value = BclHelpers.ReadDateTime(reader); continue; + case ProtoTypeCode.Decimal: value = BclHelpers.ReadDecimal(reader); continue; + case ProtoTypeCode.String: value = reader.ReadString(); continue; + case ProtoTypeCode.ByteArray: value = ProtoReader.AppendBytes((byte[])value, reader); continue; + case ProtoTypeCode.TimeSpan: value = BclHelpers.ReadTimeSpan(reader); continue; + case ProtoTypeCode.Guid: value = BclHelpers.ReadGuid(reader); continue; + case ProtoTypeCode.Uri: value = new Uri(reader.ReadString(), UriKind.RelativeOrAbsolute); continue; + } + + } + if (!found && !asListItem && autoCreate) + { + if (type != typeof(string)) + { + value = Activator.CreateInstance(type); + } + } + return found; + } + +#if !NO_RUNTIME + /// + /// Creates a new runtime model, to which the caller + /// can add support for a range of types. A model + /// can be used "as is", or can be compiled for + /// optimal performance. + /// + [Obsolete("Please use RuntimeTypeModel.Create", false)] + public static RuntimeTypeModel Create() + { + return RuntimeTypeModel.Create(); + } +#endif + + /// + /// Applies common proxy scenarios, resolving the actual type to consider + /// + protected internal static Type ResolveProxies(Type type) + { + if (type == null) return null; +#if !NO_GENERICS + if (type.IsGenericParameter) return null; + // Nullable + Type tmp = Helpers.GetUnderlyingType(type); + if (tmp != null) return tmp; +#endif + +#if !CF + // EF POCO + string fullName = type.FullName; + if (fullName != null && fullName.StartsWith("System.Data.Entity.DynamicProxies.")) + { +#if COREFX || PROFILE259 + return type.GetTypeInfo().BaseType; +#else + return type.BaseType; +#endif + } + + // NHibernate +#if PROFILE259 + IEnumerable interfaces = type.GetTypeInfo().ImplementedInterfaces; +#else + Type[] interfaces = type.GetInterfaces(); +#endif + foreach (Type t in interfaces) + { + switch (t.FullName) + { + case "NHibernate.Proxy.INHibernateProxy": + case "NHibernate.Proxy.DynamicProxy.IProxy": + case "NHibernate.Intercept.IFieldInterceptorAccessor": +#if COREFX || PROFILE259 + return type.GetTypeInfo().BaseType; +#else + return type.BaseType; +#endif + } + } +#endif + return null; + } + + /// + /// Indicates whether the supplied type is explicitly modelled by the model + /// + public bool IsDefined(Type type) => GetKey(ref type) >= 0; + + readonly Dictionary knownKeys = new Dictionary(); + + // essentially just a ValueTuple - I just don't want the extra dependency + private readonly struct KnownTypeKey + { + public KnownTypeKey(Type type, int key) + { + Type = type; + Key = key; + } + + public int Key { get; } + + public Type Type { get; } + } + + /// + /// Provides the key that represents a given type in the current model. + /// The type is also normalized for proxies at the same time. + /// + protected internal int GetKey(ref Type type) + { + if (type == null) return -1; + int key; + lock (knownKeys) + { + if (knownKeys.TryGetValue(type, out var tuple)) + { + // the type can be changed via ResolveProxies etc +#if DEBUG + var actualKey = GetKeyImpl(type); + if(actualKey != tuple.Key) + { + throw new InvalidOperationException( + $"Key cache failure; got {tuple.Key} instead of {actualKey} for '{type.Name}'"); + } +#endif + type = tuple.Type; + return tuple.Key; + } + } + key = GetKeyImpl(type); + Type originalType = type; + if (key < 0) + { + Type normalized = ResolveProxies(type); + if (normalized != null && normalized != type) + { + type = normalized; // hence ref + key = GetKeyImpl(type); + } + } + lock (knownKeys) + { + knownKeys[originalType] = new KnownTypeKey(type, key); + } + return key; + } + + /// + /// Advertise that a type's key can have changed + /// + internal void ResetKeyCache() + { + // clear *everything* (think: multi-level - can be many descendents) + lock(knownKeys) + { + knownKeys.Clear(); + } + } + + /// + /// Provides the key that represents a given type in the current model. + /// + protected abstract int GetKeyImpl(Type type); + /// + /// Writes a protocol-buffer representation of the given instance to the supplied stream. + /// + /// Represents the type (including inheritance) to consider. + /// The existing instance to be serialized (cannot be null). + /// The destination stream to write to. + protected internal abstract void Serialize(int key, object value, ProtoWriter dest); + + /// + /// Applies a protocol-buffer stream to an existing instance (which may be null). + /// + /// Represents the type (including inheritance) to consider. + /// The existing instance to be modified (can be null). + /// The binary stream to apply to the instance (cannot be null). + /// The updated instance; this may be different to the instance argument if + /// either the original instance was null, or the stream defines a known sub-type of the + /// original instance. + protected internal abstract object Deserialize(int key, object value, ProtoReader source); + + //internal ProtoSerializer Create(IProtoSerializer head) + //{ + // return new RuntimeSerializer(head, this); + //} + //internal ProtoSerializer Compile + + /// + /// Indicates the type of callback to be used + /// + protected internal enum CallbackType + { + /// + /// Invoked before an object is serialized + /// + BeforeSerialize, + /// + /// Invoked after an object is serialized + /// + AfterSerialize, + /// + /// Invoked before an object is deserialized (or when a new instance is created) + /// + BeforeDeserialize, + /// + /// Invoked after an object is deserialized + /// + AfterDeserialize + } + + /// + /// Create a deep clone of the supplied instance; any sub-items are also cloned. + /// + public object DeepClone(object value) + { + if (value == null) return null; + Type type = value.GetType(); + int key = GetKey(ref type); + + if (key >= 0 && !Helpers.IsEnum(type)) + { + using (MemoryStream ms = new MemoryStream()) + { + using (ProtoWriter writer = ProtoWriter.Create(ms, this, null)) + { + writer.SetRootObject(value); + Serialize(key, value, writer); + writer.Close(); + } + ms.Position = 0; + ProtoReader reader = null; + try + { + reader = ProtoReader.Create(ms, this, null, ProtoReader.TO_EOF); + return Deserialize(key, null, reader); + } + finally + { + ProtoReader.Recycle(reader); + } + } + } + if (type == typeof(byte[])) + { + byte[] orig = (byte[])value, clone = new byte[orig.Length]; + Buffer.BlockCopy(orig, 0, clone, 0, orig.Length); + return clone; + } + else if (GetWireType(Helpers.GetTypeCode(type), DataFormat.Default, ref type, out int modelKey) != WireType.None && modelKey < 0) + { // immutable; just return the original value + return value; + } + using (MemoryStream ms = new MemoryStream()) + { + using (ProtoWriter writer = ProtoWriter.Create(ms, this, null)) + { + if (!TrySerializeAuxiliaryType(writer, type, DataFormat.Default, Serializer.ListItemTag, value, false, null)) ThrowUnexpectedType(type); + writer.Close(); + } + ms.Position = 0; + ProtoReader reader = null; + try + { + reader = ProtoReader.Create(ms, this, null, ProtoReader.TO_EOF); + value = null; // start from scratch! + TryDeserializeAuxiliaryType(reader, DataFormat.Default, Serializer.ListItemTag, type, ref value, true, false, true, false, null); + return value; + } + finally + { + ProtoReader.Recycle(reader); + } + } + } + + /// + /// Indicates that while an inheritance tree exists, the exact type encountered was not + /// specified in that hierarchy and cannot be processed. + /// + protected internal static void ThrowUnexpectedSubtype(Type expected, Type actual) + { + if (expected != TypeModel.ResolveProxies(actual)) + { + throw new InvalidOperationException("Unexpected sub-type: " + actual.FullName); + } + } + + /// + /// Indicates that the given type was not expected, and cannot be processed. + /// + protected internal static void ThrowUnexpectedType(Type type) + { + string fullName = type == null ? "(unknown)" : type.FullName; + + if (type != null) + { + Type baseType = type +#if COREFX || PROFILE259 + .GetTypeInfo() +#endif + .BaseType; + if (baseType != null && baseType +#if COREFX || PROFILE259 + .GetTypeInfo() +#endif + .IsGenericType && baseType.GetGenericTypeDefinition().Name == "GeneratedMessage`2") + { + throw new InvalidOperationException( + "Are you mixing protobuf-net and protobuf-csharp-port? See https://stackoverflow.com/q/11564914/23354; type: " + fullName); + } + } + + throw new InvalidOperationException("Type is not expected, and no contract can be inferred: " + fullName); + } + + internal static Exception CreateNestedListsNotSupported(Type type) + { + return new NotSupportedException("Nested or jagged lists and arrays are not supported: " + (type?.FullName ?? "(null)")); + } + + /// + /// Indicates that the given type cannot be constructed; it may still be possible to + /// deserialize into existing instances. + /// + public static void ThrowCannotCreateInstance(Type type) + { + throw new ProtoException("No parameterless constructor found for " + (type?.FullName ?? "(null)")); + } + + internal static string SerializeType(TypeModel model, System.Type type) + { + if (model != null) + { + TypeFormatEventHandler handler = model.DynamicTypeFormatting; + if (handler != null) + { + TypeFormatEventArgs args = new TypeFormatEventArgs(type); + handler(model, args); + if (!string.IsNullOrEmpty(args.FormattedName)) return args.FormattedName; + } + } + return type.AssemblyQualifiedName; + } + + internal static Type DeserializeType(TypeModel model, string value) + { + + if (model != null) + { + TypeFormatEventHandler handler = model.DynamicTypeFormatting; + if (handler != null) + { + TypeFormatEventArgs args = new TypeFormatEventArgs(value); + handler(model, args); + if (args.Type != null) return args.Type; + } + } + return Type.GetType(value); + } + + /// + /// Returns true if the type supplied is either a recognised contract type, + /// or a *list* of a recognised contract type. + /// + /// Note that primitives always return false, even though the engine + /// will, if forced, try to serialize such + /// True if this type is recognised as a serializable entity, else false + public bool CanSerializeContractType(Type type) => CanSerialize(type, false, true, true); + + /// + /// Returns true if the type supplied is a basic type with inbuilt handling, + /// a recognised contract type, or a *list* of a basic / contract type. + /// + public bool CanSerialize(Type type) => CanSerialize(type, true, true, true); + + /// + /// Returns true if the type supplied is a basic type with inbuilt handling, + /// or a *list* of a basic type with inbuilt handling + /// + public bool CanSerializeBasicType(Type type) => CanSerialize(type, true, false, true); + + private bool CanSerialize(Type type, bool allowBasic, bool allowContract, bool allowLists) + { + if (type == null) throw new ArgumentNullException(nameof(type)); + Type tmp = Helpers.GetUnderlyingType(type); + if (tmp != null) type = tmp; + + // is it a basic type? + ProtoTypeCode typeCode = Helpers.GetTypeCode(type); + switch (typeCode) + { + case ProtoTypeCode.Empty: + case ProtoTypeCode.Unknown: + break; + default: + return allowBasic; // well-known basic type + } + int modelKey = GetKey(ref type); + if (modelKey >= 0) return allowContract; // known contract type + + // is it a list? + if (allowLists) + { + Type itemType = null; + if (type.IsArray) + { // note we don't need to exclude byte[], as that is handled by GetTypeCode already + if (type.GetArrayRank() == 1) itemType = type.GetElementType(); + } + else + { + itemType = GetListItemType(this, type); + } + if (itemType != null) return CanSerialize(itemType, allowBasic, allowContract, false); + } + return false; + } + + /// + /// Suggest a .proto definition for the given type + /// + /// The type to generate a .proto definition for, or null to generate a .proto that represents the entire model + /// The .proto definition as a string + public virtual string GetSchema(Type type) => GetSchema(type, ProtoSyntax.Proto2); + + /// + /// Suggest a .proto definition for the given type + /// + /// The type to generate a .proto definition for, or null to generate a .proto that represents the entire model + /// The .proto definition as a string + /// The .proto syntax to use for the operation + public virtual string GetSchema(Type type, ProtoSyntax syntax) + { + throw new NotSupportedException(); + } + + /// + /// Used to provide custom services for writing and parsing type names when using dynamic types. Both parsing and formatting + /// are provided on a single API as it is essential that both are mapped identically at all times. + /// + public event TypeFormatEventHandler DynamicTypeFormatting; + +#if PLAT_BINARYFORMATTER && !(COREFX || PROFILE259) + /// + /// Creates a new IFormatter that uses protocol-buffer [de]serialization. + /// + /// A new IFormatter to be used during [de]serialization. + /// The type of object to be [de]deserialized by the formatter. + public System.Runtime.Serialization.IFormatter CreateFormatter(Type type) + { + return new Formatter(this, type); + } + + internal sealed class Formatter : System.Runtime.Serialization.IFormatter + { + private readonly TypeModel model; + private readonly Type type; + internal Formatter(TypeModel model, Type type) + { + this.model = model ?? throw new ArgumentNullException(nameof(model)); + this.type = type ?? throw new ArgumentNullException(nameof(type)); + } + private System.Runtime.Serialization.SerializationBinder binder; + public System.Runtime.Serialization.SerializationBinder Binder + { + get { return binder; } + set { binder = value; } + } + + private System.Runtime.Serialization.StreamingContext context; + public System.Runtime.Serialization.StreamingContext Context + { + get { return context; } + set { context = value; } + } + + public object Deserialize(Stream source) + { + return model.Deserialize(source, null, type, (long)-1, Context); + } + + public void Serialize(Stream destination, object graph) + { + model.Serialize(destination, graph, Context); + } + + private System.Runtime.Serialization.ISurrogateSelector surrogateSelector; + public System.Runtime.Serialization.ISurrogateSelector SurrogateSelector + { + get { return surrogateSelector; } + set { surrogateSelector = value; } + } + } +#endif + +#if DEBUG // this is used by some unit tests only, to ensure no buffering when buffering is disabled + private bool forwardsOnly; + /// + /// If true, buffering of nested objects is disabled + /// + public bool ForwardsOnly + { + get { return forwardsOnly; } + set { forwardsOnly = value; } + } +#endif + + internal virtual Type GetType(string fullName, Assembly context) + { + return ResolveKnownType(fullName, this, context); + } + + [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)] + internal static Type ResolveKnownType(string name, TypeModel model, Assembly assembly) + { + if (string.IsNullOrEmpty(name)) return null; + try + { + Type type = Type.GetType(name); + + if (type != null) return type; + } + catch { } + try + { + int i = name.IndexOf(','); + string fullName = (i > 0 ? name.Substring(0, i) : name).Trim(); +#if !(COREFX || PROFILE259) + if (assembly == null) assembly = Assembly.GetCallingAssembly(); +#endif + Type type = assembly?.GetType(fullName); + if (type != null) return type; + } + catch { } + return null; + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Meta/TypeModel.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Meta/TypeModel.cs.meta new file mode 100644 index 0000000..cc869c3 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Meta/TypeModel.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e5eb182ec8bc8c5469c7819c0e3f7fb4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Meta/ValueMember.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Meta/ValueMember.cs new file mode 100644 index 0000000..9566312 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Meta/ValueMember.cs @@ -0,0 +1,855 @@ +#if !NO_RUNTIME +using System; + +using ProtoBuf.Serializers; +using System.Globalization; +using System.Collections.Generic; + +#if PROFILE259 +using System.Reflection; +using System.Linq; +#else +using System.Reflection; +#endif + +namespace ProtoBuf.Meta +{ + /// + /// Represents a member (property/field) that is mapped to a protobuf field + /// + public class ValueMember + { + private int _fieldNumber; + /// + /// The number that identifies this member in a protobuf stream + /// + public int FieldNumber + { + get => _fieldNumber; + internal set + { + if (_fieldNumber != value) + { + MetaType.AssertValidFieldNumber(value); + ThrowIfFrozen(); + _fieldNumber = value; + } + } + } + + private readonly MemberInfo originalMember; + private MemberInfo backingMember; + /// + /// Gets the member (field/property) which this member relates to. + /// + public MemberInfo Member { get { return originalMember; } } + /// + /// Gets the backing member (field/property) which this member relates to + /// + public MemberInfo BackingMember + { + get { return backingMember; } + set + { + if (backingMember != value) + { + ThrowIfFrozen(); + backingMember = value; + } + } + } + + private readonly Type parentType, itemType, defaultType, memberType; + private object defaultValue; + + /// + /// Within a list / array / etc, the type of object for each item in the list (especially useful with ArrayList) + /// + public Type ItemType => itemType; + + /// + /// The underlying type of the member + /// + public Type MemberType => memberType; + + /// + /// For abstract types (IList etc), the type of concrete object to create (if required) + /// + public Type DefaultType => defaultType; + + /// + /// The type the defines the member + /// + public Type ParentType => parentType; + + /// + /// The default value of the item (members with this value will not be serialized) + /// + public object DefaultValue + { + get { return defaultValue; } + set + { + if (defaultValue != value) + { + ThrowIfFrozen(); + defaultValue = value; + } + } + } + + private readonly RuntimeTypeModel model; + /// + /// Creates a new ValueMember instance + /// + public ValueMember(RuntimeTypeModel model, Type parentType, int fieldNumber, MemberInfo member, Type memberType, Type itemType, Type defaultType, DataFormat dataFormat, object defaultValue) + : this(model, fieldNumber, memberType, itemType, defaultType, dataFormat) + { + if (parentType == null) throw new ArgumentNullException("parentType"); + if (fieldNumber < 1 && !Helpers.IsEnum(parentType)) throw new ArgumentOutOfRangeException("fieldNumber"); + + this.originalMember = member ?? throw new ArgumentNullException("member"); + this.parentType = parentType; + if (fieldNumber < 1 && !Helpers.IsEnum(parentType)) throw new ArgumentOutOfRangeException("fieldNumber"); + //#if WINRT + if (defaultValue != null && model.MapType(defaultValue.GetType()) != memberType) + //#else + // if (defaultValue != null && !memberType.IsInstanceOfType(defaultValue)) + //#endif + { + defaultValue = ParseDefaultValue(memberType, defaultValue); + } + this.defaultValue = defaultValue; + + MetaType type = model.FindWithoutAdd(memberType); + if (type != null) + { + AsReference = type.AsReferenceDefault; + } + else + { // we need to scan the hard way; can't risk recursion by fully walking it + AsReference = MetaType.GetAsReferenceDefault(model, memberType); + } + } + /// + /// Creates a new ValueMember instance + /// + internal ValueMember(RuntimeTypeModel model, int fieldNumber, Type memberType, Type itemType, Type defaultType, DataFormat dataFormat) + { + _fieldNumber = fieldNumber; + this.memberType = memberType ?? throw new ArgumentNullException(nameof(memberType)); + this.itemType = itemType; + this.defaultType = defaultType; + + this.model = model ?? throw new ArgumentNullException(nameof(model)); + this.dataFormat = dataFormat; + } + internal object GetRawEnumValue() + { +#if PORTABLE || CF || COREFX || PROFILE259 + object value = ((FieldInfo)originalMember).GetValue(null); + switch(Helpers.GetTypeCode(Enum.GetUnderlyingType(((FieldInfo)originalMember).FieldType))) + { + case ProtoTypeCode.SByte: return (sbyte)value; + case ProtoTypeCode.Byte: return (byte)value; + case ProtoTypeCode.Int16: return (short)value; + case ProtoTypeCode.UInt16: return (ushort)value; + case ProtoTypeCode.Int32: return (int)value; + case ProtoTypeCode.UInt32: return (uint)value; + case ProtoTypeCode.Int64: return (long)value; + case ProtoTypeCode.UInt64: return (ulong)value; + default: + throw new InvalidOperationException(); + } +#else + return ((FieldInfo)originalMember).GetRawConstantValue(); +#endif + } + private static object ParseDefaultValue(Type type, object value) + { + { + Type tmp = Helpers.GetUnderlyingType(type); + if (tmp != null) type = tmp; + } + if (value is string s) + { + if (Helpers.IsEnum(type)) return Helpers.ParseEnum(type, s); + + switch (Helpers.GetTypeCode(type)) + { + case ProtoTypeCode.Boolean: return bool.Parse(s); + case ProtoTypeCode.Byte: return byte.Parse(s, NumberStyles.Integer, CultureInfo.InvariantCulture); + case ProtoTypeCode.Char: // char.Parse missing on CF/phone7 + if (s.Length == 1) return s[0]; + throw new FormatException("Single character expected: \"" + s + "\""); + case ProtoTypeCode.DateTime: return DateTime.Parse(s, CultureInfo.InvariantCulture); + case ProtoTypeCode.Decimal: return decimal.Parse(s, NumberStyles.Any, CultureInfo.InvariantCulture); + case ProtoTypeCode.Double: return double.Parse(s, NumberStyles.Any, CultureInfo.InvariantCulture); + case ProtoTypeCode.Int16: return short.Parse(s, NumberStyles.Any, CultureInfo.InvariantCulture); + case ProtoTypeCode.Int32: return int.Parse(s, NumberStyles.Any, CultureInfo.InvariantCulture); + case ProtoTypeCode.Int64: return long.Parse(s, NumberStyles.Any, CultureInfo.InvariantCulture); + case ProtoTypeCode.SByte: return sbyte.Parse(s, NumberStyles.Integer, CultureInfo.InvariantCulture); + case ProtoTypeCode.Single: return float.Parse(s, NumberStyles.Any, CultureInfo.InvariantCulture); + case ProtoTypeCode.String: return s; + case ProtoTypeCode.UInt16: return ushort.Parse(s, NumberStyles.Any, CultureInfo.InvariantCulture); + case ProtoTypeCode.UInt32: return uint.Parse(s, NumberStyles.Any, CultureInfo.InvariantCulture); + case ProtoTypeCode.UInt64: return ulong.Parse(s, NumberStyles.Any, CultureInfo.InvariantCulture); + case ProtoTypeCode.TimeSpan: return TimeSpan.Parse(s); + case ProtoTypeCode.Uri: return s; // Uri is decorated as string + case ProtoTypeCode.Guid: return new Guid(s); + } + } + + if (Helpers.IsEnum(type)) return Enum.ToObject(type, value); + return Convert.ChangeType(value, type, CultureInfo.InvariantCulture); + + } + + private IProtoSerializer serializer; + internal IProtoSerializer Serializer + { + get + { + return serializer ?? (serializer = BuildSerializer()); + } + } + + private DataFormat dataFormat; + /// + /// Specifies the rules used to process the field; this is used to determine the most appropriate + /// wite-type, but also to describe subtypes within that wire-type (such as SignedVariant) + /// + public DataFormat DataFormat + { + get { return dataFormat; } + set + { + if (value != dataFormat) + { + ThrowIfFrozen(); + this.dataFormat = value; + } + } + } + + /// + /// Indicates whether this field should follow strict encoding rules; this means (for example) that if a "fixed32" + /// is encountered when "variant" is defined, then it will fail (throw an exception) when parsing. Note that + /// when serializing the defined type is always used. + /// + public bool IsStrict + { + get { return HasFlag(OPTIONS_IsStrict); } + set { SetFlag(OPTIONS_IsStrict, value, true); } + } + + /// + /// Indicates whether this field should use packed encoding (which can save lots of space for repeated primitive values). + /// This option only applies to list/array data of primitive types (int, double, etc). + /// + public bool IsPacked + { + get { return HasFlag(OPTIONS_IsPacked); } + set { SetFlag(OPTIONS_IsPacked, value, true); } + } + + /// + /// Indicates whether this field should *repace* existing values (the default is false, meaning *append*). + /// This option only applies to list/array data. + /// + public bool OverwriteList + { + get { return HasFlag(OPTIONS_OverwriteList); } + set { SetFlag(OPTIONS_OverwriteList, value, true); } + } + + /// + /// Indicates whether this field is mandatory. + /// + public bool IsRequired + { + get { return HasFlag(OPTIONS_IsRequired); } + set { SetFlag(OPTIONS_IsRequired, value, true); } + } + + /// + /// Enables full object-tracking/full-graph support. + /// + public bool AsReference + { + get { return HasFlag(OPTIONS_AsReference); } + set { SetFlag(OPTIONS_AsReference, value, true); } + } + + /// + /// Embeds the type information into the stream, allowing usage with types not known in advance. + /// + public bool DynamicType + { + get { return HasFlag(OPTIONS_DynamicType); } + set { SetFlag(OPTIONS_DynamicType, value, true); } + } + + /// + /// Indicates that the member should be treated as a protobuf Map + /// + public bool IsMap + { + get { return HasFlag(OPTIONS_IsMap); } + set { SetFlag(OPTIONS_IsMap, value, true); } + } + + private DataFormat mapKeyFormat, mapValueFormat; + /// + /// Specifies the data-format that should be used for the key, when IsMap is enabled + /// + public DataFormat MapKeyFormat + { + get { return mapKeyFormat; } + set + { + if (mapKeyFormat != value) + { + ThrowIfFrozen(); + mapKeyFormat = value; + } + } + } + /// + /// Specifies the data-format that should be used for the value, when IsMap is enabled + /// + public DataFormat MapValueFormat + { + get { return mapValueFormat; } + set + { + if (mapValueFormat != value) + { + ThrowIfFrozen(); + mapValueFormat = value; + } + } + } + + private MethodInfo getSpecified, setSpecified; + /// + /// Specifies methods for working with optional data members. + /// + /// Provides a method (null for none) to query whether this member should + /// be serialized; it must be of the form "bool {Method}()". The member is only serialized if the + /// method returns true. + /// Provides a method (null for none) to indicate that a member was + /// deserialized; it must be of the form "void {Method}(bool)", and will be called with "true" + /// when data is found. + public void SetSpecified(MethodInfo getSpecified, MethodInfo setSpecified) + { + if (this.getSpecified != getSpecified || this.setSpecified != setSpecified) + { + if (getSpecified != null) + { + if (getSpecified.ReturnType != model.MapType(typeof(bool)) + || getSpecified.IsStatic + || getSpecified.GetParameters().Length != 0) + { + throw new ArgumentException("Invalid pattern for checking member-specified", "getSpecified"); + } + } + if (setSpecified != null) + { + ParameterInfo[] args; + if (setSpecified.ReturnType != model.MapType(typeof(void)) + || setSpecified.IsStatic + || (args = setSpecified.GetParameters()).Length != 1 + || args[0].ParameterType != model.MapType(typeof(bool))) + { + throw new ArgumentException("Invalid pattern for setting member-specified", "setSpecified"); + } + } + + ThrowIfFrozen(); + this.getSpecified = getSpecified; + this.setSpecified = setSpecified; + } + } + + private void ThrowIfFrozen() + { + if (serializer != null) throw new InvalidOperationException("The type cannot be changed once a serializer has been generated"); + } + + internal bool ResolveMapTypes(out Type dictionaryType, out Type keyType, out Type valueType) + { + dictionaryType = keyType = valueType = null; + try + { +#if COREFX || PROFILE259 + var info = memberType.GetTypeInfo(); +#else + var info = memberType; +#endif + if (ImmutableCollectionDecorator.IdentifyImmutable(model, MemberType, out _, out _, out _, out _, out _, out _)) + { + return false; + } + if (info.IsInterface && info.IsGenericType && info.GetGenericTypeDefinition() == typeof(IDictionary<,>)) + { +#if PROFILE259 + var typeArgs = memberType.GetGenericTypeDefinition().GenericTypeArguments; +#else + var typeArgs = memberType.GetGenericArguments(); +#endif + if (IsValidMapKeyType(typeArgs[0])) + { + keyType = typeArgs[0]; + valueType = typeArgs[1]; + dictionaryType = memberType; + } + return false; + } +#if PROFILE259 + foreach (var iType in memberType.GetTypeInfo().ImplementedInterfaces) +#else + foreach (var iType in memberType.GetInterfaces()) +#endif + { +#if COREFX || PROFILE259 + info = iType.GetTypeInfo(); +#else + info = iType; +#endif + if (info.IsGenericType && info.GetGenericTypeDefinition() == typeof(IDictionary<,>)) + { + if (dictionaryType != null) throw new InvalidOperationException("Multiple dictionary interfaces implemented by type: " + memberType.FullName); +#if PROFILE259 + var typeArgs = iType.GetGenericTypeDefinition().GenericTypeArguments; +#else + var typeArgs = iType.GetGenericArguments(); +#endif + if (IsValidMapKeyType(typeArgs[0])) + { + keyType = typeArgs[0]; + valueType = typeArgs[1]; + dictionaryType = memberType; + } + } + } + if (dictionaryType == null) return false; + + // (note we checked the key type already) + // not a map if value is repeated + Type itemType = null, defaultType = null; + model.ResolveListTypes(valueType, ref itemType, ref defaultType); + if (itemType != null) return false; + + return dictionaryType != null; + } + catch + { + // if it isn't a good fit; don't use "map" + return false; + } + } + + static bool IsValidMapKeyType(Type type) + { + if (type == null || Helpers.IsEnum(type)) return false; + switch (Helpers.GetTypeCode(type)) + { + case ProtoTypeCode.Boolean: + case ProtoTypeCode.Byte: + case ProtoTypeCode.Char: + case ProtoTypeCode.Int16: + case ProtoTypeCode.Int32: + case ProtoTypeCode.Int64: + case ProtoTypeCode.String: + + case ProtoTypeCode.SByte: + case ProtoTypeCode.UInt16: + case ProtoTypeCode.UInt32: + case ProtoTypeCode.UInt64: + return true; + } + return false; + } + private IProtoSerializer BuildSerializer() + { + int opaqueToken = 0; + try + { + model.TakeLock(ref opaqueToken);// check nobody is still adding this type + var member = backingMember ?? originalMember; + IProtoSerializer ser; + if (IsMap) + { + ResolveMapTypes(out var dictionaryType, out var keyType, out var valueType); + + if (dictionaryType == null) + { + throw new InvalidOperationException("Unable to resolve map type for type: " + memberType.FullName); + } + var concreteType = defaultType; + if (concreteType == null && Helpers.IsClass(memberType)) + { + concreteType = memberType; + } + var keySer = TryGetCoreSerializer(model, MapKeyFormat, keyType, out var keyWireType, false, false, false, false); + if (!AsReference) + { + AsReference = MetaType.GetAsReferenceDefault(model, valueType); + } + var valueSer = TryGetCoreSerializer(model, MapValueFormat, valueType, out var valueWireType, AsReference, DynamicType, false, true); +#if PROFILE259 + IEnumerable ctors = typeof(MapDecorator<,,>).MakeGenericType(new Type[] { dictionaryType, keyType, valueType }).GetTypeInfo().DeclaredConstructors; + if (ctors.Count() != 1) + { + throw new InvalidOperationException("Unable to resolve MapDecorator constructor"); + } + ser = (IProtoSerializer)ctors.First().Invoke(new object[] {model, concreteType, keySer, valueSer, _fieldNumber, + DataFormat == DataFormat.Group ? WireType.StartGroup : WireType.String, keyWireType, valueWireType, OverwriteList }); +#else + var ctors = typeof(MapDecorator<,,>).MakeGenericType(new Type[] { dictionaryType, keyType, valueType }).GetConstructors( + BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance); + if (ctors.Length != 1) throw new InvalidOperationException("Unable to resolve MapDecorator constructor"); + ser = (IProtoSerializer)ctors[0].Invoke(new object[] {model, concreteType, keySer, valueSer, _fieldNumber, + DataFormat == DataFormat.Group ? WireType.StartGroup : WireType.String, keyWireType, valueWireType, OverwriteList }); +#endif + } + else + { + Type finalType = itemType ?? memberType; + ser = TryGetCoreSerializer(model, dataFormat, finalType, out WireType wireType, AsReference, DynamicType, OverwriteList, true); + if (ser == null) + { + throw new InvalidOperationException("No serializer defined for type: " + finalType.FullName); + } + + // apply tags + if (itemType != null && SupportNull) + { + if (IsPacked) + { + throw new NotSupportedException("Packed encodings cannot support null values"); + } + ser = new TagDecorator(NullDecorator.Tag, wireType, IsStrict, ser); + ser = new NullDecorator(model, ser); + ser = new TagDecorator(_fieldNumber, WireType.StartGroup, false, ser); + } + else + { + ser = new TagDecorator(_fieldNumber, wireType, IsStrict, ser); + } + // apply lists if appropriate + if (itemType != null) + { + Type underlyingItemType = SupportNull ? itemType : Helpers.GetUnderlyingType(itemType) ?? itemType; + + Helpers.DebugAssert(underlyingItemType == ser.ExpectedType + || (ser.ExpectedType == model.MapType(typeof(object)) && !Helpers.IsValueType(underlyingItemType)) + , "Wrong type in the tail; expected {0}, received {1}", ser.ExpectedType, underlyingItemType); + if (memberType.IsArray) + { + ser = new ArrayDecorator(model, ser, _fieldNumber, IsPacked, wireType, memberType, OverwriteList, SupportNull); + } + else + { + ser = ListDecorator.Create(model, memberType, defaultType, ser, _fieldNumber, IsPacked, wireType, member != null && PropertyDecorator.CanWrite(model, member), OverwriteList, SupportNull); + } + } + else if (defaultValue != null && !IsRequired && getSpecified == null) + { // note: "ShouldSerialize*" / "*Specified" / etc ^^^^ take precedence over defaultValue, + // as does "IsRequired" + ser = new DefaultValueDecorator(model, defaultValue, ser); + } + if (memberType == model.MapType(typeof(Uri))) + { + ser = new UriDecorator(model, ser); + } +#if PORTABLE + else if(memberType.FullName == typeof(Uri).FullName) + { + // In PCLs, the Uri type may not match (WinRT uses Internal/Uri, .Net uses System/Uri) + ser = new ReflectedUriDecorator(memberType, model, ser); + } +#endif + } + if (member != null) + { + if (member is PropertyInfo prop) + { + ser = new PropertyDecorator(model, parentType, prop, ser); + } + else if (member is FieldInfo fld) + { + ser = new FieldDecorator(parentType, fld, ser); + } + else + { + throw new InvalidOperationException(); + } + + if (getSpecified != null || setSpecified != null) + { + ser = new MemberSpecifiedDecorator(getSpecified, setSpecified, ser); + } + } + return ser; + } + finally + { + model.ReleaseLock(opaqueToken); + } + } + + private static WireType GetIntWireType(DataFormat format, int width) + { + switch (format) + { + case DataFormat.ZigZag: return WireType.SignedVariant; + case DataFormat.FixedSize: return width == 32 ? WireType.Fixed32 : WireType.Fixed64; + case DataFormat.TwosComplement: + case DataFormat.Default: return WireType.Variant; + default: throw new InvalidOperationException(); + } + } + private static WireType GetDateTimeWireType(DataFormat format) + { + switch (format) + { + + case DataFormat.Group: return WireType.StartGroup; + case DataFormat.FixedSize: return WireType.Fixed64; + case DataFormat.WellKnown: + case DataFormat.Default: + return WireType.String; + default: throw new InvalidOperationException(); + } + } + + internal static IProtoSerializer TryGetCoreSerializer(RuntimeTypeModel model, DataFormat dataFormat, Type type, out WireType defaultWireType, + bool asReference, bool dynamicType, bool overwriteList, bool allowComplexTypes) + { + { + Type tmp = Helpers.GetUnderlyingType(type); + if (tmp != null) type = tmp; + } + if (Helpers.IsEnum(type)) + { + if (allowComplexTypes && model != null) + { + // need to do this before checking the typecode; an int enum will report Int32 etc + defaultWireType = WireType.Variant; + return new EnumSerializer(type, model.GetEnumMap(type)); + } + else + { // enum is fine for adding as a meta-type + defaultWireType = WireType.None; + return null; + } + } + ProtoTypeCode code = Helpers.GetTypeCode(type); + switch (code) + { + case ProtoTypeCode.Int32: + defaultWireType = GetIntWireType(dataFormat, 32); + return new Int32Serializer(model); + case ProtoTypeCode.UInt32: + defaultWireType = GetIntWireType(dataFormat, 32); + return new UInt32Serializer(model); + case ProtoTypeCode.Int64: + defaultWireType = GetIntWireType(dataFormat, 64); + return new Int64Serializer(model); + case ProtoTypeCode.UInt64: + defaultWireType = GetIntWireType(dataFormat, 64); + return new UInt64Serializer(model); + case ProtoTypeCode.String: + defaultWireType = WireType.String; + if (asReference) + { + return new NetObjectSerializer(model, model.MapType(typeof(string)), 0, BclHelpers.NetObjectOptions.AsReference); + } + return new StringSerializer(model); + case ProtoTypeCode.Single: + defaultWireType = WireType.Fixed32; + return new SingleSerializer(model); + case ProtoTypeCode.Double: + defaultWireType = WireType.Fixed64; + return new DoubleSerializer(model); + case ProtoTypeCode.Boolean: + defaultWireType = WireType.Variant; + return new BooleanSerializer(model); + case ProtoTypeCode.DateTime: + defaultWireType = GetDateTimeWireType(dataFormat); + return new DateTimeSerializer(dataFormat, model); + case ProtoTypeCode.Decimal: + defaultWireType = WireType.String; + return new DecimalSerializer(model); + case ProtoTypeCode.Byte: + defaultWireType = GetIntWireType(dataFormat, 32); + return new ByteSerializer(model); + case ProtoTypeCode.SByte: + defaultWireType = GetIntWireType(dataFormat, 32); + return new SByteSerializer(model); + case ProtoTypeCode.Char: + defaultWireType = WireType.Variant; + return new CharSerializer(model); + case ProtoTypeCode.Int16: + defaultWireType = GetIntWireType(dataFormat, 32); + return new Int16Serializer(model); + case ProtoTypeCode.UInt16: + defaultWireType = GetIntWireType(dataFormat, 32); + return new UInt16Serializer(model); + case ProtoTypeCode.TimeSpan: + defaultWireType = GetDateTimeWireType(dataFormat); + return new TimeSpanSerializer(dataFormat, model); + case ProtoTypeCode.Guid: + defaultWireType = dataFormat == DataFormat.Group ? WireType.StartGroup : WireType.String; + return new GuidSerializer(model); + case ProtoTypeCode.Uri: + defaultWireType = WireType.String; + return new StringSerializer(model); + case ProtoTypeCode.ByteArray: + defaultWireType = WireType.String; + return new BlobSerializer(model, overwriteList); + case ProtoTypeCode.Type: + defaultWireType = WireType.String; + return new SystemTypeSerializer(model); + } + IProtoSerializer parseable = model.AllowParseableTypes ? ParseableSerializer.TryCreate(type, model) : null; + if (parseable != null) + { + defaultWireType = WireType.String; + return parseable; + } + if (allowComplexTypes && model != null) + { + int key = model.GetKey(type, false, true); + MetaType meta = null; + if (key >= 0) + { + meta = model[type]; + if (dataFormat == DataFormat.Default && meta.IsGroup) + { + dataFormat = DataFormat.Group; + } + } + + if (asReference || dynamicType) + { + BclHelpers.NetObjectOptions options = BclHelpers.NetObjectOptions.None; + if (asReference) options |= BclHelpers.NetObjectOptions.AsReference; + if (dynamicType) options |= BclHelpers.NetObjectOptions.DynamicType; + if (meta != null) + { // exists + if (asReference && Helpers.IsValueType(type)) + { + string message = "AsReference cannot be used with value-types"; + + if (type.Name == "KeyValuePair`2") + { + message += "; please see https://stackoverflow.com/q/14436606/23354"; + } + else + { + message += ": " + type.FullName; + } + throw new InvalidOperationException(message); + } + + if (asReference && meta.IsAutoTuple) options |= BclHelpers.NetObjectOptions.LateSet; + if (meta.UseConstructor) options |= BclHelpers.NetObjectOptions.UseConstructor; + } + defaultWireType = dataFormat == DataFormat.Group ? WireType.StartGroup : WireType.String; + return new NetObjectSerializer(model, type, key, options); + } + if (key >= 0) + { + defaultWireType = dataFormat == DataFormat.Group ? WireType.StartGroup : WireType.String; + return new SubItemSerializer(type, key, meta, true); + } + } + defaultWireType = WireType.None; + return null; + } + + + private string name; + internal void SetName(string name) + { + if (name != this.name) + { + ThrowIfFrozen(); + this.name = name; + } + } + /// + /// Gets the logical name for this member in the schema (this is not critical for binary serialization, but may be used + /// when inferring a schema). + /// + public string Name + { + get { return string.IsNullOrEmpty(name) ? originalMember.Name : name; } + set { SetName(value); } + } + + private const byte + OPTIONS_IsStrict = 1, + OPTIONS_IsPacked = 2, + OPTIONS_IsRequired = 4, + OPTIONS_OverwriteList = 8, + OPTIONS_SupportNull = 16, + OPTIONS_AsReference = 32, + OPTIONS_IsMap = 64, + OPTIONS_DynamicType = 128; + + private byte flags; + private bool HasFlag(byte flag) { return (flags & flag) == flag; } + private void SetFlag(byte flag, bool value, bool throwIfFrozen) + { + if (throwIfFrozen && HasFlag(flag) != value) + { + ThrowIfFrozen(); + } + if (value) + flags |= flag; + else + flags = (byte)(flags & ~flag); + } + + /// + /// Should lists have extended support for null values? Note this makes the serialization less efficient. + /// + public bool SupportNull + { + get { return HasFlag(OPTIONS_SupportNull); } + set { SetFlag(OPTIONS_SupportNull, value, true); } + } + + internal string GetSchemaTypeName(bool applyNetObjectProxy, ref RuntimeTypeModel.CommonImports imports) + { + Type effectiveType = ItemType; + if (effectiveType == null) effectiveType = MemberType; + return model.GetSchemaTypeName(effectiveType, DataFormat, applyNetObjectProxy && AsReference, applyNetObjectProxy && DynamicType, ref imports); + } + + + internal sealed class Comparer : System.Collections.IComparer, IComparer + { + public static readonly Comparer Default = new Comparer(); + + public int Compare(object x, object y) + { + return Compare(x as ValueMember, y as ValueMember); + } + + public int Compare(ValueMember x, ValueMember y) + { + if (ReferenceEquals(x, y)) return 0; + if (x == null) return -1; + if (y == null) return 1; + + return x.FieldNumber.CompareTo(y.FieldNumber); + } + } + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Meta/ValueMember.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Meta/ValueMember.cs.meta new file mode 100644 index 0000000..d3eeb78 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Meta/ValueMember.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: dba7fd2d1d1c883469e153f7ac5fdd86 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/NetObjectCache.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/NetObjectCache.cs new file mode 100644 index 0000000..8e83549 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/NetObjectCache.cs @@ -0,0 +1,190 @@ +using System; +using System.Collections.Generic; +using ProtoBuf.Meta; + +namespace ProtoBuf +{ + internal sealed class NetObjectCache + { + internal const int Root = 0; + private MutableList underlyingList; + + private MutableList List => underlyingList ?? (underlyingList = new MutableList()); + + internal object GetKeyedObject(int key) + { + if (key-- == Root) + { + if (rootObject == null) throw new ProtoException("No root object assigned"); + return rootObject; + } + BasicList list = List; + + if (key < 0 || key >= list.Count) + { + Helpers.DebugWriteLine("Missing key: " + key); + throw new ProtoException("Internal error; a missing key occurred"); + } + + object tmp = list[key]; + if (tmp == null) + { + throw new ProtoException("A deferred key does not have a value yet"); + } + return tmp; + } + + internal void SetKeyedObject(int key, object value) + { + if (key-- == Root) + { + if (value == null) throw new ArgumentNullException(nameof(value)); + if (rootObject != null && ((object)rootObject != (object)value)) throw new ProtoException("The root object cannot be reassigned"); + rootObject = value; + } + else + { + MutableList list = List; + if (key < list.Count) + { + object oldVal = list[key]; + if (oldVal == null) + { + list[key] = value; + } + else if (!ReferenceEquals(oldVal, value)) + { + throw new ProtoException("Reference-tracked objects cannot change reference"); + } // otherwise was the same; nothing to do + } + else if (key != list.Add(value)) + { + throw new ProtoException("Internal error; a key mismatch occurred"); + } + } + } + + private object rootObject; + internal int AddObjectKey(object value, out bool existing) + { + if (value == null) throw new ArgumentNullException(nameof(value)); + + if ((object)value == (object)rootObject) // (object) here is no-op, but should be + { // preserved even if this was typed - needs ref-check + existing = true; + return Root; + } + + string s = value as string; + BasicList list = List; + int index; + + if (s == null) + { +#if CF || PORTABLE // CF has very limited proper object ref-tracking; so instead, we'll search it the hard way + index = list.IndexOfReference(value); +#else + if (objectKeys == null) + { + objectKeys = new Dictionary(ReferenceComparer.Default); + index = -1; + } + else + { + if (!objectKeys.TryGetValue(value, out index)) index = -1; + } +#endif + } + else + { + if (stringKeys == null) + { + stringKeys = new Dictionary(); + index = -1; + } + else + { + if (!stringKeys.TryGetValue(s, out index)) index = -1; + } + } + + if (!(existing = index >= 0)) + { + index = list.Add(value); + + if (s == null) + { +#if !CF && !PORTABLE // CF can't handle the object keys very well + objectKeys.Add(value, index); +#endif + } + else + { + stringKeys.Add(s, index); + } + } + return index + 1; + } + + private int trapStartIndex; // defaults to 0 - optimization for RegisterTrappedObject + // to make it faster at seeking to find deferred-objects + + internal void RegisterTrappedObject(object value) + { + if (rootObject == null) + { + rootObject = value; + } + else + { + if (underlyingList != null) + { + for (int i = trapStartIndex; i < underlyingList.Count; i++) + { + trapStartIndex = i + 1; // things never *become* null; whether or + // not the next item is null, it will never + // need to be checked again + + if (underlyingList[i] == null) + { + underlyingList[i] = value; + break; + } + } + } + } + } + + private Dictionary stringKeys; + +#if !CF && !PORTABLE // CF lacks the ability to get a robust reference-based hash-code, so we'll do it the harder way instead + private System.Collections.Generic.Dictionary objectKeys; + private sealed class ReferenceComparer : IEqualityComparer + { + public readonly static ReferenceComparer Default = new ReferenceComparer(); + private ReferenceComparer() { } + + bool IEqualityComparer.Equals(object x, object y) + { + return x == y; // ref equality + } + + int IEqualityComparer.GetHashCode(object obj) + { + return System.Runtime.CompilerServices.RuntimeHelpers.GetHashCode(obj); + } + } +#endif + + internal void Clear() + { + trapStartIndex = 0; + rootObject = null; + if (underlyingList != null) underlyingList.Clear(); + if (stringKeys != null) stringKeys.Clear(); +#if !CF && !PORTABLE + if (objectKeys != null) objectKeys.Clear(); +#endif + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/NetObjectCache.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/NetObjectCache.cs.meta new file mode 100644 index 0000000..862acc0 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/NetObjectCache.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a7ec59f6037764d43b3d585baf2343e2 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/PrefixStyle.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/PrefixStyle.cs new file mode 100644 index 0000000..0ebef04 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/PrefixStyle.cs @@ -0,0 +1,26 @@ + +namespace ProtoBuf +{ + /// + /// Specifies the type of prefix that should be applied to messages. + /// + public enum PrefixStyle + { + /// + /// No length prefix is applied to the data; the data is terminated only be the end of the stream. + /// + None = 0, + /// + /// A base-128 ("varint", the default prefix format in protobuf) length prefix is applied to the data (efficient for short messages). + /// + Base128 = 1, + /// + /// A fixed-length (little-endian) length prefix is applied to the data (useful for compatibility). + /// + Fixed32 = 2, + /// + /// A fixed-length (big-endian) length prefix is applied to the data (useful for compatibility). + /// + Fixed32BigEndian = 3 + } +} diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/PrefixStyle.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/PrefixStyle.cs.meta new file mode 100644 index 0000000..a955c1f --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/PrefixStyle.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c6f16948bce1f2d4eb805ed31a2bb878 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/ProtoContractAttribute.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/ProtoContractAttribute.cs new file mode 100644 index 0000000..e2e8054 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/ProtoContractAttribute.cs @@ -0,0 +1,175 @@ +using System; + +namespace ProtoBuf +{ + /// + /// Indicates that a type is defined for protocol-buffer serialization. + /// + [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum | AttributeTargets.Interface, + AllowMultiple = false, Inherited = false)] + public sealed class ProtoContractAttribute : Attribute + { + /// + /// Gets or sets the defined name of the type. + /// + public string Name { get; set; } + + /// + /// Gets or sets the fist offset to use with implicit field tags; + /// only uesd if ImplicitFields is set. + /// + public int ImplicitFirstTag + { + get { return implicitFirstTag; } + set + { + if (value < 1) throw new ArgumentOutOfRangeException("ImplicitFirstTag"); + implicitFirstTag = value; + } + } + private int implicitFirstTag; + + /// + /// If specified, alternative contract markers (such as markers for XmlSerailizer or DataContractSerializer) are ignored. + /// + public bool UseProtoMembersOnly + { + get { return HasFlag(OPTIONS_UseProtoMembersOnly); } + set { SetFlag(OPTIONS_UseProtoMembersOnly, value); } + } + + /// + /// If specified, do NOT treat this type as a list, even if it looks like one. + /// + public bool IgnoreListHandling + { + get { return HasFlag(OPTIONS_IgnoreListHandling); } + set { SetFlag(OPTIONS_IgnoreListHandling, value); } + } + + /// + /// Gets or sets the mechanism used to automatically infer field tags + /// for members. This option should be used in advanced scenarios only. + /// Please review the important notes against the ImplicitFields enumeration. + /// + public ImplicitFields ImplicitFields { get; set; } + + /// + /// Enables/disables automatic tag generation based on the existing name / order + /// of the defined members. This option is not used for members marked + /// with ProtoMemberAttribute, as intended to provide compatibility with + /// WCF serialization. WARNING: when adding new fields you must take + /// care to increase the Order for new elements, otherwise data corruption + /// may occur. + /// + /// If not explicitly specified, the default is assumed from Serializer.GlobalOptions.InferTagFromName. + public bool InferTagFromName + { + get { return HasFlag(OPTIONS_InferTagFromName); } + set + { + SetFlag(OPTIONS_InferTagFromName, value); + SetFlag(OPTIONS_InferTagFromNameHasValue, true); + } + } + + /// + /// Has a InferTagFromName value been explicitly set? if not, the default from the type-model is assumed. + /// + internal bool InferTagFromNameHasValue + { // note that this property is accessed via reflection and should not be removed + get { return HasFlag(OPTIONS_InferTagFromNameHasValue); } + } + + /// + /// Specifies an offset to apply to [DataMember(Order=...)] markers; + /// this is useful when working with mex-generated classes that have + /// a different origin (usually 1 vs 0) than the original data-contract. + /// + /// This value is added to the Order of each member. + /// + public int DataMemberOffset { get; set; } + + /// + /// If true, the constructor for the type is bypassed during deserialization, meaning any field initializers + /// or other initialization code is skipped. + /// + public bool SkipConstructor + { + get { return HasFlag(OPTIONS_SkipConstructor); } + set { SetFlag(OPTIONS_SkipConstructor, value); } + } + + /// + /// Should this type be treated as a reference by default? Please also see the implications of this, + /// as recorded on ProtoMemberAttribute.AsReference + /// + public bool AsReferenceDefault + { + get { return HasFlag(OPTIONS_AsReferenceDefault); } + set + { + SetFlag(OPTIONS_AsReferenceDefault, value); + } + } + + /// + /// Indicates whether this type should always be treated as a "group" (rather than a string-prefixed sub-message) + /// + public bool IsGroup + { + get { return HasFlag(OPTIONS_IsGroup); } + set + { + SetFlag(OPTIONS_IsGroup, value); + } + } + + private bool HasFlag(ushort flag) { return (flags & flag) == flag; } + private void SetFlag(ushort flag, bool value) + { + if (value) flags |= flag; + else flags = (ushort)(flags & ~flag); + } + + private ushort flags; + + private const ushort + OPTIONS_InferTagFromName = 1, + OPTIONS_InferTagFromNameHasValue = 2, + OPTIONS_UseProtoMembersOnly = 4, + OPTIONS_SkipConstructor = 8, + OPTIONS_IgnoreListHandling = 16, + OPTIONS_AsReferenceDefault = 32, + OPTIONS_EnumPassthru = 64, + OPTIONS_EnumPassthruHasValue = 128, + OPTIONS_IsGroup = 256; + + /// + /// Applies only to enums (not to DTO classes themselves); gets or sets a value indicating that an enum should be treated directly as an int/short/etc, rather + /// than enforcing .proto enum rules. This is useful *in particul* for [Flags] enums. + /// + public bool EnumPassthru + { + get { return HasFlag(OPTIONS_EnumPassthru); } + set + { + SetFlag(OPTIONS_EnumPassthru, value); + SetFlag(OPTIONS_EnumPassthruHasValue, true); + } + } + + /// + /// Allows to define a surrogate type used for serialization/deserialization purpose. + /// + public Type Surrogate { get; set; } + + /// + /// Has a EnumPassthru value been explicitly set? + /// + internal bool EnumPassthruHasValue + { // note that this property is accessed via reflection and should not be removed + get { return HasFlag(OPTIONS_EnumPassthruHasValue); } + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/ProtoContractAttribute.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/ProtoContractAttribute.cs.meta new file mode 100644 index 0000000..d000688 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/ProtoContractAttribute.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e5d57dba877f0854c999b91a6514d93d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/ProtoConverterAttribute.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/ProtoConverterAttribute.cs new file mode 100644 index 0000000..b75bb80 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/ProtoConverterAttribute.cs @@ -0,0 +1,13 @@ +using System; + +namespace ProtoBuf +{ + /// + /// Indicates that a static member should be considered the same as though + /// were an implicit / explicit conversion operator; in particular, this + /// is useful for conversions that operator syntax does not allow, such as + /// to/from interface types. + /// + [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)] + public class ProtoConverterAttribute : Attribute { } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/ProtoConverterAttribute.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/ProtoConverterAttribute.cs.meta new file mode 100644 index 0000000..323a3a4 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/ProtoConverterAttribute.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 399681000a748834f87d721feda5f459 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/ProtoEnumAttribute.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/ProtoEnumAttribute.cs new file mode 100644 index 0000000..1d82645 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/ProtoEnumAttribute.cs @@ -0,0 +1,36 @@ +using System; + +namespace ProtoBuf +{ + /// + /// Used to define protocol-buffer specific behavior for + /// enumerated values. + /// + [AttributeUsage(AttributeTargets.Field, AllowMultiple = false)] + public sealed class ProtoEnumAttribute : Attribute + { + /// + /// Gets or sets the specific value to use for this enum during serialization. + /// + public int Value + { + get { return enumValue; } + set { this.enumValue = value; hasValue = true; } + } + + /// + /// Indicates whether this instance has a customised value mapping + /// + /// true if a specific value is set + public bool HasValue() => hasValue; + + private bool hasValue; + private int enumValue; + + /// + /// Gets or sets the defined name of the enum, as used in .proto + /// (this name is not used during serialization). + /// + public string Name { get; set; } + } +} diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/ProtoEnumAttribute.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/ProtoEnumAttribute.cs.meta new file mode 100644 index 0000000..a5cada9 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/ProtoEnumAttribute.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3b3e030ed91e74b49b87bb0cd9acf139 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/ProtoException.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/ProtoException.cs new file mode 100644 index 0000000..f502527 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/ProtoException.cs @@ -0,0 +1,30 @@ +using System; + +#if PLAT_BINARYFORMATTER && !(COREFX || PROFILE259) +using System.Runtime.Serialization; +#endif +namespace ProtoBuf +{ + /// + /// Indicates an error during serialization/deserialization of a proto stream. + /// +#if PLAT_BINARYFORMATTER && !(COREFX || PROFILE259) + [Serializable] +#endif + public class ProtoException : Exception + { + /// Creates a new ProtoException instance. + public ProtoException() { } + + /// Creates a new ProtoException instance. + public ProtoException(string message) : base(message) { } + + /// Creates a new ProtoException instance. + public ProtoException(string message, Exception innerException) : base(message, innerException) { } + +#if PLAT_BINARYFORMATTER && !(COREFX || PROFILE259) + /// Creates a new ProtoException instance. + protected ProtoException(SerializationInfo info, StreamingContext context) : base(info, context) { } +#endif + } +} diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/ProtoException.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/ProtoException.cs.meta new file mode 100644 index 0000000..28099e5 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/ProtoException.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8629683d41766534fa00bcb5d1a324e0 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/ProtoIgnoreAttribute.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/ProtoIgnoreAttribute.cs new file mode 100644 index 0000000..775674e --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/ProtoIgnoreAttribute.cs @@ -0,0 +1,40 @@ +using System; + +namespace ProtoBuf +{ + /// + /// Indicates that a member should be excluded from serialization; this + /// is only normally used when using implict fields. + /// + [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, + AllowMultiple = false, Inherited = true)] + public class ProtoIgnoreAttribute : Attribute { } + + /// + /// Indicates that a member should be excluded from serialization; this + /// is only normally used when using implict fields. This allows + /// ProtoIgnoreAttribute usage + /// even for partial classes where the individual members are not + /// under direct control. + /// + [AttributeUsage(AttributeTargets.Class, + AllowMultiple = true, Inherited = false)] + public sealed class ProtoPartialIgnoreAttribute : ProtoIgnoreAttribute + { + /// + /// Creates a new ProtoPartialIgnoreAttribute instance. + /// + /// Specifies the member to be ignored. + public ProtoPartialIgnoreAttribute(string memberName) + : base() + { + if (string.IsNullOrEmpty(memberName)) throw new ArgumentNullException(nameof(memberName)); + + MemberName = memberName; + } + /// + /// The name of the member to be ignored. + /// + public string MemberName { get; } + } +} diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/ProtoIgnoreAttribute.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/ProtoIgnoreAttribute.cs.meta new file mode 100644 index 0000000..00afe26 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/ProtoIgnoreAttribute.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b012b09d39a7c2445aba79ffee82b117 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/ProtoIncludeAttribute.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/ProtoIncludeAttribute.cs new file mode 100644 index 0000000..bb83ef7 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/ProtoIncludeAttribute.cs @@ -0,0 +1,60 @@ +using System; +using System.ComponentModel; + +using ProtoBuf.Meta; + +namespace ProtoBuf +{ + /// + /// Indicates the known-types to support for an individual + /// message. This serializes each level in the hierarchy as + /// a nested message to retain wire-compatibility with + /// other protocol-buffer implementations. + /// + [AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface, AllowMultiple = true, Inherited = false)] + public sealed class ProtoIncludeAttribute : Attribute + { + /// + /// Creates a new instance of the ProtoIncludeAttribute. + /// + /// The unique index (within the type) that will identify this data. + /// The additional type to serialize/deserialize. + public ProtoIncludeAttribute(int tag, Type knownType) + : this(tag, knownType == null ? "" : knownType.AssemblyQualifiedName) { } + + /// + /// Creates a new instance of the ProtoIncludeAttribute. + /// + /// The unique index (within the type) that will identify this data. + /// The additional type to serialize/deserialize. + public ProtoIncludeAttribute(int tag, string knownTypeName) + { + if (tag <= 0) throw new ArgumentOutOfRangeException(nameof(tag), "Tags must be positive integers"); + if (string.IsNullOrEmpty(knownTypeName)) throw new ArgumentNullException(nameof(knownTypeName), "Known type cannot be blank"); + Tag = tag; + KnownTypeName = knownTypeName; + } + + /// + /// Gets the unique index (within the type) that will identify this data. + /// + public int Tag { get; } + + /// + /// Gets the additional type to serialize/deserialize. + /// + public string KnownTypeName { get; } + + /// + /// Gets the additional type to serialize/deserialize. + /// + public Type KnownType => TypeModel.ResolveKnownType(KnownTypeName, null, null); + + /// + /// Specifies whether the inherited sype's sub-message should be + /// written with a length-prefix (default), or with group markers. + /// + [DefaultValue(DataFormat.Default)] + public DataFormat DataFormat { get; set; } = DataFormat.Default; + } +} diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/ProtoIncludeAttribute.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/ProtoIncludeAttribute.cs.meta new file mode 100644 index 0000000..edebcb5 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/ProtoIncludeAttribute.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 40d89f2230d5a4f4badf122df4ed9fae +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/ProtoMapAttribute.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/ProtoMapAttribute.cs new file mode 100644 index 0000000..e85441a --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/ProtoMapAttribute.cs @@ -0,0 +1,29 @@ +using System; + +namespace ProtoBuf +{ + /// + /// Controls the formatting of elements in a dictionary, and indicates that + /// "map" rules should be used: duplicates *replace* earlier values, rather + /// than throwing an exception + /// + [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)] + public class ProtoMapAttribute : Attribute + { + /// + /// Describes the data-format used to store the key + /// + public DataFormat KeyFormat { get; set; } + /// + /// Describes the data-format used to store the value + /// + public DataFormat ValueFormat { get; set; } + + /// + /// Disables "map" handling; dictionaries will use ".Add(key,value)" instead of "[key] = value", + /// which means duplicate keys will cause an exception (instead of retaining the final value); if + /// a proto schema is emitted, it will be produced using "repeated" instead of "map" + /// + public bool DisableMap { get; set; } + } +} diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/ProtoMapAttribute.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/ProtoMapAttribute.cs.meta new file mode 100644 index 0000000..cf765ae --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/ProtoMapAttribute.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2d41a983b561e9043a8ce693aeb9c835 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/ProtoMemberAttribute.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/ProtoMemberAttribute.cs new file mode 100644 index 0000000..e5ab896 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/ProtoMemberAttribute.cs @@ -0,0 +1,228 @@ +using System; +using System.Reflection; + +namespace ProtoBuf +{ + /// + /// Declares a member to be used in protocol-buffer serialization, using + /// the given Tag. A DataFormat may be used to optimise the serialization + /// format (for instance, using zigzag encoding for negative numbers, or + /// fixed-length encoding for large values. + /// + [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, + AllowMultiple = false, Inherited = true)] + public class ProtoMemberAttribute : Attribute + , IComparable + , IComparable + + { + /// + /// Compare with another ProtoMemberAttribute for sorting purposes + /// + public int CompareTo(object other) => CompareTo(other as ProtoMemberAttribute); + /// + /// Compare with another ProtoMemberAttribute for sorting purposes + /// + public int CompareTo(ProtoMemberAttribute other) + { + if (other == null) return -1; + if ((object)this == (object)other) return 0; + int result = this.tag.CompareTo(other.tag); + if (result == 0) result = string.CompareOrdinal(this.name, other.name); + return result; + } + + /// + /// Creates a new ProtoMemberAttribute instance. + /// + /// Specifies the unique tag used to identify this member within the type. + public ProtoMemberAttribute(int tag) : this(tag, false) + { } + + internal ProtoMemberAttribute(int tag, bool forced) + { + if (tag <= 0 && !forced) throw new ArgumentOutOfRangeException(nameof(tag)); + this.tag = tag; + } + +#if !NO_RUNTIME + internal MemberInfo Member, BackingMember; + internal bool TagIsPinned; +#endif + /// + /// Gets or sets the original name defined in the .proto; not used + /// during serialization. + /// + public string Name { get { return name; } set { name = value; } } + private string name; + + /// + /// Gets or sets the data-format to be used when encoding this value. + /// + public DataFormat DataFormat { get { return dataFormat; } set { dataFormat = value; } } + private DataFormat dataFormat; + + /// + /// Gets the unique tag used to identify this member within the type. + /// + public int Tag { get { return tag; } } + private int tag; + internal void Rebase(int tag) { this.tag = tag; } + + /// + /// Gets or sets a value indicating whether this member is mandatory. + /// + public bool IsRequired + { + get { return (options & MemberSerializationOptions.Required) == MemberSerializationOptions.Required; } + set + { + if (value) options |= MemberSerializationOptions.Required; + else options &= ~MemberSerializationOptions.Required; + } + } + + /// + /// Gets a value indicating whether this member is packed. + /// This option only applies to list/array data of primitive types (int, double, etc). + /// + public bool IsPacked + { + get { return (options & MemberSerializationOptions.Packed) == MemberSerializationOptions.Packed; } + set + { + if (value) options |= MemberSerializationOptions.Packed; + else options &= ~MemberSerializationOptions.Packed; + } + } + + /// + /// Indicates whether this field should *repace* existing values (the default is false, meaning *append*). + /// This option only applies to list/array data. + /// + public bool OverwriteList + { + get { return (options & MemberSerializationOptions.OverwriteList) == MemberSerializationOptions.OverwriteList; } + set + { + if (value) options |= MemberSerializationOptions.OverwriteList; + else options &= ~MemberSerializationOptions.OverwriteList; + } + } + + /// + /// Enables full object-tracking/full-graph support. + /// + public bool AsReference + { + get { return (options & MemberSerializationOptions.AsReference) == MemberSerializationOptions.AsReference; } + set + { + if (value) options |= MemberSerializationOptions.AsReference; + else options &= ~MemberSerializationOptions.AsReference; + + options |= MemberSerializationOptions.AsReferenceHasValue; + } + } + + internal bool AsReferenceHasValue + { + get { return (options & MemberSerializationOptions.AsReferenceHasValue) == MemberSerializationOptions.AsReferenceHasValue; } + set + { + if (value) options |= MemberSerializationOptions.AsReferenceHasValue; + else options &= ~MemberSerializationOptions.AsReferenceHasValue; + } + } + + /// + /// Embeds the type information into the stream, allowing usage with types not known in advance. + /// + public bool DynamicType + { + get { return (options & MemberSerializationOptions.DynamicType) == MemberSerializationOptions.DynamicType; } + set + { + if (value) options |= MemberSerializationOptions.DynamicType; + else options &= ~MemberSerializationOptions.DynamicType; + } + } + + /// + /// Gets or sets a value indicating whether this member is packed (lists/arrays). + /// + public MemberSerializationOptions Options { get { return options; } set { options = value; } } + private MemberSerializationOptions options; + + + } + + /// + /// Additional (optional) settings that control serialization of members + /// + [Flags] + public enum MemberSerializationOptions + { + /// + /// Default; no additional options + /// + None = 0, + /// + /// Indicates that repeated elements should use packed (length-prefixed) encoding + /// + Packed = 1, + /// + /// Indicates that the given item is required + /// + Required = 2, + /// + /// Enables full object-tracking/full-graph support + /// + AsReference = 4, + /// + /// Embeds the type information into the stream, allowing usage with types not known in advance + /// + DynamicType = 8, + /// + /// Indicates whether this field should *repace* existing values (the default is false, meaning *append*). + /// This option only applies to list/array data. + /// + OverwriteList = 16, + /// + /// Determines whether the types AsReferenceDefault value is used, or whether this member's AsReference should be used + /// + AsReferenceHasValue = 32 + } + + /// + /// Declares a member to be used in protocol-buffer serialization, using + /// the given Tag and MemberName. This allows ProtoMemberAttribute usage + /// even for partial classes where the individual members are not + /// under direct control. + /// A DataFormat may be used to optimise the serialization + /// format (for instance, using zigzag encoding for negative numbers, or + /// fixed-length encoding for large values. + /// + [AttributeUsage(AttributeTargets.Class, + AllowMultiple = true, Inherited = false)] + public sealed class ProtoPartialMemberAttribute : ProtoMemberAttribute + { + /// + /// Creates a new ProtoMemberAttribute instance. + /// + /// Specifies the unique tag used to identify this member within the type. + /// Specifies the member to be serialized. + public ProtoPartialMemberAttribute(int tag, string memberName) + : base(tag) + { +#if !NO_RUNTIME + if (string.IsNullOrEmpty(memberName)) throw new ArgumentNullException(nameof(memberName)); +#endif + this.MemberName = memberName; + } + /// + /// The name of the member to be serialized. + /// + public string MemberName { get; private set; } + } +} diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/ProtoMemberAttribute.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/ProtoMemberAttribute.cs.meta new file mode 100644 index 0000000..2f3dfc9 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/ProtoMemberAttribute.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 262c0823543b1b3499e2b67ca22f4e62 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/ProtoReader.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/ProtoReader.cs new file mode 100644 index 0000000..3ea9bf9 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/ProtoReader.cs @@ -0,0 +1,1444 @@ + +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; +using ProtoBuf.Meta; + +namespace ProtoBuf +{ + /// + /// A stateful reader, used to read a protobuf stream. Typical usage would be (sequentially) to call + /// ReadFieldHeader and (after matching the field) an appropriate Read* method. + /// + public sealed class ProtoReader : IDisposable + { + Stream source; + byte[] ioBuffer; + TypeModel model; + int fieldNumber, depth, ioIndex, available; + long position64, blockEnd64, dataRemaining64; + WireType wireType; + bool isFixedLength, internStrings; + private NetObjectCache netCache; + + // this is how many outstanding objects do not currently have + // values for the purposes of reference tracking; we'll default + // to just trapping the root object + // note: objects are trapped (the ref and key mapped) via NoteObject + uint trapCount; // uint is so we can use beq/bne more efficiently than bgt + + /// + /// Gets the number of the field being processed. + /// + public int FieldNumber => fieldNumber; + + /// + /// Indicates the underlying proto serialization format on the wire. + /// + public WireType WireType => wireType; + + /// + /// Creates a new reader against a stream + /// + /// The source stream + /// The model to use for serialization; this can be null, but this will impair the ability to deserialize sub-objects + /// Additional context about this serialization operation + [Obsolete("Please use ProtoReader.Create; this API may be removed in a future version", error: false)] + public ProtoReader(Stream source, TypeModel model, SerializationContext context) + { + + Init(this, source, model, context, TO_EOF); + } + + internal const long TO_EOF = -1; + + /// + /// Gets / sets a flag indicating whether strings should be checked for repetition; if + /// true, any repeated UTF-8 byte sequence will result in the same String instance, rather + /// than a second instance of the same string. Enabled by default. Note that this uses + /// a custom interner - the system-wide string interner is not used. + /// + public bool InternStrings { get { return internStrings; } set { internStrings = value; } } + + /// + /// Creates a new reader against a stream + /// + /// The source stream + /// The model to use for serialization; this can be null, but this will impair the ability to deserialize sub-objects + /// Additional context about this serialization operation + /// The number of bytes to read, or -1 to read until the end of the stream + [Obsolete("Please use ProtoReader.Create; this API may be removed in a future version", error: false)] + public ProtoReader(Stream source, TypeModel model, SerializationContext context, int length) + { + Init(this, source, model, context, length); + } + + /// + /// Creates a new reader against a stream + /// + /// The source stream + /// The model to use for serialization; this can be null, but this will impair the ability to deserialize sub-objects + /// Additional context about this serialization operation + /// The number of bytes to read, or -1 to read until the end of the stream + [Obsolete("Please use ProtoReader.Create; this API may be removed in a future version", error: false)] + public ProtoReader(Stream source, TypeModel model, SerializationContext context, long length) + { + Init(this, source, model, context, length); + } + + private static void Init(ProtoReader reader, Stream source, TypeModel model, SerializationContext context, long length) + { + if (source == null) throw new ArgumentNullException(nameof(source)); + if (!source.CanRead) throw new ArgumentException("Cannot read from stream", nameof(source)); + reader.source = source; + reader.ioBuffer = BufferPool.GetBuffer(); + reader.model = model; + bool isFixedLength = length >= 0; + reader.isFixedLength = isFixedLength; + reader.dataRemaining64 = isFixedLength ? length : 0; + + if (context == null) { context = SerializationContext.Default; } + else { context.Freeze(); } + reader.context = context; + reader.position64 = 0; + reader.available = reader.depth = reader.fieldNumber = reader.ioIndex = 0; + reader.blockEnd64 = long.MaxValue; + reader.internStrings = RuntimeTypeModel.Default.InternStrings; + reader.wireType = WireType.None; + reader.trapCount = 1; + if (reader.netCache == null) reader.netCache = new NetObjectCache(); + } + + private SerializationContext context; + + /// + /// Addition information about this deserialization operation. + /// + public SerializationContext Context => context; + + /// + /// Releases resources used by the reader, but importantly does not Dispose the + /// underlying stream; in many typical use-cases the stream is used for different + /// processes, so it is assumed that the consumer will Dispose their stream separately. + /// + public void Dispose() + { + // importantly, this does **not** own the stream, and does not dispose it + source = null; + model = null; + BufferPool.ReleaseBufferToPool(ref ioBuffer); + if (stringInterner != null) + { + stringInterner.Clear(); + stringInterner = null; + } + if (netCache != null) netCache.Clear(); + } + internal int TryReadUInt32VariantWithoutMoving(bool trimNegative, out uint value) + { + if (available < 10) Ensure(10, false); + if (available == 0) + { + value = 0; + return 0; + } + int readPos = ioIndex; + value = ioBuffer[readPos++]; + if ((value & 0x80) == 0) return 1; + value &= 0x7F; + if (available == 1) throw EoF(this); + + uint chunk = ioBuffer[readPos++]; + value |= (chunk & 0x7F) << 7; + if ((chunk & 0x80) == 0) return 2; + if (available == 2) throw EoF(this); + + chunk = ioBuffer[readPos++]; + value |= (chunk & 0x7F) << 14; + if ((chunk & 0x80) == 0) return 3; + if (available == 3) throw EoF(this); + + chunk = ioBuffer[readPos++]; + value |= (chunk & 0x7F) << 21; + if ((chunk & 0x80) == 0) return 4; + if (available == 4) throw EoF(this); + + chunk = ioBuffer[readPos]; + value |= chunk << 28; // can only use 4 bits from this chunk + if ((chunk & 0xF0) == 0) return 5; + + if (trimNegative // allow for -ve values + && (chunk & 0xF0) == 0xF0 + && available >= 10 + && ioBuffer[++readPos] == 0xFF + && ioBuffer[++readPos] == 0xFF + && ioBuffer[++readPos] == 0xFF + && ioBuffer[++readPos] == 0xFF + && ioBuffer[++readPos] == 0x01) + { + return 10; + } + throw AddErrorData(new OverflowException(), this); + } + + private uint ReadUInt32Variant(bool trimNegative) + { + int read = TryReadUInt32VariantWithoutMoving(trimNegative, out uint value); + if (read > 0) + { + ioIndex += read; + available -= read; + position64 += read; + return value; + } + throw EoF(this); + } + + private bool TryReadUInt32Variant(out uint value) + { + int read = TryReadUInt32VariantWithoutMoving(false, out value); + if (read > 0) + { + ioIndex += read; + available -= read; + position64 += read; + return true; + } + return false; + } + + /// + /// Reads an unsigned 32-bit integer from the stream; supported wire-types: Variant, Fixed32, Fixed64 + /// + public uint ReadUInt32() + { + switch (wireType) + { + case WireType.Variant: + return ReadUInt32Variant(false); + case WireType.Fixed32: + if (available < 4) Ensure(4, true); + position64 += 4; + available -= 4; + return ((uint)ioBuffer[ioIndex++]) + | (((uint)ioBuffer[ioIndex++]) << 8) + | (((uint)ioBuffer[ioIndex++]) << 16) + | (((uint)ioBuffer[ioIndex++]) << 24); + case WireType.Fixed64: + ulong val = ReadUInt64(); + checked { return (uint)val; } + default: + throw CreateWireTypeException(); + } + } + + /// + /// Returns the position of the current reader (note that this is not necessarily the same as the position + /// in the underlying stream, if multiple readers are used on the same stream) + /// + public int Position { get { return checked((int)position64); } } + + /// + /// Returns the position of the current reader (note that this is not necessarily the same as the position + /// in the underlying stream, if multiple readers are used on the same stream) + /// + public long LongPosition { get { return position64; } } + internal void Ensure(int count, bool strict) + { + Helpers.DebugAssert(available <= count, "Asking for data without checking first"); + if (count > ioBuffer.Length) + { + BufferPool.ResizeAndFlushLeft(ref ioBuffer, count, ioIndex, available); + ioIndex = 0; + } + else if (ioIndex + count >= ioBuffer.Length) + { + // need to shift the buffer data to the left to make space + Buffer.BlockCopy(ioBuffer, ioIndex, ioBuffer, 0, available); + ioIndex = 0; + } + count -= available; + int writePos = ioIndex + available, bytesRead; + int canRead = ioBuffer.Length - writePos; + if (isFixedLength) + { // throttle it if needed + if (dataRemaining64 < canRead) canRead = (int)dataRemaining64; + } + while (count > 0 && canRead > 0 && (bytesRead = source.Read(ioBuffer, writePos, canRead)) > 0) + { + available += bytesRead; + count -= bytesRead; + canRead -= bytesRead; + writePos += bytesRead; + if (isFixedLength) { dataRemaining64 -= bytesRead; } + } + if (strict && count > 0) + { + throw EoF(this); + } + + } + /// + /// Reads a signed 16-bit integer from the stream: Variant, Fixed32, Fixed64, SignedVariant + /// + public short ReadInt16() + { + checked { return (short)ReadInt32(); } + } + /// + /// Reads an unsigned 16-bit integer from the stream; supported wire-types: Variant, Fixed32, Fixed64 + /// + public ushort ReadUInt16() + { + checked { return (ushort)ReadUInt32(); } + } + + /// + /// Reads an unsigned 8-bit integer from the stream; supported wire-types: Variant, Fixed32, Fixed64 + /// + public byte ReadByte() + { + checked { return (byte)ReadUInt32(); } + } + + /// + /// Reads a signed 8-bit integer from the stream; supported wire-types: Variant, Fixed32, Fixed64, SignedVariant + /// + public sbyte ReadSByte() + { + checked { return (sbyte)ReadInt32(); } + } + + /// + /// Reads a signed 32-bit integer from the stream; supported wire-types: Variant, Fixed32, Fixed64, SignedVariant + /// + public int ReadInt32() + { + switch (wireType) + { + case WireType.Variant: + return (int)ReadUInt32Variant(true); + case WireType.Fixed32: + if (available < 4) Ensure(4, true); + position64 += 4; + available -= 4; + return ((int)ioBuffer[ioIndex++]) + | (((int)ioBuffer[ioIndex++]) << 8) + | (((int)ioBuffer[ioIndex++]) << 16) + | (((int)ioBuffer[ioIndex++]) << 24); + case WireType.Fixed64: + long l = ReadInt64(); + checked { return (int)l; } + case WireType.SignedVariant: + return Zag(ReadUInt32Variant(true)); + default: + throw CreateWireTypeException(); + } + } + private const long Int64Msb = ((long)1) << 63; + private const int Int32Msb = ((int)1) << 31; + private static int Zag(uint ziggedValue) + { + int value = (int)ziggedValue; + return (-(value & 0x01)) ^ ((value >> 1) & ~ProtoReader.Int32Msb); + } + + private static long Zag(ulong ziggedValue) + { + long value = (long)ziggedValue; + return (-(value & 0x01L)) ^ ((value >> 1) & ~ProtoReader.Int64Msb); + } + /// + /// Reads a signed 64-bit integer from the stream; supported wire-types: Variant, Fixed32, Fixed64, SignedVariant + /// + public long ReadInt64() + { + switch (wireType) + { + case WireType.Variant: + return (long)ReadUInt64Variant(); + case WireType.Fixed32: + return ReadInt32(); + case WireType.Fixed64: + if (available < 8) Ensure(8, true); + position64 += 8; + available -= 8; + +#if NETCOREAPP2_1 + var result = System.Buffers.Binary.BinaryPrimitives.ReadInt64LittleEndian(ioBuffer.AsSpan(ioIndex, 8)); + + ioIndex+= 8; + + return result; +#else + return ((long)ioBuffer[ioIndex++]) + | (((long)ioBuffer[ioIndex++]) << 8) + | (((long)ioBuffer[ioIndex++]) << 16) + | (((long)ioBuffer[ioIndex++]) << 24) + | (((long)ioBuffer[ioIndex++]) << 32) + | (((long)ioBuffer[ioIndex++]) << 40) + | (((long)ioBuffer[ioIndex++]) << 48) + | (((long)ioBuffer[ioIndex++]) << 56); +#endif + case WireType.SignedVariant: + return Zag(ReadUInt64Variant()); + default: + throw CreateWireTypeException(); + } + } + + private int TryReadUInt64VariantWithoutMoving(out ulong value) + { + if (available < 10) Ensure(10, false); + if (available == 0) + { + value = 0; + return 0; + } + int readPos = ioIndex; + value = ioBuffer[readPos++]; + if ((value & 0x80) == 0) return 1; + value &= 0x7F; + if (available == 1) throw EoF(this); + + ulong chunk = ioBuffer[readPos++]; + value |= (chunk & 0x7F) << 7; + if ((chunk & 0x80) == 0) return 2; + if (available == 2) throw EoF(this); + + chunk = ioBuffer[readPos++]; + value |= (chunk & 0x7F) << 14; + if ((chunk & 0x80) == 0) return 3; + if (available == 3) throw EoF(this); + + chunk = ioBuffer[readPos++]; + value |= (chunk & 0x7F) << 21; + if ((chunk & 0x80) == 0) return 4; + if (available == 4) throw EoF(this); + + chunk = ioBuffer[readPos++]; + value |= (chunk & 0x7F) << 28; + if ((chunk & 0x80) == 0) return 5; + if (available == 5) throw EoF(this); + + chunk = ioBuffer[readPos++]; + value |= (chunk & 0x7F) << 35; + if ((chunk & 0x80) == 0) return 6; + if (available == 6) throw EoF(this); + + chunk = ioBuffer[readPos++]; + value |= (chunk & 0x7F) << 42; + if ((chunk & 0x80) == 0) return 7; + if (available == 7) throw EoF(this); + + + chunk = ioBuffer[readPos++]; + value |= (chunk & 0x7F) << 49; + if ((chunk & 0x80) == 0) return 8; + if (available == 8) throw EoF(this); + + chunk = ioBuffer[readPos++]; + value |= (chunk & 0x7F) << 56; + if ((chunk & 0x80) == 0) return 9; + if (available == 9) throw EoF(this); + + chunk = ioBuffer[readPos]; + value |= chunk << 63; // can only use 1 bit from this chunk + + if ((chunk & ~(ulong)0x01) != 0) throw AddErrorData(new OverflowException(), this); + return 10; + } + + private ulong ReadUInt64Variant() + { + int read = TryReadUInt64VariantWithoutMoving(out ulong value); + if (read > 0) + { + ioIndex += read; + available -= read; + position64 += read; + return value; + } + throw EoF(this); + } + + private Dictionary stringInterner; + private string Intern(string value) + { + if (value == null) return null; + if (value.Length == 0) return ""; + if (stringInterner == null) + { + stringInterner = new Dictionary + { + { value, value } + }; + } + else if (stringInterner.TryGetValue(value, out string found)) + { + value = found; + } + else + { + stringInterner.Add(value, value); + } + return value; + } + +#if COREFX + static readonly Encoding encoding = Encoding.UTF8; +#else + static readonly UTF8Encoding encoding = new UTF8Encoding(); +#endif + /// + /// Reads a string from the stream (using UTF8); supported wire-types: String + /// + public string ReadString() + { + if (wireType == WireType.String) + { + int bytes = (int)ReadUInt32Variant(false); + if (bytes == 0) return ""; + if (bytes < 0) ThrowInvalidLength(bytes); + if (available < bytes) Ensure(bytes, true); + + string s = encoding.GetString(ioBuffer, ioIndex, bytes); + + if (internStrings) { s = Intern(s); } + available -= bytes; + position64 += bytes; + ioIndex += bytes; + return s; + } + throw CreateWireTypeException(); + } + /// + /// Throws an exception indication that the given value cannot be mapped to an enum. + /// + public void ThrowEnumException(Type type, int value) + { + string desc = type == null ? "" : type.FullName; + throw AddErrorData(new ProtoException("No " + desc + " enum is mapped to the wire-value " + value.ToString()), this); + } + + private void ThrowInvalidLength(long length) + { + throw AddErrorData(new InvalidOperationException("Invalid length: " + length.ToString()), this); + } + + private Exception CreateWireTypeException() + { + return CreateException("Invalid wire-type; this usually means you have over-written a file without truncating or setting the length; see https://stackoverflow.com/q/2152978/23354"); + } + + private Exception CreateException(string message) + { + return AddErrorData(new ProtoException(message), this); + } + /// + /// Reads a double-precision number from the stream; supported wire-types: Fixed32, Fixed64 + /// + public +#if !FEAT_SAFE + unsafe +#endif + double ReadDouble() + { + switch (wireType) + { + case WireType.Fixed32: + return ReadSingle(); + case WireType.Fixed64: + long value = ReadInt64(); +#if FEAT_SAFE + return BitConverter.ToDouble(BitConverter.GetBytes(value), 0); +#else + return *(double*)&value; +#endif + default: + throw CreateWireTypeException(); + } + } + + /// + /// Reads (merges) a sub-message from the stream, internally calling StartSubItem and EndSubItem, and (in between) + /// parsing the message in accordance with the model associated with the reader + /// + public static object ReadObject(object value, int key, ProtoReader reader) + { + return ReadTypedObject(value, key, reader, null); + } + + internal static object ReadTypedObject(object value, int key, ProtoReader reader, Type type) + { + if (reader.model == null) + { + throw AddErrorData(new InvalidOperationException("Cannot deserialize sub-objects unless a model is provided"), reader); + } + SubItemToken token = ProtoReader.StartSubItem(reader); + if (key >= 0) + { + value = reader.model.Deserialize(key, value, reader); + } + else if (type != null && reader.model.TryDeserializeAuxiliaryType(reader, DataFormat.Default, Serializer.ListItemTag, type, ref value, true, false, true, false, null)) + { + // ok + } + else + { + TypeModel.ThrowUnexpectedType(type); + } + ProtoReader.EndSubItem(token, reader); + return value; + } + + /// + /// Makes the end of consuming a nested message in the stream; the stream must be either at the correct EndGroup + /// marker, or all fields of the sub-message must have been consumed (in either case, this means ReadFieldHeader + /// should return zero) + /// + public static void EndSubItem(SubItemToken token, ProtoReader reader) + { + if (reader == null) throw new ArgumentNullException("reader"); + long value64 = token.value64; + switch (reader.wireType) + { + case WireType.EndGroup: + if (value64 >= 0) throw AddErrorData(new ArgumentException("token"), reader); + if (-(int)value64 != reader.fieldNumber) throw reader.CreateException("Wrong group was ended"); // wrong group ended! + reader.wireType = WireType.None; // this releases ReadFieldHeader + reader.depth--; + break; + // case WireType.None: // TODO reinstate once reads reset the wire-type + default: + if (value64 < reader.position64) throw reader.CreateException($"Sub-message not read entirely; expected {value64}, was {reader.position64}"); + if (reader.blockEnd64 != reader.position64 && reader.blockEnd64 != long.MaxValue) + { + throw reader.CreateException("Sub-message not read correctly"); + } + reader.blockEnd64 = value64; + reader.depth--; + break; + /*default: + throw reader.BorkedIt(); */ + } + } + + /// + /// Begins consuming a nested message in the stream; supported wire-types: StartGroup, String + /// + /// The token returned must be help and used when callining EndSubItem + public static SubItemToken StartSubItem(ProtoReader reader) + { + if (reader == null) throw new ArgumentNullException("reader"); + switch (reader.wireType) + { + case WireType.StartGroup: + reader.wireType = WireType.None; // to prevent glitches from double-calling + reader.depth++; + return new SubItemToken((long)(-reader.fieldNumber)); + case WireType.String: + long len = (long)reader.ReadUInt64Variant(); + if (len < 0) reader.ThrowInvalidLength(len); + long lastEnd = reader.blockEnd64; + reader.blockEnd64 = reader.position64 + len; + reader.depth++; + return new SubItemToken(lastEnd); + default: + throw reader.CreateWireTypeException(); // throws + } + } + + /// + /// Reads a field header from the stream, setting the wire-type and retuning the field number. If no + /// more fields are available, then 0 is returned. This methods respects sub-messages. + /// + public int ReadFieldHeader() + { + // at the end of a group the caller must call EndSubItem to release the + // reader (which moves the status to Error, since ReadFieldHeader must + // then be called) + if (blockEnd64 <= position64 || wireType == WireType.EndGroup) { return 0; } + + if (TryReadUInt32Variant(out uint tag) && tag != 0) + { + wireType = (WireType)(tag & 7); + fieldNumber = (int)(tag >> 3); + if (fieldNumber < 1) throw new ProtoException("Invalid field in source data: " + fieldNumber.ToString()); + } + else + { + wireType = WireType.None; + fieldNumber = 0; + } + if (wireType == ProtoBuf.WireType.EndGroup) + { + if (depth > 0) return 0; // spoof an end, but note we still set the field-number + throw new ProtoException("Unexpected end-group in source data; this usually means the source data is corrupt"); + } + return fieldNumber; + } + /// + /// Looks ahead to see whether the next field in the stream is what we expect + /// (typically; what we've just finished reading - for example ot read successive list items) + /// + public bool TryReadFieldHeader(int field) + { + // check for virtual end of stream + if (blockEnd64 <= position64 || wireType == WireType.EndGroup) { return false; } + + int read = TryReadUInt32VariantWithoutMoving(false, out uint tag); + WireType tmpWireType; // need to catch this to exclude (early) any "end group" tokens + if (read > 0 && ((int)tag >> 3) == field + && (tmpWireType = (WireType)(tag & 7)) != WireType.EndGroup) + { + wireType = tmpWireType; + fieldNumber = field; + position64 += read; + ioIndex += read; + available -= read; + return true; + } + return false; + } + + /// + /// Get the TypeModel associated with this reader + /// + public TypeModel Model { get { return model; } } + + /// + /// Compares the streams current wire-type to the hinted wire-type, updating the reader if necessary; for example, + /// a Variant may be updated to SignedVariant. If the hinted wire-type is unrelated then no change is made. + /// + public void Hint(WireType wireType) + { + if (this.wireType == wireType) { } // fine; everything as we expect + else if (((int)wireType & 7) == (int)this.wireType) + { // the underling type is a match; we're customising it with an extension + this.wireType = wireType; + } + // note no error here; we're OK about using alternative data + } + + /// + /// Verifies that the stream's current wire-type is as expected, or a specialized sub-type (for example, + /// SignedVariant) - in which case the current wire-type is updated. Otherwise an exception is thrown. + /// + public void Assert(WireType wireType) + { + if (this.wireType == wireType) { } // fine; everything as we expect + else if (((int)wireType & 7) == (int)this.wireType) + { // the underling type is a match; we're customising it with an extension + this.wireType = wireType; + } + else + { // nope; that is *not* what we were expecting! + throw CreateWireTypeException(); + } + } + + /// + /// Discards the data for the current field. + /// + public void SkipField() + { + switch (wireType) + { + case WireType.Fixed32: + if (available < 4) Ensure(4, true); + available -= 4; + ioIndex += 4; + position64 += 4; + return; + case WireType.Fixed64: + if (available < 8) Ensure(8, true); + available -= 8; + ioIndex += 8; + position64 += 8; + return; + case WireType.String: + long len = (long)ReadUInt64Variant(); + if (len < 0) ThrowInvalidLength(len); + if (len <= available) + { // just jump it! + available -= (int)len; + ioIndex += (int)len; + position64 += len; + return; + } + // everything remaining in the buffer is garbage + position64 += len; // assumes success, but if it fails we're screwed anyway + len -= available; // discount anything we've got to-hand + ioIndex = available = 0; // note that we have no data in the buffer + if (isFixedLength) + { + if (len > dataRemaining64) throw EoF(this); + // else assume we're going to be OK + dataRemaining64 -= len; + } + ProtoReader.Seek(source, len, ioBuffer); + return; + case WireType.Variant: + case WireType.SignedVariant: + ReadUInt64Variant(); // and drop it + return; + case WireType.StartGroup: + int originalFieldNumber = this.fieldNumber; + depth++; // need to satisfy the sanity-checks in ReadFieldHeader + while (ReadFieldHeader() > 0) { SkipField(); } + depth--; + if (wireType == WireType.EndGroup && fieldNumber == originalFieldNumber) + { // we expect to exit in a similar state to how we entered + wireType = ProtoBuf.WireType.None; + return; + } + throw CreateWireTypeException(); + case WireType.None: // treat as explicit errorr + case WireType.EndGroup: // treat as explicit error + default: // treat as implicit error + throw CreateWireTypeException(); + } + } + + /// + /// Reads an unsigned 64-bit integer from the stream; supported wire-types: Variant, Fixed32, Fixed64 + /// + public ulong ReadUInt64() + { + switch (wireType) + { + case WireType.Variant: + return ReadUInt64Variant(); + case WireType.Fixed32: + return ReadUInt32(); + case WireType.Fixed64: + if (available < 8) Ensure(8, true); + position64 += 8; + available -= 8; + + return ((ulong)ioBuffer[ioIndex++]) + | (((ulong)ioBuffer[ioIndex++]) << 8) + | (((ulong)ioBuffer[ioIndex++]) << 16) + | (((ulong)ioBuffer[ioIndex++]) << 24) + | (((ulong)ioBuffer[ioIndex++]) << 32) + | (((ulong)ioBuffer[ioIndex++]) << 40) + | (((ulong)ioBuffer[ioIndex++]) << 48) + | (((ulong)ioBuffer[ioIndex++]) << 56); + default: + throw CreateWireTypeException(); + } + } + /// + /// Reads a single-precision number from the stream; supported wire-types: Fixed32, Fixed64 + /// + public +#if !FEAT_SAFE + unsafe +#endif + float ReadSingle() + { + switch (wireType) + { + case WireType.Fixed32: + { + int value = ReadInt32(); +#if FEAT_SAFE + return BitConverter.ToSingle(BitConverter.GetBytes(value), 0); +#else + return *(float*)&value; +#endif + } + case WireType.Fixed64: + { + double value = ReadDouble(); + float f = (float)value; + if (float.IsInfinity(f) && !double.IsInfinity(value)) + { + throw AddErrorData(new OverflowException(), this); + } + return f; + } + default: + throw CreateWireTypeException(); + } + } + + /// + /// Reads a boolean value from the stream; supported wire-types: Variant, Fixed32, Fixed64 + /// + /// + public bool ReadBoolean() + { + switch (ReadUInt32()) + { + case 0: return false; + case 1: return true; + default: throw CreateException("Unexpected boolean value"); + } + } + + private static readonly byte[] EmptyBlob = new byte[0]; + /// + /// Reads a byte-sequence from the stream, appending them to an existing byte-sequence (which can be null); supported wire-types: String + /// + public static byte[] AppendBytes(byte[] value, ProtoReader reader) + { + if (reader == null) throw new ArgumentNullException(nameof(reader)); + switch (reader.wireType) + { + case WireType.String: + int len = (int)reader.ReadUInt32Variant(false); + reader.wireType = WireType.None; + if (len == 0) return value ?? EmptyBlob; + if (len < 0) reader.ThrowInvalidLength(len); + int offset; + if (value == null || value.Length == 0) + { + offset = 0; + value = new byte[len]; + } + else + { + offset = value.Length; + byte[] tmp = new byte[value.Length + len]; + Buffer.BlockCopy(value, 0, tmp, 0, value.Length); + value = tmp; + } + // value is now sized with the final length, and (if necessary) + // contains the old data up to "offset" + reader.position64 += len; // assume success + while (len > reader.available) + { + if (reader.available > 0) + { + // copy what we *do* have + Buffer.BlockCopy(reader.ioBuffer, reader.ioIndex, value, offset, reader.available); + len -= reader.available; + offset += reader.available; + reader.ioIndex = reader.available = 0; // we've drained the buffer + } + // now refill the buffer (without overflowing it) + int count = len > reader.ioBuffer.Length ? reader.ioBuffer.Length : len; + if (count > 0) reader.Ensure(count, true); + } + // at this point, we know that len <= available + if (len > 0) + { // still need data, but we have enough buffered + Buffer.BlockCopy(reader.ioBuffer, reader.ioIndex, value, offset, len); + reader.ioIndex += len; + reader.available -= len; + } + return value; + case WireType.Variant: + return new byte[0]; + default: + throw reader.CreateWireTypeException(); + } + } + + //static byte[] ReadBytes(Stream stream, int length) + //{ + // if (stream == null) throw new ArgumentNullException("stream"); + // if (length < 0) throw new ArgumentOutOfRangeException("length"); + // byte[] buffer = new byte[length]; + // int offset = 0, read; + // while (length > 0 && (read = stream.Read(buffer, offset, length)) > 0) + // { + // length -= read; + // } + // if (length > 0) throw EoF(null); + // return buffer; + //} + private static int ReadByteOrThrow(Stream source) + { + int val = source.ReadByte(); + if (val < 0) throw EoF(null); + return val; + } + + /// + /// Reads the length-prefix of a message from a stream without buffering additional data, allowing a fixed-length + /// reader to be created. + /// + public static int ReadLengthPrefix(Stream source, bool expectHeader, PrefixStyle style, out int fieldNumber) + => ReadLengthPrefix(source, expectHeader, style, out fieldNumber, out int bytesRead); + + /// + /// Reads a little-endian encoded integer. An exception is thrown if the data is not all available. + /// + public static int DirectReadLittleEndianInt32(Stream source) + { + return ReadByteOrThrow(source) + | (ReadByteOrThrow(source) << 8) + | (ReadByteOrThrow(source) << 16) + | (ReadByteOrThrow(source) << 24); + } + + /// + /// Reads a big-endian encoded integer. An exception is thrown if the data is not all available. + /// + public static int DirectReadBigEndianInt32(Stream source) + { + return (ReadByteOrThrow(source) << 24) + | (ReadByteOrThrow(source) << 16) + | (ReadByteOrThrow(source) << 8) + | ReadByteOrThrow(source); + } + + /// + /// Reads a varint encoded integer. An exception is thrown if the data is not all available. + /// + public static int DirectReadVarintInt32(Stream source) + { + int bytes = TryReadUInt64Variant(source, out ulong val); + if (bytes <= 0) throw EoF(null); + return checked((int)val); + } + + /// + /// Reads a string (of a given lenth, in bytes) directly from the source into a pre-existing buffer. An exception is thrown if the data is not all available. + /// + public static void DirectReadBytes(Stream source, byte[] buffer, int offset, int count) + { + int read; + if (source == null) throw new ArgumentNullException("source"); + while (count > 0 && (read = source.Read(buffer, offset, count)) > 0) + { + count -= read; + offset += read; + } + if (count > 0) throw EoF(null); + } + + /// + /// Reads a given number of bytes directly from the source. An exception is thrown if the data is not all available. + /// + public static byte[] DirectReadBytes(Stream source, int count) + { + byte[] buffer = new byte[count]; + DirectReadBytes(source, buffer, 0, count); + return buffer; + } + + /// + /// Reads a string (of a given lenth, in bytes) directly from the source. An exception is thrown if the data is not all available. + /// + public static string DirectReadString(Stream source, int length) + { + byte[] buffer = new byte[length]; + DirectReadBytes(source, buffer, 0, length); + return Encoding.UTF8.GetString(buffer, 0, length); + } + + /// + /// Reads the length-prefix of a message from a stream without buffering additional data, allowing a fixed-length + /// reader to be created. + /// + public static int ReadLengthPrefix(Stream source, bool expectHeader, PrefixStyle style, out int fieldNumber, out int bytesRead) + { + if (style == PrefixStyle.None) + { + bytesRead = fieldNumber = 0; + return int.MaxValue; // avoid the long.maxvalue causing overflow + } + long len64 = ReadLongLengthPrefix(source, expectHeader, style, out fieldNumber, out bytesRead); + return checked((int)len64); + } + + /// + /// Reads the length-prefix of a message from a stream without buffering additional data, allowing a fixed-length + /// reader to be created. + /// + public static long ReadLongLengthPrefix(Stream source, bool expectHeader, PrefixStyle style, out int fieldNumber, out int bytesRead) + { + fieldNumber = 0; + switch (style) + { + case PrefixStyle.None: + bytesRead = 0; + return long.MaxValue; + case PrefixStyle.Base128: + ulong val; + int tmpBytesRead; + bytesRead = 0; + if (expectHeader) + { + tmpBytesRead = ProtoReader.TryReadUInt64Variant(source, out val); + bytesRead += tmpBytesRead; + if (tmpBytesRead > 0) + { + if ((val & 7) != (uint)WireType.String) + { // got a header, but it isn't a string + throw new InvalidOperationException(); + } + fieldNumber = (int)(val >> 3); + tmpBytesRead = ProtoReader.TryReadUInt64Variant(source, out val); + bytesRead += tmpBytesRead; + if (bytesRead == 0) + { // got a header, but no length + throw EoF(null); + } + return (long)val; + } + else + { // no header + bytesRead = 0; + return -1; + } + } + // check for a length + tmpBytesRead = ProtoReader.TryReadUInt64Variant(source, out val); + bytesRead += tmpBytesRead; + return bytesRead < 0 ? -1 : (long)val; + + case PrefixStyle.Fixed32: + { + int b = source.ReadByte(); + if (b < 0) + { + bytesRead = 0; + return -1; + } + bytesRead = 4; + return b + | (ReadByteOrThrow(source) << 8) + | (ReadByteOrThrow(source) << 16) + | (ReadByteOrThrow(source) << 24); + } + case PrefixStyle.Fixed32BigEndian: + { + int b = source.ReadByte(); + if (b < 0) + { + bytesRead = 0; + return -1; + } + bytesRead = 4; + return (b << 24) + | (ReadByteOrThrow(source) << 16) + | (ReadByteOrThrow(source) << 8) + | ReadByteOrThrow(source); + } + default: + throw new ArgumentOutOfRangeException("style"); + } + } + + /// The number of bytes consumed; 0 if no data available + private static int TryReadUInt64Variant(Stream source, out ulong value) + { + value = 0; + int b = source.ReadByte(); + if (b < 0) { return 0; } + value = (uint)b; + if ((value & 0x80) == 0) { return 1; } + value &= 0x7F; + int bytesRead = 1, shift = 7; + while (bytesRead < 9) + { + b = source.ReadByte(); + if (b < 0) throw EoF(null); + value |= ((ulong)b & 0x7F) << shift; + shift += 7; + bytesRead++; + + if ((b & 0x80) == 0) return bytesRead; + } + b = source.ReadByte(); + if (b < 0) throw EoF(null); + if ((b & 1) == 0) // only use 1 bit from the last byte + { + value |= ((ulong)b & 0x7F) << shift; + return ++bytesRead; + } + throw new OverflowException(); + } + + internal static void Seek(Stream source, long count, byte[] buffer) + { + if (source.CanSeek) + { + source.Seek(count, SeekOrigin.Current); + count = 0; + } + else if (buffer != null) + { + int bytesRead; + while (count > buffer.Length && (bytesRead = source.Read(buffer, 0, buffer.Length)) > 0) + { + count -= bytesRead; + } + while (count > 0 && (bytesRead = source.Read(buffer, 0, (int)count)) > 0) + { + count -= bytesRead; + } + } + else // borrow a buffer + { + buffer = BufferPool.GetBuffer(); + try + { + int bytesRead; + while (count > buffer.Length && (bytesRead = source.Read(buffer, 0, buffer.Length)) > 0) + { + count -= bytesRead; + } + while (count > 0 && (bytesRead = source.Read(buffer, 0, (int)count)) > 0) + { + count -= bytesRead; + } + } + finally + { + BufferPool.ReleaseBufferToPool(ref buffer); + } + } + if (count > 0) throw EoF(null); + } + internal static Exception AddErrorData(Exception exception, ProtoReader source) + { +#if !CF && !PORTABLE + if (exception != null && source != null && !exception.Data.Contains("protoSource")) + { + exception.Data.Add("protoSource", string.Format("tag={0}; wire-type={1}; offset={2}; depth={3}", + source.fieldNumber, source.wireType, source.position64, source.depth)); + } +#endif + return exception; + } + + private static Exception EoF(ProtoReader source) + { + return AddErrorData(new EndOfStreamException(), source); + } + + /// + /// Copies the current field into the instance as extension data + /// + public void AppendExtensionData(IExtensible instance) + { + if (instance == null) throw new ArgumentNullException(nameof(instance)); + IExtension extn = instance.GetExtensionObject(true); + bool commit = false; + // unusually we *don't* want "using" here; the "finally" does that, with + // the extension object being responsible for disposal etc + Stream dest = extn.BeginAppend(); + try + { + //TODO: replace this with stream-based, buffered raw copying + using (ProtoWriter writer = ProtoWriter.Create(dest, model, null)) + { + AppendExtensionField(writer); + writer.Close(); + } + commit = true; + } + finally { extn.EndAppend(dest, commit); } + } + + private void AppendExtensionField(ProtoWriter writer) + { + //TODO: replace this with stream-based, buffered raw copying + ProtoWriter.WriteFieldHeader(fieldNumber, wireType, writer); + switch (wireType) + { + case WireType.Fixed32: + ProtoWriter.WriteInt32(ReadInt32(), writer); + return; + case WireType.Variant: + case WireType.SignedVariant: + case WireType.Fixed64: + ProtoWriter.WriteInt64(ReadInt64(), writer); + return; + case WireType.String: + ProtoWriter.WriteBytes(AppendBytes(null, this), writer); + return; + case WireType.StartGroup: + SubItemToken readerToken = StartSubItem(this), + writerToken = ProtoWriter.StartSubItem(null, writer); + while (ReadFieldHeader() > 0) { AppendExtensionField(writer); } + EndSubItem(readerToken, this); + ProtoWriter.EndSubItem(writerToken, writer); + return; + case WireType.None: // treat as explicit errorr + case WireType.EndGroup: // treat as explicit error + default: // treat as implicit error + throw CreateWireTypeException(); + } + } + + /// + /// Indicates whether the reader still has data remaining in the current sub-item, + /// additionally setting the wire-type for the next field if there is more data. + /// This is used when decoding packed data. + /// + public static bool HasSubValue(ProtoBuf.WireType wireType, ProtoReader source) + { + if (source == null) throw new ArgumentNullException("source"); + // check for virtual end of stream + if (source.blockEnd64 <= source.position64 || wireType == WireType.EndGroup) { return false; } + source.wireType = wireType; + return true; + } + + internal int GetTypeKey(ref Type type) + { + return model.GetKey(ref type); + } + + internal NetObjectCache NetCache => netCache; + + internal Type DeserializeType(string value) + { + return TypeModel.DeserializeType(model, value); + } + + internal void SetRootObject(object value) + { + netCache.SetKeyedObject(NetObjectCache.Root, value); + trapCount--; + } + + /// + /// Utility method, not intended for public use; this helps maintain the root object is complex scenarios + /// + public static void NoteObject(object value, ProtoReader reader) + { + if (reader == null) throw new ArgumentNullException("reader"); + if (reader.trapCount != 0) + { + reader.netCache.RegisterTrappedObject(value); + reader.trapCount--; + } + } + + /// + /// Reads a Type from the stream, using the model's DynamicTypeFormatting if appropriate; supported wire-types: String + /// + public Type ReadType() + { + return TypeModel.DeserializeType(model, ReadString()); + } + + internal void TrapNextObject(int newObjectKey) + { + trapCount++; + netCache.SetKeyedObject(newObjectKey, null); // use null as a temp + } + + internal void CheckFullyConsumed() + { + if (isFixedLength) + { + if (dataRemaining64 != 0) throw new ProtoException("Incorrect number of bytes consumed"); + } + else + { + if (available != 0) throw new ProtoException("Unconsumed data left in the buffer; this suggests corrupt input"); + } + } + + /// + /// Merge two objects using the details from the current reader; this is used to change the type + /// of objects when an inheritance relationship is discovered later than usual during deserilazation. + /// + public static object Merge(ProtoReader parent, object from, object to) + { + if (parent == null) throw new ArgumentNullException("parent"); + TypeModel model = parent.Model; + SerializationContext ctx = parent.Context; + if (model == null) throw new InvalidOperationException("Types cannot be merged unless a type-model has been specified"); + using (var ms = new MemoryStream()) + { + model.Serialize(ms, from, ctx); + ms.Position = 0; + return model.Deserialize(ms, to, null); + } + } + + #region RECYCLER + + internal static ProtoReader Create(Stream source, TypeModel model, SerializationContext context, int len) + => Create(source, model, context, (long)len); + /// + /// Creates a new reader against a stream + /// + /// The source stream + /// The model to use for serialization; this can be null, but this will impair the ability to deserialize sub-objects + /// Additional context about this serialization operation + /// The number of bytes to read, or -1 to read until the end of the stream + public static ProtoReader Create(Stream source, TypeModel model, SerializationContext context = null, long length = TO_EOF) + { + ProtoReader reader = GetRecycled(); + if (reader == null) + { +#pragma warning disable CS0618 + return new ProtoReader(source, model, context, length); +#pragma warning restore CS0618 + } + Init(reader, source, model, context, length); + return reader; + } + +#if !PLAT_NO_THREADSTATIC + [ThreadStatic] + private static ProtoReader lastReader; + + private static ProtoReader GetRecycled() + { + ProtoReader tmp = lastReader; + lastReader = null; + return tmp; + } + internal static void Recycle(ProtoReader reader) + { + if (reader != null) + { + reader.Dispose(); + lastReader = reader; + } + } +#elif !PLAT_NO_INTERLOCKED + private static object lastReader; + private static ProtoReader GetRecycled() + { + return (ProtoReader)System.Threading.Interlocked.Exchange(ref lastReader, null); + } + internal static void Recycle(ProtoReader reader) + { + if(reader != null) + { + reader.Dispose(); + System.Threading.Interlocked.Exchange(ref lastReader, reader); + } + } +#else + private static readonly object recycleLock = new object(); + private static ProtoReader lastReader; + private static ProtoReader GetRecycled() + { + lock(recycleLock) + { + ProtoReader tmp = lastReader; + lastReader = null; + return tmp; + } + } + internal static void Recycle(ProtoReader reader) + { + if(reader != null) + { + reader.Dispose(); + lock(recycleLock) + { + lastReader = reader; + } + } + } +#endif + + #endregion + } +} diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/ProtoReader.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/ProtoReader.cs.meta new file mode 100644 index 0000000..0826a16 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/ProtoReader.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: bd9c8ee218e18b14b9058926b6bbc8fe +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/ProtoWriter.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/ProtoWriter.cs new file mode 100644 index 0000000..23fa42d --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/ProtoWriter.cs @@ -0,0 +1,1003 @@ +using System; +using System.IO; +using System.Text; +using ProtoBuf.Meta; + +namespace ProtoBuf +{ + /// + /// Represents an output stream for writing protobuf data. + /// + /// Why is the API backwards (static methods with writer arguments)? + /// See: http://marcgravell.blogspot.com/2010/03/last-will-be-first-and-first-will-be.html + /// + public sealed class ProtoWriter : IDisposable + { + private Stream dest; + TypeModel model; + /// + /// Write an encapsulated sub-object, using the supplied unique key (reprasenting a type). + /// + /// The object to write. + /// The key that uniquely identifies the type within the model. + /// The destination. + public static void WriteObject(object value, int key, ProtoWriter writer) + { + if (writer == null) throw new ArgumentNullException("writer"); + if (writer.model == null) + { + throw new InvalidOperationException("Cannot serialize sub-objects unless a model is provided"); + } + + SubItemToken token = StartSubItem(value, writer); + if (key >= 0) + { + writer.model.Serialize(key, value, writer); + } + else if (writer.model != null && writer.model.TrySerializeAuxiliaryType(writer, value.GetType(), DataFormat.Default, Serializer.ListItemTag, value, false, null)) + { + // all ok + } + else + { + TypeModel.ThrowUnexpectedType(value.GetType()); + } + + EndSubItem(token, writer); + } + /// + /// Write an encapsulated sub-object, using the supplied unique key (reprasenting a type) - but the + /// caller is asserting that this relationship is non-recursive; no recursion check will be + /// performed. + /// + /// The object to write. + /// The key that uniquely identifies the type within the model. + /// The destination. + public static void WriteRecursionSafeObject(object value, int key, ProtoWriter writer) + { + if (writer == null) throw new ArgumentNullException(nameof(writer)); + if (writer.model == null) + { + throw new InvalidOperationException("Cannot serialize sub-objects unless a model is provided"); + } + SubItemToken token = StartSubItem(null, writer); + writer.model.Serialize(key, value, writer); + EndSubItem(token, writer); + } + + internal static void WriteObject(object value, int key, ProtoWriter writer, PrefixStyle style, int fieldNumber) + { + if (writer.model == null) + { + throw new InvalidOperationException("Cannot serialize sub-objects unless a model is provided"); + } + if (writer.wireType != WireType.None) throw ProtoWriter.CreateException(writer); + + switch (style) + { + case PrefixStyle.Base128: + writer.wireType = WireType.String; + writer.fieldNumber = fieldNumber; + if (fieldNumber > 0) WriteHeaderCore(fieldNumber, WireType.String, writer); + break; + case PrefixStyle.Fixed32: + case PrefixStyle.Fixed32BigEndian: + writer.fieldNumber = 0; + writer.wireType = WireType.Fixed32; + break; + default: + throw new ArgumentOutOfRangeException("style"); + } + SubItemToken token = StartSubItem(value, writer, true); + if (key < 0) + { + if (!writer.model.TrySerializeAuxiliaryType(writer, value.GetType(), DataFormat.Default, Serializer.ListItemTag, value, false, null)) + { + TypeModel.ThrowUnexpectedType(value.GetType()); + } + } + else + { + writer.model.Serialize(key, value, writer); + } + EndSubItem(token, writer, style); + } + + internal int GetTypeKey(ref Type type) + { + return model.GetKey(ref type); + } + + private readonly NetObjectCache netCache = new NetObjectCache(); + internal NetObjectCache NetCache => netCache; + + private int fieldNumber, flushLock; + WireType wireType; + internal WireType WireType { get { return wireType; } } + /// + /// Writes a field-header, indicating the format of the next data we plan to write. + /// + public static void WriteFieldHeader(int fieldNumber, WireType wireType, ProtoWriter writer) + { + if (writer == null) throw new ArgumentNullException("writer"); + if (writer.wireType != WireType.None) throw new InvalidOperationException("Cannot write a " + wireType.ToString() + + " header until the " + writer.wireType.ToString() + " data has been written"); + if (fieldNumber < 0) throw new ArgumentOutOfRangeException("fieldNumber"); +#if DEBUG + switch (wireType) + { // validate requested header-type + case WireType.Fixed32: + case WireType.Fixed64: + case WireType.String: + case WireType.StartGroup: + case WireType.SignedVariant: + case WireType.Variant: + break; // fine + case WireType.None: + case WireType.EndGroup: + default: + throw new ArgumentException("Invalid wire-type: " + wireType.ToString(), "wireType"); + } +#endif + if (writer.packedFieldNumber == 0) + { + writer.fieldNumber = fieldNumber; + writer.wireType = wireType; + WriteHeaderCore(fieldNumber, wireType, writer); + } + else if (writer.packedFieldNumber == fieldNumber) + { // we'll set things up, but note we *don't* actually write the header here + switch (wireType) + { + case WireType.Fixed32: + case WireType.Fixed64: + case WireType.Variant: + case WireType.SignedVariant: + break; // fine + default: + throw new InvalidOperationException("Wire-type cannot be encoded as packed: " + wireType.ToString()); + } + writer.fieldNumber = fieldNumber; + writer.wireType = wireType; + } + else + { + throw new InvalidOperationException("Field mismatch during packed encoding; expected " + writer.packedFieldNumber.ToString() + " but received " + fieldNumber.ToString()); + } + } + internal static void WriteHeaderCore(int fieldNumber, WireType wireType, ProtoWriter writer) + { + uint header = (((uint)fieldNumber) << 3) + | (((uint)wireType) & 7); + WriteUInt32Variant(header, writer); + } + + /// + /// Writes a byte-array to the stream; supported wire-types: String + /// + public static void WriteBytes(byte[] data, ProtoWriter writer) + { + if (data == null) throw new ArgumentNullException(nameof(data)); + ProtoWriter.WriteBytes(data, 0, data.Length, writer); + } + /// + /// Writes a byte-array to the stream; supported wire-types: String + /// + public static void WriteBytes(byte[] data, int offset, int length, ProtoWriter writer) + { + if (data == null) throw new ArgumentNullException(nameof(data)); + if (writer == null) throw new ArgumentNullException(nameof(writer)); + switch (writer.wireType) + { + case WireType.Fixed32: + if (length != 4) throw new ArgumentException(nameof(length)); + goto CopyFixedLength; // ugly but effective + case WireType.Fixed64: + if (length != 8) throw new ArgumentException(nameof(length)); + goto CopyFixedLength; // ugly but effective + case WireType.String: + WriteUInt32Variant((uint)length, writer); + writer.wireType = WireType.None; + if (length == 0) return; + if (writer.flushLock != 0 || length <= writer.ioBuffer.Length) // write to the buffer + { + goto CopyFixedLength; // ugly but effective + } + // writing data that is bigger than the buffer (and the buffer + // isn't currently locked due to a sub-object needing the size backfilled) + Flush(writer); // commit any existing data from the buffer + // now just write directly to the underlying stream + writer.dest.Write(data, offset, length); + writer.position64 += length; // since we've flushed offset etc is 0, and remains + // zero since we're writing directly to the stream + return; + } + throw CreateException(writer); + CopyFixedLength: // no point duplicating this lots of times, and don't really want another stackframe + DemandSpace(length, writer); + Buffer.BlockCopy(data, offset, writer.ioBuffer, writer.ioIndex, length); + IncrementedAndReset(length, writer); + } + private static void CopyRawFromStream(Stream source, ProtoWriter writer) + { + byte[] buffer = writer.ioBuffer; + int space = buffer.Length - writer.ioIndex, bytesRead = 1; // 1 here to spoof case where already full + + // try filling the buffer first + while (space > 0 && (bytesRead = source.Read(buffer, writer.ioIndex, space)) > 0) + { + writer.ioIndex += bytesRead; + writer.position64 += bytesRead; + space -= bytesRead; + } + if (bytesRead <= 0) return; // all done using just the buffer; stream exhausted + + // at this point the stream still has data, but buffer is full; + if (writer.flushLock == 0) + { + // flush the buffer and write to the underlying stream instead + Flush(writer); + while ((bytesRead = source.Read(buffer, 0, buffer.Length)) > 0) + { + writer.dest.Write(buffer, 0, bytesRead); + writer.position64 += bytesRead; + } + } + else + { + do + { + // need more space; resize (double) as necessary, + // requesting a reasonable minimum chunk each time + // (128 is the minimum; there may actually be much + // more space than this in the buffer) + DemandSpace(128, writer); + if ((bytesRead = source.Read(writer.ioBuffer, writer.ioIndex, + writer.ioBuffer.Length - writer.ioIndex)) <= 0) break; + writer.position64 += bytesRead; + writer.ioIndex += bytesRead; + } while (true); + } + + } + private static void IncrementedAndReset(int length, ProtoWriter writer) + { + Helpers.DebugAssert(length >= 0); + writer.ioIndex += length; + writer.position64 += length; + writer.wireType = WireType.None; + } + int depth = 0; + const int RecursionCheckDepth = 25; + /// + /// Indicates the start of a nested record. + /// + /// The instance to write. + /// The destination. + /// A token representing the state of the stream; this token is given to EndSubItem. + public static SubItemToken StartSubItem(object instance, ProtoWriter writer) + { + return StartSubItem(instance, writer, false); + } + + MutableList recursionStack; + private void CheckRecursionStackAndPush(object instance) + { + int hitLevel; + if (recursionStack == null) { recursionStack = new MutableList(); } + else if (instance != null && (hitLevel = recursionStack.IndexOfReference(instance)) >= 0) + { +#if DEBUG + Helpers.DebugWriteLine("Stack:"); + foreach (object obj in recursionStack) + { + Helpers.DebugWriteLine(obj == null ? "" : obj.ToString()); + } + Helpers.DebugWriteLine(instance == null ? "" : instance.ToString()); +#endif + throw new ProtoException("Possible recursion detected (offset: " + (recursionStack.Count - hitLevel).ToString() + " level(s)): " + instance.ToString()); + } + recursionStack.Add(instance); + } + private void PopRecursionStack() { recursionStack.RemoveLast(); } + + private static SubItemToken StartSubItem(object instance, ProtoWriter writer, bool allowFixed) + { + if (writer == null) throw new ArgumentNullException("writer"); + if (++writer.depth > RecursionCheckDepth) + { + writer.CheckRecursionStackAndPush(instance); + } + if (writer.packedFieldNumber != 0) throw new InvalidOperationException("Cannot begin a sub-item while performing packed encoding"); + switch (writer.wireType) + { + case WireType.StartGroup: + writer.wireType = WireType.None; + return new SubItemToken((long)(-writer.fieldNumber)); + case WireType.String: +#if DEBUG + if (writer.model != null && writer.model.ForwardsOnly) + { + throw new ProtoException("Should not be buffering data: " + instance ?? "(null)"); + } +#endif + writer.wireType = WireType.None; + DemandSpace(32, writer); // make some space in anticipation... + writer.flushLock++; + writer.position64++; + return new SubItemToken((long)(writer.ioIndex++)); // leave 1 space (optimistic) for length + case WireType.Fixed32: + { + if (!allowFixed) throw CreateException(writer); + DemandSpace(32, writer); // make some space in anticipation... + writer.flushLock++; + SubItemToken token = new SubItemToken((long)writer.ioIndex); + ProtoWriter.IncrementedAndReset(4, writer); // leave 4 space (rigid) for length + return token; + } + default: + throw CreateException(writer); + } + } + + /// + /// Indicates the end of a nested record. + /// + /// The token obtained from StartubItem. + /// The destination. + public static void EndSubItem(SubItemToken token, ProtoWriter writer) + { + EndSubItem(token, writer, PrefixStyle.Base128); + } + private static void EndSubItem(SubItemToken token, ProtoWriter writer, PrefixStyle style) + { + if (writer == null) throw new ArgumentNullException("writer"); + if (writer.wireType != WireType.None) { throw CreateException(writer); } + int value = (int)token.value64; + if (writer.depth <= 0) throw CreateException(writer); + if (writer.depth-- > RecursionCheckDepth) + { + writer.PopRecursionStack(); + } + writer.packedFieldNumber = 0; // ending the sub-item always wipes packed encoding + if (value < 0) + { // group - very simple append + WriteHeaderCore(-value, WireType.EndGroup, writer); + writer.wireType = WireType.None; + return; + } + + // so we're backfilling the length into an existing sequence + int len; + switch (style) + { + case PrefixStyle.Fixed32: + len = (int)((writer.ioIndex - value) - 4); + ProtoWriter.WriteInt32ToBuffer(len, writer.ioBuffer, value); + break; + case PrefixStyle.Fixed32BigEndian: + len = (int)((writer.ioIndex - value) - 4); + byte[] buffer = writer.ioBuffer; + ProtoWriter.WriteInt32ToBuffer(len, buffer, value); + // and swap the byte order + byte b = buffer[value]; + buffer[value] = buffer[value + 3]; + buffer[value + 3] = b; + b = buffer[value + 1]; + buffer[value + 1] = buffer[value + 2]; + buffer[value + 2] = b; + break; + case PrefixStyle.Base128: + // string - complicated because we only reserved one byte; + // if the prefix turns out to need more than this then + // we need to shuffle the existing data + len = (int)((writer.ioIndex - value) - 1); + int offset = 0; + uint tmp = (uint)len; + while ((tmp >>= 7) != 0) offset++; + if (offset == 0) + { + writer.ioBuffer[value] = (byte)(len & 0x7F); + } + else + { + DemandSpace(offset, writer); + byte[] blob = writer.ioBuffer; + Buffer.BlockCopy(blob, value + 1, blob, value + 1 + offset, len); + tmp = (uint)len; + do + { + blob[value++] = (byte)((tmp & 0x7F) | 0x80); + } while ((tmp >>= 7) != 0); + blob[value - 1] = (byte)(blob[value - 1] & ~0x80); + writer.position64 += offset; + writer.ioIndex += offset; + } + break; + default: + throw new ArgumentOutOfRangeException("style"); + } + // and this object is no longer a blockage - also flush if sensible + const int ADVISORY_FLUSH_SIZE = 1024; + if (--writer.flushLock == 0 && writer.ioIndex >= ADVISORY_FLUSH_SIZE) + { + ProtoWriter.Flush(writer); + } + + } + + /// + /// Creates a new writer against a stream + /// + /// The destination stream + /// The model to use for serialization; this can be null, but this will impair the ability to serialize sub-objects + /// Additional context about this serialization operation + public static ProtoWriter Create(Stream dest, TypeModel model, SerializationContext context = null) +#pragma warning disable CS0618 + => new ProtoWriter(dest, model, context); +#pragma warning restore CS0618 + + /// + /// Creates a new writer against a stream + /// + /// The destination stream + /// The model to use for serialization; this can be null, but this will impair the ability to serialize sub-objects + /// Additional context about this serialization operation + [Obsolete("Please use ProtoWriter.Create; this API may be removed in a future version", error: false)] + public ProtoWriter(Stream dest, TypeModel model, SerializationContext context) + { + if (dest == null) throw new ArgumentNullException("dest"); + if (!dest.CanWrite) throw new ArgumentException("Cannot write to stream", "dest"); + //if (model == null) throw new ArgumentNullException("model"); + this.dest = dest; + this.ioBuffer = BufferPool.GetBuffer(); + this.model = model; + this.wireType = WireType.None; + if (context == null) { context = SerializationContext.Default; } + else { context.Freeze(); } + this.context = context; + + } + + private readonly SerializationContext context; + /// + /// Addition information about this serialization operation. + /// + public SerializationContext Context => context; + + void IDisposable.Dispose() + { + Dispose(); + } + + private void Dispose() + { // importantly, this does **not** own the stream, and does not dispose it + if (dest != null) + { + Flush(this); + dest = null; + } + model = null; + BufferPool.ReleaseBufferToPool(ref ioBuffer); + } + + private byte[] ioBuffer; + private int ioIndex; + // note that this is used by some of the unit tests and should not be removed + internal static long GetLongPosition(ProtoWriter writer) { return writer.position64; } + internal static int GetPosition(ProtoWriter writer) { return checked((int)writer.position64); } + private long position64; + private static void DemandSpace(int required, ProtoWriter writer) + { + // check for enough space + if ((writer.ioBuffer.Length - writer.ioIndex) < required) + { + TryFlushOrResize(required, writer); + } + } + + private static void TryFlushOrResize(int required, ProtoWriter writer) + { + if (writer.flushLock == 0) + { + Flush(writer); // try emptying the buffer + if ((writer.ioBuffer.Length - writer.ioIndex) >= required) return; + } + + // either can't empty the buffer, or that didn't help; need more space + BufferPool.ResizeAndFlushLeft(ref writer.ioBuffer, required + writer.ioIndex, 0, writer.ioIndex); + } + + /// + /// Flushes data to the underlying stream, and releases any resources. The underlying stream is *not* disposed + /// by this operation. + /// + public void Close() + { + if (depth != 0 || flushLock != 0) throw new InvalidOperationException("Unable to close stream in an incomplete state"); + Dispose(); + } + + internal void CheckDepthFlushlock() + { + if (depth != 0 || flushLock != 0) throw new InvalidOperationException("The writer is in an incomplete state"); + } + + /// + /// Get the TypeModel associated with this writer + /// + public TypeModel Model => model; + + /// + /// Writes any buffered data (if possible) to the underlying stream. + /// + /// The writer to flush + /// It is not always possible to fully flush, since some sequences + /// may require values to be back-filled into the byte-stream. + internal static void Flush(ProtoWriter writer) + { + if (writer.flushLock == 0 && writer.ioIndex != 0) + { + writer.dest.Write(writer.ioBuffer, 0, writer.ioIndex); + writer.ioIndex = 0; + } + } + + /// + /// Writes an unsigned 32-bit integer to the stream; supported wire-types: Variant, Fixed32, Fixed64 + /// + private static void WriteUInt32Variant(uint value, ProtoWriter writer) + { + DemandSpace(5, writer); + int count = 0; + do + { + writer.ioBuffer[writer.ioIndex++] = (byte)((value & 0x7F) | 0x80); + count++; + } while ((value >>= 7) != 0); + writer.ioBuffer[writer.ioIndex - 1] &= 0x7F; + writer.position64 += count; + } + +#if COREFX + static readonly Encoding encoding = Encoding.UTF8; +#else + static readonly UTF8Encoding encoding = new UTF8Encoding(); +#endif + + internal static uint Zig(int value) + { + return (uint)((value << 1) ^ (value >> 31)); + } + + internal static ulong Zig(long value) + { + return (ulong)((value << 1) ^ (value >> 63)); + } + + private static void WriteUInt64Variant(ulong value, ProtoWriter writer) + { + DemandSpace(10, writer); + int count = 0; + do + { + writer.ioBuffer[writer.ioIndex++] = (byte)((value & 0x7F) | 0x80); + count++; + } while ((value >>= 7) != 0); + writer.ioBuffer[writer.ioIndex - 1] &= 0x7F; + writer.position64 += count; + } + + /// + /// Writes a string to the stream; supported wire-types: String + /// + public static void WriteString(string value, ProtoWriter writer) + { + if (writer == null) throw new ArgumentNullException("writer"); + if (writer.wireType != WireType.String) throw CreateException(writer); + if (value == null) throw new ArgumentNullException("value"); // written header; now what? + int len = value.Length; + if (len == 0) + { + WriteUInt32Variant(0, writer); + writer.wireType = WireType.None; + return; // just a header + } + int predicted = encoding.GetByteCount(value); + WriteUInt32Variant((uint)predicted, writer); + DemandSpace(predicted, writer); + int actual = encoding.GetBytes(value, 0, value.Length, writer.ioBuffer, writer.ioIndex); + Helpers.DebugAssert(predicted == actual); + IncrementedAndReset(actual, writer); + } + + /// + /// Writes an unsigned 64-bit integer to the stream; supported wire-types: Variant, Fixed32, Fixed64 + /// + public static void WriteUInt64(ulong value, ProtoWriter writer) + { + if (writer == null) throw new ArgumentNullException(nameof(writer)); + switch (writer.wireType) + { + case WireType.Fixed64: + ProtoWriter.WriteInt64((long)value, writer); + return; + case WireType.Variant: + WriteUInt64Variant(value, writer); + writer.wireType = WireType.None; + return; + case WireType.Fixed32: + checked { ProtoWriter.WriteUInt32((uint)value, writer); } + return; + default: + throw CreateException(writer); + } + } + + /// + /// Writes a signed 64-bit integer to the stream; supported wire-types: Variant, Fixed32, Fixed64, SignedVariant + /// + public static void WriteInt64(long value, ProtoWriter writer) + { + byte[] buffer; + int index; + if (writer == null) throw new ArgumentNullException(nameof(writer)); + switch (writer.wireType) + { + case WireType.Fixed64: + DemandSpace(8, writer); + buffer = writer.ioBuffer; + index = writer.ioIndex; + +#if NETCOREAPP2_1 + System.Buffers.Binary.BinaryPrimitives.WriteInt64LittleEndian(buffer.AsSpan(index, 8), value); +#else + buffer[index] = (byte)value; + buffer[index + 1] = (byte)(value >> 8); + buffer[index + 2] = (byte)(value >> 16); + buffer[index + 3] = (byte)(value >> 24); + buffer[index + 4] = (byte)(value >> 32); + buffer[index + 5] = (byte)(value >> 40); + buffer[index + 6] = (byte)(value >> 48); + buffer[index + 7] = (byte)(value >> 56); +#endif + IncrementedAndReset(8, writer); + return; + case WireType.SignedVariant: + WriteUInt64Variant(Zig(value), writer); + writer.wireType = WireType.None; + return; + case WireType.Variant: + if (value >= 0) + { + WriteUInt64Variant((ulong)value, writer); + writer.wireType = WireType.None; + } + else + { + DemandSpace(10, writer); + buffer = writer.ioBuffer; + index = writer.ioIndex; + buffer[index] = (byte)(value | 0x80); + buffer[index + 1] = (byte)((int)(value >> 7) | 0x80); + buffer[index + 2] = (byte)((int)(value >> 14) | 0x80); + buffer[index + 3] = (byte)((int)(value >> 21) | 0x80); + buffer[index + 4] = (byte)((int)(value >> 28) | 0x80); + buffer[index + 5] = (byte)((int)(value >> 35) | 0x80); + buffer[index + 6] = (byte)((int)(value >> 42) | 0x80); + buffer[index + 7] = (byte)((int)(value >> 49) | 0x80); + buffer[index + 8] = (byte)((int)(value >> 56) | 0x80); + buffer[index + 9] = 0x01; // sign bit + IncrementedAndReset(10, writer); + } + return; + case WireType.Fixed32: + checked { WriteInt32((int)value, writer); } + return; + default: + throw CreateException(writer); + } + } + + /// + /// Writes an unsigned 16-bit integer to the stream; supported wire-types: Variant, Fixed32, Fixed64 + /// + public static void WriteUInt32(uint value, ProtoWriter writer) + { + if (writer == null) throw new ArgumentNullException("writer"); + switch (writer.wireType) + { + case WireType.Fixed32: + ProtoWriter.WriteInt32((int)value, writer); + return; + case WireType.Fixed64: + ProtoWriter.WriteInt64((int)value, writer); + return; + case WireType.Variant: + WriteUInt32Variant(value, writer); + writer.wireType = WireType.None; + return; + default: + throw CreateException(writer); + } + } + + /// + /// Writes a signed 16-bit integer to the stream; supported wire-types: Variant, Fixed32, Fixed64, SignedVariant + /// + public static void WriteInt16(short value, ProtoWriter writer) + { + ProtoWriter.WriteInt32(value, writer); + } + + /// + /// Writes an unsigned 16-bit integer to the stream; supported wire-types: Variant, Fixed32, Fixed64 + /// + public static void WriteUInt16(ushort value, ProtoWriter writer) + { + ProtoWriter.WriteUInt32(value, writer); + } + + /// + /// Writes an unsigned 8-bit integer to the stream; supported wire-types: Variant, Fixed32, Fixed64 + /// + public static void WriteByte(byte value, ProtoWriter writer) + { + ProtoWriter.WriteUInt32(value, writer); + } + /// + /// Writes a signed 8-bit integer to the stream; supported wire-types: Variant, Fixed32, Fixed64, SignedVariant + /// + public static void WriteSByte(sbyte value, ProtoWriter writer) + { + ProtoWriter.WriteInt32(value, writer); + } + + private static void WriteInt32ToBuffer(int value, byte[] buffer, int index) + { +#if NETCOREAPP2_1 + System.Buffers.Binary.BinaryPrimitives.WriteInt32LittleEndian(buffer.AsSpan(index, 4), value); +#else + buffer[index] = (byte)value; + buffer[index + 1] = (byte)(value >> 8); + buffer[index + 2] = (byte)(value >> 16); + buffer[index + 3] = (byte)(value >> 24); +#endif + } + + /// + /// Writes a signed 32-bit integer to the stream; supported wire-types: Variant, Fixed32, Fixed64, SignedVariant + /// + public static void WriteInt32(int value, ProtoWriter writer) + { + byte[] buffer; + int index; + if (writer == null) throw new ArgumentNullException(nameof(writer)); + switch (writer.wireType) + { + case WireType.Fixed32: + DemandSpace(4, writer); + WriteInt32ToBuffer(value, writer.ioBuffer, writer.ioIndex); + IncrementedAndReset(4, writer); + return; + case WireType.Fixed64: + DemandSpace(8, writer); + buffer = writer.ioBuffer; + index = writer.ioIndex; + buffer[index] = (byte)value; + buffer[index + 1] = (byte)(value >> 8); + buffer[index + 2] = (byte)(value >> 16); + buffer[index + 3] = (byte)(value >> 24); + buffer[index + 4] = buffer[index + 5] = + buffer[index + 6] = buffer[index + 7] = 0; + IncrementedAndReset(8, writer); + return; + case WireType.SignedVariant: + WriteUInt32Variant(Zig(value), writer); + writer.wireType = WireType.None; + return; + case WireType.Variant: + if (value >= 0) + { + WriteUInt32Variant((uint)value, writer); + writer.wireType = WireType.None; + } + else + { + DemandSpace(10, writer); + buffer = writer.ioBuffer; + index = writer.ioIndex; + buffer[index] = (byte)(value | 0x80); + buffer[index + 1] = (byte)((value >> 7) | 0x80); + buffer[index + 2] = (byte)((value >> 14) | 0x80); + buffer[index + 3] = (byte)((value >> 21) | 0x80); + buffer[index + 4] = (byte)((value >> 28) | 0x80); + buffer[index + 5] = buffer[index + 6] = + buffer[index + 7] = buffer[index + 8] = (byte)0xFF; + buffer[index + 9] = (byte)0x01; + IncrementedAndReset(10, writer); + } + return; + default: + throw CreateException(writer); + } + } + + /// + /// Writes a double-precision number to the stream; supported wire-types: Fixed32, Fixed64 + /// + public +#if !FEAT_SAFE + unsafe +#endif + + static void WriteDouble(double value, ProtoWriter writer) + { + if (writer == null) throw new ArgumentNullException("writer"); + switch (writer.wireType) + { + case WireType.Fixed32: + float f = (float)value; + if (float.IsInfinity(f) && !double.IsInfinity(value)) + { + throw new OverflowException(); + } + ProtoWriter.WriteSingle(f, writer); + return; + case WireType.Fixed64: +#if FEAT_SAFE + ProtoWriter.WriteInt64(BitConverter.ToInt64(BitConverter.GetBytes(value), 0), writer); +#else + ProtoWriter.WriteInt64(*(long*)&value, writer); +#endif + return; + default: + throw CreateException(writer); + } + } + /// + /// Writes a single-precision number to the stream; supported wire-types: Fixed32, Fixed64 + /// + public +#if !FEAT_SAFE + unsafe +#endif + static void WriteSingle(float value, ProtoWriter writer) + { + if (writer == null) throw new ArgumentNullException("writer"); + switch (writer.wireType) + { + case WireType.Fixed32: +#if FEAT_SAFE + ProtoWriter.WriteInt32(BitConverter.ToInt32(BitConverter.GetBytes(value), 0), writer); +#else + ProtoWriter.WriteInt32(*(int*)&value, writer); +#endif + return; + case WireType.Fixed64: + ProtoWriter.WriteDouble((double)value, writer); + return; + default: + throw CreateException(writer); + } + } + + /// + /// Throws an exception indicating that the given enum cannot be mapped to a serialized value. + /// + public static void ThrowEnumException(ProtoWriter writer, object enumValue) + { + if (writer == null) throw new ArgumentNullException("writer"); + string rhs = enumValue == null ? "" : (enumValue.GetType().FullName + "." + enumValue.ToString()); + throw new ProtoException("No wire-value is mapped to the enum " + rhs + " at position " + writer.position64.ToString()); + } + + // general purpose serialization exception message + internal static Exception CreateException(ProtoWriter writer) + { + if (writer == null) throw new ArgumentNullException("writer"); + return new ProtoException("Invalid serialization operation with wire-type " + writer.wireType.ToString() + " at position " + writer.position64.ToString()); + } + + /// + /// Writes a boolean to the stream; supported wire-types: Variant, Fixed32, Fixed64 + /// + public static void WriteBoolean(bool value, ProtoWriter writer) + { + ProtoWriter.WriteUInt32(value ? (uint)1 : (uint)0, writer); + } + + /// + /// Copies any extension data stored for the instance to the underlying stream + /// + public static void AppendExtensionData(IExtensible instance, ProtoWriter writer) + { + if (instance == null) throw new ArgumentNullException(nameof(instance)); + if (writer == null) throw new ArgumentNullException(nameof(writer)); + // we expect the writer to be raw here; the extension data will have the + // header detail, so we'll copy it implicitly + if (writer.wireType != WireType.None) throw CreateException(writer); + + IExtension extn = instance.GetExtensionObject(false); + if (extn != null) + { + // unusually we *don't* want "using" here; the "finally" does that, with + // the extension object being responsible for disposal etc + Stream source = extn.BeginQuery(); + try + { + CopyRawFromStream(source, writer); + } + finally { extn.EndQuery(source); } + } + } + + private int packedFieldNumber; + /// + /// Used for packed encoding; indicates that the next field should be skipped rather than + /// a field header written. Note that the field number must match, else an exception is thrown + /// when the attempt is made to write the (incorrect) field. The wire-type is taken from the + /// subsequent call to WriteFieldHeader. Only primitive types can be packed. + /// + public static void SetPackedField(int fieldNumber, ProtoWriter writer) + { + if (fieldNumber <= 0) throw new ArgumentOutOfRangeException(nameof(fieldNumber)); + if (writer == null) throw new ArgumentNullException(nameof(writer)); + writer.packedFieldNumber = fieldNumber; + } + + /// + /// Used for packed encoding; explicitly reset the packed field marker; this is not required + /// if using StartSubItem/EndSubItem + /// + public static void ClearPackedField(int fieldNumber, ProtoWriter writer) + { + if (fieldNumber != writer.packedFieldNumber) + throw new InvalidOperationException("Field mismatch during packed encoding; expected " + writer.packedFieldNumber.ToString() + " but received " + fieldNumber.ToString()); + writer.packedFieldNumber = 0; + } + + /// + /// Used for packed encoding; writes the length prefix using fixed sizes rather than using + /// buffering. Only valid for fixed-32 and fixed-64 encoding. + /// + public static void WritePackedPrefix(int elementCount, WireType wireType, ProtoWriter writer) + { + if (writer.WireType != WireType.String) throw new InvalidOperationException("Invalid wire-type: " + writer.WireType); + if (elementCount < 0) throw new ArgumentOutOfRangeException(nameof(elementCount)); + ulong bytes; + switch (wireType) + { + // use long in case very large arrays are enabled + case WireType.Fixed32: bytes = ((ulong)elementCount) << 2; break; // x4 + case WireType.Fixed64: bytes = ((ulong)elementCount) << 3; break; // x8 + default: + throw new ArgumentOutOfRangeException(nameof(wireType), "Invalid wire-type: " + wireType); + } + WriteUInt64Variant(bytes, writer); + writer.wireType = WireType.None; + } + + internal string SerializeType(Type type) + { + return TypeModel.SerializeType(model, type); + } + + /// + /// Specifies a known root object to use during reference-tracked serialization + /// + public void SetRootObject(object value) + { + NetCache.SetKeyedObject(NetObjectCache.Root, value); + } + + /// + /// Writes a Type to the stream, using the model's DynamicTypeFormatting if appropriate; supported wire-types: String + /// + public static void WriteType(Type value, ProtoWriter writer) + { + if (writer == null) throw new ArgumentNullException(nameof(writer)); + WriteString(writer.SerializeType(value), writer); + } + } +} diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/ProtoWriter.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/ProtoWriter.cs.meta new file mode 100644 index 0000000..5b91b67 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/ProtoWriter.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 63b2636e44dc3824ca2dbc35316e96ec +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/SerializationContext.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/SerializationContext.cs new file mode 100644 index 0000000..80b76af --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/SerializationContext.cs @@ -0,0 +1,76 @@ +using System; + +namespace ProtoBuf +{ + /// + /// Additional information about a serialization operation + /// + public sealed class SerializationContext + { + private bool frozen; + internal void Freeze() { frozen = true; } + private void ThrowIfFrozen() { if (frozen) throw new InvalidOperationException("The serialization-context cannot be changed once it is in use"); } + private object context; + /// + /// Gets or sets a user-defined object containing additional information about this serialization/deserialization operation. + /// + public object Context + { + get { return context; } + set { if (context != value) { ThrowIfFrozen(); context = value; } } + } + + private static readonly SerializationContext @default; + + static SerializationContext() + { + @default = new SerializationContext(); + @default.Freeze(); + } + /// + /// A default SerializationContext, with minimal information. + /// + internal static SerializationContext Default => @default; +#if PLAT_BINARYFORMATTER + +#if !(COREFX || PROFILE259) + private System.Runtime.Serialization.StreamingContextStates state = System.Runtime.Serialization.StreamingContextStates.Persistence; + /// + /// Gets or sets the source or destination of the transmitted data. + /// + public System.Runtime.Serialization.StreamingContextStates State + { + get { return state; } + set { if (state != value) { ThrowIfFrozen(); state = value; } } + } +#endif + /// + /// Convert a SerializationContext to a StreamingContext + /// + public static implicit operator System.Runtime.Serialization.StreamingContext(SerializationContext ctx) + { +#if COREFX + return new System.Runtime.Serialization.StreamingContext(); +#else + if (ctx == null) return new System.Runtime.Serialization.StreamingContext(System.Runtime.Serialization.StreamingContextStates.Persistence); + return new System.Runtime.Serialization.StreamingContext(ctx.state, ctx.context); +#endif + } + /// + /// Convert a StreamingContext to a SerializationContext + /// + public static implicit operator SerializationContext (System.Runtime.Serialization.StreamingContext ctx) + { + SerializationContext result = new SerializationContext(); + +#if !(COREFX || PROFILE259) + result.Context = ctx.Context; + result.State = ctx.State; +#endif + + return result; + } +#endif + } + +} diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/SerializationContext.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/SerializationContext.cs.meta new file mode 100644 index 0000000..9bd8dcc --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/SerializationContext.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9361aaa524d95b14fbf398ba5bc075a1 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializer.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializer.cs new file mode 100644 index 0000000..8a4c38a --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializer.cs @@ -0,0 +1,514 @@ +using ProtoBuf.Meta; +using System; +using System.IO; +using System.Collections.Generic; +using System.Reflection; + +namespace ProtoBuf +{ + /// + /// Provides protocol-buffer serialization capability for concrete, attributed types. This + /// is a *default* model, but custom serializer models are also supported. + /// + /// + /// Protocol-buffer serialization is a compact binary format, designed to take + /// advantage of sparse data and knowledge of specific data types; it is also + /// extensible, allowing a type to be deserialized / merged even if some data is + /// not recognised. + /// + public static class Serializer + { +#if !NO_RUNTIME + /// + /// Suggest a .proto definition for the given type + /// + /// The type to generate a .proto definition for + /// The .proto definition as a string + public static string GetProto() => GetProto(ProtoSyntax.Proto2); + + /// + /// Suggest a .proto definition for the given type + /// + /// The type to generate a .proto definition for + /// The .proto definition as a string + public static string GetProto(ProtoSyntax syntax) + { + return RuntimeTypeModel.Default.GetSchema(RuntimeTypeModel.Default.MapType(typeof(T)), syntax); + } + /// + /// Create a deep clone of the supplied instance; any sub-items are also cloned. + /// + public static T DeepClone(T instance) + { + return instance == null ? instance : (T)RuntimeTypeModel.Default.DeepClone(instance); + } + + /// + /// Applies a protocol-buffer stream to an existing instance. + /// + /// The type being merged. + /// The existing instance to be modified (can be null). + /// The binary stream to apply to the instance (cannot be null). + /// The updated instance; this may be different to the instance argument if + /// either the original instance was null, or the stream defines a known sub-type of the + /// original instance. + public static T Merge(Stream source, T instance) + { + return (T)RuntimeTypeModel.Default.Deserialize(source, instance, typeof(T)); + } + + /// + /// Creates a new instance from a protocol-buffer stream + /// + /// The type to be created. + /// The binary stream to apply to the new instance (cannot be null). + /// A new, initialized instance. + public static T Deserialize(Stream source) + { + return (T)RuntimeTypeModel.Default.Deserialize(source, null, typeof(T)); + } + + /// + /// Creates a new instance from a protocol-buffer stream + /// + /// The type to be created. + /// The binary stream to apply to the new instance (cannot be null). + /// A new, initialized instance. + public static object Deserialize(Type type, Stream source) + { + return RuntimeTypeModel.Default.Deserialize(source, null, type); + } + + /// + /// Writes a protocol-buffer representation of the given instance to the supplied stream. + /// + /// The existing instance to be serialized (cannot be null). + /// The destination stream to write to. + public static void Serialize(Stream destination, T instance) + { + if (instance != null) + { + RuntimeTypeModel.Default.Serialize(destination, instance); + } + } + + /// + /// Serializes a given instance and deserializes it as a different type; + /// this can be used to translate between wire-compatible objects (where + /// two .NET types represent the same data), or to promote/demote a type + /// through an inheritance hierarchy. + /// + /// No assumption of compatibility is made between the types. + /// The type of the object being copied. + /// The type of the new object to be created. + /// The existing instance to use as a template. + /// A new instane of type TNewType, with the data from TOldType. + public static TTo ChangeType(TFrom instance) + { + using (var ms = new MemoryStream()) + { + Serialize(ms, instance); + ms.Position = 0; + return Deserialize(ms); + } + } +#if PLAT_BINARYFORMATTER && !(COREFX || PROFILE259) + /// + /// Writes a protocol-buffer representation of the given instance to the supplied SerializationInfo. + /// + /// The type being serialized. + /// The existing instance to be serialized (cannot be null). + /// The destination SerializationInfo to write to. + public static void Serialize(System.Runtime.Serialization.SerializationInfo info, T instance) where T : class, System.Runtime.Serialization.ISerializable + { + Serialize(info, new System.Runtime.Serialization.StreamingContext(System.Runtime.Serialization.StreamingContextStates.Persistence), instance); + } + /// + /// Writes a protocol-buffer representation of the given instance to the supplied SerializationInfo. + /// + /// The type being serialized. + /// The existing instance to be serialized (cannot be null). + /// The destination SerializationInfo to write to. + /// Additional information about this serialization operation. + public static void Serialize(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context, T instance) where T : class, System.Runtime.Serialization.ISerializable + { + // note: also tried byte[]... it doesn't perform hugely well with either (compared to regular serialization) + if (info == null) throw new ArgumentNullException("info"); + if (instance == null) throw new ArgumentNullException("instance"); + if (instance.GetType() != typeof(T)) throw new ArgumentException("Incorrect type", "instance"); + using (MemoryStream ms = new MemoryStream()) + { + RuntimeTypeModel.Default.Serialize(ms, instance, context); + info.AddValue(ProtoBinaryField, ms.ToArray()); + } + } +#endif +#if PLAT_XMLSERIALIZER + /// + /// Writes a protocol-buffer representation of the given instance to the supplied XmlWriter. + /// + /// The type being serialized. + /// The existing instance to be serialized (cannot be null). + /// The destination XmlWriter to write to. + public static void Serialize(System.Xml.XmlWriter writer, T instance) where T : System.Xml.Serialization.IXmlSerializable + { + if (writer == null) throw new ArgumentNullException("writer"); + if (instance == null) throw new ArgumentNullException("instance"); + + using (MemoryStream ms = new MemoryStream()) + { + Serializer.Serialize(ms, instance); + writer.WriteBase64(Helpers.GetBuffer(ms), 0, (int)ms.Length); + } + } + /// + /// Applies a protocol-buffer from an XmlReader to an existing instance. + /// + /// The type being merged. + /// The existing instance to be modified (cannot be null). + /// The XmlReader containing the data to apply to the instance (cannot be null). + public static void Merge(System.Xml.XmlReader reader, T instance) where T : System.Xml.Serialization.IXmlSerializable + { + if (reader == null) throw new ArgumentNullException("reader"); + if (instance == null) throw new ArgumentNullException("instance"); + + const int LEN = 4096; + byte[] buffer = new byte[LEN]; + int read; + using (MemoryStream ms = new MemoryStream()) + { + int depth = reader.Depth; + while(reader.Read() && reader.Depth > depth) + { + if (reader.NodeType == System.Xml.XmlNodeType.Text) + { + while ((read = reader.ReadContentAsBase64(buffer, 0, LEN)) > 0) + { + ms.Write(buffer, 0, read); + } + if (reader.Depth <= depth) break; + } + } + ms.Position = 0; + Serializer.Merge(ms, instance); + } + } +#endif + + private const string ProtoBinaryField = "proto"; +#if PLAT_BINARYFORMATTER && !(COREFX || PROFILE259) + /// + /// Applies a protocol-buffer from a SerializationInfo to an existing instance. + /// + /// The type being merged. + /// The existing instance to be modified (cannot be null). + /// The SerializationInfo containing the data to apply to the instance (cannot be null). + public static void Merge(System.Runtime.Serialization.SerializationInfo info, T instance) where T : class, System.Runtime.Serialization.ISerializable + { + Merge(info, new System.Runtime.Serialization.StreamingContext(System.Runtime.Serialization.StreamingContextStates.Persistence), instance); + } + /// + /// Applies a protocol-buffer from a SerializationInfo to an existing instance. + /// + /// The type being merged. + /// The existing instance to be modified (cannot be null). + /// The SerializationInfo containing the data to apply to the instance (cannot be null). + /// Additional information about this serialization operation. + public static void Merge(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context, T instance) where T : class, System.Runtime.Serialization.ISerializable + { + // note: also tried byte[]... it doesn't perform hugely well with either (compared to regular serialization) + if (info == null) throw new ArgumentNullException("info"); + if (instance == null) throw new ArgumentNullException("instance"); + if (instance.GetType() != typeof(T)) throw new ArgumentException("Incorrect type", "instance"); + + byte[] buffer = (byte[])info.GetValue(ProtoBinaryField, typeof(byte[])); + using (MemoryStream ms = new MemoryStream(buffer)) + { + T result = (T)RuntimeTypeModel.Default.Deserialize(ms, instance, typeof(T), context); + if (!ReferenceEquals(result, instance)) + { + throw new ProtoException("Deserialization changed the instance; cannot succeed."); + } + } + } +#endif + + /// + /// Precompiles the serializer for a given type. + /// + public static void PrepareSerializer() + { + NonGeneric.PrepareSerializer(typeof(T)); + } + +#if PLAT_BINARYFORMATTER && !(COREFX || PROFILE259) + /// + /// Creates a new IFormatter that uses protocol-buffer [de]serialization. + /// + /// The type of object to be [de]deserialized by the formatter. + /// A new IFormatter to be used during [de]serialization. + public static System.Runtime.Serialization.IFormatter CreateFormatter() + { + return RuntimeTypeModel.Default.CreateFormatter(typeof(T)); + } +#endif + /// + /// Reads a sequence of consecutive length-prefixed items from a stream, using + /// either base-128 or fixed-length prefixes. Base-128 prefixes with a tag + /// are directly comparable to serializing multiple items in succession + /// (use the tag to emulate the implicit behavior + /// when serializing a list/array). When a tag is + /// specified, any records with different tags are silently omitted. The + /// tag is ignored. The tag is ignored for fixed-length prefixes. + /// + /// The type of object to deserialize. + /// The binary stream containing the serialized records. + /// The prefix style used in the data. + /// The tag of records to return (if non-positive, then no tag is + /// expected and all records are returned). + /// The sequence of deserialized objects. + public static IEnumerable DeserializeItems(Stream source, PrefixStyle style, int fieldNumber) + { + return RuntimeTypeModel.Default.DeserializeItems(source, style, fieldNumber); + } + + /// + /// Creates a new instance from a protocol-buffer stream that has a length-prefix + /// on data (to assist with network IO). + /// + /// The type to be created. + /// The binary stream to apply to the new instance (cannot be null). + /// How to encode the length prefix. + /// A new, initialized instance. + public static T DeserializeWithLengthPrefix(Stream source, PrefixStyle style) + { + return DeserializeWithLengthPrefix(source, style, 0); + } + + /// + /// Creates a new instance from a protocol-buffer stream that has a length-prefix + /// on data (to assist with network IO). + /// + /// The type to be created. + /// The binary stream to apply to the new instance (cannot be null). + /// How to encode the length prefix. + /// The expected tag of the item (only used with base-128 prefix style). + /// A new, initialized instance. + public static T DeserializeWithLengthPrefix(Stream source, PrefixStyle style, int fieldNumber) + { + RuntimeTypeModel model = RuntimeTypeModel.Default; + return (T)model.DeserializeWithLengthPrefix(source, null, model.MapType(typeof(T)), style, fieldNumber); + } + + /// + /// Applies a protocol-buffer stream to an existing instance, using length-prefixed + /// data - useful with network IO. + /// + /// The type being merged. + /// The existing instance to be modified (can be null). + /// The binary stream to apply to the instance (cannot be null). + /// How to encode the length prefix. + /// The updated instance; this may be different to the instance argument if + /// either the original instance was null, or the stream defines a known sub-type of the + /// original instance. + public static T MergeWithLengthPrefix(Stream source, T instance, PrefixStyle style) + { + RuntimeTypeModel model = RuntimeTypeModel.Default; + return (T)model.DeserializeWithLengthPrefix(source, instance, model.MapType(typeof(T)), style, 0); + } + + /// + /// Writes a protocol-buffer representation of the given instance to the supplied stream, + /// with a length-prefix. This is useful for socket programming, + /// as DeserializeWithLengthPrefix/MergeWithLengthPrefix can be used to read the single object back + /// from an ongoing stream. + /// + /// The type being serialized. + /// The existing instance to be serialized (cannot be null). + /// How to encode the length prefix. + /// The destination stream to write to. + public static void SerializeWithLengthPrefix(Stream destination, T instance, PrefixStyle style) + { + SerializeWithLengthPrefix(destination, instance, style, 0); + } + + /// + /// Writes a protocol-buffer representation of the given instance to the supplied stream, + /// with a length-prefix. This is useful for socket programming, + /// as DeserializeWithLengthPrefix/MergeWithLengthPrefix can be used to read the single object back + /// from an ongoing stream. + /// + /// The type being serialized. + /// The existing instance to be serialized (cannot be null). + /// How to encode the length prefix. + /// The destination stream to write to. + /// The tag used as a prefix to each record (only used with base-128 style prefixes). + public static void SerializeWithLengthPrefix(Stream destination, T instance, PrefixStyle style, int fieldNumber) + { + RuntimeTypeModel model = RuntimeTypeModel.Default; + model.SerializeWithLengthPrefix(destination, instance, model.MapType(typeof(T)), style, fieldNumber); + } + + /// Indicates the number of bytes expected for the next message. + /// The stream containing the data to investigate for a length. + /// The algorithm used to encode the length. + /// The length of the message, if it could be identified. + /// True if a length could be obtained, false otherwise. + public static bool TryReadLengthPrefix(Stream source, PrefixStyle style, out int length) + { + length = ProtoReader.ReadLengthPrefix(source, false, style, out int fieldNumber, out int bytesRead); + return bytesRead > 0; + } + + /// Indicates the number of bytes expected for the next message. + /// The buffer containing the data to investigate for a length. + /// The offset of the first byte to read from the buffer. + /// The number of bytes to read from the buffer. + /// The algorithm used to encode the length. + /// The length of the message, if it could be identified. + /// True if a length could be obtained, false otherwise. + public static bool TryReadLengthPrefix(byte[] buffer, int index, int count, PrefixStyle style, out int length) + { + using (Stream source = new MemoryStream(buffer, index, count)) + { + return TryReadLengthPrefix(source, style, out length); + } + } +#endif + /// + /// The field number that is used as a default when serializing/deserializing a list of objects. + /// The data is treated as repeated message with field number 1. + /// + public const int ListItemTag = 1; + + +#if !NO_RUNTIME + /// + /// Provides non-generic access to the default serializer. + /// + public static class NonGeneric + { + /// + /// Create a deep clone of the supplied instance; any sub-items are also cloned. + /// + public static object DeepClone(object instance) + { + return instance == null ? null : RuntimeTypeModel.Default.DeepClone(instance); + } + + /// + /// Writes a protocol-buffer representation of the given instance to the supplied stream. + /// + /// The existing instance to be serialized (cannot be null). + /// The destination stream to write to. + public static void Serialize(Stream dest, object instance) + { + if (instance != null) + { + RuntimeTypeModel.Default.Serialize(dest, instance); + } + } + + /// + /// Creates a new instance from a protocol-buffer stream + /// + /// The type to be created. + /// The binary stream to apply to the new instance (cannot be null). + /// A new, initialized instance. + public static object Deserialize(Type type, Stream source) + { + return RuntimeTypeModel.Default.Deserialize(source, null, type); + } + + /// Applies a protocol-buffer stream to an existing instance. + /// The existing instance to be modified (cannot be null). + /// The binary stream to apply to the instance (cannot be null). + /// The updated instance + public static object Merge(Stream source, object instance) + { + if (instance == null) throw new ArgumentNullException(nameof(instance)); + return RuntimeTypeModel.Default.Deserialize(source, instance, instance.GetType(), null); + } + + /// + /// Writes a protocol-buffer representation of the given instance to the supplied stream, + /// with a length-prefix. This is useful for socket programming, + /// as DeserializeWithLengthPrefix/MergeWithLengthPrefix can be used to read the single object back + /// from an ongoing stream. + /// + /// The existing instance to be serialized (cannot be null). + /// How to encode the length prefix. + /// The destination stream to write to. + /// The tag used as a prefix to each record (only used with base-128 style prefixes). + public static void SerializeWithLengthPrefix(Stream destination, object instance, PrefixStyle style, int fieldNumber) + { + if (instance == null) throw new ArgumentNullException(nameof(instance)); + RuntimeTypeModel model = RuntimeTypeModel.Default; + model.SerializeWithLengthPrefix(destination, instance, model.MapType(instance.GetType()), style, fieldNumber); + } + /// + /// Applies a protocol-buffer stream to an existing instance (or null), using length-prefixed + /// data - useful with network IO. + /// + /// The existing instance to be modified (can be null). + /// The binary stream to apply to the instance (cannot be null). + /// How to encode the length prefix. + /// Used to resolve types on a per-field basis. + /// The updated instance; this may be different to the instance argument if + /// either the original instance was null, or the stream defines a known sub-type of the + /// original instance. + public static bool TryDeserializeWithLengthPrefix(Stream source, PrefixStyle style, TypeResolver resolver, out object value) + { + value = RuntimeTypeModel.Default.DeserializeWithLengthPrefix(source, null, null, style, 0, resolver); + return value != null; + } + + /// + /// Indicates whether the supplied type is explicitly modelled by the model + /// + public static bool CanSerialize(Type type) => RuntimeTypeModel.Default.IsDefined(type); + + /// + /// Precompiles the serializer for a given type. + /// + public static void PrepareSerializer(Type t) + { +#if FEAT_COMPILER + RuntimeTypeModel model = RuntimeTypeModel.Default; + model[model.MapType(t)].CompileInPlace(); +#endif + } + } + + /// + /// Global switches that change the behavior of protobuf-net + /// + public static class GlobalOptions + { + /// + /// + /// + [Obsolete("Please use RuntimeTypeModel.Default.InferTagFromNameDefault instead (or on a per-model basis)", false)] + public static bool InferTagFromName + { + get { return RuntimeTypeModel.Default.InferTagFromNameDefault; } + set { RuntimeTypeModel.Default.InferTagFromNameDefault = value; } + } + } +#endif + /// + /// Maps a field-number to a type + /// + public delegate Type TypeResolver(int fieldNumber); + + /// + /// Releases any internal buffers that have been reserved for efficiency; this does not affect any serialization + /// operations; simply: it can be used (optionally) to release the buffers for garbage collection (at the expense + /// of having to re-allocate a new buffer for the next operation, rather than re-use prior buffers). + /// + public static void FlushPool() + { + BufferPool.Flush(); + } + } +} diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializer.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializer.cs.meta new file mode 100644 index 0000000..63cf57d --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: dbd7fc6a1f1a0e34b8a1bce7e93c4f61 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers.meta new file mode 100644 index 0000000..569acba --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 90bd17a736284764ca22da41661472de +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/ArrayDecorator.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/ArrayDecorator.cs new file mode 100644 index 0000000..cad005f --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/ArrayDecorator.cs @@ -0,0 +1,310 @@ +#if !NO_RUNTIME +using System; +using System.Collections; +using System.Reflection; +using ProtoBuf.Meta; + +namespace ProtoBuf.Serializers +{ + sealed class ArrayDecorator : ProtoDecoratorBase + { + private readonly int fieldNumber; + private const byte + OPTIONS_WritePacked = 1, + OPTIONS_OverwriteList = 2, + OPTIONS_SupportNull = 4; + private readonly byte options; + private readonly WireType packedWireType; + public ArrayDecorator(TypeModel model, IProtoSerializer tail, int fieldNumber, bool writePacked, WireType packedWireType, Type arrayType, bool overwriteList, bool supportNull) + : base(tail) + { + Helpers.DebugAssert(arrayType != null, "arrayType should be non-null"); + Helpers.DebugAssert(arrayType.IsArray && arrayType.GetArrayRank() == 1, "should be single-dimension array; " + arrayType.FullName); + this.itemType = arrayType.GetElementType(); + Type underlyingItemType = supportNull ? itemType : (Helpers.GetUnderlyingType(itemType) ?? itemType); + + Helpers.DebugAssert(underlyingItemType == Tail.ExpectedType + || (Tail.ExpectedType == model.MapType(typeof(object)) && !Helpers.IsValueType(underlyingItemType)), "invalid tail"); + Helpers.DebugAssert(Tail.ExpectedType != model.MapType(typeof(byte)), "Should have used BlobSerializer"); + if ((writePacked || packedWireType != WireType.None) && fieldNumber <= 0) throw new ArgumentOutOfRangeException("fieldNumber"); + if (!ListDecorator.CanPack(packedWireType)) + { + if (writePacked) throw new InvalidOperationException("Only simple data-types can use packed encoding"); + packedWireType = WireType.None; + } + this.fieldNumber = fieldNumber; + this.packedWireType = packedWireType; + if (writePacked) options |= OPTIONS_WritePacked; + if (overwriteList) options |= OPTIONS_OverwriteList; + if (supportNull) options |= OPTIONS_SupportNull; + this.arrayType = arrayType; + } + readonly Type arrayType, itemType; // this is, for example, typeof(int[]) + public override Type ExpectedType { get { return arrayType; } } + public override bool RequiresOldValue { get { return AppendToCollection; } } + public override bool ReturnsValue { get { return true; } } + private bool CanUsePackedPrefix() => CanUsePackedPrefix(packedWireType, itemType); + + internal static bool CanUsePackedPrefix(WireType packedWireType, Type itemType) + { + // needs to be a suitably simple type *and* be definitely not nullable + switch (packedWireType) + { + case WireType.Fixed32: + case WireType.Fixed64: + break; + default: + return false; // nope + } + if (!Helpers.IsValueType(itemType)) return false; + return Helpers.GetUnderlyingType(itemType) == null; + } + +#if FEAT_COMPILER + protected override void EmitWrite(ProtoBuf.Compiler.CompilerContext ctx, ProtoBuf.Compiler.Local valueFrom) + { + // int i and T[] arr + using (Compiler.Local arr = ctx.GetLocalWithValue(arrayType, valueFrom)) + using (Compiler.Local i = new ProtoBuf.Compiler.Local(ctx, ctx.MapType(typeof(int)))) + { + bool writePacked = (options & OPTIONS_WritePacked) != 0; + bool fixedLengthPacked = writePacked && CanUsePackedPrefix(); + + using (Compiler.Local token = (writePacked && !fixedLengthPacked) ? new Compiler.Local(ctx, ctx.MapType(typeof(SubItemToken))) : null) + { + Type mappedWriter = ctx.MapType(typeof(ProtoWriter)); + if (writePacked) + { + ctx.LoadValue(fieldNumber); + ctx.LoadValue((int)WireType.String); + ctx.LoadReaderWriter(); + ctx.EmitCall(mappedWriter.GetMethod("WriteFieldHeader")); + + if (fixedLengthPacked) + { + // write directly - no need for buffering + ctx.LoadLength(arr, false); + ctx.LoadValue((int)packedWireType); + ctx.LoadReaderWriter(); + ctx.EmitCall(mappedWriter.GetMethod("WritePackedPrefix")); + } + else + { + ctx.LoadValue(arr); + ctx.LoadReaderWriter(); + ctx.EmitCall(mappedWriter.GetMethod("StartSubItem")); + ctx.StoreValue(token); + } + ctx.LoadValue(fieldNumber); + ctx.LoadReaderWriter(); + ctx.EmitCall(mappedWriter.GetMethod("SetPackedField")); + } + EmitWriteArrayLoop(ctx, i, arr); + + if (writePacked) + { + if (fixedLengthPacked) + { + ctx.LoadValue(fieldNumber); + ctx.LoadReaderWriter(); + ctx.EmitCall(mappedWriter.GetMethod("ClearPackedField")); + } + else + { + ctx.LoadValue(token); + ctx.LoadReaderWriter(); + ctx.EmitCall(mappedWriter.GetMethod("EndSubItem")); + } + } + } + } + } + + private void EmitWriteArrayLoop(Compiler.CompilerContext ctx, Compiler.Local i, Compiler.Local arr) + { + // i = 0 + ctx.LoadValue(0); + ctx.StoreValue(i); + + // range test is last (to minimise branches) + Compiler.CodeLabel loopTest = ctx.DefineLabel(), processItem = ctx.DefineLabel(); + ctx.Branch(loopTest, false); + ctx.MarkLabel(processItem); + + // {...} + ctx.LoadArrayValue(arr, i); + if (SupportNull) + { + Tail.EmitWrite(ctx, null); + } + else + { + ctx.WriteNullCheckedTail(itemType, Tail, null); + } + + // i++ + ctx.LoadValue(i); + ctx.LoadValue(1); + ctx.Add(); + ctx.StoreValue(i); + + // i < arr.Length + ctx.MarkLabel(loopTest); + ctx.LoadValue(i); + ctx.LoadLength(arr, false); + ctx.BranchIfLess(processItem, false); + } +#endif + private bool AppendToCollection => (options & OPTIONS_OverwriteList) == 0; + + private bool SupportNull { get { return (options & OPTIONS_SupportNull) != 0; } } + + public override void Write(object value, ProtoWriter dest) + { + IList arr = (IList)value; + int len = arr.Count; + SubItemToken token; + bool writePacked = (options & OPTIONS_WritePacked) != 0; + bool fixedLengthPacked = writePacked && CanUsePackedPrefix(); + + if (writePacked) + { + ProtoWriter.WriteFieldHeader(fieldNumber, WireType.String, dest); + + if (fixedLengthPacked) + { + ProtoWriter.WritePackedPrefix(arr.Count, packedWireType, dest); + token = new SubItemToken(); // default + } + else + { + token = ProtoWriter.StartSubItem(value, dest); + } + ProtoWriter.SetPackedField(fieldNumber, dest); + } + else + { + token = new SubItemToken(); // default + } + bool checkForNull = !SupportNull; + for (int i = 0; i < len; i++) + { + object obj = arr[i]; + if (checkForNull && obj == null) { throw new NullReferenceException(); } + Tail.Write(obj, dest); + } + if (writePacked) + { + if (fixedLengthPacked) + { + ProtoWriter.ClearPackedField(fieldNumber, dest); + } + else + { + ProtoWriter.EndSubItem(token, dest); + } + } + } + public override object Read(object value, ProtoReader source) + { + int field = source.FieldNumber; + BasicList list = new BasicList(); + if (packedWireType != WireType.None && source.WireType == WireType.String) + { + SubItemToken token = ProtoReader.StartSubItem(source); + while (ProtoReader.HasSubValue(packedWireType, source)) + { + list.Add(Tail.Read(null, source)); + } + ProtoReader.EndSubItem(token, source); + } + else + { + do + { + list.Add(Tail.Read(null, source)); + } while (source.TryReadFieldHeader(field)); + } + int oldLen = AppendToCollection ? ((value == null ? 0 : ((Array)value).Length)) : 0; + Array result = Array.CreateInstance(itemType, oldLen + list.Count); + if (oldLen != 0) ((Array)value).CopyTo(result, 0); + list.CopyTo(result, oldLen); + return result; + } + +#if FEAT_COMPILER + protected override void EmitRead(ProtoBuf.Compiler.CompilerContext ctx, ProtoBuf.Compiler.Local valueFrom) + { + Type listType; + listType = ctx.MapType(typeof(System.Collections.Generic.List<>)).MakeGenericType(itemType); + Type expected = ExpectedType; + using (Compiler.Local oldArr = AppendToCollection ? ctx.GetLocalWithValue(expected, valueFrom) : null) + using (Compiler.Local newArr = new Compiler.Local(ctx, expected)) + using (Compiler.Local list = new Compiler.Local(ctx, listType)) + { + ctx.EmitCtor(listType); + ctx.StoreValue(list); + ListDecorator.EmitReadList(ctx, list, Tail, listType.GetMethod("Add"), packedWireType, false); + + // leave this "using" here, as it can share the "FieldNumber" local with EmitReadList + using (Compiler.Local oldLen = AppendToCollection ? new ProtoBuf.Compiler.Local(ctx, ctx.MapType(typeof(int))) : null) + { + Type[] copyToArrayInt32Args = new Type[] { ctx.MapType(typeof(Array)), ctx.MapType(typeof(int)) }; + + if (AppendToCollection) + { + ctx.LoadLength(oldArr, true); + ctx.CopyValue(); + ctx.StoreValue(oldLen); + + ctx.LoadAddress(list, listType); + ctx.LoadValue(listType.GetProperty("Count")); + ctx.Add(); + ctx.CreateArray(itemType, null); // length is on the stack + ctx.StoreValue(newArr); + + ctx.LoadValue(oldLen); + Compiler.CodeLabel nothingToCopy = ctx.DefineLabel(); + ctx.BranchIfFalse(nothingToCopy, true); + ctx.LoadValue(oldArr); + ctx.LoadValue(newArr); + ctx.LoadValue(0); // index in target + + ctx.EmitCall(expected.GetMethod("CopyTo", copyToArrayInt32Args)); + ctx.MarkLabel(nothingToCopy); + + ctx.LoadValue(list); + ctx.LoadValue(newArr); + ctx.LoadValue(oldLen); + + } + else + { + ctx.LoadAddress(list, listType); + ctx.LoadValue(listType.GetProperty("Count")); + ctx.CreateArray(itemType, null); + ctx.StoreValue(newArr); + + ctx.LoadAddress(list, listType); + ctx.LoadValue(newArr); + ctx.LoadValue(0); + } + + copyToArrayInt32Args[0] = expected; // // prefer: CopyTo(T[], int) + MethodInfo copyTo = listType.GetMethod("CopyTo", copyToArrayInt32Args); + if (copyTo == null) + { // fallback: CopyTo(Array, int) + copyToArrayInt32Args[1] = ctx.MapType(typeof(Array)); + copyTo = listType.GetMethod("CopyTo", copyToArrayInt32Args); + } + ctx.EmitCall(copyTo); + } + ctx.LoadValue(newArr); + } + + + } +#endif + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/ArrayDecorator.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/ArrayDecorator.cs.meta new file mode 100644 index 0000000..6958590 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/ArrayDecorator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3689dde3ac5fd544a9e66158c9713872 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/BlobSerializer.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/BlobSerializer.cs new file mode 100644 index 0000000..40b2b89 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/BlobSerializer.cs @@ -0,0 +1,59 @@ +#if !NO_RUNTIME +using System; +#if COREFX +using System.Reflection; +#endif +#if FEAT_COMPILER +using System.Reflection.Emit; +#endif + +namespace ProtoBuf.Serializers +{ + sealed class BlobSerializer : IProtoSerializer + { + public Type ExpectedType { get { return expectedType; } } + + static readonly Type expectedType = typeof(byte[]); + + public BlobSerializer(ProtoBuf.Meta.TypeModel model, bool overwriteList) + { + this.overwriteList = overwriteList; + } + + private readonly bool overwriteList; + + public object Read(object value, ProtoReader source) + { + return ProtoReader.AppendBytes(overwriteList ? null : (byte[])value, source); + } + + public void Write(object value, ProtoWriter dest) + { + ProtoWriter.WriteBytes((byte[])value, dest); + } + + bool IProtoSerializer.RequiresOldValue { get { return !overwriteList; } } + bool IProtoSerializer.ReturnsValue { get { return true; } } +#if FEAT_COMPILER + void IProtoSerializer.EmitWrite(Compiler.CompilerContext ctx, Compiler.Local valueFrom) + { + ctx.EmitBasicWrite("WriteBytes", valueFrom); + } + void IProtoSerializer.EmitRead(Compiler.CompilerContext ctx, Compiler.Local valueFrom) + { + if (overwriteList) + { + ctx.LoadNullRef(); + } + else + { + ctx.LoadValue(valueFrom); + } + ctx.LoadReaderWriter(); + ctx.EmitCall(ctx.MapType(typeof(ProtoReader)) + .GetMethod("AppendBytes")); + } +#endif + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/BlobSerializer.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/BlobSerializer.cs.meta new file mode 100644 index 0000000..49dd403 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/BlobSerializer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c04427a4647d6314e82d8a63882dcb8b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/BooleanSerializer.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/BooleanSerializer.cs new file mode 100644 index 0000000..c64886a --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/BooleanSerializer.cs @@ -0,0 +1,41 @@ +#if !NO_RUNTIME +using System; + +namespace ProtoBuf.Serializers +{ + sealed class BooleanSerializer : IProtoSerializer + { + static readonly Type expectedType = typeof(bool); + + public BooleanSerializer(ProtoBuf.Meta.TypeModel model) { } + + public Type ExpectedType => expectedType; + + public void Write(object value, ProtoWriter dest) + { + ProtoWriter.WriteBoolean((bool)value, dest); + } + + public object Read(object value, ProtoReader source) + { + Helpers.DebugAssert(value == null); // since replaces + return source.ReadBoolean(); + } + + bool IProtoSerializer.RequiresOldValue => false; + + bool IProtoSerializer.ReturnsValue => true; + +#if FEAT_COMPILER + void IProtoSerializer.EmitWrite(Compiler.CompilerContext ctx, Compiler.Local valueFrom) + { + ctx.EmitBasicWrite("WriteBoolean", valueFrom); + } + void IProtoSerializer.EmitRead(Compiler.CompilerContext ctx, Compiler.Local valueFrom) + { + ctx.EmitBasicRead("ReadBoolean", ExpectedType); + } +#endif + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/BooleanSerializer.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/BooleanSerializer.cs.meta new file mode 100644 index 0000000..f982384 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/BooleanSerializer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8b73f749f97802947812dc66867ed1f5 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/ByteSerializer.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/ByteSerializer.cs new file mode 100644 index 0000000..e44a83c --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/ByteSerializer.cs @@ -0,0 +1,42 @@ +#if !NO_RUNTIME +using System; + +namespace ProtoBuf.Serializers +{ + sealed class ByteSerializer : IProtoSerializer + { + public Type ExpectedType { get { return expectedType; } } + + static readonly Type expectedType = typeof(byte); + + public ByteSerializer(ProtoBuf.Meta.TypeModel model) { } + + bool IProtoSerializer.RequiresOldValue => false; + + bool IProtoSerializer.ReturnsValue => true; + + public void Write(object value, ProtoWriter dest) + { + ProtoWriter.WriteByte((byte)value, dest); + } + + public object Read(object value, ProtoReader source) + { + Helpers.DebugAssert(value == null); // since replaces + return source.ReadByte(); + } + +#if FEAT_COMPILER + void IProtoSerializer.EmitWrite(Compiler.CompilerContext ctx, Compiler.Local valueFrom) + { + ctx.EmitBasicWrite("WriteByte", valueFrom); + } + + void IProtoSerializer.EmitRead(Compiler.CompilerContext ctx, Compiler.Local valueFrom) + { + ctx.EmitBasicRead("ReadByte", ExpectedType); + } +#endif + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/ByteSerializer.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/ByteSerializer.cs.meta new file mode 100644 index 0000000..23a58b1 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/ByteSerializer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c17779da4eb6b1d489531294afcb2a32 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/CharSerializer.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/CharSerializer.cs new file mode 100644 index 0000000..3bc30d0 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/CharSerializer.cs @@ -0,0 +1,32 @@ +#if !NO_RUNTIME +using System; + +namespace ProtoBuf.Serializers +{ + sealed class CharSerializer : UInt16Serializer + { + static readonly Type expectedType = typeof(char); + + public CharSerializer(ProtoBuf.Meta.TypeModel model) : base(model) + { + + } + + public override Type ExpectedType => expectedType; + + public override void Write(object value, ProtoWriter dest) + { + ProtoWriter.WriteUInt16((ushort)(char)value, dest); + } + + public override object Read(object value, ProtoReader source) + { + Helpers.DebugAssert(value == null); // since replaces + return (char)source.ReadUInt16(); + } + + // no need for any special IL here; ushort and char are + // interchangeable as long as there is no boxing/unboxing + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/CharSerializer.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/CharSerializer.cs.meta new file mode 100644 index 0000000..0424efc --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/CharSerializer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 526090cb730f087469b7f20948f4932a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/CompiledSerializer.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/CompiledSerializer.cs new file mode 100644 index 0000000..1ec3027 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/CompiledSerializer.cs @@ -0,0 +1,88 @@ +#if FEAT_COMPILER +using System; +using ProtoBuf.Meta; + +namespace ProtoBuf.Serializers +{ + sealed class CompiledSerializer : IProtoTypeSerializer + { + bool IProtoTypeSerializer.HasCallbacks(TypeModel.CallbackType callbackType) + { + return head.HasCallbacks(callbackType); // these routes only used when bits of the model not compiled + } + + bool IProtoTypeSerializer.CanCreateInstance() + { + return head.CanCreateInstance(); + } + + object IProtoTypeSerializer.CreateInstance(ProtoReader source) + { + return head.CreateInstance(source); + } + + public void Callback(object value, TypeModel.CallbackType callbackType, SerializationContext context) + { + head.Callback(value, callbackType, context); // these routes only used when bits of the model not compiled + } + + public static CompiledSerializer Wrap(IProtoTypeSerializer head, TypeModel model) + { + CompiledSerializer result = head as CompiledSerializer; + if (result == null) + { + result = new CompiledSerializer(head, model); + Helpers.DebugAssert(((IProtoTypeSerializer)result).ExpectedType == head.ExpectedType); + } + return result; + } + + private readonly IProtoTypeSerializer head; + private readonly Compiler.ProtoSerializer serializer; + private readonly Compiler.ProtoDeserializer deserializer; + + private CompiledSerializer(IProtoTypeSerializer head, TypeModel model) + { + this.head = head; + serializer = Compiler.CompilerContext.BuildSerializer(head, model); + deserializer = Compiler.CompilerContext.BuildDeserializer(head, model); + } + + bool IProtoSerializer.RequiresOldValue => head.RequiresOldValue; + + bool IProtoSerializer.ReturnsValue => head.ReturnsValue; + + Type IProtoSerializer.ExpectedType => head.ExpectedType; + + void IProtoSerializer.Write(object value, ProtoWriter dest) + { + serializer(value, dest); + } + + object IProtoSerializer.Read(object value, ProtoReader source) + { + return deserializer(value, source); + } + + void IProtoSerializer.EmitWrite(Compiler.CompilerContext ctx, Compiler.Local valueFrom) + { + head.EmitWrite(ctx, valueFrom); + } + + void IProtoSerializer.EmitRead(Compiler.CompilerContext ctx, Compiler.Local valueFrom) + { + head.EmitRead(ctx, valueFrom); + } + + void IProtoTypeSerializer.EmitCallback(Compiler.CompilerContext ctx, Compiler.Local valueFrom, TypeModel.CallbackType callbackType) + { + head.EmitCallback(ctx, valueFrom, callbackType); + } + + void IProtoTypeSerializer.EmitCreateInstance(Compiler.CompilerContext ctx) + { + head.EmitCreateInstance(ctx); + } + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/CompiledSerializer.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/CompiledSerializer.cs.meta new file mode 100644 index 0000000..ddef875 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/CompiledSerializer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 90821da5568834a4682d1a42d7f66963 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/DateTimeSerializer.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/DateTimeSerializer.cs new file mode 100644 index 0000000..9755df9 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/DateTimeSerializer.cs @@ -0,0 +1,65 @@ +#if !NO_RUNTIME +using System; +using System.Reflection; + +namespace ProtoBuf.Serializers +{ + internal sealed class DateTimeSerializer : IProtoSerializer + { + private static readonly Type expectedType = typeof(DateTime); + + public Type ExpectedType => expectedType; + + bool IProtoSerializer.RequiresOldValue => false; + bool IProtoSerializer.ReturnsValue => true; + + private readonly bool includeKind, wellKnown; + + public DateTimeSerializer(DataFormat dataFormat, ProtoBuf.Meta.TypeModel model) + { + wellKnown = dataFormat == DataFormat.WellKnown; + includeKind = model?.SerializeDateTimeKind() == true; + } + + public object Read(object value, ProtoReader source) + { + if (wellKnown) + { + return BclHelpers.ReadTimestamp(source); + } + else + { + Helpers.DebugAssert(value == null); // since replaces + return BclHelpers.ReadDateTime(source); + } + } + + public void Write(object value, ProtoWriter dest) + { + if (wellKnown) + BclHelpers.WriteTimestamp((DateTime)value, dest); + else if (includeKind) + BclHelpers.WriteDateTimeWithKind((DateTime)value, dest); + else + BclHelpers.WriteDateTime((DateTime)value, dest); + } +#if FEAT_COMPILER + void IProtoSerializer.EmitWrite(Compiler.CompilerContext ctx, Compiler.Local valueFrom) + { + ctx.EmitWrite(ctx.MapType(typeof(BclHelpers)), + wellKnown ? nameof(BclHelpers.WriteTimestamp) + : includeKind ? nameof(BclHelpers.WriteDateTimeWithKind) : nameof(BclHelpers.WriteDateTime), valueFrom); + } + + void IProtoSerializer.EmitRead(Compiler.CompilerContext ctx, Compiler.Local entity) + { + if (wellKnown) ctx.LoadValue(entity); + ctx.EmitBasicRead(ctx.MapType(typeof(BclHelpers)), + wellKnown ? nameof(BclHelpers.ReadTimestamp) : nameof(BclHelpers.ReadDateTime), + ExpectedType); + } +#endif + + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/DateTimeSerializer.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/DateTimeSerializer.cs.meta new file mode 100644 index 0000000..6757f0c --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/DateTimeSerializer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: dfba0a8c252b2e54c96478c9e690c7d3 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/DecimalSerializer.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/DecimalSerializer.cs new file mode 100644 index 0000000..1edc621 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/DecimalSerializer.cs @@ -0,0 +1,42 @@ +#if !NO_RUNTIME +using System; + +namespace ProtoBuf.Serializers +{ + sealed class DecimalSerializer : IProtoSerializer + { + static readonly Type expectedType = typeof(decimal); + + public DecimalSerializer(ProtoBuf.Meta.TypeModel model) { } + + public Type ExpectedType => expectedType; + + bool IProtoSerializer.RequiresOldValue => false; + + bool IProtoSerializer.ReturnsValue => true; + + public object Read(object value, ProtoReader source) + { + Helpers.DebugAssert(value == null); // since replaces + return BclHelpers.ReadDecimal(source); + } + + public void Write(object value, ProtoWriter dest) + { + BclHelpers.WriteDecimal((decimal)value, dest); + } + +#if FEAT_COMPILER + void IProtoSerializer.EmitWrite(Compiler.CompilerContext ctx, Compiler.Local valueFrom) + { + ctx.EmitWrite(ctx.MapType(typeof(BclHelpers)), "WriteDecimal", valueFrom); + } + void IProtoSerializer.EmitRead(Compiler.CompilerContext ctx, Compiler.Local valueFrom) + { + ctx.EmitBasicRead(ctx.MapType(typeof(BclHelpers)), "ReadDecimal", ExpectedType); + } +#endif + + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/DecimalSerializer.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/DecimalSerializer.cs.meta new file mode 100644 index 0000000..f8e097a --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/DecimalSerializer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 80efe6cca6916ab46b430c27dc58369c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/DefaultValueDecorator.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/DefaultValueDecorator.cs new file mode 100644 index 0000000..895d0c4 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/DefaultValueDecorator.cs @@ -0,0 +1,259 @@ +#if !NO_RUNTIME +using System; +using System.Reflection; +using ProtoBuf.Meta; + +namespace ProtoBuf.Serializers +{ + sealed class DefaultValueDecorator : ProtoDecoratorBase + { + public override Type ExpectedType => Tail.ExpectedType; + + public override bool RequiresOldValue => Tail.RequiresOldValue; + + public override bool ReturnsValue => Tail.ReturnsValue; + + private readonly object defaultValue; + public DefaultValueDecorator(TypeModel model, object defaultValue, IProtoSerializer tail) : base(tail) + { + if (defaultValue == null) throw new ArgumentNullException(nameof(defaultValue)); + Type type = model.MapType(defaultValue.GetType()); + if (type != tail.ExpectedType) + { + throw new ArgumentException("Default value is of incorrect type", "defaultValue"); + } + this.defaultValue = defaultValue; + } + + public override void Write(object value, ProtoWriter dest) + { + if (!object.Equals(value, defaultValue)) + { + Tail.Write(value, dest); + } + } + + public override object Read(object value, ProtoReader source) + { + return Tail.Read(value, source); + } + +#if FEAT_COMPILER + protected override void EmitWrite(Compiler.CompilerContext ctx, Compiler.Local valueFrom) + { + Compiler.CodeLabel done = ctx.DefineLabel(); + if (valueFrom == null) + { + ctx.CopyValue(); // on the stack + Compiler.CodeLabel needToPop = ctx.DefineLabel(); + EmitBranchIfDefaultValue(ctx, needToPop); + Tail.EmitWrite(ctx, null); + ctx.Branch(done, true); + ctx.MarkLabel(needToPop); + ctx.DiscardValue(); + } + else + { + ctx.LoadValue(valueFrom); // variable/parameter + EmitBranchIfDefaultValue(ctx, done); + Tail.EmitWrite(ctx, valueFrom); + } + ctx.MarkLabel(done); + } + private void EmitBeq(Compiler.CompilerContext ctx, Compiler.CodeLabel label, Type type) + { + switch (Helpers.GetTypeCode(type)) + { + case ProtoTypeCode.Boolean: + case ProtoTypeCode.Byte: + case ProtoTypeCode.Char: + case ProtoTypeCode.Double: + case ProtoTypeCode.Int16: + case ProtoTypeCode.Int32: + case ProtoTypeCode.Int64: + case ProtoTypeCode.SByte: + case ProtoTypeCode.Single: + case ProtoTypeCode.UInt16: + case ProtoTypeCode.UInt32: + case ProtoTypeCode.UInt64: + ctx.BranchIfEqual(label, false); + break; + default: +#if COREFX + MethodInfo method = type.GetMethod("op_Equality", new Type[] { type, type }); + if (method == null || !method.IsPublic || !method.IsStatic) method = null; +#else + MethodInfo method = type.GetMethod("op_Equality", BindingFlags.Public | BindingFlags.Static, + null, new Type[] { type, type }, null); +#endif + if (method == null || method.ReturnType != ctx.MapType(typeof(bool))) + { + throw new InvalidOperationException("No suitable equality operator found for default-values of type: " + type.FullName); + } + ctx.EmitCall(method); + ctx.BranchIfTrue(label, false); + break; + + } + } + private void EmitBranchIfDefaultValue(Compiler.CompilerContext ctx, Compiler.CodeLabel label) + { + Type expected = ExpectedType; + switch (Helpers.GetTypeCode(expected)) + { + case ProtoTypeCode.Boolean: + if ((bool)defaultValue) + { + ctx.BranchIfTrue(label, false); + } + else + { + ctx.BranchIfFalse(label, false); + } + break; + case ProtoTypeCode.Byte: + if ((byte)defaultValue == (byte)0) + { + ctx.BranchIfFalse(label, false); + } + else + { + ctx.LoadValue((int)(byte)defaultValue); + EmitBeq(ctx, label, expected); + } + break; + case ProtoTypeCode.SByte: + if ((sbyte)defaultValue == (sbyte)0) + { + ctx.BranchIfFalse(label, false); + } + else + { + ctx.LoadValue((int)(sbyte)defaultValue); + EmitBeq(ctx, label, expected); + } + break; + case ProtoTypeCode.Int16: + if ((short)defaultValue == (short)0) + { + ctx.BranchIfFalse(label, false); + } + else + { + ctx.LoadValue((int)(short)defaultValue); + EmitBeq(ctx, label, expected); + } + break; + case ProtoTypeCode.UInt16: + if ((ushort)defaultValue == (ushort)0) + { + ctx.BranchIfFalse(label, false); + } + else + { + ctx.LoadValue((int)(ushort)defaultValue); + EmitBeq(ctx, label, expected); + } + break; + case ProtoTypeCode.Int32: + if ((int)defaultValue == (int)0) + { + ctx.BranchIfFalse(label, false); + } + else + { + ctx.LoadValue((int)defaultValue); + EmitBeq(ctx, label, expected); + } + break; + case ProtoTypeCode.UInt32: + if ((uint)defaultValue == (uint)0) + { + ctx.BranchIfFalse(label, false); + } + else + { + ctx.LoadValue((int)(uint)defaultValue); + EmitBeq(ctx, label, expected); + } + break; + case ProtoTypeCode.Char: + if ((char)defaultValue == (char)0) + { + ctx.BranchIfFalse(label, false); + } + else + { + ctx.LoadValue((int)(char)defaultValue); + EmitBeq(ctx, label, expected); + } + break; + case ProtoTypeCode.Int64: + ctx.LoadValue((long)defaultValue); + EmitBeq(ctx, label, expected); + break; + case ProtoTypeCode.UInt64: + ctx.LoadValue((long)(ulong)defaultValue); + EmitBeq(ctx, label, expected); + break; + case ProtoTypeCode.Double: + ctx.LoadValue((double)defaultValue); + EmitBeq(ctx, label, expected); + break; + case ProtoTypeCode.Single: + ctx.LoadValue((float)defaultValue); + EmitBeq(ctx, label, expected); + break; + case ProtoTypeCode.String: + ctx.LoadValue((string)defaultValue); + EmitBeq(ctx, label, expected); + break; + case ProtoTypeCode.Decimal: + { + decimal d = (decimal)defaultValue; + ctx.LoadValue(d); + EmitBeq(ctx, label, expected); + } + break; + case ProtoTypeCode.TimeSpan: + { + TimeSpan ts = (TimeSpan)defaultValue; + if (ts == TimeSpan.Zero) + { + ctx.LoadValue(typeof(TimeSpan).GetField("Zero")); + } + else + { + ctx.LoadValue(ts.Ticks); + ctx.EmitCall(ctx.MapType(typeof(TimeSpan)).GetMethod("FromTicks")); + } + EmitBeq(ctx, label, expected); + break; + } + case ProtoTypeCode.Guid: + { + ctx.LoadValue((Guid)defaultValue); + EmitBeq(ctx, label, expected); + break; + } + case ProtoTypeCode.DateTime: + { + ctx.LoadValue(((DateTime)defaultValue).ToBinary()); + ctx.EmitCall(ctx.MapType(typeof(DateTime)).GetMethod("FromBinary")); + + EmitBeq(ctx, label, expected); + break; + } + default: + throw new NotSupportedException("Type cannot be represented as a default value: " + expected.FullName); + } + } + + protected override void EmitRead(Compiler.CompilerContext ctx, Compiler.Local valueFrom) + { + Tail.EmitRead(ctx, valueFrom); + } +#endif + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/DefaultValueDecorator.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/DefaultValueDecorator.cs.meta new file mode 100644 index 0000000..7cbd6ed --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/DefaultValueDecorator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ad3a3e386e17b67488f858d409d3e8a7 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/DoubleSerializer.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/DoubleSerializer.cs new file mode 100644 index 0000000..8b25523 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/DoubleSerializer.cs @@ -0,0 +1,42 @@ +#if !NO_RUNTIME +using System; + +namespace ProtoBuf.Serializers +{ + sealed class DoubleSerializer : IProtoSerializer + { + static readonly Type expectedType = typeof(double); + + public DoubleSerializer(ProtoBuf.Meta.TypeModel model) { } + + public Type ExpectedType => expectedType; + + bool IProtoSerializer.RequiresOldValue => false; + + bool IProtoSerializer.ReturnsValue => true; + + public object Read(object value, ProtoReader source) + { + Helpers.DebugAssert(value == null); // since replaces + return source.ReadDouble(); + } + + public void Write(object value, ProtoWriter dest) + { + ProtoWriter.WriteDouble((double)value, dest); + } + +#if FEAT_COMPILER + void IProtoSerializer.EmitWrite(Compiler.CompilerContext ctx, Compiler.Local valueFrom) + { + ctx.EmitBasicWrite("WriteDouble", valueFrom); + } + + void IProtoSerializer.EmitRead(Compiler.CompilerContext ctx, Compiler.Local valueFrom) + { + ctx.EmitBasicRead("ReadDouble", ExpectedType); + } +#endif + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/DoubleSerializer.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/DoubleSerializer.cs.meta new file mode 100644 index 0000000..cdba0a7 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/DoubleSerializer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 65b598b3ebee04946abf8957a0f92762 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/EnumSerializer.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/EnumSerializer.cs new file mode 100644 index 0000000..78cb78a --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/EnumSerializer.cs @@ -0,0 +1,267 @@ +#if !NO_RUNTIME +using System; +using ProtoBuf.Meta; +using System.Reflection; + +namespace ProtoBuf.Serializers +{ + sealed class EnumSerializer : IProtoSerializer + { + public readonly struct EnumPair + { + public readonly object RawValue; // note that this is boxing, but I'll live with it + public readonly Enum TypedValue; // note that this is boxing, but I'll live with it + public readonly int WireValue; + public EnumPair(int wireValue, object raw, Type type) + { + WireValue = wireValue; + RawValue = raw; + TypedValue = (Enum)Enum.ToObject(type, raw); + } + } + + private readonly Type enumType; + private readonly EnumPair[] map; + public EnumSerializer(Type enumType, EnumPair[] map) + { + this.enumType = enumType ?? throw new ArgumentNullException(nameof(enumType)); + this.map = map; + if (map != null) + { + for (int i = 1; i < map.Length; i++) + for (int j = 0; j < i; j++) + { + if (map[i].WireValue == map[j].WireValue && !Equals(map[i].RawValue, map[j].RawValue)) + { + throw new ProtoException("Multiple enums with wire-value " + map[i].WireValue.ToString()); + } + if (Equals(map[i].RawValue, map[j].RawValue) && map[i].WireValue != map[j].WireValue) + { + throw new ProtoException("Multiple enums with deserialized-value " + map[i].RawValue); + } + } + + } + } + + private ProtoTypeCode GetTypeCode() + { + Type type = Helpers.GetUnderlyingType(enumType); + if (type == null) type = enumType; + return Helpers.GetTypeCode(type); + } + + public Type ExpectedType => enumType; + + bool IProtoSerializer.RequiresOldValue => false; + + bool IProtoSerializer.ReturnsValue => true; + + private int EnumToWire(object value) + { + unchecked + { + switch (GetTypeCode()) + { // unbox then convert to int + case ProtoTypeCode.Byte: return (int)(byte)value; + case ProtoTypeCode.SByte: return (int)(sbyte)value; + case ProtoTypeCode.Int16: return (int)(short)value; + case ProtoTypeCode.Int32: return (int)value; + case ProtoTypeCode.Int64: return (int)(long)value; + case ProtoTypeCode.UInt16: return (int)(ushort)value; + case ProtoTypeCode.UInt32: return (int)(uint)value; + case ProtoTypeCode.UInt64: return (int)(ulong)value; + default: throw new InvalidOperationException(); + } + } + } + + private object WireToEnum(int value) + { + unchecked + { + switch (GetTypeCode()) + { // convert from int then box + case ProtoTypeCode.Byte: return Enum.ToObject(enumType, (byte)value); + case ProtoTypeCode.SByte: return Enum.ToObject(enumType, (sbyte)value); + case ProtoTypeCode.Int16: return Enum.ToObject(enumType, (short)value); + case ProtoTypeCode.Int32: return Enum.ToObject(enumType, value); + case ProtoTypeCode.Int64: return Enum.ToObject(enumType, (long)value); + case ProtoTypeCode.UInt16: return Enum.ToObject(enumType, (ushort)value); + case ProtoTypeCode.UInt32: return Enum.ToObject(enumType, (uint)value); + case ProtoTypeCode.UInt64: return Enum.ToObject(enumType, (ulong)value); + default: throw new InvalidOperationException(); + } + } + } + + public object Read(object value, ProtoReader source) + { + Helpers.DebugAssert(value == null); // since replaces + int wireValue = source.ReadInt32(); + if (map == null) + { + return WireToEnum(wireValue); + } + for (int i = 0; i < map.Length; i++) + { + if (map[i].WireValue == wireValue) + { + return map[i].TypedValue; + } + } + source.ThrowEnumException(ExpectedType, wireValue); + return null; // to make compiler happy + } + + public void Write(object value, ProtoWriter dest) + { + if (map == null) + { + ProtoWriter.WriteInt32(EnumToWire(value), dest); + } + else + { + for (int i = 0; i < map.Length; i++) + { + if (object.Equals(map[i].TypedValue, value)) + { + ProtoWriter.WriteInt32(map[i].WireValue, dest); + return; + } + } + ProtoWriter.ThrowEnumException(dest, value); + } + } + +#if FEAT_COMPILER + void IProtoSerializer.EmitWrite(Compiler.CompilerContext ctx, Compiler.Local valueFrom) + { + ProtoTypeCode typeCode = GetTypeCode(); + if (map == null) + { + ctx.LoadValue(valueFrom); + ctx.ConvertToInt32(typeCode, false); + ctx.EmitBasicWrite("WriteInt32", null); + } + else + { + using (Compiler.Local loc = ctx.GetLocalWithValue(ExpectedType, valueFrom)) + { + Compiler.CodeLabel @continue = ctx.DefineLabel(); + for (int i = 0; i < map.Length; i++) + { + Compiler.CodeLabel tryNextValue = ctx.DefineLabel(), processThisValue = ctx.DefineLabel(); + ctx.LoadValue(loc); + WriteEnumValue(ctx, typeCode, map[i].RawValue); + ctx.BranchIfEqual(processThisValue, true); + ctx.Branch(tryNextValue, true); + ctx.MarkLabel(processThisValue); + ctx.LoadValue(map[i].WireValue); + ctx.EmitBasicWrite("WriteInt32", null); + ctx.Branch(@continue, false); + ctx.MarkLabel(tryNextValue); + } + ctx.LoadReaderWriter(); + ctx.LoadValue(loc); + ctx.CastToObject(ExpectedType); + ctx.EmitCall(ctx.MapType(typeof(ProtoWriter)).GetMethod("ThrowEnumException")); + ctx.MarkLabel(@continue); + } + } + } + + void IProtoSerializer.EmitRead(Compiler.CompilerContext ctx, Compiler.Local valueFrom) + { + ProtoTypeCode typeCode = GetTypeCode(); + if (map == null) + { + ctx.EmitBasicRead("ReadInt32", ctx.MapType(typeof(int))); + ctx.ConvertFromInt32(typeCode, false); + } + else + { + int[] wireValues = new int[map.Length]; + object[] values = new object[map.Length]; + for (int i = 0; i < map.Length; i++) + { + wireValues[i] = map[i].WireValue; + values[i] = map[i].RawValue; + } + using (Compiler.Local result = new Compiler.Local(ctx, ExpectedType)) + using (Compiler.Local wireValue = new Compiler.Local(ctx, ctx.MapType(typeof(int)))) + { + ctx.EmitBasicRead("ReadInt32", ctx.MapType(typeof(int))); + ctx.StoreValue(wireValue); + Compiler.CodeLabel @continue = ctx.DefineLabel(); + foreach (BasicList.Group group in BasicList.GetContiguousGroups(wireValues, values)) + { + Compiler.CodeLabel tryNextGroup = ctx.DefineLabel(); + int groupItemCount = group.Items.Count; + if (groupItemCount == 1) + { + // discreet group; use an equality test + ctx.LoadValue(wireValue); + ctx.LoadValue(group.First); + Compiler.CodeLabel processThisValue = ctx.DefineLabel(); + ctx.BranchIfEqual(processThisValue, true); + ctx.Branch(tryNextGroup, false); + WriteEnumValue(ctx, typeCode, processThisValue, @continue, group.Items[0], @result); + } + else + { + // implement as a jump-table-based switch + ctx.LoadValue(wireValue); + ctx.LoadValue(group.First); + ctx.Subtract(); // jump-tables are zero-based + Compiler.CodeLabel[] jmp = new Compiler.CodeLabel[groupItemCount]; + for (int i = 0; i < groupItemCount; i++) + { + jmp[i] = ctx.DefineLabel(); + } + ctx.Switch(jmp); + // write the default... + ctx.Branch(tryNextGroup, false); + for (int i = 0; i < groupItemCount; i++) + { + WriteEnumValue(ctx, typeCode, jmp[i], @continue, group.Items[i], @result); + } + } + ctx.MarkLabel(tryNextGroup); + } + // throw source.CreateEnumException(ExpectedType, wireValue); + ctx.LoadReaderWriter(); + ctx.LoadValue(ExpectedType); + ctx.LoadValue(wireValue); + ctx.EmitCall(ctx.MapType(typeof(ProtoReader)).GetMethod("ThrowEnumException")); + ctx.MarkLabel(@continue); + ctx.LoadValue(result); + } + } + } + private static void WriteEnumValue(Compiler.CompilerContext ctx, ProtoTypeCode typeCode, object value) + { + switch (typeCode) + { + case ProtoTypeCode.Byte: ctx.LoadValue((int)(byte)value); break; + case ProtoTypeCode.SByte: ctx.LoadValue((int)(sbyte)value); break; + case ProtoTypeCode.Int16: ctx.LoadValue((int)(short)value); break; + case ProtoTypeCode.Int32: ctx.LoadValue((int)(int)value); break; + case ProtoTypeCode.Int64: ctx.LoadValue((long)(long)value); break; + case ProtoTypeCode.UInt16: ctx.LoadValue((int)(ushort)value); break; + case ProtoTypeCode.UInt32: ctx.LoadValue((int)(uint)value); break; + case ProtoTypeCode.UInt64: ctx.LoadValue((long)(ulong)value); break; + default: throw new InvalidOperationException(); + } + } + private static void WriteEnumValue(Compiler.CompilerContext ctx, ProtoTypeCode typeCode, Compiler.CodeLabel handler, Compiler.CodeLabel @continue, object value, Compiler.Local local) + { + ctx.MarkLabel(handler); + WriteEnumValue(ctx, typeCode, value); + ctx.StoreValue(local); + ctx.Branch(@continue, false); // "continue" + } +#endif + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/EnumSerializer.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/EnumSerializer.cs.meta new file mode 100644 index 0000000..b58d866 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/EnumSerializer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ef6c6d630a8f5ca449eec10513147563 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/FieldDecorator.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/FieldDecorator.cs new file mode 100644 index 0000000..26c0452 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/FieldDecorator.cs @@ -0,0 +1,104 @@ +#if !NO_RUNTIME +using System; +using System.Reflection; + +namespace ProtoBuf.Serializers +{ + sealed class FieldDecorator : ProtoDecoratorBase + { + public override Type ExpectedType => forType; + private readonly FieldInfo field; + private readonly Type forType; + public override bool RequiresOldValue => true; + public override bool ReturnsValue => false; + public FieldDecorator(Type forType, FieldInfo field, IProtoSerializer tail) : base(tail) + { + Helpers.DebugAssert(forType != null); + Helpers.DebugAssert(field != null); + this.forType = forType; + this.field = field; + } + + public override void Write(object value, ProtoWriter dest) + { + Helpers.DebugAssert(value != null); + value = field.GetValue(value); + if (value != null) Tail.Write(value, dest); + } + + public override object Read(object value, ProtoReader source) + { + Helpers.DebugAssert(value != null); + object newValue = Tail.Read((Tail.RequiresOldValue ? field.GetValue(value) : null), source); + if (newValue != null) field.SetValue(value, newValue); + return null; + } + + +#if FEAT_COMPILER + protected override void EmitWrite(Compiler.CompilerContext ctx, Compiler.Local valueFrom) + { + ctx.LoadAddress(valueFrom, ExpectedType); + ctx.LoadValue(field); + ctx.WriteNullCheckedTail(field.FieldType, Tail, null); + } + protected override void EmitRead(Compiler.CompilerContext ctx, Compiler.Local valueFrom) + { + using (Compiler.Local loc = ctx.GetLocalWithValue(ExpectedType, valueFrom)) + { + if (Tail.RequiresOldValue) + { + ctx.LoadAddress(loc, ExpectedType); + ctx.LoadValue(field); + } + // value is either now on the stack or not needed + ctx.ReadNullCheckedTail(field.FieldType, Tail, null); + + // the field could be a backing field that needs to be raised back to + // the property if we're doing a full compile + MemberInfo member = field; + ctx.CheckAccessibility(ref member); + bool writeValue = member is FieldInfo; + + if (writeValue) + { + if (Tail.ReturnsValue) + { + using (Compiler.Local newVal = new Compiler.Local(ctx, field.FieldType)) + { + ctx.StoreValue(newVal); + if (Helpers.IsValueType(field.FieldType)) + { + ctx.LoadAddress(loc, ExpectedType); + ctx.LoadValue(newVal); + ctx.StoreValue(field); + } + else + { + Compiler.CodeLabel allDone = ctx.DefineLabel(); + ctx.LoadValue(newVal); + ctx.BranchIfFalse(allDone, true); // interpret null as "don't assign" + + ctx.LoadAddress(loc, ExpectedType); + ctx.LoadValue(newVal); + ctx.StoreValue(field); + + ctx.MarkLabel(allDone); + } + } + } + } + else + { + // can't use result + if (Tail.ReturnsValue) + { + ctx.DiscardValue(); + } + } + } + } +#endif + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/FieldDecorator.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/FieldDecorator.cs.meta new file mode 100644 index 0000000..63065a7 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/FieldDecorator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f7c1c3141cd2fad47b3112747b44314a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/GuidSerializer.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/GuidSerializer.cs new file mode 100644 index 0000000..27556d5 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/GuidSerializer.cs @@ -0,0 +1,43 @@ +#if !NO_RUNTIME +using System; + +namespace ProtoBuf.Serializers +{ + sealed class GuidSerializer : IProtoSerializer + { + static readonly Type expectedType = typeof(Guid); + + public GuidSerializer(ProtoBuf.Meta.TypeModel model) { } + + public Type ExpectedType { get { return expectedType; } } + + bool IProtoSerializer.RequiresOldValue => false; + + bool IProtoSerializer.ReturnsValue => true; + + public void Write(object value, ProtoWriter dest) + { + BclHelpers.WriteGuid((Guid)value, dest); + } + + public object Read(object value, ProtoReader source) + { + Helpers.DebugAssert(value == null); // since replaces + return BclHelpers.ReadGuid(source); + } + +#if FEAT_COMPILER + void IProtoSerializer.EmitWrite(Compiler.CompilerContext ctx, Compiler.Local valueFrom) + { + ctx.EmitWrite(ctx.MapType(typeof(BclHelpers)), "WriteGuid", valueFrom); + } + + void IProtoSerializer.EmitRead(Compiler.CompilerContext ctx, Compiler.Local valueFrom) + { + ctx.EmitBasicRead(ctx.MapType(typeof(BclHelpers)), "ReadGuid", ExpectedType); + } +#endif + + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/GuidSerializer.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/GuidSerializer.cs.meta new file mode 100644 index 0000000..7eeb096 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/GuidSerializer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 362fe2dd035b0cb4eaff2c7b7337fc66 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/IProtoSerializer.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/IProtoSerializer.cs new file mode 100644 index 0000000..59e8cc2 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/IProtoSerializer.cs @@ -0,0 +1,64 @@ +#if !NO_RUNTIME +using System; + + +namespace ProtoBuf.Serializers +{ + interface IProtoSerializer + { + /// + /// The type that this serializer is intended to work for. + /// + Type ExpectedType { get; } + + /// + /// Perform the steps necessary to serialize this data. + /// + /// The value to be serialized. + /// The writer entity that is accumulating the output data. + void Write(object value, ProtoWriter dest); + + /// + /// Perform the steps necessary to deserialize this data. + /// + /// The current value, if appropriate. + /// The reader providing the input data. + /// The updated / replacement value. + object Read(object value, ProtoReader source); + + /// + /// Indicates whether a Read operation replaces the existing value, or + /// extends the value. If false, the "value" parameter to Read is + /// discarded, and should be passed in as null. + /// + bool RequiresOldValue { get; } + /// + /// Now all Read operations return a value (although most do); if false no + /// value should be expected. + /// + bool ReturnsValue { get; } + +#if FEAT_COMPILER + /// Emit the IL necessary to perform the given actions + /// to serialize this data. + /// + /// Details and utilities for the method being generated. + /// The source of the data to work against; + /// If the value is only needed once, then LoadValue is sufficient. If + /// the value is needed multiple times, then note that a "null" + /// means "the top of the stack", in which case you should create your + /// own copy - GetLocalWithValue. + void EmitWrite(Compiler.CompilerContext ctx, Compiler.Local valueFrom); + + /// + /// Emit the IL necessary to perform the given actions to deserialize this data. + /// + /// Details and utilities for the method being generated. + /// For nested values, the instance holding the values; note + /// that this is not always provided - a null means not supplied. Since this is always + /// a variable or argument, it is not necessary to consume this value. + void EmitRead(Compiler.CompilerContext ctx, Compiler.Local entity); +#endif + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/IProtoSerializer.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/IProtoSerializer.cs.meta new file mode 100644 index 0000000..40d402d --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/IProtoSerializer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6acc35442de99c94aade5d43c7992338 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/IProtoTypeSerializer.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/IProtoTypeSerializer.cs new file mode 100644 index 0000000..da1439b --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/IProtoTypeSerializer.cs @@ -0,0 +1,20 @@ +#if !NO_RUNTIME +using ProtoBuf.Meta; +namespace ProtoBuf.Serializers +{ + interface IProtoTypeSerializer : IProtoSerializer + { + bool HasCallbacks(TypeModel.CallbackType callbackType); + bool CanCreateInstance(); + object CreateInstance(ProtoReader source); + void Callback(object value, TypeModel.CallbackType callbackType, SerializationContext context); + +#if FEAT_COMPILER + void EmitCallback(Compiler.CompilerContext ctx, Compiler.Local valueFrom, TypeModel.CallbackType callbackType); +#endif +#if FEAT_COMPILER + void EmitCreateInstance(Compiler.CompilerContext ctx); +#endif + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/IProtoTypeSerializer.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/IProtoTypeSerializer.cs.meta new file mode 100644 index 0000000..d4c96cf --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/IProtoTypeSerializer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6974491708512ec41b7a5f29805e4c69 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/ISerializerProxy.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/ISerializerProxy.cs new file mode 100644 index 0000000..3ab2cb8 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/ISerializerProxy.cs @@ -0,0 +1,10 @@ +#if !NO_RUNTIME + +namespace ProtoBuf.Serializers +{ + interface ISerializerProxy + { + IProtoSerializer Serializer { get; } + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/ISerializerProxy.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/ISerializerProxy.cs.meta new file mode 100644 index 0000000..aa3cdfa --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/ISerializerProxy.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f717dd1190cbe174587e3bff7dd3dd76 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/ImmutableCollectionDecorator.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/ImmutableCollectionDecorator.cs new file mode 100644 index 0000000..918d1fd --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/ImmutableCollectionDecorator.cs @@ -0,0 +1,304 @@ +#if !NO_RUNTIME +using System; +using System.Collections; +using System.Reflection; +using ProtoBuf.Meta; + +namespace ProtoBuf.Serializers +{ + sealed class ImmutableCollectionDecorator : ListDecorator + { + protected override bool RequireAdd { get { return false; } } + + static Type ResolveIReadOnlyCollection(Type declaredType, Type t) + { +#if COREFX || PROFILE259 + if (CheckIsIReadOnlyCollectionExactly(declaredType.GetTypeInfo())) return declaredType; + foreach (Type intImplBasic in declaredType.GetTypeInfo().ImplementedInterfaces) + { + TypeInfo intImpl = intImplBasic.GetTypeInfo(); + if (CheckIsIReadOnlyCollectionExactly(intImpl)) return intImplBasic; + } +#else + if (CheckIsIReadOnlyCollectionExactly(declaredType)) return declaredType; + foreach (Type intImpl in declaredType.GetInterfaces()) + { + if (CheckIsIReadOnlyCollectionExactly(intImpl)) return intImpl; + } +#endif + return null; + } + +#if WINRT || COREFX || PROFILE259 + static bool CheckIsIReadOnlyCollectionExactly(TypeInfo t) +#else + static bool CheckIsIReadOnlyCollectionExactly(Type t) +#endif + { + if (t != null && t.IsGenericType && t.Name.StartsWith("IReadOnlyCollection`")) + { +#if WINRT || COREFX || PROFILE259 + Type[] typeArgs = t.GenericTypeArguments; + if (typeArgs.Length != 1 && typeArgs[0].GetTypeInfo().Equals(t)) return false; +#else + Type[] typeArgs = t.GetGenericArguments(); + if (typeArgs.Length != 1 && typeArgs[0] != t) return false; +#endif + + return true; + } + return false; + } + + internal static bool IdentifyImmutable(TypeModel model, Type declaredType, out MethodInfo builderFactory, out PropertyInfo isEmpty, out PropertyInfo length, out MethodInfo add, out MethodInfo addRange, out MethodInfo finish) + { + builderFactory = add = addRange = finish = null; + isEmpty = length = null; + if (model == null || declaredType == null) return false; +#if COREFX || PROFILE259 + TypeInfo declaredTypeInfo = declaredType.GetTypeInfo(); +#else + Type declaredTypeInfo = declaredType; +#endif + + // try to detect immutable collections; firstly, they are all generic, and all implement IReadOnlyCollection for some T + if (!declaredTypeInfo.IsGenericType) return false; + +#if COREFX || PROFILE259 + Type[] typeArgs = declaredTypeInfo.GenericTypeArguments, effectiveType; +#else + Type[] typeArgs = declaredTypeInfo.GetGenericArguments(), effectiveType; +#endif + switch (typeArgs.Length) + { + case 1: + effectiveType = typeArgs; + break; // fine + case 2: + Type kvp = model.MapType(typeof(System.Collections.Generic.KeyValuePair<,>)); + if (kvp == null) return false; + kvp = kvp.MakeGenericType(typeArgs); + effectiveType = new Type[] { kvp }; + break; + default: + return false; // no clue! + } + + if (ResolveIReadOnlyCollection(declaredType, null) == null) return false; // no IReadOnlyCollection found + + // and we want to use the builder API, so for generic Foo or IFoo we want to use Foo.CreateBuilder + string name = declaredType.Name; + int i = name.IndexOf('`'); + if (i <= 0) return false; + name = declaredTypeInfo.IsInterface ? name.Substring(1, i - 1) : name.Substring(0, i); + + Type outerType = model.GetType(declaredType.Namespace + "." + name, declaredTypeInfo.Assembly); + // I hate special-cases... + if (outerType == null && name == "ImmutableSet") + { + outerType = model.GetType(declaredType.Namespace + ".ImmutableHashSet", declaredTypeInfo.Assembly); + } + if (outerType == null) return false; + +#if PROFILE259 + foreach (MethodInfo method in outerType.GetTypeInfo().DeclaredMethods) +#else + foreach (MethodInfo method in outerType.GetMethods()) +#endif + { + if (!method.IsStatic || method.Name != "CreateBuilder" || !method.IsGenericMethodDefinition || method.GetParameters().Length != 0 + || method.GetGenericArguments().Length != typeArgs.Length) continue; + + builderFactory = method.MakeGenericMethod(typeArgs); + break; + } + Type voidType = model.MapType(typeof(void)); + if (builderFactory == null || builderFactory.ReturnType == null || builderFactory.ReturnType == voidType) return false; + +#if COREFX + TypeInfo typeInfo = declaredType.GetTypeInfo(); +#else + Type typeInfo = declaredType; +#endif + isEmpty = Helpers.GetProperty(typeInfo, "IsDefaultOrEmpty", false); //struct based immutabletypes can have both a "default" and "empty" state + if (isEmpty == null) isEmpty = Helpers.GetProperty(typeInfo, "IsEmpty", false); + if (isEmpty == null) + { + //Fallback to checking length if a "IsEmpty" property is not found + length = Helpers.GetProperty(typeInfo, "Length", false); + if (length == null) length = Helpers.GetProperty(typeInfo, "Count", false); + + if (length == null) length = Helpers.GetProperty(ResolveIReadOnlyCollection(declaredType, effectiveType[0]), "Count", false); + + if (length == null) return false; + } + + add = Helpers.GetInstanceMethod(builderFactory.ReturnType, "Add", effectiveType); + if (add == null) return false; + + finish = Helpers.GetInstanceMethod(builderFactory.ReturnType, "ToImmutable", Helpers.EmptyTypes); + if (finish == null || finish.ReturnType == null || finish.ReturnType == voidType) return false; + + if (!(finish.ReturnType == declaredType || Helpers.IsAssignableFrom(declaredType, finish.ReturnType))) return false; + + addRange = Helpers.GetInstanceMethod(builderFactory.ReturnType, "AddRange", new Type[] { declaredType }); + if (addRange == null) + { + Type enumerable = model.MapType(typeof(System.Collections.Generic.IEnumerable<>), false); + if (enumerable != null) + { + addRange = Helpers.GetInstanceMethod(builderFactory.ReturnType, "AddRange", new Type[] { enumerable.MakeGenericType(effectiveType) }); + } + } + + return true; + } + + private readonly MethodInfo builderFactory, add, addRange, finish; + private readonly PropertyInfo isEmpty, length; + internal ImmutableCollectionDecorator(TypeModel model, Type declaredType, Type concreteType, IProtoSerializer tail, int fieldNumber, bool writePacked, WireType packedWireType, bool returnList, bool overwriteList, bool supportNull, + MethodInfo builderFactory, PropertyInfo isEmpty, PropertyInfo length, MethodInfo add, MethodInfo addRange, MethodInfo finish) + : base(model, declaredType, concreteType, tail, fieldNumber, writePacked, packedWireType, returnList, overwriteList, supportNull) + { + this.builderFactory = builderFactory; + this.isEmpty = isEmpty; + this.length = length; + this.add = add; + this.addRange = addRange; + this.finish = finish; + } + + public override object Read(object value, ProtoReader source) + { + object builderInstance = builderFactory.Invoke(null, null); + int field = source.FieldNumber; + object[] args = new object[1]; + if (AppendToCollection && value != null && (isEmpty != null ? !(bool)isEmpty.GetValue(value, null) : (int)length.GetValue(value, null) != 0)) + { + if (addRange != null) + { + args[0] = value; + addRange.Invoke(builderInstance, args); + } + else + { + foreach (object item in (ICollection)value) + { + args[0] = item; + add.Invoke(builderInstance, args); + } + } + } + + if (packedWireType != WireType.None && source.WireType == WireType.String) + { + SubItemToken token = ProtoReader.StartSubItem(source); + while (ProtoReader.HasSubValue(packedWireType, source)) + { + args[0] = Tail.Read(null, source); + add.Invoke(builderInstance, args); + } + ProtoReader.EndSubItem(token, source); + } + else + { + do + { + args[0] = Tail.Read(null, source); + add.Invoke(builderInstance, args); + } while (source.TryReadFieldHeader(field)); + } + + return finish.Invoke(builderInstance, null); + } + +#if FEAT_COMPILER + protected override void EmitRead(Compiler.CompilerContext ctx, Compiler.Local valueFrom) + { + using (Compiler.Local oldList = AppendToCollection ? ctx.GetLocalWithValue(ExpectedType, valueFrom) : null) + using (Compiler.Local builder = new Compiler.Local(ctx, builderFactory.ReturnType)) + { + ctx.EmitCall(builderFactory); + ctx.StoreValue(builder); + + if (AppendToCollection) + { + Compiler.CodeLabel done = ctx.DefineLabel(); + if (!Helpers.IsValueType(ExpectedType)) + { + ctx.LoadValue(oldList); + ctx.BranchIfFalse(done, false); // old value null; nothing to add + } + + ctx.LoadAddress(oldList, oldList.Type); + if (isEmpty != null) + { + ctx.EmitCall(Helpers.GetGetMethod(isEmpty, false, false)); + ctx.BranchIfTrue(done, false); // old list is empty; nothing to add + } + else + { + ctx.EmitCall(Helpers.GetGetMethod(length, false, false)); + ctx.BranchIfFalse(done, false); // old list is empty; nothing to add + } + + Type voidType = ctx.MapType(typeof(void)); + if (addRange != null) + { + ctx.LoadValue(builder); + ctx.LoadValue(oldList); + ctx.EmitCall(addRange); + if (addRange.ReturnType != null && add.ReturnType != voidType) ctx.DiscardValue(); + } + else + { + // loop and call Add repeatedly + MethodInfo moveNext, current, getEnumerator = GetEnumeratorInfo(ctx.Model, out moveNext, out current); + Helpers.DebugAssert(moveNext != null); + Helpers.DebugAssert(current != null); + Helpers.DebugAssert(getEnumerator != null); + + Type enumeratorType = getEnumerator.ReturnType; + using (Compiler.Local iter = new Compiler.Local(ctx, enumeratorType)) + { + ctx.LoadAddress(oldList, ExpectedType); + ctx.EmitCall(getEnumerator); + ctx.StoreValue(iter); + using (ctx.Using(iter)) + { + Compiler.CodeLabel body = ctx.DefineLabel(), next = ctx.DefineLabel(); + ctx.Branch(next, false); + + ctx.MarkLabel(body); + ctx.LoadAddress(builder, builder.Type); + ctx.LoadAddress(iter, enumeratorType); + ctx.EmitCall(current); + ctx.EmitCall(add); + if (add.ReturnType != null && add.ReturnType != voidType) ctx.DiscardValue(); + + ctx.MarkLabel(@next); + ctx.LoadAddress(iter, enumeratorType); + ctx.EmitCall(moveNext); + ctx.BranchIfTrue(body, false); + } + } + } + + + ctx.MarkLabel(done); + } + + EmitReadList(ctx, builder, Tail, add, packedWireType, false); + + ctx.LoadAddress(builder, builder.Type); + ctx.EmitCall(finish); + if (ExpectedType != finish.ReturnType) + { + ctx.Cast(ExpectedType); + } + } + } +#endif + } +} +#endif diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/ImmutableCollectionDecorator.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/ImmutableCollectionDecorator.cs.meta new file mode 100644 index 0000000..f8d9012 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/ImmutableCollectionDecorator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 00a3af58286d1674ca64bcf5fd9f0228 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/Int16Serializer.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/Int16Serializer.cs new file mode 100644 index 0000000..eac4eb4 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/Int16Serializer.cs @@ -0,0 +1,42 @@ +#if !NO_RUNTIME +using System; + +namespace ProtoBuf.Serializers +{ + sealed class Int16Serializer : IProtoSerializer + { + static readonly Type expectedType = typeof(short); + + public Int16Serializer(ProtoBuf.Meta.TypeModel model) { } + + public Type ExpectedType => expectedType; + + bool IProtoSerializer.RequiresOldValue => false; + + bool IProtoSerializer.ReturnsValue => true; + + public object Read(object value, ProtoReader source) + { + Helpers.DebugAssert(value == null); // since replaces + return source.ReadInt16(); + } + + public void Write(object value, ProtoWriter dest) + { + ProtoWriter.WriteInt16((short)value, dest); + } + +#if FEAT_COMPILER + void IProtoSerializer.EmitWrite(Compiler.CompilerContext ctx, Compiler.Local valueFrom) + { + ctx.EmitBasicWrite("WriteInt16", valueFrom); + } + void IProtoSerializer.EmitRead(Compiler.CompilerContext ctx, Compiler.Local valueFrom) + { + ctx.EmitBasicRead("ReadInt16", ExpectedType); + } +#endif + + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/Int16Serializer.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/Int16Serializer.cs.meta new file mode 100644 index 0000000..546159f --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/Int16Serializer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e45229312d2a4fe45b519e513326b708 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/Int32Serializer.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/Int32Serializer.cs new file mode 100644 index 0000000..204880e --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/Int32Serializer.cs @@ -0,0 +1,42 @@ +#if !NO_RUNTIME +using System; + +namespace ProtoBuf.Serializers +{ + sealed class Int32Serializer : IProtoSerializer + { + static readonly Type expectedType = typeof(int); + + public Int32Serializer(ProtoBuf.Meta.TypeModel model) { } + + public Type ExpectedType => expectedType; + + bool IProtoSerializer.RequiresOldValue => false; + + bool IProtoSerializer.ReturnsValue => true; + + public object Read(object value, ProtoReader source) + { + Helpers.DebugAssert(value == null); // since replaces + return source.ReadInt32(); + } + + public void Write(object value, ProtoWriter dest) + { + ProtoWriter.WriteInt32((int)value, dest); + } + +#if FEAT_COMPILER + void IProtoSerializer.EmitWrite(Compiler.CompilerContext ctx, Compiler.Local valueFrom) + { + ctx.EmitBasicWrite("WriteInt32", valueFrom); + } + void IProtoSerializer.EmitRead(Compiler.CompilerContext ctx, Compiler.Local valueFrom) + { + ctx.EmitBasicRead("ReadInt32", ExpectedType); + } +#endif + + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/Int32Serializer.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/Int32Serializer.cs.meta new file mode 100644 index 0000000..1be4c7e --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/Int32Serializer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4a7c49bc45156f442bfe84fc7eef04b9 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/Int64Serializer.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/Int64Serializer.cs new file mode 100644 index 0000000..2791a1e --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/Int64Serializer.cs @@ -0,0 +1,41 @@ +#if !NO_RUNTIME +using System; + +namespace ProtoBuf.Serializers +{ + sealed class Int64Serializer : IProtoSerializer + { + static readonly Type expectedType = typeof(long); + + public Int64Serializer(ProtoBuf.Meta.TypeModel model) { } + + public Type ExpectedType => expectedType; + + bool IProtoSerializer.RequiresOldValue => false; + + bool IProtoSerializer.ReturnsValue => true; + + public object Read(object value, ProtoReader source) + { + Helpers.DebugAssert(value == null); // since replaces + return source.ReadInt64(); + } + + public void Write(object value, ProtoWriter dest) + { + ProtoWriter.WriteInt64((long)value, dest); + } + +#if FEAT_COMPILER + void IProtoSerializer.EmitWrite(Compiler.CompilerContext ctx, Compiler.Local valueFrom) + { + ctx.EmitBasicWrite("WriteInt64", valueFrom); + } + void IProtoSerializer.EmitRead(Compiler.CompilerContext ctx, Compiler.Local valueFrom) + { + ctx.EmitBasicRead("ReadInt64", ExpectedType); + } +#endif + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/Int64Serializer.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/Int64Serializer.cs.meta new file mode 100644 index 0000000..8dbba5e --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/Int64Serializer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 03f2770a306f45046b6e8eab757c9188 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/ListDecorator.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/ListDecorator.cs new file mode 100644 index 0000000..82bb128 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/ListDecorator.cs @@ -0,0 +1,579 @@ +#if !NO_RUNTIME +using System; +using System.Collections; +using ProtoBuf.Meta; +using System.Reflection; + +namespace ProtoBuf.Serializers +{ + class ListDecorator : ProtoDecoratorBase + { + internal static bool CanPack(WireType wireType) + { + switch (wireType) + { + case WireType.Fixed32: + case WireType.Fixed64: + case WireType.SignedVariant: + case WireType.Variant: + return true; + default: + return false; + } + } + + private readonly byte options; + + private const byte OPTIONS_IsList = 1, + OPTIONS_SuppressIList = 2, + OPTIONS_WritePacked = 4, + OPTIONS_ReturnList = 8, + OPTIONS_OverwriteList = 16, + OPTIONS_SupportNull = 32; + + private readonly Type declaredType, concreteType; + + private readonly MethodInfo add; + + private readonly int fieldNumber; + + private bool IsList { get { return (options & OPTIONS_IsList) != 0; } } + private bool SuppressIList { get { return (options & OPTIONS_SuppressIList) != 0; } } + private bool WritePacked { get { return (options & OPTIONS_WritePacked) != 0; } } + private bool SupportNull { get { return (options & OPTIONS_SupportNull) != 0; } } + private bool ReturnList { get { return (options & OPTIONS_ReturnList) != 0; } } + protected readonly WireType packedWireType; + + internal static ListDecorator Create(TypeModel model, Type declaredType, Type concreteType, IProtoSerializer tail, int fieldNumber, bool writePacked, WireType packedWireType, bool returnList, bool overwriteList, bool supportNull) + { + if (returnList && ImmutableCollectionDecorator.IdentifyImmutable(model, declaredType, + out MethodInfo builderFactory, + out PropertyInfo isEmpty, + out PropertyInfo length, + out MethodInfo add, + out MethodInfo addRange, + out MethodInfo finish)) + { + return new ImmutableCollectionDecorator( + model, declaredType, concreteType, tail, fieldNumber, writePacked, packedWireType, returnList, overwriteList, supportNull, + builderFactory, isEmpty, length, add, addRange, finish); + } + + return new ListDecorator(model, declaredType, concreteType, tail, fieldNumber, writePacked, packedWireType, returnList, overwriteList, supportNull); + } + + protected ListDecorator(TypeModel model, Type declaredType, Type concreteType, IProtoSerializer tail, int fieldNumber, bool writePacked, WireType packedWireType, bool returnList, bool overwriteList, bool supportNull) + : base(tail) + { + if (returnList) options |= OPTIONS_ReturnList; + if (overwriteList) options |= OPTIONS_OverwriteList; + if (supportNull) options |= OPTIONS_SupportNull; + if ((writePacked || packedWireType != WireType.None) && fieldNumber <= 0) throw new ArgumentOutOfRangeException("fieldNumber"); + if (!CanPack(packedWireType)) + { + if (writePacked) throw new InvalidOperationException("Only simple data-types can use packed encoding"); + packedWireType = WireType.None; + } + + this.fieldNumber = fieldNumber; + if (writePacked) options |= OPTIONS_WritePacked; + this.packedWireType = packedWireType; + if (declaredType == null) throw new ArgumentNullException("declaredType"); + if (declaredType.IsArray) throw new ArgumentException("Cannot treat arrays as lists", "declaredType"); + this.declaredType = declaredType; + this.concreteType = concreteType; + + // look for a public list.Add(typedObject) method + if (RequireAdd) + { + bool isList; + add = TypeModel.ResolveListAdd(model, declaredType, tail.ExpectedType, out isList); + if (isList) + { + options |= OPTIONS_IsList; + string fullName = declaredType.FullName; + if (fullName != null && fullName.StartsWith("System.Data.Linq.EntitySet`1[[")) + { // see http://stackoverflow.com/questions/6194639/entityset-is-there-a-sane-reason-that-ilist-add-doesnt-set-assigned + options |= OPTIONS_SuppressIList; + } + } + if (add == null) throw new InvalidOperationException("Unable to resolve a suitable Add method for " + declaredType.FullName); + } + + } + protected virtual bool RequireAdd => true; + + public override Type ExpectedType => declaredType; + + public override bool RequiresOldValue => AppendToCollection; + + public override bool ReturnsValue => ReturnList; + + protected bool AppendToCollection + { + get { return (options & OPTIONS_OverwriteList) == 0; } + } + +#if FEAT_COMPILER + protected override void EmitRead(ProtoBuf.Compiler.CompilerContext ctx, ProtoBuf.Compiler.Local valueFrom) + { + /* This looks more complex than it is. Look at the non-compiled Read to + * see what it is trying to do, but note that it needs to cope with a + * few more scenarios. Note that it picks the **most specific** Add, + * unlike the runtime version that uses IList when possible. The core + * is just a "do {list.Add(readValue())} while {thereIsMore}" + * + * The complexity is due to: + * - value types vs reference types (boxing etc) + * - initialization if we need to pass in a value to the tail + * - handling whether or not the tail *returns* the value vs updates the input + */ + bool returnList = ReturnList; + + using (Compiler.Local list = AppendToCollection ? ctx.GetLocalWithValue(ExpectedType, valueFrom) : new Compiler.Local(ctx, declaredType)) + using (Compiler.Local origlist = (returnList && AppendToCollection && !Helpers.IsValueType(ExpectedType)) ? new Compiler.Local(ctx, ExpectedType) : null) + { + if (!AppendToCollection) + { // always new + ctx.LoadNullRef(); + ctx.StoreValue(list); + } + else if (returnList && origlist != null) + { // need a copy + ctx.LoadValue(list); + ctx.StoreValue(origlist); + } + if (concreteType != null) + { + ctx.LoadValue(list); + Compiler.CodeLabel notNull = ctx.DefineLabel(); + ctx.BranchIfTrue(notNull, true); + ctx.EmitCtor(concreteType); + ctx.StoreValue(list); + ctx.MarkLabel(notNull); + } + + bool castListForAdd = !add.DeclaringType.IsAssignableFrom(declaredType); + EmitReadList(ctx, list, Tail, add, packedWireType, castListForAdd); + + if (returnList) + { + if (AppendToCollection && origlist != null) + { + // remember ^^^^ we had a spare copy of the list on the stack; now we'll compare + ctx.LoadValue(origlist); + ctx.LoadValue(list); // [orig] [new-value] + Compiler.CodeLabel sameList = ctx.DefineLabel(), allDone = ctx.DefineLabel(); + ctx.BranchIfEqual(sameList, true); + ctx.LoadValue(list); + ctx.Branch(allDone, true); + ctx.MarkLabel(sameList); + ctx.LoadNullRef(); + ctx.MarkLabel(allDone); + } + else + { + ctx.LoadValue(list); + } + } + } + } + + internal static void EmitReadList(ProtoBuf.Compiler.CompilerContext ctx, Compiler.Local list, IProtoSerializer tail, MethodInfo add, WireType packedWireType, bool castListForAdd) + { + using (Compiler.Local fieldNumber = new Compiler.Local(ctx, ctx.MapType(typeof(int)))) + { + Compiler.CodeLabel readPacked = packedWireType == WireType.None ? new Compiler.CodeLabel() : ctx.DefineLabel(); + if (packedWireType != WireType.None) + { + ctx.LoadReaderWriter(); + ctx.LoadValue(typeof(ProtoReader).GetProperty("WireType")); + ctx.LoadValue((int)WireType.String); + ctx.BranchIfEqual(readPacked, false); + } + ctx.LoadReaderWriter(); + ctx.LoadValue(typeof(ProtoReader).GetProperty("FieldNumber")); + ctx.StoreValue(fieldNumber); + + Compiler.CodeLabel @continue = ctx.DefineLabel(); + ctx.MarkLabel(@continue); + + EmitReadAndAddItem(ctx, list, tail, add, castListForAdd); + + ctx.LoadReaderWriter(); + ctx.LoadValue(fieldNumber); + ctx.EmitCall(ctx.MapType(typeof(ProtoReader)).GetMethod("TryReadFieldHeader")); + ctx.BranchIfTrue(@continue, false); + + if (packedWireType != WireType.None) + { + Compiler.CodeLabel allDone = ctx.DefineLabel(); + ctx.Branch(allDone, false); + ctx.MarkLabel(readPacked); + + ctx.LoadReaderWriter(); + ctx.EmitCall(ctx.MapType(typeof(ProtoReader)).GetMethod("StartSubItem")); + + Compiler.CodeLabel testForData = ctx.DefineLabel(), noMoreData = ctx.DefineLabel(); + ctx.MarkLabel(testForData); + ctx.LoadValue((int)packedWireType); + ctx.LoadReaderWriter(); + ctx.EmitCall(ctx.MapType(typeof(ProtoReader)).GetMethod("HasSubValue")); + ctx.BranchIfFalse(noMoreData, false); + + EmitReadAndAddItem(ctx, list, tail, add, castListForAdd); + ctx.Branch(testForData, false); + + ctx.MarkLabel(noMoreData); + ctx.LoadReaderWriter(); + ctx.EmitCall(ctx.MapType(typeof(ProtoReader)).GetMethod("EndSubItem")); + ctx.MarkLabel(allDone); + } + } + } + + private static void EmitReadAndAddItem(Compiler.CompilerContext ctx, Compiler.Local list, IProtoSerializer tail, MethodInfo add, bool castListForAdd) + { + ctx.LoadAddress(list, list.Type); // needs to be the reference in case the list is value-type (static-call) + if (castListForAdd) ctx.Cast(add.DeclaringType); + + Type itemType = tail.ExpectedType; + bool tailReturnsValue = tail.ReturnsValue; + if (tail.RequiresOldValue) + { + if (Helpers.IsValueType(itemType) || !tailReturnsValue) + { + // going to need a variable + using (Compiler.Local item = new Compiler.Local(ctx, itemType)) + { + if (Helpers.IsValueType(itemType)) + { // initialise the struct + ctx.LoadAddress(item, itemType); + ctx.EmitCtor(itemType); + } + else + { // assign null + ctx.LoadNullRef(); + ctx.StoreValue(item); + } + tail.EmitRead(ctx, item); + if (!tailReturnsValue) { ctx.LoadValue(item); } + } + } + else + { // no variable; pass the null on the stack and take the value *off* the stack + ctx.LoadNullRef(); + tail.EmitRead(ctx, null); + } + } + else + { + if (tailReturnsValue) + { // out only (on the stack); just emit it + tail.EmitRead(ctx, null); + } + else + { // doesn't take anything in nor return anything! WTF? + throw new InvalidOperationException(); + } + } + // our "Add" is chosen either to take the correct type, or to take "object"; + // we may need to box the value + + Type addParamType = add.GetParameters()[0].ParameterType; + if (addParamType != itemType) + { + if (addParamType == ctx.MapType(typeof(object))) + { + ctx.CastToObject(itemType); + } + else if (Helpers.GetUnderlyingType(addParamType) == itemType) + { // list is nullable + ConstructorInfo ctor = Helpers.GetConstructor(addParamType, new Type[] { itemType }, false); + ctx.EmitCtor(ctor); // the itemType on the stack is now a Nullable + } + else + { + throw new InvalidOperationException("Conflicting item/add type"); + } + } + ctx.EmitCall(add, list.Type); + if (add.ReturnType != ctx.MapType(typeof(void))) + { + ctx.DiscardValue(); + } + } +#endif + +#if COREFX + private static readonly TypeInfo ienumeratorType = typeof(IEnumerator).GetTypeInfo(), ienumerableType = typeof (IEnumerable).GetTypeInfo(); +#else + private static readonly System.Type ienumeratorType = typeof(IEnumerator), ienumerableType = typeof(IEnumerable); +#endif + protected MethodInfo GetEnumeratorInfo(TypeModel model, out MethodInfo moveNext, out MethodInfo current) + => GetEnumeratorInfo(model, ExpectedType, Tail.ExpectedType, out moveNext, out current); + internal static MethodInfo GetEnumeratorInfo(TypeModel model, Type expectedType, Type itemType, out MethodInfo moveNext, out MethodInfo current) + { + +#if COREFX + TypeInfo enumeratorType = null, iteratorType; +#else + Type enumeratorType = null, iteratorType; +#endif + + // try a custom enumerator + MethodInfo getEnumerator = Helpers.GetInstanceMethod(expectedType, "GetEnumerator", null); + + Type getReturnType = null; + if (getEnumerator != null) + { + getReturnType = getEnumerator.ReturnType; + iteratorType = getReturnType +#if COREFX || COREFX + .GetTypeInfo() +#endif + ; + moveNext = Helpers.GetInstanceMethod(iteratorType, "MoveNext", null); + PropertyInfo prop = Helpers.GetProperty(iteratorType, "Current", false); + current = prop == null ? null : Helpers.GetGetMethod(prop, false, false); +#if PROFILE259 + if (moveNext == null && (model.MapType(ienumeratorType).GetTypeInfo().IsAssignableFrom(iteratorType.GetTypeInfo()))) +#else + if (moveNext == null && (model.MapType(ienumeratorType).IsAssignableFrom(iteratorType))) +#endif + { + moveNext = Helpers.GetInstanceMethod(model.MapType(ienumeratorType), "MoveNext", null); + } + // fully typed + if (moveNext != null && moveNext.ReturnType == model.MapType(typeof(bool)) + && current != null && current.ReturnType == itemType) + { + return getEnumerator; + } + moveNext = current = getEnumerator = null; + } + + // try IEnumerable + Type tmp = model.MapType(typeof(System.Collections.Generic.IEnumerable<>), false); + + if (tmp != null) + { + tmp = tmp.MakeGenericType(itemType); + +#if COREFX + enumeratorType = tmp.GetTypeInfo(); +#else + enumeratorType = tmp; +#endif + } +; +#if PROFILE259 + if (enumeratorType != null && enumeratorType.GetTypeInfo().IsAssignableFrom(expectedType +#else + if (enumeratorType != null && enumeratorType.IsAssignableFrom(expectedType +#endif +#if COREFX || PROFILE259 + .GetTypeInfo() +#endif + )) + { + getEnumerator = Helpers.GetInstanceMethod(enumeratorType, "GetEnumerator"); + getReturnType = getEnumerator.ReturnType; + +#if COREFX + iteratorType = getReturnType.GetTypeInfo(); +#else + iteratorType = getReturnType; +#endif + + moveNext = Helpers.GetInstanceMethod(model.MapType(ienumeratorType), "MoveNext"); + current = Helpers.GetGetMethod(Helpers.GetProperty(iteratorType, "Current", false), false, false); + return getEnumerator; + } + // give up and fall-back to non-generic IEnumerable + enumeratorType = model.MapType(ienumerableType); + getEnumerator = Helpers.GetInstanceMethod(enumeratorType, "GetEnumerator"); + getReturnType = getEnumerator.ReturnType; + iteratorType = getReturnType +#if COREFX + .GetTypeInfo() +#endif + ; + moveNext = Helpers.GetInstanceMethod(iteratorType, "MoveNext"); + current = Helpers.GetGetMethod(Helpers.GetProperty(iteratorType, "Current", false), false, false); + return getEnumerator; + } +#if FEAT_COMPILER + protected override void EmitWrite(ProtoBuf.Compiler.CompilerContext ctx, ProtoBuf.Compiler.Local valueFrom) + { + using (Compiler.Local list = ctx.GetLocalWithValue(ExpectedType, valueFrom)) + { + MethodInfo getEnumerator = GetEnumeratorInfo(ctx.Model, out MethodInfo moveNext, out MethodInfo current); + Helpers.DebugAssert(moveNext != null); + Helpers.DebugAssert(current != null); + Helpers.DebugAssert(getEnumerator != null); + Type enumeratorType = getEnumerator.ReturnType; + bool writePacked = WritePacked; + using (Compiler.Local iter = new Compiler.Local(ctx, enumeratorType)) + using (Compiler.Local token = writePacked ? new Compiler.Local(ctx, ctx.MapType(typeof(SubItemToken))) : null) + { + if (writePacked) + { + ctx.LoadValue(fieldNumber); + ctx.LoadValue((int)WireType.String); + ctx.LoadReaderWriter(); + ctx.EmitCall(ctx.MapType(typeof(ProtoWriter)).GetMethod("WriteFieldHeader")); + + ctx.LoadValue(list); + ctx.LoadReaderWriter(); + ctx.EmitCall(ctx.MapType(typeof(ProtoWriter)).GetMethod("StartSubItem")); + ctx.StoreValue(token); + + ctx.LoadValue(fieldNumber); + ctx.LoadReaderWriter(); + ctx.EmitCall(ctx.MapType(typeof(ProtoWriter)).GetMethod("SetPackedField")); + } + + ctx.LoadAddress(list, ExpectedType); + ctx.EmitCall(getEnumerator, ExpectedType); + ctx.StoreValue(iter); + using (ctx.Using(iter)) + { + Compiler.CodeLabel body = ctx.DefineLabel(), next = ctx.DefineLabel(); + ctx.Branch(next, false); + + ctx.MarkLabel(body); + + ctx.LoadAddress(iter, enumeratorType); + ctx.EmitCall(current, enumeratorType); + Type itemType = Tail.ExpectedType; + if (itemType != ctx.MapType(typeof(object)) && current.ReturnType == ctx.MapType(typeof(object))) + { + ctx.CastFromObject(itemType); + } + Tail.EmitWrite(ctx, null); + + ctx.MarkLabel(@next); + ctx.LoadAddress(iter, enumeratorType); + ctx.EmitCall(moveNext, enumeratorType); + ctx.BranchIfTrue(body, false); + } + + if (writePacked) + { + ctx.LoadValue(token); + ctx.LoadReaderWriter(); + ctx.EmitCall(ctx.MapType(typeof(ProtoWriter)).GetMethod("EndSubItem")); + } + } + } + } +#endif + + public override void Write(object value, ProtoWriter dest) + { + SubItemToken token; + bool writePacked = WritePacked; + bool fixedSizePacked = writePacked & CanUsePackedPrefix(value) && value is ICollection; + if (writePacked) + { + ProtoWriter.WriteFieldHeader(fieldNumber, WireType.String, dest); + if (fixedSizePacked) + { + ProtoWriter.WritePackedPrefix(((ICollection)value).Count, packedWireType, dest); + token = default(SubItemToken); + } + else + { + token = ProtoWriter.StartSubItem(value, dest); + } + ProtoWriter.SetPackedField(fieldNumber, dest); + } + else + { + token = new SubItemToken(); // default + } + bool checkForNull = !SupportNull; + foreach (object subItem in (IEnumerable)value) + { + if (checkForNull && subItem == null) { throw new NullReferenceException(); } + Tail.Write(subItem, dest); + } + if (writePacked) + { + if (fixedSizePacked) + { + ProtoWriter.ClearPackedField(fieldNumber, dest); + } + else + { + ProtoWriter.EndSubItem(token, dest); + } + } + } + + private bool CanUsePackedPrefix(object obj) => + ArrayDecorator.CanUsePackedPrefix(packedWireType, Tail.ExpectedType); + + public override object Read(object value, ProtoReader source) + { + try + { + int field = source.FieldNumber; + object origValue = value; + if (value == null) value = Activator.CreateInstance(concreteType); + bool isList = IsList && !SuppressIList; + if (packedWireType != WireType.None && source.WireType == WireType.String) + { + SubItemToken token = ProtoReader.StartSubItem(source); + if (isList) + { + IList list = (IList)value; + while (ProtoReader.HasSubValue(packedWireType, source)) + { + list.Add(Tail.Read(null, source)); + } + } + else + { + object[] args = new object[1]; + while (ProtoReader.HasSubValue(packedWireType, source)) + { + args[0] = Tail.Read(null, source); + add.Invoke(value, args); + } + } + ProtoReader.EndSubItem(token, source); + } + else + { + if (isList) + { + IList list = (IList)value; + do + { + list.Add(Tail.Read(null, source)); + } while (source.TryReadFieldHeader(field)); + } + else + { + object[] args = new object[1]; + do + { + args[0] = Tail.Read(null, source); + add.Invoke(value, args); + } while (source.TryReadFieldHeader(field)); + } + } + return origValue == value ? null : value; + } + catch (TargetInvocationException tie) + { + if (tie.InnerException != null) throw tie.InnerException; + throw; + } + } + + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/ListDecorator.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/ListDecorator.cs.meta new file mode 100644 index 0000000..a5980a2 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/ListDecorator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: eb7a73aa78c887c478b0af6d506337d5 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/MapDecorator.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/MapDecorator.cs new file mode 100644 index 0000000..033cf26 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/MapDecorator.cs @@ -0,0 +1,298 @@ +using ProtoBuf.Meta; +using System; +#if FEAT_COMPILER +using ProtoBuf.Compiler; +#endif +using System.Collections.Generic; +using System.Reflection; + +namespace ProtoBuf.Serializers +{ + class MapDecorator : ProtoDecoratorBase where TDictionary : class, IDictionary + { + private readonly Type concreteType; + private readonly IProtoSerializer keyTail; + private readonly int fieldNumber; + private readonly WireType wireType; + + internal MapDecorator(TypeModel model, Type concreteType, IProtoSerializer keyTail, IProtoSerializer valueTail, + int fieldNumber, WireType wireType, WireType keyWireType, WireType valueWireType, bool overwriteList) + : base(DefaultValue == null + ? (IProtoSerializer)new TagDecorator(2, valueWireType, false, valueTail) + : (IProtoSerializer)new DefaultValueDecorator(model, DefaultValue, new TagDecorator(2, valueWireType, false, valueTail))) + { + this.wireType = wireType; + this.keyTail = new DefaultValueDecorator(model, DefaultKey, new TagDecorator(1, keyWireType, false, keyTail)); + this.fieldNumber = fieldNumber; + this.concreteType = concreteType ?? typeof(TDictionary); + + if (keyTail.RequiresOldValue) throw new InvalidOperationException("Key tail should not require the old value"); + if (!keyTail.ReturnsValue) throw new InvalidOperationException("Key tail should return a value"); + if (!valueTail.ReturnsValue) throw new InvalidOperationException("Value tail should return a value"); + + AppendToCollection = !overwriteList; + } + + private static readonly MethodInfo indexerSet = GetIndexerSetter(); + + private static MethodInfo GetIndexerSetter() + { +#if PROFILE259 + foreach(var prop in typeof(TDictionary).GetRuntimeProperties()) +#else + foreach (var prop in typeof(TDictionary).GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)) +#endif + { + if (prop.Name != "Item") continue; + if (prop.PropertyType != typeof(TValue)) continue; + + var args = prop.GetIndexParameters(); + if (args == null || args.Length != 1) continue; + + if (args[0].ParameterType != typeof(TKey)) continue; +#if PROFILE259 + var method = prop.SetMethod; +#else + var method = prop.GetSetMethod(true); +#endif + if (method != null) + { + return method; + } + } + throw new InvalidOperationException("Unable to resolve indexer for map"); + } + + private static readonly TKey DefaultKey = (typeof(TKey) == typeof(string)) ? (TKey)(object)"" : default(TKey); + private static readonly TValue DefaultValue = (typeof(TValue) == typeof(string)) ? (TValue)(object)"" : default(TValue); + public override Type ExpectedType => typeof(TDictionary); + + public override bool ReturnsValue => true; + + public override bool RequiresOldValue => AppendToCollection; + + private bool AppendToCollection { get; } + + public override object Read(object untyped, ProtoReader source) + { + TDictionary typed = AppendToCollection ? ((TDictionary)untyped) : null; + if (typed == null) typed = (TDictionary)Activator.CreateInstance(concreteType); + + do + { + var key = DefaultKey; + var value = DefaultValue; + SubItemToken token = ProtoReader.StartSubItem(source); + int field; + while ((field = source.ReadFieldHeader()) > 0) + { + switch (field) + { + case 1: + key = (TKey)keyTail.Read(null, source); + break; + case 2: + value = (TValue)Tail.Read(Tail.RequiresOldValue ? (object)value : null, source); + break; + default: + source.SkipField(); + break; + } + } + + ProtoReader.EndSubItem(token, source); + typed[key] = value; + } while (source.TryReadFieldHeader(fieldNumber)); + + return typed; + } + + public override void Write(object untyped, ProtoWriter dest) + { + foreach (var pair in (TDictionary)untyped) + { + ProtoWriter.WriteFieldHeader(fieldNumber, wireType, dest); + var token = ProtoWriter.StartSubItem(null, dest); + if (pair.Key != null) keyTail.Write(pair.Key, dest); + if (pair.Value != null) Tail.Write(pair.Value, dest); + ProtoWriter.EndSubItem(token, dest); + } + } + +#if FEAT_COMPILER + protected override void EmitWrite(CompilerContext ctx, Local valueFrom) + { + Type itemType = typeof(KeyValuePair); + MethodInfo moveNext, current, getEnumerator = ListDecorator.GetEnumeratorInfo(ctx.Model, + ExpectedType, itemType, out moveNext, out current); + Type enumeratorType = getEnumerator.ReturnType; + + MethodInfo key = itemType.GetProperty(nameof(KeyValuePair.Key)).GetGetMethod(), + @value = itemType.GetProperty(nameof(KeyValuePair.Value)).GetGetMethod(); + + using (Compiler.Local list = ctx.GetLocalWithValue(ExpectedType, valueFrom)) + using (Compiler.Local iter = new Compiler.Local(ctx, enumeratorType)) + using (Compiler.Local token = new Compiler.Local(ctx, typeof(SubItemToken))) + using (Compiler.Local kvp = new Compiler.Local(ctx, itemType)) + { + ctx.LoadAddress(list, ExpectedType); + ctx.EmitCall(getEnumerator, ExpectedType); + ctx.StoreValue(iter); + using (ctx.Using(iter)) + { + Compiler.CodeLabel body = ctx.DefineLabel(), next = ctx.DefineLabel(); + ctx.Branch(next, false); + + ctx.MarkLabel(body); + + ctx.LoadAddress(iter, enumeratorType); + ctx.EmitCall(current, enumeratorType); + + if (itemType != ctx.MapType(typeof(object)) && current.ReturnType == ctx.MapType(typeof(object))) + { + ctx.CastFromObject(itemType); + } + ctx.StoreValue(kvp); + + ctx.LoadValue(fieldNumber); + ctx.LoadValue((int)wireType); + ctx.LoadReaderWriter(); + ctx.EmitCall(ctx.MapType(typeof(ProtoWriter)).GetMethod("WriteFieldHeader")); + + ctx.LoadNullRef(); + ctx.LoadReaderWriter(); + ctx.EmitCall(ctx.MapType(typeof(ProtoWriter)).GetMethod("StartSubItem")); + ctx.StoreValue(token); + + ctx.LoadAddress(kvp, itemType); + ctx.EmitCall(key, itemType); + ctx.WriteNullCheckedTail(typeof(TKey), keyTail, null); + + ctx.LoadAddress(kvp, itemType); + ctx.EmitCall(value, itemType); + ctx.WriteNullCheckedTail(typeof(TValue), Tail, null); + + ctx.LoadValue(token); + ctx.LoadReaderWriter(); + ctx.EmitCall(ctx.MapType(typeof(ProtoWriter)).GetMethod("EndSubItem")); + + ctx.MarkLabel(@next); + ctx.LoadAddress(iter, enumeratorType); + ctx.EmitCall(moveNext, enumeratorType); + ctx.BranchIfTrue(body, false); + } + } + } + protected override void EmitRead(CompilerContext ctx, Local valueFrom) + { + using (Compiler.Local list = AppendToCollection ? ctx.GetLocalWithValue(ExpectedType, valueFrom) + : new Compiler.Local(ctx, typeof(TDictionary))) + using (Compiler.Local token = new Compiler.Local(ctx, typeof(SubItemToken))) + using (Compiler.Local key = new Compiler.Local(ctx, typeof(TKey))) + using (Compiler.Local @value = new Compiler.Local(ctx, typeof(TValue))) + using (Compiler.Local fieldNumber = new Compiler.Local(ctx, ctx.MapType(typeof(int)))) + { + if (!AppendToCollection) + { // always new + ctx.LoadNullRef(); + ctx.StoreValue(list); + } + if (concreteType != null) + { + ctx.LoadValue(list); + Compiler.CodeLabel notNull = ctx.DefineLabel(); + ctx.BranchIfTrue(notNull, true); + ctx.EmitCtor(concreteType); + ctx.StoreValue(list); + ctx.MarkLabel(notNull); + } + + var redoFromStart = ctx.DefineLabel(); + ctx.MarkLabel(redoFromStart); + + // key = default(TKey); value = default(TValue); + if (typeof(TKey) == typeof(string)) + { + ctx.LoadValue(""); + ctx.StoreValue(key); + } + else + { + ctx.InitLocal(typeof(TKey), key); + } + if (typeof(TValue) == typeof(string)) + { + ctx.LoadValue(""); + ctx.StoreValue(value); + } + else + { + ctx.InitLocal(typeof(TValue), @value); + } + + // token = ProtoReader.StartSubItem(reader); + ctx.LoadReaderWriter(); + ctx.EmitCall(ctx.MapType(typeof(ProtoReader)).GetMethod("StartSubItem")); + ctx.StoreValue(token); + + Compiler.CodeLabel @continue = ctx.DefineLabel(), processField = ctx.DefineLabel(); + // while ... + ctx.Branch(@continue, false); + + // switch(fieldNumber) + ctx.MarkLabel(processField); + ctx.LoadValue(fieldNumber); + CodeLabel @default = ctx.DefineLabel(), one = ctx.DefineLabel(), two = ctx.DefineLabel(); + ctx.Switch(new[] { @default, one, two }); // zero based, hence explicit 0 + + // case 0: default: reader.SkipField(); + ctx.MarkLabel(@default); + ctx.LoadReaderWriter(); + ctx.EmitCall(ctx.MapType(typeof(ProtoReader)).GetMethod("SkipField")); + ctx.Branch(@continue, false); + + // case 1: key = ... + ctx.MarkLabel(one); + keyTail.EmitRead(ctx, null); + ctx.StoreValue(key); + ctx.Branch(@continue, false); + + // case 2: value = ... + ctx.MarkLabel(two); + Tail.EmitRead(ctx, Tail.RequiresOldValue ? @value : null); + ctx.StoreValue(value); + + // (fieldNumber = reader.ReadFieldHeader()) > 0 + ctx.MarkLabel(@continue); + ctx.EmitBasicRead("ReadFieldHeader", ctx.MapType(typeof(int))); + ctx.CopyValue(); + ctx.StoreValue(fieldNumber); + ctx.LoadValue(0); + ctx.BranchIfGreater(processField, false); + + // ProtoReader.EndSubItem(token, reader); + ctx.LoadValue(token); + ctx.LoadReaderWriter(); + ctx.EmitCall(ctx.MapType(typeof(ProtoReader)).GetMethod("EndSubItem")); + + // list[key] = value; + ctx.LoadAddress(list, ExpectedType); + ctx.LoadValue(key); + ctx.LoadValue(@value); + ctx.EmitCall(indexerSet); + + // while reader.TryReadFieldReader(fieldNumber) + ctx.LoadReaderWriter(); + ctx.LoadValue(this.fieldNumber); + ctx.EmitCall(ctx.MapType(typeof(ProtoReader)).GetMethod("TryReadFieldHeader")); + ctx.BranchIfTrue(redoFromStart, false); + + if (ReturnsValue) + { + ctx.LoadValue(list); + } + } + } +#endif + } +} diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/MapDecorator.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/MapDecorator.cs.meta new file mode 100644 index 0000000..51c4525 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/MapDecorator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 522b5c8a0fa5be14591bc9cbe3b194d3 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/MemberSpecifiedDecorator.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/MemberSpecifiedDecorator.cs new file mode 100644 index 0000000..3ee80a5 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/MemberSpecifiedDecorator.cs @@ -0,0 +1,76 @@ +#if !NO_RUNTIME +using System; +using System.Reflection; + +namespace ProtoBuf.Serializers +{ + sealed class MemberSpecifiedDecorator : ProtoDecoratorBase + { + public override Type ExpectedType => Tail.ExpectedType; + + public override bool RequiresOldValue => Tail.RequiresOldValue; + + public override bool ReturnsValue => Tail.ReturnsValue; + + private readonly MethodInfo getSpecified, setSpecified; + public MemberSpecifiedDecorator(MethodInfo getSpecified, MethodInfo setSpecified, IProtoSerializer tail) + : base(tail) + { + if (getSpecified == null && setSpecified == null) throw new InvalidOperationException(); + this.getSpecified = getSpecified; + this.setSpecified = setSpecified; + } + + public override void Write(object value, ProtoWriter dest) + { + if (getSpecified == null || (bool)getSpecified.Invoke(value, null)) + { + Tail.Write(value, dest); + } + } + + public override object Read(object value, ProtoReader source) + { + object result = Tail.Read(value, source); + if (setSpecified != null) setSpecified.Invoke(value, new object[] { true }); + return result; + } + +#if FEAT_COMPILER + protected override void EmitWrite(Compiler.CompilerContext ctx, Compiler.Local valueFrom) + { + if (getSpecified == null) + { + Tail.EmitWrite(ctx, valueFrom); + return; + } + using (Compiler.Local loc = ctx.GetLocalWithValue(ExpectedType, valueFrom)) + { + ctx.LoadAddress(loc, ExpectedType); + ctx.EmitCall(getSpecified); + Compiler.CodeLabel done = ctx.DefineLabel(); + ctx.BranchIfFalse(done, false); + Tail.EmitWrite(ctx, loc); + ctx.MarkLabel(done); + } + + } + protected override void EmitRead(Compiler.CompilerContext ctx, Compiler.Local valueFrom) + { + if (setSpecified == null) + { + Tail.EmitRead(ctx, valueFrom); + return; + } + using (Compiler.Local loc = ctx.GetLocalWithValue(ExpectedType, valueFrom)) + { + Tail.EmitRead(ctx, loc); + ctx.LoadAddress(loc, ExpectedType); + ctx.LoadValue(1); // true + ctx.EmitCall(setSpecified); + } + } +#endif + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/MemberSpecifiedDecorator.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/MemberSpecifiedDecorator.cs.meta new file mode 100644 index 0000000..f2d6187 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/MemberSpecifiedDecorator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 58836f822e85e2447817d187f3bcd5de +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/NetObjectSerializer.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/NetObjectSerializer.cs new file mode 100644 index 0000000..c3d685b --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/NetObjectSerializer.cs @@ -0,0 +1,64 @@ +#if !NO_RUNTIME +using System; +using System.Reflection; +using ProtoBuf.Meta; + +namespace ProtoBuf.Serializers +{ + sealed class NetObjectSerializer : IProtoSerializer + { + private readonly int key; + private readonly Type type; + + private readonly BclHelpers.NetObjectOptions options; + + public NetObjectSerializer(TypeModel model, Type type, int key, BclHelpers.NetObjectOptions options) + { + bool dynamicType = (options & BclHelpers.NetObjectOptions.DynamicType) != 0; + this.key = dynamicType ? -1 : key; + this.type = dynamicType ? model.MapType(typeof(object)) : type; + this.options = options; + } + + public Type ExpectedType => type; + + public bool ReturnsValue => true; + + public bool RequiresOldValue => true; + + public object Read(object value, ProtoReader source) + { + return BclHelpers.ReadNetObject(value, source, key, type == typeof(object) ? null : type, options); + } + + public void Write(object value, ProtoWriter dest) + { + BclHelpers.WriteNetObject(value, dest, key, options); + } + +#if FEAT_COMPILER + public void EmitRead(Compiler.CompilerContext ctx, Compiler.Local valueFrom) + { + ctx.LoadValue(valueFrom); + ctx.CastToObject(type); + ctx.LoadReaderWriter(); + ctx.LoadValue(ctx.MapMetaKeyToCompiledKey(key)); + if (type == ctx.MapType(typeof(object))) ctx.LoadNullRef(); + else ctx.LoadValue(type); + ctx.LoadValue((int)options); + ctx.EmitCall(ctx.MapType(typeof(BclHelpers)).GetMethod("ReadNetObject")); + ctx.CastFromObject(type); + } + public void EmitWrite(Compiler.CompilerContext ctx, Compiler.Local valueFrom) + { + ctx.LoadValue(valueFrom); + ctx.CastToObject(type); + ctx.LoadReaderWriter(); + ctx.LoadValue(ctx.MapMetaKeyToCompiledKey(key)); + ctx.LoadValue((int)options); + ctx.EmitCall(ctx.MapType(typeof(BclHelpers)).GetMethod("WriteNetObject")); + } +#endif + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/NetObjectSerializer.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/NetObjectSerializer.cs.meta new file mode 100644 index 0000000..f53dfad --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/NetObjectSerializer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: dd6edd815f76150449f39f7571679912 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/NullDecorator.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/NullDecorator.cs new file mode 100644 index 0000000..52db14c --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/NullDecorator.cs @@ -0,0 +1,167 @@ +#if !NO_RUNTIME +using System; +using System.Reflection; + +using ProtoBuf.Meta; + +namespace ProtoBuf.Serializers +{ + sealed class NullDecorator : ProtoDecoratorBase + { + private readonly Type expectedType; + public const int Tag = 1; + public NullDecorator(TypeModel model, IProtoSerializer tail) : base(tail) + { + if (!tail.ReturnsValue) + throw new NotSupportedException("NullDecorator only supports implementations that return values"); + + Type tailType = tail.ExpectedType; + if (Helpers.IsValueType(tailType)) + { + expectedType = model.MapType(typeof(Nullable<>)).MakeGenericType(tailType); + } + else + { + expectedType = tailType; + } + } + + public override Type ExpectedType => expectedType; + + public override bool ReturnsValue => true; + + public override bool RequiresOldValue => true; + +#if FEAT_COMPILER + protected override void EmitRead(Compiler.CompilerContext ctx, Compiler.Local valueFrom) + { + using (Compiler.Local oldValue = ctx.GetLocalWithValue(expectedType, valueFrom)) + using (Compiler.Local token = new Compiler.Local(ctx, ctx.MapType(typeof(SubItemToken)))) + using (Compiler.Local field = new Compiler.Local(ctx, ctx.MapType(typeof(int)))) + { + ctx.LoadReaderWriter(); + ctx.EmitCall(ctx.MapType(typeof(ProtoReader)).GetMethod("StartSubItem")); + ctx.StoreValue(token); + + Compiler.CodeLabel next = ctx.DefineLabel(), processField = ctx.DefineLabel(), end = ctx.DefineLabel(); + + ctx.MarkLabel(next); + + ctx.EmitBasicRead("ReadFieldHeader", ctx.MapType(typeof(int))); + ctx.CopyValue(); + ctx.StoreValue(field); + ctx.LoadValue(Tag); // = 1 - process + ctx.BranchIfEqual(processField, true); + ctx.LoadValue(field); + ctx.LoadValue(1); // < 1 - exit + ctx.BranchIfLess(end, false); + + // default: skip + ctx.LoadReaderWriter(); + ctx.EmitCall(ctx.MapType(typeof(ProtoReader)).GetMethod("SkipField")); + ctx.Branch(next, true); + + // process + ctx.MarkLabel(processField); + if (Tail.RequiresOldValue) + { + if (Helpers.IsValueType(expectedType)) + { + ctx.LoadAddress(oldValue, expectedType); + ctx.EmitCall(expectedType.GetMethod("GetValueOrDefault", Helpers.EmptyTypes)); + } + else + { + ctx.LoadValue(oldValue); + } + } + Tail.EmitRead(ctx, null); + // note we demanded always returns a value + if (Helpers.IsValueType(expectedType)) + { + ctx.EmitCtor(expectedType, Tail.ExpectedType); // re-nullable it + } + ctx.StoreValue(oldValue); + ctx.Branch(next, false); + + // outro + ctx.MarkLabel(end); + + ctx.LoadValue(token); + ctx.LoadReaderWriter(); + ctx.EmitCall(ctx.MapType(typeof(ProtoReader)).GetMethod("EndSubItem")); + ctx.LoadValue(oldValue); // load the old value + } + } + protected override void EmitWrite(Compiler.CompilerContext ctx, Compiler.Local valueFrom) + { + using (Compiler.Local valOrNull = ctx.GetLocalWithValue(expectedType, valueFrom)) + using (Compiler.Local token = new Compiler.Local(ctx, ctx.MapType(typeof(SubItemToken)))) + { + ctx.LoadNullRef(); + ctx.LoadReaderWriter(); + ctx.EmitCall(ctx.MapType(typeof(ProtoWriter)).GetMethod("StartSubItem")); + ctx.StoreValue(token); + + if (Helpers.IsValueType(expectedType)) + { + ctx.LoadAddress(valOrNull, expectedType); + ctx.LoadValue(expectedType.GetProperty("HasValue")); + } + else + { + ctx.LoadValue(valOrNull); + } + Compiler.CodeLabel @end = ctx.DefineLabel(); + ctx.BranchIfFalse(@end, false); + if (Helpers.IsValueType(expectedType)) + { + ctx.LoadAddress(valOrNull, expectedType); + ctx.EmitCall(expectedType.GetMethod("GetValueOrDefault", Helpers.EmptyTypes)); + } + else + { + ctx.LoadValue(valOrNull); + } + Tail.EmitWrite(ctx, null); + + ctx.MarkLabel(@end); + + ctx.LoadValue(token); + ctx.LoadReaderWriter(); + ctx.EmitCall(ctx.MapType(typeof(ProtoWriter)).GetMethod("EndSubItem")); + } + } +#endif + + public override object Read(object value, ProtoReader source) + { + SubItemToken tok = ProtoReader.StartSubItem(source); + int field; + while ((field = source.ReadFieldHeader()) > 0) + { + if (field == Tag) + { + value = Tail.Read(value, source); + } + else + { + source.SkipField(); + } + } + ProtoReader.EndSubItem(tok, source); + return value; + } + + public override void Write(object value, ProtoWriter dest) + { + SubItemToken token = ProtoWriter.StartSubItem(null, dest); + if (value != null) + { + Tail.Write(value, dest); + } + ProtoWriter.EndSubItem(token, dest); + } + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/NullDecorator.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/NullDecorator.cs.meta new file mode 100644 index 0000000..4fb2a35 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/NullDecorator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4728d79a9a96bde4097e4c599266a6e4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/ParseableSerializer.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/ParseableSerializer.cs new file mode 100644 index 0000000..9a4bb07 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/ParseableSerializer.cs @@ -0,0 +1,111 @@ +#if !NO_RUNTIME +using System; +using System.Net; +using ProtoBuf.Meta; +using System.Reflection; + +namespace ProtoBuf.Serializers +{ + sealed class ParseableSerializer : IProtoSerializer + { + private readonly MethodInfo parse; + public static ParseableSerializer TryCreate(Type type, TypeModel model) + { + if (type == null) throw new ArgumentNullException("type"); +#if PORTABLE || COREFX || PROFILE259 + MethodInfo method = null; + +#if COREFX || PROFILE259 + foreach (MethodInfo tmp in type.GetTypeInfo().GetDeclaredMethods("Parse")) +#else + foreach (MethodInfo tmp in type.GetMethods(BindingFlags.Public | BindingFlags.Static | BindingFlags.DeclaredOnly)) +#endif + { + ParameterInfo[] p; + if (tmp.Name == "Parse" && tmp.IsPublic && tmp.IsStatic && tmp.DeclaringType == type && (p = tmp.GetParameters()) != null && p.Length == 1 && p[0].ParameterType == typeof(string)) + { + method = tmp; + break; + } + } +#else + MethodInfo method = type.GetMethod("Parse", + BindingFlags.Public | BindingFlags.Static | BindingFlags.DeclaredOnly, + null, new Type[] { model.MapType(typeof(string)) }, null); +#endif + if (method != null && method.ReturnType == type) + { + if (Helpers.IsValueType(type)) + { + MethodInfo toString = GetCustomToString(type); + if (toString == null || toString.ReturnType != model.MapType(typeof(string))) return null; // need custom ToString, fools + } + return new ParseableSerializer(method); + } + return null; + } + private static MethodInfo GetCustomToString(Type type) + { +#if PORTABLE || COREFX || PROFILE259 + MethodInfo method = Helpers.GetInstanceMethod(type, "ToString", Helpers.EmptyTypes); + if (method == null || !method.IsPublic || method.IsStatic || method.DeclaringType != type) return null; + return method; +#else + + return type.GetMethod("ToString", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly, + null, Helpers.EmptyTypes, null); +#endif + } + + private ParseableSerializer(MethodInfo parse) + { + this.parse = parse; + } + + public Type ExpectedType => parse.DeclaringType; + + bool IProtoSerializer.RequiresOldValue { get { return false; } } + bool IProtoSerializer.ReturnsValue { get { return true; } } + + public object Read(object value, ProtoReader source) + { + Helpers.DebugAssert(value == null); // since replaces + return parse.Invoke(null, new object[] { source.ReadString() }); + } + + public void Write(object value, ProtoWriter dest) + { + ProtoWriter.WriteString(value.ToString(), dest); + } + +#if FEAT_COMPILER + void IProtoSerializer.EmitWrite(Compiler.CompilerContext ctx, Compiler.Local valueFrom) + { + Type type = ExpectedType; + if (Helpers.IsValueType(type)) + { // note that for structs, we've already asserted that a custom ToString + // exists; no need to handle the box/callvirt scenario + + // force it to a variable if needed, so we can take the address + using (Compiler.Local loc = ctx.GetLocalWithValue(type, valueFrom)) + { + ctx.LoadAddress(loc, type); + ctx.EmitCall(GetCustomToString(type)); + } + } + else + { + ctx.EmitCall(ctx.MapType(typeof(object)).GetMethod("ToString")); + } + ctx.EmitBasicWrite("WriteString", valueFrom); + } + void IProtoSerializer.EmitRead(Compiler.CompilerContext ctx, Compiler.Local valueFrom) + { + ctx.EmitBasicRead("ReadString", ctx.MapType(typeof(string))); + ctx.EmitCall(parse); + } +#endif + + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/ParseableSerializer.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/ParseableSerializer.cs.meta new file mode 100644 index 0000000..9ee5ec1 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/ParseableSerializer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 562e4dd519901854fba22d511f594b82 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/PropertyDecorator.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/PropertyDecorator.cs new file mode 100644 index 0000000..8b0a014 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/PropertyDecorator.cs @@ -0,0 +1,167 @@ +#if !NO_RUNTIME +using System; +using System.Reflection; + +using ProtoBuf.Meta; + +namespace ProtoBuf.Serializers +{ + sealed class PropertyDecorator : ProtoDecoratorBase + { + public override Type ExpectedType => forType; + private readonly PropertyInfo property; + private readonly Type forType; + public override bool RequiresOldValue => true; + public override bool ReturnsValue => false; + private readonly bool readOptionsWriteValue; + private readonly MethodInfo shadowSetter; + + public PropertyDecorator(TypeModel model, Type forType, PropertyInfo property, IProtoSerializer tail) : base(tail) + { + Helpers.DebugAssert(forType != null); + Helpers.DebugAssert(property != null); + this.forType = forType; + this.property = property; + SanityCheck(model, property, tail, out readOptionsWriteValue, true, true); + shadowSetter = GetShadowSetter(model, property); + } + + private static void SanityCheck(TypeModel model, PropertyInfo property, IProtoSerializer tail, out bool writeValue, bool nonPublic, bool allowInternal) + { + if (property == null) throw new ArgumentNullException("property"); + + writeValue = tail.ReturnsValue && (GetShadowSetter(model, property) != null || (property.CanWrite && Helpers.GetSetMethod(property, nonPublic, allowInternal) != null)); + if (!property.CanRead || Helpers.GetGetMethod(property, nonPublic, allowInternal) == null) + { + throw new InvalidOperationException("Cannot serialize property without a get accessor"); + } + if (!writeValue && (!tail.RequiresOldValue || Helpers.IsValueType(tail.ExpectedType))) + { // so we can't save the value, and the tail doesn't use it either... not helpful + // or: can't write the value, so the struct value will be lost + throw new InvalidOperationException("Cannot apply changes to property " + property.DeclaringType.FullName + "." + property.Name); + } + } + static MethodInfo GetShadowSetter(TypeModel model, PropertyInfo property) + { +#if COREFX + MethodInfo method = Helpers.GetInstanceMethod(property.DeclaringType.GetTypeInfo(), "Set" + property.Name, new Type[] { property.PropertyType }); +#else + +#if PROFILE259 + Type reflectedType = property.DeclaringType; +#else + Type reflectedType = property.ReflectedType; +#endif + MethodInfo method = Helpers.GetInstanceMethod(reflectedType, "Set" + property.Name, new Type[] { property.PropertyType }); +#endif + if (method == null || !method.IsPublic || method.ReturnType != model.MapType(typeof(void))) return null; + return method; + } + + public override void Write(object value, ProtoWriter dest) + { + Helpers.DebugAssert(value != null); + value = property.GetValue(value, null); + if (value != null) Tail.Write(value, dest); + } + + public override object Read(object value, ProtoReader source) + { + Helpers.DebugAssert(value != null); + + object oldVal = Tail.RequiresOldValue ? property.GetValue(value, null) : null; + object newVal = Tail.Read(oldVal, source); + if (readOptionsWriteValue && newVal != null) // if the tail returns a null, intepret that as *no assign* + { + if (shadowSetter == null) + { + property.SetValue(value, newVal, null); + } + else + { + shadowSetter.Invoke(value, new object[] { newVal }); + } + } + return null; + } + +#if FEAT_COMPILER + protected override void EmitWrite(Compiler.CompilerContext ctx, Compiler.Local valueFrom) + { + ctx.LoadAddress(valueFrom, ExpectedType); + ctx.LoadValue(property); + ctx.WriteNullCheckedTail(property.PropertyType, Tail, null); + } + + protected override void EmitRead(Compiler.CompilerContext ctx, Compiler.Local valueFrom) + { + SanityCheck(ctx.Model, property, Tail, out bool writeValue, ctx.NonPublic, ctx.AllowInternal(property)); + if (Helpers.IsValueType(ExpectedType) && valueFrom == null) + { + throw new InvalidOperationException("Attempt to mutate struct on the head of the stack; changes would be lost"); + } + + using (Compiler.Local loc = ctx.GetLocalWithValue(ExpectedType, valueFrom)) + { + if (Tail.RequiresOldValue) + { + ctx.LoadAddress(loc, ExpectedType); // stack is: old-addr + ctx.LoadValue(property); // stack is: old-value + } + Type propertyType = property.PropertyType; + ctx.ReadNullCheckedTail(propertyType, Tail, null); // stack is [new-value] + + if (writeValue) + { + using (Compiler.Local newVal = new Compiler.Local(ctx, property.PropertyType)) + { + ctx.StoreValue(newVal); // stack is empty + + Compiler.CodeLabel allDone = new Compiler.CodeLabel(); // <=== default structs + if (!Helpers.IsValueType(propertyType)) + { // if the tail returns a null, intepret that as *no assign* + allDone = ctx.DefineLabel(); + ctx.LoadValue(newVal); // stack is: new-value + ctx.BranchIfFalse(@allDone, true); // stack is empty + } + // assign the value + ctx.LoadAddress(loc, ExpectedType); // parent-addr + ctx.LoadValue(newVal); // parent-obj|new-value + if (shadowSetter == null) + { + ctx.StoreValue(property); // empty + } + else + { + ctx.EmitCall(shadowSetter); // empty + } + if (!Helpers.IsValueType(propertyType)) + { + ctx.MarkLabel(allDone); + } + } + + } + else + { // don't want return value; drop it if anything there + // stack is [new-value] + if (Tail.ReturnsValue) { ctx.DiscardValue(); } + } + } + } +#endif + + internal static bool CanWrite(TypeModel model, MemberInfo member) + { + if (member == null) throw new ArgumentNullException(nameof(member)); + + if (member is PropertyInfo prop) + { + return prop.CanWrite || GetShadowSetter(model, prop) != null; + } + + return member is FieldInfo; // fields are always writeable; anything else: JUST SAY NO! + } + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/PropertyDecorator.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/PropertyDecorator.cs.meta new file mode 100644 index 0000000..5aca94d --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/PropertyDecorator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2b21fd2b2435fed4da28bd193e2ce80d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/ProtoDecoratorBase.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/ProtoDecoratorBase.cs new file mode 100644 index 0000000..e7f2b34 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/ProtoDecoratorBase.cs @@ -0,0 +1,24 @@ +#if !NO_RUNTIME +using System; + +namespace ProtoBuf.Serializers +{ + abstract class ProtoDecoratorBase : IProtoSerializer + { + public abstract Type ExpectedType { get; } + protected readonly IProtoSerializer Tail; + protected ProtoDecoratorBase(IProtoSerializer tail) { this.Tail = tail; } + public abstract bool ReturnsValue { get; } + public abstract bool RequiresOldValue { get; } + public abstract void Write(object value, ProtoWriter dest); + public abstract object Read(object value, ProtoReader source); + +#if FEAT_COMPILER + void IProtoSerializer.EmitWrite(Compiler.CompilerContext ctx, Compiler.Local valueFrom) { EmitWrite(ctx, valueFrom); } + protected abstract void EmitWrite(Compiler.CompilerContext ctx, Compiler.Local valueFrom); + void IProtoSerializer.EmitRead(Compiler.CompilerContext ctx, Compiler.Local valueFrom) { EmitRead(ctx, valueFrom); } + protected abstract void EmitRead(Compiler.CompilerContext ctx, Compiler.Local valueFrom); +#endif + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/ProtoDecoratorBase.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/ProtoDecoratorBase.cs.meta new file mode 100644 index 0000000..92acdfc --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/ProtoDecoratorBase.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1e9afbb9465ade140ab0fcd217ea0b66 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/ReflectedUriDecorator.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/ReflectedUriDecorator.cs new file mode 100644 index 0000000..44edef0 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/ReflectedUriDecorator.cs @@ -0,0 +1,90 @@ +#if !NO_RUNTIME +#if PORTABLE +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; + +namespace ProtoBuf.Serializers +{ + /// + /// Manipulates with uris via reflection rather than strongly typed objects. + /// This is because in PCLs, the Uri type may not match (WinRT uses Internal/Uri, .Net uses System/Uri) + /// + sealed class ReflectedUriDecorator : ProtoDecoratorBase + { + private readonly Type expectedType; + + private readonly PropertyInfo absoluteUriProperty; + + private readonly ConstructorInfo typeConstructor; + + public ReflectedUriDecorator(Type type, ProtoBuf.Meta.TypeModel model, IProtoSerializer tail) : base(tail) + { + expectedType = type; + +#if PROFILE259 + absoluteUriProperty = expectedType.GetRuntimeProperty("AbsoluteUri"); + IEnumerable constructors = expectedType.GetTypeInfo().DeclaredConstructors; + typeConstructor = null; + foreach(ConstructorInfo constructor in constructors) + { + ParameterInfo[] parameters = constructor.GetParameters(); + ParameterInfo parameterFirst = parameters.FirstOrDefault(); + Type stringType = typeof(string); + if (parameterFirst != null && + parameterFirst.ParameterType == stringType) + { + typeConstructor = constructor; + break; + } + } +#else + absoluteUriProperty = expectedType.GetProperty("AbsoluteUri"); + typeConstructor = expectedType.GetConstructor(new Type[] { typeof(string) }); +#endif + } + public override Type ExpectedType { get { return expectedType; } } + public override bool RequiresOldValue { get { return false; } } + public override bool ReturnsValue { get { return true; } } + + public override void Write(object value, ProtoWriter dest) + { + Tail.Write(absoluteUriProperty.GetValue(value, null), dest); + } + public override object Read(object value, ProtoReader source) + { + Helpers.DebugAssert(value == null); // not expecting incoming + string s = (string)Tail.Read(null, source); + + return s.Length == 0 ? null : typeConstructor.Invoke(new object[] { s }); + } + +#if FEAT_COMPILER + protected override void EmitWrite(Compiler.CompilerContext ctx, Compiler.Local valueFrom) + { + ctx.LoadValue(valueFrom); + ctx.LoadValue(absoluteUriProperty); + Tail.EmitWrite(ctx, null); + } + protected override void EmitRead(Compiler.CompilerContext ctx, Compiler.Local valueFrom) + { + Tail.EmitRead(ctx, valueFrom); + ctx.CopyValue(); + Compiler.CodeLabel @nonEmpty = ctx.DefineLabel(), @end = ctx.DefineLabel(); + ctx.LoadValue(typeof(string).GetProperty("Length")); + ctx.BranchIfTrue(@nonEmpty, true); + ctx.DiscardValue(); + ctx.LoadNullRef(); + ctx.Branch(@end, true); + ctx.MarkLabel(@nonEmpty); + ctx.EmitCtor(expectedType, ctx.MapType(typeof(string))); + ctx.MarkLabel(@end); + + } +#endif + } +} +#endif +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/ReflectedUriDecorator.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/ReflectedUriDecorator.cs.meta new file mode 100644 index 0000000..2441cdf --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/ReflectedUriDecorator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6cf63470b1970d84ead637b9ee2bface +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/SByteSerializer.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/SByteSerializer.cs new file mode 100644 index 0000000..81d233e --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/SByteSerializer.cs @@ -0,0 +1,45 @@ +#if !NO_RUNTIME +using System; + +namespace ProtoBuf.Serializers +{ + sealed class SByteSerializer : IProtoSerializer + { + static readonly Type expectedType = typeof(sbyte); + + public SByteSerializer(ProtoBuf.Meta.TypeModel model) + { + + } + + public Type ExpectedType => expectedType; + + bool IProtoSerializer.RequiresOldValue => false; + + bool IProtoSerializer.ReturnsValue => true; + + public object Read(object value, ProtoReader source) + { + Helpers.DebugAssert(value == null); // since replaces + return source.ReadSByte(); + } + + public void Write(object value, ProtoWriter dest) + { + ProtoWriter.WriteSByte((sbyte)value, dest); + } + +#if FEAT_COMPILER + void IProtoSerializer.EmitWrite(Compiler.CompilerContext ctx, Compiler.Local valueFrom) + { + ctx.EmitBasicWrite("WriteSByte", valueFrom); + } + void IProtoSerializer.EmitRead(Compiler.CompilerContext ctx, Compiler.Local valueFrom) + { + ctx.EmitBasicRead("ReadSByte", ExpectedType); + } +#endif + + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/SByteSerializer.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/SByteSerializer.cs.meta new file mode 100644 index 0000000..7d71fef --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/SByteSerializer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 09de0f3e56d4834428cb8ba75929d216 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/SingleSerializer.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/SingleSerializer.cs new file mode 100644 index 0000000..c5ade13 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/SingleSerializer.cs @@ -0,0 +1,45 @@ +#if !NO_RUNTIME +using System; +using ProtoBuf.Meta; + +namespace ProtoBuf.Serializers +{ + sealed class SingleSerializer : IProtoSerializer + { + static readonly Type expectedType = typeof(float); + + public Type ExpectedType { get { return expectedType; } } + + public SingleSerializer(TypeModel model) + { + } + + bool IProtoSerializer.RequiresOldValue => false; + + bool IProtoSerializer.ReturnsValue => true; + + public object Read(object value, ProtoReader source) + { + Helpers.DebugAssert(value == null); // since replaces + return source.ReadSingle(); + } + + public void Write(object value, ProtoWriter dest) + { + ProtoWriter.WriteSingle((float)value, dest); + } + + +#if FEAT_COMPILER + void IProtoSerializer.EmitWrite(Compiler.CompilerContext ctx, Compiler.Local valueFrom) + { + ctx.EmitBasicWrite("WriteSingle", valueFrom); + } + void IProtoSerializer.EmitRead(Compiler.CompilerContext ctx, Compiler.Local valueFrom) + { + ctx.EmitBasicRead("ReadSingle", ExpectedType); + } +#endif + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/SingleSerializer.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/SingleSerializer.cs.meta new file mode 100644 index 0000000..ee64e5a --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/SingleSerializer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9b89c111cae2d81469987d208a41af4b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/StringSerializer.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/StringSerializer.cs new file mode 100644 index 0000000..399b4bb --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/StringSerializer.cs @@ -0,0 +1,41 @@ +#if !NO_RUNTIME +using System; + +namespace ProtoBuf.Serializers +{ + sealed class StringSerializer : IProtoSerializer + { + static readonly Type expectedType = typeof(string); + + public StringSerializer(ProtoBuf.Meta.TypeModel model) + { + } + + public Type ExpectedType => expectedType; + + public void Write(object value, ProtoWriter dest) + { + ProtoWriter.WriteString((string)value, dest); + } + bool IProtoSerializer.RequiresOldValue => false; + + bool IProtoSerializer.ReturnsValue => true; + + public object Read(object value, ProtoReader source) + { + Helpers.DebugAssert(value == null); // since replaces + return source.ReadString(); + } +#if FEAT_COMPILER + void IProtoSerializer.EmitWrite(Compiler.CompilerContext ctx, Compiler.Local valueFrom) + { + ctx.EmitBasicWrite("WriteString", valueFrom); + } + void IProtoSerializer.EmitRead(Compiler.CompilerContext ctx, Compiler.Local valueFrom) + { + ctx.EmitBasicRead("ReadString", ExpectedType); + } +#endif + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/StringSerializer.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/StringSerializer.cs.meta new file mode 100644 index 0000000..697d8c2 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/StringSerializer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 80c8f3efc5f697845b352b56780105ae +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/SubItemSerializer.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/SubItemSerializer.cs new file mode 100644 index 0000000..58015aa --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/SubItemSerializer.cs @@ -0,0 +1,138 @@ +#if !NO_RUNTIME +using System; +using ProtoBuf.Meta; + +#if FEAT_COMPILER +using System.Reflection.Emit; +#endif + +namespace ProtoBuf.Serializers +{ + sealed class SubItemSerializer : IProtoTypeSerializer + { + bool IProtoTypeSerializer.HasCallbacks(TypeModel.CallbackType callbackType) + { + return ((IProtoTypeSerializer)proxy.Serializer).HasCallbacks(callbackType); + } + + bool IProtoTypeSerializer.CanCreateInstance() + { + return ((IProtoTypeSerializer)proxy.Serializer).CanCreateInstance(); + } + +#if FEAT_COMPILER + void IProtoTypeSerializer.EmitCallback(Compiler.CompilerContext ctx, Compiler.Local valueFrom, TypeModel.CallbackType callbackType) + { + ((IProtoTypeSerializer)proxy.Serializer).EmitCallback(ctx, valueFrom, callbackType); + } + + void IProtoTypeSerializer.EmitCreateInstance(Compiler.CompilerContext ctx) + { + ((IProtoTypeSerializer)proxy.Serializer).EmitCreateInstance(ctx); + } +#endif + + void IProtoTypeSerializer.Callback(object value, TypeModel.CallbackType callbackType, SerializationContext context) + { + ((IProtoTypeSerializer)proxy.Serializer).Callback(value, callbackType, context); + } + + object IProtoTypeSerializer.CreateInstance(ProtoReader source) + { + return ((IProtoTypeSerializer)proxy.Serializer).CreateInstance(source); + } + + private readonly int key; + private readonly Type type; + private readonly ISerializerProxy proxy; + private readonly bool recursionCheck; + public SubItemSerializer(Type type, int key, ISerializerProxy proxy, bool recursionCheck) + { + this.type = type ?? throw new ArgumentNullException(nameof(type)); + this.proxy = proxy ?? throw new ArgumentNullException(nameof(proxy)); + this.key = key; + this.recursionCheck = recursionCheck; + } + + Type IProtoSerializer.ExpectedType => type; + + bool IProtoSerializer.RequiresOldValue => true; + + bool IProtoSerializer.ReturnsValue => true; + + void IProtoSerializer.Write(object value, ProtoWriter dest) + { + if (recursionCheck) + { + ProtoWriter.WriteObject(value, key, dest); + } + else + { + ProtoWriter.WriteRecursionSafeObject(value, key, dest); + } + } + + object IProtoSerializer.Read(object value, ProtoReader source) + { + return ProtoReader.ReadObject(value, key, source); + } + +#if FEAT_COMPILER + bool EmitDedicatedMethod(Compiler.CompilerContext ctx, Compiler.Local valueFrom, bool read) + { + MethodBuilder method = ctx.GetDedicatedMethod(key, read); + if (method == null) return false; + + using (Compiler.Local token = new ProtoBuf.Compiler.Local(ctx, ctx.MapType(typeof(SubItemToken)))) + { + Type rwType = ctx.MapType(read ? typeof(ProtoReader) : typeof(ProtoWriter)); + ctx.LoadValue(valueFrom); + if (!read) // write requires the object for StartSubItem; read doesn't + { // (if recursion-check is disabled [subtypes] then null is fine too) + if (Helpers.IsValueType(type) || !recursionCheck) { ctx.LoadNullRef(); } + else { ctx.CopyValue(); } + } + ctx.LoadReaderWriter(); + ctx.EmitCall(Helpers.GetStaticMethod(rwType, "StartSubItem", + read ? new Type[] { rwType } : new Type[] { ctx.MapType(typeof(object)), rwType })); + ctx.StoreValue(token); + + // note: value already on the stack + ctx.LoadReaderWriter(); + ctx.EmitCall(method); + // handle inheritance (we will be calling the *base* version of things, + // but we expect Read to return the "type" type) + if (read && type != method.ReturnType) ctx.Cast(this.type); + ctx.LoadValue(token); + ctx.LoadReaderWriter(); + ctx.EmitCall(Helpers.GetStaticMethod(rwType, "EndSubItem", new Type[] { ctx.MapType(typeof(SubItemToken)), rwType })); + } + return true; + } + void IProtoSerializer.EmitWrite(Compiler.CompilerContext ctx, Compiler.Local valueFrom) + { + if (!EmitDedicatedMethod(ctx, valueFrom, false)) + { + ctx.LoadValue(valueFrom); + if (Helpers.IsValueType(type)) ctx.CastToObject(type); + ctx.LoadValue(ctx.MapMetaKeyToCompiledKey(key)); // re-map for formality, but would expect identical, else dedicated method + ctx.LoadReaderWriter(); + ctx.EmitCall(Helpers.GetStaticMethod(ctx.MapType(typeof(ProtoWriter)), recursionCheck ? "WriteObject" : "WriteRecursionSafeObject", new Type[] { ctx.MapType(typeof(object)), ctx.MapType(typeof(int)), ctx.MapType(typeof(ProtoWriter)) })); + } + } + void IProtoSerializer.EmitRead(Compiler.CompilerContext ctx, Compiler.Local valueFrom) + { + if (!EmitDedicatedMethod(ctx, valueFrom, true)) + { + ctx.LoadValue(valueFrom); + if (Helpers.IsValueType(type)) ctx.CastToObject(type); + ctx.LoadValue(ctx.MapMetaKeyToCompiledKey(key)); // re-map for formality, but would expect identical, else dedicated method + ctx.LoadReaderWriter(); + ctx.EmitCall(Helpers.GetStaticMethod(ctx.MapType(typeof(ProtoReader)), "ReadObject")); + ctx.CastFromObject(type); + } + } +#endif + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/SubItemSerializer.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/SubItemSerializer.cs.meta new file mode 100644 index 0000000..aaeac6f --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/SubItemSerializer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6d29a14abe6c62349930c948a6d438c4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/SurrogateSerializer.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/SurrogateSerializer.cs new file mode 100644 index 0000000..86275eb --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/SurrogateSerializer.cs @@ -0,0 +1,157 @@ +#if !NO_RUNTIME +using System; +using ProtoBuf.Meta; +using System.Reflection; + +namespace ProtoBuf.Serializers +{ + sealed class SurrogateSerializer : IProtoTypeSerializer + { + bool IProtoTypeSerializer.HasCallbacks(ProtoBuf.Meta.TypeModel.CallbackType callbackType) { return false; } +#if FEAT_COMPILER + void IProtoTypeSerializer.EmitCallback(Compiler.CompilerContext ctx, Compiler.Local valueFrom, ProtoBuf.Meta.TypeModel.CallbackType callbackType) { } + void IProtoTypeSerializer.EmitCreateInstance(Compiler.CompilerContext ctx) { throw new NotSupportedException(); } +#endif + bool IProtoTypeSerializer.CanCreateInstance() => false; + + object IProtoTypeSerializer.CreateInstance(ProtoReader source) => throw new NotSupportedException(); + + void IProtoTypeSerializer.Callback(object value, ProtoBuf.Meta.TypeModel.CallbackType callbackType, SerializationContext context) { } + + public bool ReturnsValue => false; + + public bool RequiresOldValue => true; + + public Type ExpectedType => forType; + + private readonly Type forType, declaredType; + private readonly MethodInfo toTail, fromTail; + IProtoTypeSerializer rootTail; + + public SurrogateSerializer(TypeModel model, Type forType, Type declaredType, IProtoTypeSerializer rootTail) + { + Helpers.DebugAssert(forType != null, "forType"); + Helpers.DebugAssert(declaredType != null, "declaredType"); + Helpers.DebugAssert(rootTail != null, "rootTail"); + Helpers.DebugAssert(rootTail.RequiresOldValue, "RequiresOldValue"); + Helpers.DebugAssert(!rootTail.ReturnsValue, "ReturnsValue"); + Helpers.DebugAssert(declaredType == rootTail.ExpectedType || Helpers.IsSubclassOf(declaredType, rootTail.ExpectedType)); + this.forType = forType; + this.declaredType = declaredType; + this.rootTail = rootTail; + toTail = GetConversion(model, true); + fromTail = GetConversion(model, false); + } + private static bool HasCast(TypeModel model, Type type, Type from, Type to, out MethodInfo op) + { +#if PROFILE259 + System.Collections.Generic.List list = new System.Collections.Generic.List(); + foreach (var item in type.GetRuntimeMethods()) + { + if (item.IsStatic) list.Add(item); + } + MethodInfo[] found = list.ToArray(); +#else + const BindingFlags flags = BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic; + MethodInfo[] found = type.GetMethods(flags); +#endif + ParameterInfo[] paramTypes; + Type convertAttributeType = null; + for (int i = 0; i < found.Length; i++) + { + MethodInfo m = found[i]; + if (m.ReturnType != to) continue; + paramTypes = m.GetParameters(); + if (paramTypes.Length == 1 && paramTypes[0].ParameterType == from) + { + if (convertAttributeType == null) + { + convertAttributeType = model.MapType(typeof(ProtoConverterAttribute), false); + if (convertAttributeType == null) + { // attribute isn't defined in the source assembly: stop looking + break; + } + } + if (m.IsDefined(convertAttributeType, true)) + { + op = m; + return true; + } + } + } + + for (int i = 0; i < found.Length; i++) + { + MethodInfo m = found[i]; + if ((m.Name != "op_Implicit" && m.Name != "op_Explicit") || m.ReturnType != to) + { + continue; + } + paramTypes = m.GetParameters(); + if (paramTypes.Length == 1 && paramTypes[0].ParameterType == from) + { + op = m; + return true; + } + } + op = null; + return false; + } + + public MethodInfo GetConversion(TypeModel model, bool toTail) + { + Type to = toTail ? declaredType : forType; + Type from = toTail ? forType : declaredType; + MethodInfo op; + if (HasCast(model, declaredType, from, to, out op) || HasCast(model, forType, from, to, out op)) + { + return op; + } + throw new InvalidOperationException("No suitable conversion operator found for surrogate: " + + forType.FullName + " / " + declaredType.FullName); + } + + public void Write(object value, ProtoWriter writer) + { + rootTail.Write(toTail.Invoke(null, new object[] { value }), writer); + } + + public object Read(object value, ProtoReader source) + { + // convert the incoming value + object[] args = { value }; + value = toTail.Invoke(null, args); + + // invoke the tail and convert the outgoing value + args[0] = rootTail.Read(value, source); + return fromTail.Invoke(null, args); + } + +#if FEAT_COMPILER + void IProtoSerializer.EmitRead(Compiler.CompilerContext ctx, Compiler.Local valueFrom) + { + Helpers.DebugAssert(valueFrom != null); // don't support stack-head for this + using (Compiler.Local converted = new Compiler.Local(ctx, declaredType)) // declare/re-use local + { + ctx.LoadValue(valueFrom); // load primary onto stack + ctx.EmitCall(toTail); // static convert op, primary-to-surrogate + ctx.StoreValue(converted); // store into surrogate local + + rootTail.EmitRead(ctx, converted); // downstream processing against surrogate local + + ctx.LoadValue(converted); // load from surrogate local + ctx.EmitCall(fromTail); // static convert op, surrogate-to-primary + ctx.StoreValue(valueFrom); // store back into primary + } + } + + void IProtoSerializer.EmitWrite(Compiler.CompilerContext ctx, Compiler.Local valueFrom) + { + ctx.LoadValue(valueFrom); + ctx.EmitCall(toTail); + rootTail.EmitWrite(ctx, null); + } +#endif + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/SurrogateSerializer.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/SurrogateSerializer.cs.meta new file mode 100644 index 0000000..39cf419 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/SurrogateSerializer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 517911a690de2bd4c97e81f35104a81a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/SystemTypeSerializer.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/SystemTypeSerializer.cs new file mode 100644 index 0000000..4b1656d --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/SystemTypeSerializer.cs @@ -0,0 +1,46 @@ +using System; + +#if !NO_RUNTIME + +namespace ProtoBuf.Serializers +{ + sealed class SystemTypeSerializer : IProtoSerializer + { + static readonly Type expectedType = typeof(Type); + + public SystemTypeSerializer(ProtoBuf.Meta.TypeModel model) + { + + } + + public Type ExpectedType => expectedType; + + void IProtoSerializer.Write(object value, ProtoWriter dest) + { + ProtoWriter.WriteType((Type)value, dest); + } + + object IProtoSerializer.Read(object value, ProtoReader source) + { + Helpers.DebugAssert(value == null); // since replaces + return source.ReadType(); + } + + bool IProtoSerializer.RequiresOldValue => false; + + bool IProtoSerializer.ReturnsValue => true; + +#if FEAT_COMPILER + void IProtoSerializer.EmitWrite(Compiler.CompilerContext ctx, Compiler.Local valueFrom) + { + ctx.EmitBasicWrite("WriteType", valueFrom); + } + void IProtoSerializer.EmitRead(Compiler.CompilerContext ctx, Compiler.Local valueFrom) + { + ctx.EmitBasicRead("ReadType", ExpectedType); + } +#endif + } +} + +#endif diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/SystemTypeSerializer.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/SystemTypeSerializer.cs.meta new file mode 100644 index 0000000..4f43a1f --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/SystemTypeSerializer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f3b3869287521554a816dba994928f83 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/TagDecorator.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/TagDecorator.cs new file mode 100644 index 0000000..509b8a0 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/TagDecorator.cs @@ -0,0 +1,108 @@ +#if !NO_RUNTIME +using System; +using System.Reflection; + +using ProtoBuf.Meta; + +namespace ProtoBuf.Serializers +{ + sealed class TagDecorator : ProtoDecoratorBase, IProtoTypeSerializer + { + public bool HasCallbacks(TypeModel.CallbackType callbackType) + { + IProtoTypeSerializer pts = Tail as IProtoTypeSerializer; + return pts != null && pts.HasCallbacks(callbackType); + } + + public bool CanCreateInstance() + { + IProtoTypeSerializer pts = Tail as IProtoTypeSerializer; + return pts != null && pts.CanCreateInstance(); + } + + public object CreateInstance(ProtoReader source) + { + return ((IProtoTypeSerializer)Tail).CreateInstance(source); + } + + public void Callback(object value, TypeModel.CallbackType callbackType, SerializationContext context) + { + if (Tail is IProtoTypeSerializer pts) + { + pts.Callback(value, callbackType, context); + } + } + +#if FEAT_COMPILER + public void EmitCallback(Compiler.CompilerContext ctx, Compiler.Local valueFrom, TypeModel.CallbackType callbackType) + { + // we only expect this to be invoked if HasCallbacks returned true, so implicitly Tail + // **must** be of the correct type + ((IProtoTypeSerializer)Tail).EmitCallback(ctx, valueFrom, callbackType); + } + + public void EmitCreateInstance(Compiler.CompilerContext ctx) + { + ((IProtoTypeSerializer)Tail).EmitCreateInstance(ctx); + } +#endif + public override Type ExpectedType => Tail.ExpectedType; + + public TagDecorator(int fieldNumber, WireType wireType, bool strict, IProtoSerializer tail) + : base(tail) + { + this.fieldNumber = fieldNumber; + this.wireType = wireType; + this.strict = strict; + } + + public override bool RequiresOldValue => Tail.RequiresOldValue; + + public override bool ReturnsValue => Tail.ReturnsValue; + + private readonly bool strict; + private readonly int fieldNumber; + private readonly WireType wireType; + + private bool NeedsHint => ((int)wireType & ~7) != 0; + + public override object Read(object value, ProtoReader source) + { + Helpers.DebugAssert(fieldNumber == source.FieldNumber); + if (strict) { source.Assert(wireType); } + else if (NeedsHint) { source.Hint(wireType); } + return Tail.Read(value, source); + } + + public override void Write(object value, ProtoWriter dest) + { + ProtoWriter.WriteFieldHeader(fieldNumber, wireType, dest); + Tail.Write(value, dest); + } + + +#if FEAT_COMPILER + protected override void EmitWrite(Compiler.CompilerContext ctx, Compiler.Local valueFrom) + { + ctx.LoadValue((int)fieldNumber); + ctx.LoadValue((int)wireType); + ctx.LoadReaderWriter(); + ctx.EmitCall(ctx.MapType(typeof(ProtoWriter)).GetMethod("WriteFieldHeader")); + Tail.EmitWrite(ctx, valueFrom); + } + + protected override void EmitRead(ProtoBuf.Compiler.CompilerContext ctx, ProtoBuf.Compiler.Local valueFrom) + { + if (strict || NeedsHint) + { + ctx.LoadReaderWriter(); + ctx.LoadValue((int)wireType); + ctx.EmitCall(ctx.MapType(typeof(ProtoReader)).GetMethod(strict ? "Assert" : "Hint")); + } + Tail.EmitRead(ctx, valueFrom); + } +#endif + } + +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/TagDecorator.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/TagDecorator.cs.meta new file mode 100644 index 0000000..e522eda --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/TagDecorator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f807f0cbd3358f6479b78ab47c89ad48 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/TimeSpanSerializer.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/TimeSpanSerializer.cs new file mode 100644 index 0000000..4c8b828 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/TimeSpanSerializer.cs @@ -0,0 +1,63 @@ +#if !NO_RUNTIME +using System; + +namespace ProtoBuf.Serializers +{ + sealed class TimeSpanSerializer : IProtoSerializer + { + static readonly Type expectedType = typeof(TimeSpan); + private readonly bool wellKnown; + public TimeSpanSerializer(DataFormat dataFormat, ProtoBuf.Meta.TypeModel model) + { + + wellKnown = dataFormat == DataFormat.WellKnown; + } + public Type ExpectedType => expectedType; + + bool IProtoSerializer.RequiresOldValue => false; + + bool IProtoSerializer.ReturnsValue => true; + + public object Read(object value, ProtoReader source) + { + if (wellKnown) + { + return BclHelpers.ReadDuration(source); + } + else + { + Helpers.DebugAssert(value == null); // since replaces + return BclHelpers.ReadTimeSpan(source); + } + } + + public void Write(object value, ProtoWriter dest) + { + if (wellKnown) + { + BclHelpers.WriteDuration((TimeSpan)value, dest); + } + else + { + BclHelpers.WriteTimeSpan((TimeSpan)value, dest); + } + } + +#if FEAT_COMPILER + void IProtoSerializer.EmitWrite(Compiler.CompilerContext ctx, Compiler.Local valueFrom) + { + ctx.EmitWrite(ctx.MapType(typeof(BclHelpers)), + wellKnown ? nameof(BclHelpers.WriteDuration) : nameof(BclHelpers.WriteTimeSpan), valueFrom); + } + void IProtoSerializer.EmitRead(Compiler.CompilerContext ctx, Compiler.Local valueFrom) + { + if (wellKnown) ctx.LoadValue(valueFrom); + ctx.EmitBasicRead(ctx.MapType(typeof(BclHelpers)), + wellKnown ? nameof(BclHelpers.ReadDuration) : nameof(BclHelpers.ReadTimeSpan), + ExpectedType); + } +#endif + + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/TimeSpanSerializer.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/TimeSpanSerializer.cs.meta new file mode 100644 index 0000000..013bd6e --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/TimeSpanSerializer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 88ce40638421a9d4abd295d84d1991e8 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/TupleSerializer.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/TupleSerializer.cs new file mode 100644 index 0000000..b6f9c69 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/TupleSerializer.cs @@ -0,0 +1,339 @@ +#if !NO_RUNTIME +using System; +using System.Reflection; +using ProtoBuf.Meta; + +namespace ProtoBuf.Serializers +{ + sealed class TupleSerializer : IProtoTypeSerializer + { + private readonly MemberInfo[] members; + private readonly ConstructorInfo ctor; + private IProtoSerializer[] tails; + public TupleSerializer(RuntimeTypeModel model, ConstructorInfo ctor, MemberInfo[] members) + { + this.ctor = ctor ?? throw new ArgumentNullException(nameof(ctor)); + this.members = members ?? throw new ArgumentNullException(nameof(members)); + this.tails = new IProtoSerializer[members.Length]; + + ParameterInfo[] parameters = ctor.GetParameters(); + for (int i = 0; i < members.Length; i++) + { + WireType wireType; + Type finalType = parameters[i].ParameterType; + + Type itemType = null, defaultType = null; + + MetaType.ResolveListTypes(model, finalType, ref itemType, ref defaultType); + Type tmp = itemType == null ? finalType : itemType; + + bool asReference = false; + int typeIndex = model.FindOrAddAuto(tmp, false, true, false); + if (typeIndex >= 0) + { + asReference = model[tmp].AsReferenceDefault; + } + IProtoSerializer tail = ValueMember.TryGetCoreSerializer(model, DataFormat.Default, tmp, out wireType, asReference, false, false, true), serializer; + if (tail == null) + { + throw new InvalidOperationException("No serializer defined for type: " + tmp.FullName); + } + + tail = new TagDecorator(i + 1, wireType, false, tail); + if (itemType == null) + { + serializer = tail; + } + else + { + if (finalType.IsArray) + { + serializer = new ArrayDecorator(model, tail, i + 1, false, wireType, finalType, false, false); + } + else + { + serializer = ListDecorator.Create(model, finalType, defaultType, tail, i + 1, false, wireType, true, false, false); + } + } + tails[i] = serializer; + } + } + public bool HasCallbacks(Meta.TypeModel.CallbackType callbackType) + { + return false; + } + +#if FEAT_COMPILER + public void EmitCallback(Compiler.CompilerContext ctx, Compiler.Local valueFrom, Meta.TypeModel.CallbackType callbackType) { } +#endif + public Type ExpectedType => ctor.DeclaringType; + + void IProtoTypeSerializer.Callback(object value, Meta.TypeModel.CallbackType callbackType, SerializationContext context) { } + object IProtoTypeSerializer.CreateInstance(ProtoReader source) { throw new NotSupportedException(); } + private object GetValue(object obj, int index) + { + PropertyInfo prop; + FieldInfo field; + + if ((prop = members[index] as PropertyInfo) != null) + { + if (obj == null) + return Helpers.IsValueType(prop.PropertyType) ? Activator.CreateInstance(prop.PropertyType) : null; + return prop.GetValue(obj, null); + } + else if ((field = members[index] as FieldInfo) != null) + { + if (obj == null) + return Helpers.IsValueType(field.FieldType) ? Activator.CreateInstance(field.FieldType) : null; + return field.GetValue(obj); + } + else + { + throw new InvalidOperationException(); + } + } + + public object Read(object value, ProtoReader source) + { + object[] values = new object[members.Length]; + bool invokeCtor = false; + if (value == null) + { + invokeCtor = true; + } + for (int i = 0; i < values.Length; i++) + values[i] = GetValue(value, i); + int field; + while ((field = source.ReadFieldHeader()) > 0) + { + invokeCtor = true; + if (field <= tails.Length) + { + IProtoSerializer tail = tails[field - 1]; + values[field - 1] = tails[field - 1].Read(tail.RequiresOldValue ? values[field - 1] : null, source); + } + else + { + source.SkipField(); + } + } + return invokeCtor ? ctor.Invoke(values) : value; + } + + public void Write(object value, ProtoWriter dest) + { + for (int i = 0; i < tails.Length; i++) + { + object val = GetValue(value, i); + if (val != null) tails[i].Write(val, dest); + } + } + + public bool RequiresOldValue => true; + + public bool ReturnsValue => false; + + Type GetMemberType(int index) + { + Type result = Helpers.GetMemberType(members[index]); + if (result == null) throw new InvalidOperationException(); + return result; + } + + bool IProtoTypeSerializer.CanCreateInstance() { return false; } + +#if FEAT_COMPILER + public void EmitWrite(Compiler.CompilerContext ctx, Compiler.Local valueFrom) + { + using (Compiler.Local loc = ctx.GetLocalWithValue(ctor.DeclaringType, valueFrom)) + { + for (int i = 0; i < tails.Length; i++) + { + Type type = GetMemberType(i); + ctx.LoadAddress(loc, ExpectedType); + if (members[i] is FieldInfo) + { + ctx.LoadValue((FieldInfo)members[i]); + } + else if (members[i] is PropertyInfo) + { + ctx.LoadValue((PropertyInfo)members[i]); + } + ctx.WriteNullCheckedTail(type, tails[i], null); + } + } + } + + void IProtoTypeSerializer.EmitCreateInstance(Compiler.CompilerContext ctx) { throw new NotSupportedException(); } + + public void EmitRead(Compiler.CompilerContext ctx, Compiler.Local incoming) + { + using (Compiler.Local objValue = ctx.GetLocalWithValue(ExpectedType, incoming)) + { + Compiler.Local[] locals = new Compiler.Local[members.Length]; + try + { + for (int i = 0; i < locals.Length; i++) + { + Type type = GetMemberType(i); + bool store = true; + locals[i] = new Compiler.Local(ctx, type); + if (!Helpers.IsValueType(ExpectedType)) + { + // value-types always read the old value + if (Helpers.IsValueType(type)) + { + switch (Helpers.GetTypeCode(type)) + { + case ProtoTypeCode.Boolean: + case ProtoTypeCode.Byte: + case ProtoTypeCode.Int16: + case ProtoTypeCode.Int32: + case ProtoTypeCode.SByte: + case ProtoTypeCode.UInt16: + case ProtoTypeCode.UInt32: + ctx.LoadValue(0); + break; + case ProtoTypeCode.Int64: + case ProtoTypeCode.UInt64: + ctx.LoadValue(0L); + break; + case ProtoTypeCode.Single: + ctx.LoadValue(0.0F); + break; + case ProtoTypeCode.Double: + ctx.LoadValue(0.0D); + break; + case ProtoTypeCode.Decimal: + ctx.LoadValue(0M); + break; + case ProtoTypeCode.Guid: + ctx.LoadValue(Guid.Empty); + break; + default: + ctx.LoadAddress(locals[i], type); + ctx.EmitCtor(type); + store = false; + break; + } + } + else + { + ctx.LoadNullRef(); + } + if (store) + { + ctx.StoreValue(locals[i]); + } + } + } + + Compiler.CodeLabel skipOld = Helpers.IsValueType(ExpectedType) + ? new Compiler.CodeLabel() + : ctx.DefineLabel(); + if (!Helpers.IsValueType(ExpectedType)) + { + ctx.LoadAddress(objValue, ExpectedType); + ctx.BranchIfFalse(skipOld, false); + } + for (int i = 0; i < members.Length; i++) + { + ctx.LoadAddress(objValue, ExpectedType); + if (members[i] is FieldInfo) + { + ctx.LoadValue((FieldInfo)members[i]); + } + else if (members[i] is PropertyInfo) + { + ctx.LoadValue((PropertyInfo)members[i]); + } + ctx.StoreValue(locals[i]); + } + + if (!Helpers.IsValueType(ExpectedType)) ctx.MarkLabel(skipOld); + + using (Compiler.Local fieldNumber = new Compiler.Local(ctx, ctx.MapType(typeof(int)))) + { + Compiler.CodeLabel @continue = ctx.DefineLabel(), + processField = ctx.DefineLabel(), + notRecognised = ctx.DefineLabel(); + ctx.Branch(@continue, false); + + Compiler.CodeLabel[] handlers = new Compiler.CodeLabel[members.Length]; + for (int i = 0; i < members.Length; i++) + { + handlers[i] = ctx.DefineLabel(); + } + + ctx.MarkLabel(processField); + + ctx.LoadValue(fieldNumber); + ctx.LoadValue(1); + ctx.Subtract(); // jump-table is zero-based + ctx.Switch(handlers); + + // and the default: + ctx.Branch(notRecognised, false); + for (int i = 0; i < handlers.Length; i++) + { + ctx.MarkLabel(handlers[i]); + IProtoSerializer tail = tails[i]; + Compiler.Local oldValIfNeeded = tail.RequiresOldValue ? locals[i] : null; + ctx.ReadNullCheckedTail(locals[i].Type, tail, oldValIfNeeded); + if (tail.ReturnsValue) + { + if (Helpers.IsValueType(locals[i].Type)) + { + ctx.StoreValue(locals[i]); + } + else + { + Compiler.CodeLabel hasValue = ctx.DefineLabel(), allDone = ctx.DefineLabel(); + + ctx.CopyValue(); + ctx.BranchIfTrue(hasValue, true); // interpret null as "don't assign" + ctx.DiscardValue(); + ctx.Branch(allDone, true); + ctx.MarkLabel(hasValue); + ctx.StoreValue(locals[i]); + ctx.MarkLabel(allDone); + } + } + ctx.Branch(@continue, false); + } + + ctx.MarkLabel(notRecognised); + ctx.LoadReaderWriter(); + ctx.EmitCall(ctx.MapType(typeof(ProtoReader)).GetMethod("SkipField")); + + ctx.MarkLabel(@continue); + ctx.EmitBasicRead("ReadFieldHeader", ctx.MapType(typeof(int))); + ctx.CopyValue(); + ctx.StoreValue(fieldNumber); + ctx.LoadValue(0); + ctx.BranchIfGreater(processField, false); + } + for (int i = 0; i < locals.Length; i++) + { + ctx.LoadValue(locals[i]); + } + + ctx.EmitCtor(ctor); + ctx.StoreValue(objValue); + } + finally + { + for (int i = 0; i < locals.Length; i++) + { + if (locals[i] != null) + locals[i].Dispose(); // release for re-use + } + } + } + + } +#endif + } +} + +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/TupleSerializer.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/TupleSerializer.cs.meta new file mode 100644 index 0000000..df99bbe --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/TupleSerializer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7e57d0cd813299f40a1a32236d9931a9 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/TypeSerializer.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/TypeSerializer.cs new file mode 100644 index 0000000..d851b47 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/TypeSerializer.cs @@ -0,0 +1,798 @@ +#if !NO_RUNTIME +using System; +using ProtoBuf.Meta; +#if FEAT_COMPILER + +#endif + +using System.Reflection; + +namespace ProtoBuf.Serializers +{ + sealed class TypeSerializer : IProtoTypeSerializer + { + public bool HasCallbacks(TypeModel.CallbackType callbackType) + { + if (callbacks != null && callbacks[callbackType] != null) return true; + for (int i = 0; i < serializers.Length; i++) + { + if (serializers[i].ExpectedType != forType && ((IProtoTypeSerializer)serializers[i]).HasCallbacks(callbackType)) return true; + } + return false; + } + private readonly Type forType, constructType; +#if COREFX || PROFILE259 + private readonly TypeInfo typeInfo; +#endif + public Type ExpectedType { get { return forType; } } + private readonly IProtoSerializer[] serializers; + private readonly int[] fieldNumbers; + private readonly bool isRootType, useConstructor, isExtensible, hasConstructor; + private readonly CallbackSet callbacks; + private readonly MethodInfo[] baseCtorCallbacks; + private readonly MethodInfo factory; + public TypeSerializer(TypeModel model, Type forType, int[] fieldNumbers, IProtoSerializer[] serializers, MethodInfo[] baseCtorCallbacks, bool isRootType, bool useConstructor, CallbackSet callbacks, Type constructType, MethodInfo factory) + { + Helpers.DebugAssert(forType != null); + Helpers.DebugAssert(fieldNumbers != null); + Helpers.DebugAssert(serializers != null); + Helpers.DebugAssert(fieldNumbers.Length == serializers.Length); + + Helpers.Sort(fieldNumbers, serializers); + bool hasSubTypes = false; + for (int i = 0; i < fieldNumbers.Length; i++) + { + if (i != 0 && fieldNumbers[i] == fieldNumbers[i - 1]) throw new InvalidOperationException("Duplicate field-number detected; " + + fieldNumbers[i].ToString() + " on: " + forType.FullName); + if (!hasSubTypes && serializers[i].ExpectedType != forType) + { + hasSubTypes = true; + } + } + this.forType = forType; + this.factory = factory; +#if COREFX || PROFILE259 + this.typeInfo = forType.GetTypeInfo(); +#endif + if (constructType == null) + { + constructType = forType; + } + else + { +#if COREFX || PROFILE259 + if (!typeInfo.IsAssignableFrom(constructType.GetTypeInfo())) +#else + if (!forType.IsAssignableFrom(constructType)) +#endif + { + throw new InvalidOperationException(forType.FullName + " cannot be assigned from " + constructType.FullName); + } + } + this.constructType = constructType; + this.serializers = serializers; + this.fieldNumbers = fieldNumbers; + this.callbacks = callbacks; + this.isRootType = isRootType; + this.useConstructor = useConstructor; + + if (baseCtorCallbacks != null && baseCtorCallbacks.Length == 0) baseCtorCallbacks = null; + this.baseCtorCallbacks = baseCtorCallbacks; + + if (Helpers.GetUnderlyingType(forType) != null) + { + throw new ArgumentException("Cannot create a TypeSerializer for nullable types", "forType"); + } + +#if COREFX || PROFILE259 + if (iextensible.IsAssignableFrom(typeInfo)) + { + if (typeInfo.IsValueType || !isRootType || hasSubTypes) +#else + if (model.MapType(iextensible).IsAssignableFrom(forType)) + { + if (forType.IsValueType || !isRootType || hasSubTypes) +#endif + { + throw new NotSupportedException("IExtensible is not supported in structs or classes with inheritance"); + } + isExtensible = true; + } +#if COREFX || PROFILE259 + TypeInfo constructTypeInfo = constructType.GetTypeInfo(); + hasConstructor = !constructTypeInfo.IsAbstract && Helpers.GetConstructor(constructTypeInfo, Helpers.EmptyTypes, true) != null; +#else + hasConstructor = !constructType.IsAbstract && Helpers.GetConstructor(constructType, Helpers.EmptyTypes, true) != null; +#endif + if (constructType != forType && useConstructor && !hasConstructor) + { + throw new ArgumentException("The supplied default implementation cannot be created: " + constructType.FullName, "constructType"); + } + } +#if COREFX || PROFILE259 + private static readonly TypeInfo iextensible = typeof(IExtensible).GetTypeInfo(); +#else + private static readonly System.Type iextensible = typeof(IExtensible); +#endif + + private bool CanHaveInheritance + { + get + { +#if COREFX || PROFILE259 + return (typeInfo.IsClass || typeInfo.IsInterface) && !typeInfo.IsSealed; +#else + return (forType.IsClass || forType.IsInterface) && !forType.IsSealed; +#endif + } + } + + bool IProtoTypeSerializer.CanCreateInstance() { return true; } + + object IProtoTypeSerializer.CreateInstance(ProtoReader source) + { + return CreateInstance(source, false); + } + public void Callback(object value, TypeModel.CallbackType callbackType, SerializationContext context) + { + if (callbacks != null) InvokeCallback(callbacks[callbackType], value, context); + IProtoTypeSerializer ser = (IProtoTypeSerializer)GetMoreSpecificSerializer(value); + if (ser != null) ser.Callback(value, callbackType, context); + } + private IProtoSerializer GetMoreSpecificSerializer(object value) + { + if (!CanHaveInheritance) return null; + Type actualType = value.GetType(); + if (actualType == forType) return null; + + for (int i = 0; i < serializers.Length; i++) + { + IProtoSerializer ser = serializers[i]; + if (ser.ExpectedType != forType && Helpers.IsAssignableFrom(ser.ExpectedType, actualType)) + { + return ser; + } + } + if (actualType == constructType) return null; // needs to be last in case the default concrete type is also a known sub-type + TypeModel.ThrowUnexpectedSubtype(forType, actualType); // might throw (if not a proxy) + return null; + } + + public void Write(object value, ProtoWriter dest) + { + if (isRootType) Callback(value, TypeModel.CallbackType.BeforeSerialize, dest.Context); + // write inheritance first + IProtoSerializer next = GetMoreSpecificSerializer(value); + if (next != null) next.Write(value, dest); + + // write all actual fields + //Helpers.DebugWriteLine(">> Writing fields for " + forType.FullName); + for (int i = 0; i < serializers.Length; i++) + { + IProtoSerializer ser = serializers[i]; + if (ser.ExpectedType == forType) + { + //Helpers.DebugWriteLine(": " + ser.ToString()); + ser.Write(value, dest); + } + } + //Helpers.DebugWriteLine("<< Writing fields for " + forType.FullName); + if (isExtensible) ProtoWriter.AppendExtensionData((IExtensible)value, dest); + if (isRootType) Callback(value, TypeModel.CallbackType.AfterSerialize, dest.Context); + } + + public object Read(object value, ProtoReader source) + { + if (isRootType && value != null) { Callback(value, TypeModel.CallbackType.BeforeDeserialize, source.Context); } + int fieldNumber, lastFieldNumber = 0, lastFieldIndex = 0; + bool fieldHandled; + + //Helpers.DebugWriteLine(">> Reading fields for " + forType.FullName); + while ((fieldNumber = source.ReadFieldHeader()) > 0) + { + fieldHandled = false; + if (fieldNumber < lastFieldNumber) + { + lastFieldNumber = lastFieldIndex = 0; + } + for (int i = lastFieldIndex; i < fieldNumbers.Length; i++) + { + if (fieldNumbers[i] == fieldNumber) + { + IProtoSerializer ser = serializers[i]; + //Helpers.DebugWriteLine(": " + ser.ToString()); + Type serType = ser.ExpectedType; + if (value == null) + { + if (serType == forType) value = CreateInstance(source, true); + } + else + { + if (serType != forType && ((IProtoTypeSerializer)ser).CanCreateInstance() + && serType +#if COREFX || PROFILE259 + .GetTypeInfo() +#endif + .IsSubclassOf(value.GetType())) + { + value = ProtoReader.Merge(source, value, ((IProtoTypeSerializer)ser).CreateInstance(source)); + } + } + + if (ser.ReturnsValue) + { + value = ser.Read(value, source); + } + else + { // pop + ser.Read(value, source); + } + + lastFieldIndex = i; + lastFieldNumber = fieldNumber; + fieldHandled = true; + break; + } + } + if (!fieldHandled) + { + //Helpers.DebugWriteLine(": [" + fieldNumber + "] (unknown)"); + if (value == null) value = CreateInstance(source, true); + if (isExtensible) + { + source.AppendExtensionData((IExtensible)value); + } + else + { + source.SkipField(); + } + } + } + //Helpers.DebugWriteLine("<< Reading fields for " + forType.FullName); + if (value == null) value = CreateInstance(source, true); + if (isRootType) { Callback(value, TypeModel.CallbackType.AfterDeserialize, source.Context); } + return value; + } + + private object InvokeCallback(MethodInfo method, object obj, SerializationContext context) + { + object result = null; + object[] args; + if (method != null) + { // pass in a streaming context if one is needed, else null + bool handled; + ParameterInfo[] parameters = method.GetParameters(); + switch (parameters.Length) + { + case 0: + args = null; + handled = true; + break; + default: + args = new object[parameters.Length]; + handled = true; + for (int i = 0; i < args.Length; i++) + { + object val; + Type paramType = parameters[i].ParameterType; + if (paramType == typeof(SerializationContext)) val = context; + else if (paramType == typeof(System.Type)) val = constructType; +#if PLAT_BINARYFORMATTER + else if (paramType == typeof(System.Runtime.Serialization.StreamingContext)) val = (System.Runtime.Serialization.StreamingContext)context; +#endif + else + { + val = null; + handled = false; + } + args[i] = val; + } + break; + } + if (handled) + { + result = method.Invoke(obj, args); + } + else + { + throw Meta.CallbackSet.CreateInvalidCallbackSignature(method); + } + + } + return result; + } + object CreateInstance(ProtoReader source, bool includeLocalCallback) + { + //Helpers.DebugWriteLine("* creating : " + forType.FullName); + object obj; + if (factory != null) + { + obj = InvokeCallback(factory, null, source.Context); + } + else if (useConstructor) + { + if (!hasConstructor) TypeModel.ThrowCannotCreateInstance(constructType); +#if PROFILE259 + ConstructorInfo constructorInfo = System.Linq.Enumerable.First( + constructType.GetTypeInfo().DeclaredConstructors, c => c.GetParameters().Length == 0); + obj = constructorInfo.Invoke(new object[] {}); + +#else + obj = Activator.CreateInstance(constructType +#if !(CF || PORTABLE || NETSTANDARD1_3 || NETSTANDARD1_4 || UAP) + , nonPublic: true +#endif + ); +#endif + } + else + { + obj = BclHelpers.GetUninitializedObject(constructType); + } + ProtoReader.NoteObject(obj, source); + if (baseCtorCallbacks != null) + { + for (int i = 0; i < baseCtorCallbacks.Length; i++) + { + InvokeCallback(baseCtorCallbacks[i], obj, source.Context); + } + } + if (includeLocalCallback && callbacks != null) InvokeCallback(callbacks.BeforeDeserialize, obj, source.Context); + return obj; + } + + bool IProtoSerializer.RequiresOldValue { get { return true; } } + bool IProtoSerializer.ReturnsValue { get { return false; } } // updates field directly +#if FEAT_COMPILER + void IProtoSerializer.EmitWrite(Compiler.CompilerContext ctx, Compiler.Local valueFrom) + { + Type expected = ExpectedType; + using (Compiler.Local loc = ctx.GetLocalWithValue(expected, valueFrom)) + { + // pre-callbacks + EmitCallbackIfNeeded(ctx, loc, TypeModel.CallbackType.BeforeSerialize); + + Compiler.CodeLabel startFields = ctx.DefineLabel(); + // inheritance + if (CanHaveInheritance) + { + for (int i = 0; i < serializers.Length; i++) + { + IProtoSerializer ser = serializers[i]; + Type serType = ser.ExpectedType; + if (serType != forType) + { + Compiler.CodeLabel ifMatch = ctx.DefineLabel(), nextTest = ctx.DefineLabel(); + ctx.LoadValue(loc); + ctx.TryCast(serType); + ctx.CopyValue(); + ctx.BranchIfTrue(ifMatch, true); + ctx.DiscardValue(); + ctx.Branch(nextTest, true); + ctx.MarkLabel(ifMatch); + if (Helpers.IsValueType(serType)) + { + ctx.DiscardValue(); + ctx.LoadValue(loc); + ctx.CastFromObject(serType); + } + ser.EmitWrite(ctx, null); + ctx.Branch(startFields, false); + ctx.MarkLabel(nextTest); + } + } + + + if (constructType != null && constructType != forType) + { + using (Compiler.Local actualType = new Compiler.Local(ctx, ctx.MapType(typeof(System.Type)))) + { + // would have jumped to "fields" if an expected sub-type, so two options: + // a: *exactly* that type, b: an *unexpected* type + ctx.LoadValue(loc); + ctx.EmitCall(ctx.MapType(typeof(object)).GetMethod("GetType")); + ctx.CopyValue(); + ctx.StoreValue(actualType); + ctx.LoadValue(forType); + ctx.BranchIfEqual(startFields, true); + + ctx.LoadValue(actualType); + ctx.LoadValue(constructType); + ctx.BranchIfEqual(startFields, true); + } + } + else + { + // would have jumped to "fields" if an expected sub-type, so two options: + // a: *exactly* that type, b: an *unexpected* type + ctx.LoadValue(loc); + ctx.EmitCall(ctx.MapType(typeof(object)).GetMethod("GetType")); + ctx.LoadValue(forType); + ctx.BranchIfEqual(startFields, true); + } + // unexpected, then... note that this *might* be a proxy, which + // is handled by ThrowUnexpectedSubtype + ctx.LoadValue(forType); + ctx.LoadValue(loc); + ctx.EmitCall(ctx.MapType(typeof(object)).GetMethod("GetType")); + ctx.EmitCall(ctx.MapType(typeof(TypeModel)).GetMethod("ThrowUnexpectedSubtype", + BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static)); + + } + // fields + + ctx.MarkLabel(startFields); + for (int i = 0; i < serializers.Length; i++) + { + IProtoSerializer ser = serializers[i]; + if (ser.ExpectedType == forType) ser.EmitWrite(ctx, loc); + } + + // extension data + if (isExtensible) + { + ctx.LoadValue(loc); + ctx.LoadReaderWriter(); + ctx.EmitCall(ctx.MapType(typeof(ProtoWriter)).GetMethod("AppendExtensionData")); + } + // post-callbacks + EmitCallbackIfNeeded(ctx, loc, TypeModel.CallbackType.AfterSerialize); + } + } + static void EmitInvokeCallback(Compiler.CompilerContext ctx, MethodInfo method, bool copyValue, Type constructType, Type type) + { + if (method != null) + { + if (copyValue) ctx.CopyValue(); // assumes the target is on the stack, and that we want to *retain* it on the stack + ParameterInfo[] parameters = method.GetParameters(); + bool handled = true; + + for (int i = 0; i < parameters.Length; i++) + { + Type parameterType = parameters[i].ParameterType; + if (parameterType == ctx.MapType(typeof(SerializationContext))) + { + ctx.LoadSerializationContext(); + } + else if (parameterType == ctx.MapType(typeof(System.Type))) + { + Type tmp = constructType; + if (tmp == null) tmp = type; // no ?? in some C# profiles + ctx.LoadValue(tmp); + } +#if PLAT_BINARYFORMATTER + else if (parameterType == ctx.MapType(typeof(System.Runtime.Serialization.StreamingContext))) + { + ctx.LoadSerializationContext(); + MethodInfo op = ctx.MapType(typeof(SerializationContext)).GetMethod("op_Implicit", new Type[] { ctx.MapType(typeof(SerializationContext)) }); + if (op != null) + { // it isn't always! (framework versions, etc) + ctx.EmitCall(op); + handled = true; + } + } +#endif + else + { + handled = false; + } + } + if (handled) + { + ctx.EmitCall(method); + if (constructType != null) + { + if (method.ReturnType == ctx.MapType(typeof(object))) + { + ctx.CastFromObject(type); + } + } + } + else + { + throw Meta.CallbackSet.CreateInvalidCallbackSignature(method); + } + } + } + + private void EmitCallbackIfNeeded(Compiler.CompilerContext ctx, Compiler.Local valueFrom, TypeModel.CallbackType callbackType) + { + Helpers.DebugAssert(valueFrom != null); + if (isRootType && ((IProtoTypeSerializer)this).HasCallbacks(callbackType)) + { + ((IProtoTypeSerializer)this).EmitCallback(ctx, valueFrom, callbackType); + } + } + + void IProtoTypeSerializer.EmitCallback(Compiler.CompilerContext ctx, Compiler.Local valueFrom, TypeModel.CallbackType callbackType) + { + bool actuallyHasInheritance = false; + if (CanHaveInheritance) + { + + for (int i = 0; i < serializers.Length; i++) + { + IProtoSerializer ser = serializers[i]; + if (ser.ExpectedType != forType && ((IProtoTypeSerializer)ser).HasCallbacks(callbackType)) + { + actuallyHasInheritance = true; + } + } + } + + Helpers.DebugAssert(((IProtoTypeSerializer)this).HasCallbacks(callbackType), "Shouldn't be calling this if there is nothing to do"); + MethodInfo method = callbacks?[callbackType]; + if (method == null && !actuallyHasInheritance) + { + return; + } + ctx.LoadAddress(valueFrom, ExpectedType); + EmitInvokeCallback(ctx, method, actuallyHasInheritance, null, forType); + + if (actuallyHasInheritance) + { + Compiler.CodeLabel @break = ctx.DefineLabel(); + for (int i = 0; i < serializers.Length; i++) + { + IProtoSerializer ser = serializers[i]; + IProtoTypeSerializer typeser; + Type serType = ser.ExpectedType; + if (serType != forType && + (typeser = (IProtoTypeSerializer)ser).HasCallbacks(callbackType)) + { + Compiler.CodeLabel ifMatch = ctx.DefineLabel(), nextTest = ctx.DefineLabel(); + ctx.CopyValue(); + ctx.TryCast(serType); + ctx.CopyValue(); + ctx.BranchIfTrue(ifMatch, true); + ctx.DiscardValue(); + ctx.Branch(nextTest, false); + ctx.MarkLabel(ifMatch); + typeser.EmitCallback(ctx, null, callbackType); + ctx.Branch(@break, false); + ctx.MarkLabel(nextTest); + } + } + ctx.MarkLabel(@break); + ctx.DiscardValue(); + } + } + + void IProtoSerializer.EmitRead(Compiler.CompilerContext ctx, Compiler.Local valueFrom) + { + Type expected = ExpectedType; + Helpers.DebugAssert(valueFrom != null); + + using (Compiler.Local loc = ctx.GetLocalWithValue(expected, valueFrom)) + using (Compiler.Local fieldNumber = new Compiler.Local(ctx, ctx.MapType(typeof(int)))) + { + // pre-callbacks + if (HasCallbacks(TypeModel.CallbackType.BeforeDeserialize)) + { + if (Helpers.IsValueType(ExpectedType)) + { + EmitCallbackIfNeeded(ctx, loc, TypeModel.CallbackType.BeforeDeserialize); + } + else + { // could be null + Compiler.CodeLabel callbacksDone = ctx.DefineLabel(); + ctx.LoadValue(loc); + ctx.BranchIfFalse(callbacksDone, false); + EmitCallbackIfNeeded(ctx, loc, TypeModel.CallbackType.BeforeDeserialize); + ctx.MarkLabel(callbacksDone); + } + } + + Compiler.CodeLabel @continue = ctx.DefineLabel(), processField = ctx.DefineLabel(); + ctx.Branch(@continue, false); + + ctx.MarkLabel(processField); + foreach (BasicList.Group group in BasicList.GetContiguousGroups(fieldNumbers, serializers)) + { + Compiler.CodeLabel tryNextField = ctx.DefineLabel(); + int groupItemCount = group.Items.Count; + if (groupItemCount == 1) + { + // discreet group; use an equality test + ctx.LoadValue(fieldNumber); + ctx.LoadValue(group.First); + Compiler.CodeLabel processThisField = ctx.DefineLabel(); + ctx.BranchIfEqual(processThisField, true); + ctx.Branch(tryNextField, false); + WriteFieldHandler(ctx, expected, loc, processThisField, @continue, (IProtoSerializer)group.Items[0]); + } + else + { // implement as a jump-table-based switch + ctx.LoadValue(fieldNumber); + ctx.LoadValue(group.First); + ctx.Subtract(); // jump-tables are zero-based + Compiler.CodeLabel[] jmp = new Compiler.CodeLabel[groupItemCount]; + for (int i = 0; i < groupItemCount; i++) + { + jmp[i] = ctx.DefineLabel(); + } + ctx.Switch(jmp); + // write the default... + ctx.Branch(tryNextField, false); + for (int i = 0; i < groupItemCount; i++) + { + WriteFieldHandler(ctx, expected, loc, jmp[i], @continue, (IProtoSerializer)group.Items[i]); + } + } + ctx.MarkLabel(tryNextField); + } + + EmitCreateIfNull(ctx, loc); + ctx.LoadReaderWriter(); + if (isExtensible) + { + ctx.LoadValue(loc); + ctx.EmitCall(ctx.MapType(typeof(ProtoReader)).GetMethod("AppendExtensionData")); + } + else + { + ctx.EmitCall(ctx.MapType(typeof(ProtoReader)).GetMethod("SkipField")); + } + + ctx.MarkLabel(@continue); + ctx.EmitBasicRead("ReadFieldHeader", ctx.MapType(typeof(int))); + ctx.CopyValue(); + ctx.StoreValue(fieldNumber); + ctx.LoadValue(0); + ctx.BranchIfGreater(processField, false); + + EmitCreateIfNull(ctx, loc); + // post-callbacks + EmitCallbackIfNeeded(ctx, loc, TypeModel.CallbackType.AfterDeserialize); + + if (valueFrom != null && !loc.IsSame(valueFrom)) + { + ctx.LoadValue(loc); + ctx.Cast(valueFrom.Type); + ctx.StoreValue(valueFrom); + } + } + } + + private void WriteFieldHandler( + Compiler.CompilerContext ctx, Type expected, Compiler.Local loc, + Compiler.CodeLabel handler, Compiler.CodeLabel @continue, IProtoSerializer serializer) + { + ctx.MarkLabel(handler); + Type serType = serializer.ExpectedType; + if (serType == forType) + { + EmitCreateIfNull(ctx, loc); + serializer.EmitRead(ctx, loc); + } + else + { + //RuntimeTypeModel rtm = (RuntimeTypeModel)ctx.Model; + if (((IProtoTypeSerializer)serializer).CanCreateInstance()) + { + Compiler.CodeLabel allDone = ctx.DefineLabel(); + + ctx.LoadValue(loc); + ctx.BranchIfFalse(allDone, false); // null is always ok + + ctx.LoadValue(loc); + ctx.TryCast(serType); + ctx.BranchIfTrue(allDone, false); // not null, but of the correct type + + // otherwise, need to convert it + ctx.LoadReaderWriter(); + ctx.LoadValue(loc); + ((IProtoTypeSerializer)serializer).EmitCreateInstance(ctx); + ctx.EmitCall(ctx.MapType(typeof(ProtoReader)).GetMethod("Merge")); + ctx.Cast(expected); + ctx.StoreValue(loc); // Merge always returns a value + + // nothing needs doing + ctx.MarkLabel(allDone); + } + + if (Helpers.IsValueType(serType)) + { + Compiler.CodeLabel initValue = ctx.DefineLabel(); + Compiler.CodeLabel hasValue = ctx.DefineLabel(); + using (Compiler.Local emptyValue = new Compiler.Local(ctx, serType)) + { + ctx.LoadValue(loc); + ctx.BranchIfFalse(initValue, false); + + ctx.LoadValue(loc); + ctx.CastFromObject(serType); + ctx.Branch(hasValue, false); + + ctx.MarkLabel(initValue); + ctx.InitLocal(serType, emptyValue); + ctx.LoadValue(emptyValue); + + ctx.MarkLabel(hasValue); + } + } + else + { + ctx.LoadValue(loc); + ctx.Cast(serType); + } + + serializer.EmitRead(ctx, null); + + } + + if (serializer.ReturnsValue) + { // update the variable + if (Helpers.IsValueType(serType)) + { + // but box it first in case of value type + ctx.CastToObject(serType); + } + ctx.StoreValue(loc); + } + ctx.Branch(@continue, false); // "continue" + } + + void IProtoTypeSerializer.EmitCreateInstance(Compiler.CompilerContext ctx) + { + // different ways of creating a new instance + bool callNoteObject = true; + if (factory != null) + { + EmitInvokeCallback(ctx, factory, false, constructType, forType); + } + else if (!useConstructor) + { // DataContractSerializer style + ctx.LoadValue(constructType); + ctx.EmitCall(ctx.MapType(typeof(BclHelpers)).GetMethod("GetUninitializedObject")); + ctx.Cast(forType); + } + else if (Helpers.IsClass(constructType) && hasConstructor) + { // XmlSerializer style + ctx.EmitCtor(constructType); + } + else + { + ctx.LoadValue(ExpectedType); + ctx.EmitCall(ctx.MapType(typeof(TypeModel)).GetMethod("ThrowCannotCreateInstance", + BindingFlags.Static | BindingFlags.Public)); + ctx.LoadNullRef(); + callNoteObject = false; + } + if (callNoteObject) + { + // track root object creation + ctx.CopyValue(); + ctx.LoadReaderWriter(); + ctx.EmitCall(ctx.MapType(typeof(ProtoReader)).GetMethod("NoteObject", + BindingFlags.Static | BindingFlags.Public)); + } + if (baseCtorCallbacks != null) + { + for (int i = 0; i < baseCtorCallbacks.Length; i++) + { + EmitInvokeCallback(ctx, baseCtorCallbacks[i], true, null, forType); + } + } + } + private void EmitCreateIfNull(Compiler.CompilerContext ctx, Compiler.Local storage) + { + Helpers.DebugAssert(storage != null); + if (!Helpers.IsValueType(ExpectedType)) + { + Compiler.CodeLabel afterNullCheck = ctx.DefineLabel(); + ctx.LoadValue(storage); + ctx.BranchIfTrue(afterNullCheck, false); + + ((IProtoTypeSerializer)this).EmitCreateInstance(ctx); + + if (callbacks != null) EmitInvokeCallback(ctx, callbacks.BeforeDeserialize, true, null, forType); + ctx.StoreValue(storage); + ctx.MarkLabel(afterNullCheck); + } + } +#endif + } + +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/TypeSerializer.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/TypeSerializer.cs.meta new file mode 100644 index 0000000..0b9bc49 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/TypeSerializer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b3f577c98285d56469b3eb1c9190e174 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/UInt16Serializer.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/UInt16Serializer.cs new file mode 100644 index 0000000..ff9f89b --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/UInt16Serializer.cs @@ -0,0 +1,43 @@ +#if !NO_RUNTIME +using System; + +namespace ProtoBuf.Serializers +{ + class UInt16Serializer : IProtoSerializer + { + static readonly Type expectedType = typeof(ushort); + + public UInt16Serializer(ProtoBuf.Meta.TypeModel model) + { + } + + public virtual Type ExpectedType => expectedType; + + bool IProtoSerializer.RequiresOldValue => false; + + bool IProtoSerializer.ReturnsValue => true; + + public virtual object Read(object value, ProtoReader source) + { + Helpers.DebugAssert(value == null); // since replaces + return source.ReadUInt16(); + } + + public virtual void Write(object value, ProtoWriter dest) + { + ProtoWriter.WriteUInt16((ushort)value, dest); + } + +#if FEAT_COMPILER + void IProtoSerializer.EmitWrite(Compiler.CompilerContext ctx, Compiler.Local valueFrom) + { + ctx.EmitBasicWrite("WriteUInt16", valueFrom); + } + void IProtoSerializer.EmitRead(Compiler.CompilerContext ctx, Compiler.Local valueFrom) + { + ctx.EmitBasicRead("ReadUInt16", ctx.MapType(typeof(ushort))); + } +#endif + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/UInt16Serializer.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/UInt16Serializer.cs.meta new file mode 100644 index 0000000..3e94120 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/UInt16Serializer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 95fff5b2239c48c4cbb32346fee1be94 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/UInt32Serializer.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/UInt32Serializer.cs new file mode 100644 index 0000000..08b4f4b --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/UInt32Serializer.cs @@ -0,0 +1,43 @@ +#if !NO_RUNTIME +using System; + +namespace ProtoBuf.Serializers +{ + sealed class UInt32Serializer : IProtoSerializer + { + static readonly Type expectedType = typeof(uint); + + public UInt32Serializer(ProtoBuf.Meta.TypeModel model) + { + + } + + public Type ExpectedType => expectedType; + + bool IProtoSerializer.RequiresOldValue => false; + + bool IProtoSerializer.ReturnsValue => true; + + public object Read(object value, ProtoReader source) + { + Helpers.DebugAssert(value == null); // since replaces + return source.ReadUInt32(); + } + + public void Write(object value, ProtoWriter dest) + { + ProtoWriter.WriteUInt32((uint)value, dest); + } +#if FEAT_COMPILER + void IProtoSerializer.EmitWrite(Compiler.CompilerContext ctx, Compiler.Local valueFrom) + { + ctx.EmitBasicWrite("WriteUInt32", valueFrom); + } + void IProtoSerializer.EmitRead(Compiler.CompilerContext ctx, Compiler.Local valueFrom) + { + ctx.EmitBasicRead("ReadUInt32", ctx.MapType(typeof(uint))); + } +#endif + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/UInt32Serializer.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/UInt32Serializer.cs.meta new file mode 100644 index 0000000..342cdec --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/UInt32Serializer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 79149f5f69e868c45a17d389322e4bb7 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/UInt64Serializer.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/UInt64Serializer.cs new file mode 100644 index 0000000..8577edd --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/UInt64Serializer.cs @@ -0,0 +1,43 @@ +#if !NO_RUNTIME +using System; + +namespace ProtoBuf.Serializers +{ + sealed class UInt64Serializer : IProtoSerializer + { + static readonly Type expectedType = typeof(ulong); + + public UInt64Serializer(ProtoBuf.Meta.TypeModel model) + { + + } + public Type ExpectedType => expectedType; + + bool IProtoSerializer.RequiresOldValue => false; + + bool IProtoSerializer.ReturnsValue => true; + + public object Read(object value, ProtoReader source) + { + Helpers.DebugAssert(value == null); // since replaces + return source.ReadUInt64(); + } + + public void Write(object value, ProtoWriter dest) + { + ProtoWriter.WriteUInt64((ulong)value, dest); + } + +#if FEAT_COMPILER + void IProtoSerializer.EmitWrite(Compiler.CompilerContext ctx, Compiler.Local valueFrom) + { + ctx.EmitBasicWrite("WriteUInt64", valueFrom); + } + void IProtoSerializer.EmitRead(Compiler.CompilerContext ctx, Compiler.Local valueFrom) + { + ctx.EmitBasicRead("ReadUInt64", ExpectedType); + } +#endif + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/UInt64Serializer.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/UInt64Serializer.cs.meta new file mode 100644 index 0000000..72452d9 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/UInt64Serializer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e549c20b3409c4a4dbf0e7fc25062c71 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/UriDecorator.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/UriDecorator.cs new file mode 100644 index 0000000..d34ac2d --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/UriDecorator.cs @@ -0,0 +1,62 @@ +#if !NO_RUNTIME +using System; +using System.Reflection; + +#if FEAT_COMPILER +using ProtoBuf.Compiler; +#endif + +namespace ProtoBuf.Serializers +{ + sealed class UriDecorator : ProtoDecoratorBase + { + static readonly Type expectedType = typeof(Uri); + public UriDecorator(ProtoBuf.Meta.TypeModel model, IProtoSerializer tail) : base(tail) + { + + } + + public override Type ExpectedType => expectedType; + + public override bool RequiresOldValue => false; + + public override bool ReturnsValue => true; + + public override void Write(object value, ProtoWriter dest) + { + Tail.Write(((Uri)value).OriginalString, dest); + } + + public override object Read(object value, ProtoReader source) + { + Helpers.DebugAssert(value == null); // not expecting incoming + string s = (string)Tail.Read(null, source); + return s.Length == 0 ? null : new Uri(s, UriKind.RelativeOrAbsolute); + } + +#if FEAT_COMPILER + protected override void EmitWrite(Compiler.CompilerContext ctx, Compiler.Local valueFrom) + { + ctx.LoadValue(valueFrom); + ctx.LoadValue(typeof(Uri).GetProperty("OriginalString")); + Tail.EmitWrite(ctx, null); + } + protected override void EmitRead(Compiler.CompilerContext ctx, Compiler.Local valueFrom) + { + Tail.EmitRead(ctx, valueFrom); + ctx.CopyValue(); + Compiler.CodeLabel @nonEmpty = ctx.DefineLabel(), @end = ctx.DefineLabel(); + ctx.LoadValue(typeof(string).GetProperty("Length")); + ctx.BranchIfTrue(@nonEmpty, true); + ctx.DiscardValue(); + ctx.LoadNullRef(); + ctx.Branch(@end, true); + ctx.MarkLabel(@nonEmpty); + ctx.LoadValue((int)UriKind.RelativeOrAbsolute); + ctx.EmitCtor(ctx.MapType(typeof(Uri)), ctx.MapType(typeof(string)), ctx.MapType(typeof(UriKind))); + ctx.MarkLabel(@end); + } +#endif + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/UriDecorator.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/UriDecorator.cs.meta new file mode 100644 index 0000000..0095ee9 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/Serializers/UriDecorator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b784c432eb5cbf742b3d96161e7c8d73 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/ServiceModel.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/ServiceModel.meta new file mode 100644 index 0000000..36e1d95 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/ServiceModel.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: af34a7ba57dbd6340b8d3fa0bfdbd0a1 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/ServiceModel/ProtoBehaviorAttribute.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/ServiceModel/ProtoBehaviorAttribute.cs new file mode 100644 index 0000000..928207e --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/ServiceModel/ProtoBehaviorAttribute.cs @@ -0,0 +1,35 @@ +#if FEAT_SERVICEMODEL && PLAT_XMLSERIALIZER +using System; +using System.ServiceModel.Channels; +using System.ServiceModel.Description; +using System.ServiceModel.Dispatcher; + +namespace ProtoBuf.ServiceModel +{ + /// + /// Uses protocol buffer serialization on the specified operation; note that this + /// must be enabled on both the client and server. + /// + [AttributeUsage(AttributeTargets.Method, AllowMultiple = false)] + public sealed class ProtoBehaviorAttribute : Attribute, IOperationBehavior + { + void IOperationBehavior.AddBindingParameters(OperationDescription operationDescription, BindingParameterCollection bindingParameters) + { } + + void IOperationBehavior.ApplyClientBehavior(OperationDescription operationDescription, ClientOperation clientOperation) + { + IOperationBehavior innerBehavior = new ProtoOperationBehavior(operationDescription); + innerBehavior.ApplyClientBehavior(operationDescription, clientOperation); + } + + void IOperationBehavior.ApplyDispatchBehavior(OperationDescription operationDescription, DispatchOperation dispatchOperation) + { + IOperationBehavior innerBehavior = new ProtoOperationBehavior(operationDescription); + innerBehavior.ApplyDispatchBehavior(operationDescription, dispatchOperation); + } + + void IOperationBehavior.Validate(OperationDescription operationDescription) + { } + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/ServiceModel/ProtoBehaviorAttribute.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/ServiceModel/ProtoBehaviorAttribute.cs.meta new file mode 100644 index 0000000..1facc70 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/ServiceModel/ProtoBehaviorAttribute.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: feda16667cbcb8248951368dfbfef6b9 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/ServiceModel/ProtoBehaviorExtensionElement.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/ServiceModel/ProtoBehaviorExtensionElement.cs new file mode 100644 index 0000000..56edb79 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/ServiceModel/ProtoBehaviorExtensionElement.cs @@ -0,0 +1,29 @@ +#if FEAT_SERVICEMODEL && PLAT_XMLSERIALIZER && FEAT_SERVICECONFIGMODEL +using System; +using System.ServiceModel.Configuration; + +namespace ProtoBuf.ServiceModel +{ + /// + /// Configuration element to swap out DatatContractSerilaizer with the XmlProtoSerializer for a given endpoint. + /// + /// + public class ProtoBehaviorExtension : BehaviorExtensionElement + { + /// + /// Creates a new ProtoBehaviorExtension instance. + /// + public ProtoBehaviorExtension() { } + /// + /// Gets the type of behavior. + /// + public override Type BehaviorType => typeof(ProtoEndpointBehavior); + + /// + /// Creates a behavior extension based on the current configuration settings. + /// + /// The behavior extension. + protected override object CreateBehavior() => new ProtoEndpointBehavior(); + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/ServiceModel/ProtoBehaviorExtensionElement.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/ServiceModel/ProtoBehaviorExtensionElement.cs.meta new file mode 100644 index 0000000..7850781 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/ServiceModel/ProtoBehaviorExtensionElement.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c70aaa3829dd1fa45b0530efc37727f5 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/ServiceModel/ProtoEndpointBehavior.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/ServiceModel/ProtoEndpointBehavior.cs new file mode 100644 index 0000000..9bcfb99 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/ServiceModel/ProtoEndpointBehavior.cs @@ -0,0 +1,82 @@ +#if FEAT_SERVICEMODEL && PLAT_XMLSERIALIZER +using System.ServiceModel.Description; + +namespace ProtoBuf.ServiceModel +{ + /// + /// Behavior to swap out DatatContractSerilaizer with the XmlProtoSerializer for a given endpoint. + /// + /// Add the following to the server and client app.config in the system.serviceModel section: + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// Configure your endpoints to have a behaviorConfiguration as follows: + /// + /// + /// + /// + /// + /// + /// + /// + /// + public class ProtoEndpointBehavior : IEndpointBehavior + { + #region IEndpointBehavior Members + + void IEndpointBehavior.AddBindingParameters(ServiceEndpoint endpoint, System.ServiceModel.Channels.BindingParameterCollection bindingParameters) + { + } + + void IEndpointBehavior.ApplyClientBehavior(ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.ClientRuntime clientRuntime) + { + ReplaceDataContractSerializerOperationBehavior(endpoint); + } + + void IEndpointBehavior.ApplyDispatchBehavior(ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.EndpointDispatcher endpointDispatcher) + { + ReplaceDataContractSerializerOperationBehavior(endpoint); + } + + void IEndpointBehavior.Validate(ServiceEndpoint endpoint) + { + } + + private static void ReplaceDataContractSerializerOperationBehavior(ServiceEndpoint serviceEndpoint) + { + foreach (OperationDescription operationDescription in serviceEndpoint.Contract.Operations) + { + ReplaceDataContractSerializerOperationBehavior(operationDescription); + } + } + + private static void ReplaceDataContractSerializerOperationBehavior(OperationDescription description) + { + DataContractSerializerOperationBehavior dcsOperationBehavior = description.Behaviors.Find(); + if (dcsOperationBehavior != null) + { + description.Behaviors.Remove(dcsOperationBehavior); + + ProtoOperationBehavior newBehavior = new ProtoOperationBehavior(description); + newBehavior.MaxItemsInObjectGraph = dcsOperationBehavior.MaxItemsInObjectGraph; + description.Behaviors.Add(newBehavior); + } + } + + #endregion + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/ServiceModel/ProtoEndpointBehavior.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/ServiceModel/ProtoEndpointBehavior.cs.meta new file mode 100644 index 0000000..23ab783 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/ServiceModel/ProtoEndpointBehavior.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6776c4cee4f69a94e9507afa458fdb50 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/ServiceModel/ProtoOperationBehavior.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/ServiceModel/ProtoOperationBehavior.cs new file mode 100644 index 0000000..9d5f02c --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/ServiceModel/ProtoOperationBehavior.cs @@ -0,0 +1,52 @@ +#if FEAT_SERVICEMODEL && PLAT_XMLSERIALIZER +using System; +using System.Collections.Generic; +using System.Runtime.Serialization; +using System.ServiceModel.Description; +using System.Xml; +using ProtoBuf.Meta; + +namespace ProtoBuf.ServiceModel +{ + /// + /// Describes a WCF operation behaviour that can perform protobuf serialization + /// + public sealed class ProtoOperationBehavior : DataContractSerializerOperationBehavior + { + private TypeModel model; + + /// + /// Create a new ProtoOperationBehavior instance + /// + public ProtoOperationBehavior(OperationDescription operation) : base(operation) + { +#if !NO_RUNTIME + model = RuntimeTypeModel.Default; +#endif + } + + /// + /// The type-model that should be used with this behaviour + /// + public TypeModel Model + { + get { return model; } + set + { + model = value ?? throw new ArgumentNullException(nameof(value)); + } + } + + //public ProtoOperationBehavior(OperationDescription operation, DataContractFormatAttribute dataContractFormat) : base(operation, dataContractFormat) { } + + /// + /// Creates a protobuf serializer if possible (falling back to the default WCF serializer) + /// + public override XmlObjectSerializer CreateSerializer(Type type, XmlDictionaryString name, XmlDictionaryString ns, IList knownTypes) + { + if (model == null) throw new InvalidOperationException("No Model instance has been assigned to the ProtoOperationBehavior"); + return XmlProtoSerializer.TryCreate(model, type) ?? base.CreateSerializer(type, name, ns, knownTypes); + } + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/ServiceModel/ProtoOperationBehavior.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/ServiceModel/ProtoOperationBehavior.cs.meta new file mode 100644 index 0000000..3bd6fe4 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/ServiceModel/ProtoOperationBehavior.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: bc6637ab509d5ba41b14e428ed365764 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/ServiceModel/XmlProtoSerializer.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/ServiceModel/XmlProtoSerializer.cs new file mode 100644 index 0000000..23959ea --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/ServiceModel/XmlProtoSerializer.cs @@ -0,0 +1,208 @@ +#if FEAT_SERVICEMODEL && PLAT_XMLSERIALIZER +using System; +using System.IO; +using System.Runtime.Serialization; +using System.Xml; +using ProtoBuf.Meta; + +namespace ProtoBuf.ServiceModel +{ + /// + /// An xml object serializer that can embed protobuf data in a base-64 hunk (looking like a byte[]) + /// + public sealed class XmlProtoSerializer : XmlObjectSerializer + { + private readonly TypeModel model; + private readonly int key; + private readonly bool isList, isEnum; + private readonly Type type; + internal XmlProtoSerializer(TypeModel model, int key, Type type, bool isList) + { + if (key < 0) throw new ArgumentOutOfRangeException(nameof(key)); + this.model = model ?? throw new ArgumentNullException(nameof(model)); + this.key = key; + this.isList = isList; + this.type = type ?? throw new ArgumentOutOfRangeException(nameof(type)); + this.isEnum = Helpers.IsEnum(type); + } + /// + /// Attempt to create a new serializer for the given model and type + /// + /// A new serializer instance if the type is recognised by the model; null otherwise + public static XmlProtoSerializer TryCreate(TypeModel model, Type type) + { + if (model == null) throw new ArgumentNullException(nameof(model)); + if (type == null) throw new ArgumentNullException(nameof(type)); + + int key = GetKey(model, ref type, out bool isList); + if (key >= 0) + { + return new XmlProtoSerializer(model, key, type, isList); + } + return null; + } + + /// + /// Creates a new serializer for the given model and type + /// + public XmlProtoSerializer(TypeModel model, Type type) + { + if (model == null) throw new ArgumentNullException(nameof(model)); + if (type == null) throw new ArgumentNullException(nameof(type)); + + key = GetKey(model, ref type, out isList); + this.model = model; + this.type = type; + this.isEnum = Helpers.IsEnum(type); + if (key < 0) throw new ArgumentOutOfRangeException(nameof(type), "Type not recognised by the model: " + type.FullName); + } + + static int GetKey(TypeModel model, ref Type type, out bool isList) + { + if (model != null && type != null) + { + int key = model.GetKey(ref type); + if (key >= 0) + { + isList = false; + return key; + } + Type itemType = TypeModel.GetListItemType(model, type); + if (itemType != null) + { + key = model.GetKey(ref itemType); + if (key >= 0) + { + isList = true; + return key; + } + } + } + + isList = false; + return -1; + } + + /// + /// Ends an object in the output + /// + public override void WriteEndObject(XmlDictionaryWriter writer) + { + if (writer == null) throw new ArgumentNullException(nameof(writer)); + writer.WriteEndElement(); + } + + /// + /// Begins an object in the output + /// + public override void WriteStartObject(XmlDictionaryWriter writer, object graph) + { + if (writer == null) throw new ArgumentNullException(nameof(writer)); + writer.WriteStartElement(PROTO_ELEMENT); + } + + private const string PROTO_ELEMENT = "proto"; + + /// + /// Writes the body of an object in the output + /// + public override void WriteObjectContent(XmlDictionaryWriter writer, object graph) + { + if (writer == null) throw new ArgumentNullException(nameof(writer)); + if (graph == null) + { + writer.WriteAttributeString("nil", "true"); + } + else + { + using (MemoryStream ms = new MemoryStream()) + { + if (isList) + { + model.Serialize(ms, graph, null); + } + else + { + using (ProtoWriter protoWriter = ProtoWriter.Create(ms, model, null)) + { + model.Serialize(key, graph, protoWriter); + } + } + byte[] buffer = ms.GetBuffer(); + writer.WriteBase64(buffer, 0, (int)ms.Length); + } + } + } + + /// + /// Indicates whether this is the start of an object we are prepared to handle + /// + public override bool IsStartObject(XmlDictionaryReader reader) + { + if (reader == null) throw new ArgumentNullException(nameof(reader)); + reader.MoveToContent(); + return reader.NodeType == XmlNodeType.Element && reader.Name == PROTO_ELEMENT; + } + + /// + /// Reads the body of an object + /// + public override object ReadObject(XmlDictionaryReader reader, bool verifyObjectName) + { + if (reader == null) throw new ArgumentNullException(nameof(reader)); + reader.MoveToContent(); + bool isSelfClosed = reader.IsEmptyElement, isNil = reader.GetAttribute("nil") == "true"; + reader.ReadStartElement(PROTO_ELEMENT); + + // explicitly null + if (isNil) + { + if (!isSelfClosed) reader.ReadEndElement(); + return null; + } + if (isSelfClosed) // no real content + { + if (isList || isEnum) + { + return model.Deserialize(Stream.Null, null, type, null); + } + ProtoReader protoReader = null; + try + { + protoReader = ProtoReader.Create(Stream.Null, model, null, ProtoReader.TO_EOF); + return model.Deserialize(key, null, protoReader); + } + finally + { + ProtoReader.Recycle(protoReader); + } + } + + object result; + Helpers.DebugAssert(reader.CanReadBinaryContent, "CanReadBinaryContent"); + using (MemoryStream ms = new MemoryStream(reader.ReadContentAsBase64())) + { + if (isList || isEnum) + { + result = model.Deserialize(ms, null, type, null); + } + else + { + ProtoReader protoReader = null; + try + { + protoReader = ProtoReader.Create(ms, model, null, ProtoReader.TO_EOF); + result = model.Deserialize(key, null, protoReader); + } + finally + { + ProtoReader.Recycle(protoReader); + } + } + } + reader.ReadEndElement(); + return result; + } + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/ServiceModel/XmlProtoSerializer.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/ServiceModel/XmlProtoSerializer.cs.meta new file mode 100644 index 0000000..d564f13 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/ServiceModel/XmlProtoSerializer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: bca9bc75e9bb7c841b04b85204a0c9f6 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/SubItemToken.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/SubItemToken.cs new file mode 100644 index 0000000..51f4a24 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/SubItemToken.cs @@ -0,0 +1,16 @@ + +using System; + +namespace ProtoBuf +{ + /// + /// Used to hold particulars relating to nested objects. This is opaque to the caller - simply + /// give back the token you are given at the end of an object. + /// + public readonly struct SubItemToken + { + internal readonly long value64; + internal SubItemToken(int value) => value64 = value; + internal SubItemToken(long value) => value64 = value; + } +} diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/SubItemToken.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/SubItemToken.cs.meta new file mode 100644 index 0000000..75435a1 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/SubItemToken.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: bbb510795b4f3fa46aeecbd4521adfc0 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/WireType.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/WireType.cs new file mode 100644 index 0000000..ab4fa20 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/WireType.cs @@ -0,0 +1,50 @@ +namespace ProtoBuf +{ + /// + /// Indicates the encoding used to represent an individual value in a protobuf stream + /// + public enum WireType + { + /// + /// Represents an error condition + /// + None = -1, + + /// + /// Base-128 variant-length encoding + /// + Variant = 0, + + /// + /// Fixed-length 8-byte encoding + /// + Fixed64 = 1, + + /// + /// Length-variant-prefixed encoding + /// + String = 2, + + /// + /// Indicates the start of a group + /// + StartGroup = 3, + + /// + /// Indicates the end of a group + /// + EndGroup = 4, + + /// + /// Fixed-length 4-byte encoding + /// 10 + Fixed32 = 5, + + /// + /// This is not a formal wire-type in the "protocol buffers" spec, but + /// denotes a variant integer that should be interpreted using + /// zig-zag semantics (so -ve numbers aren't a significant overhead) + /// + SignedVariant = WireType.Variant | (1 << 3), + } +} diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/WireType.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/WireType.cs.meta new file mode 100644 index 0000000..2566026 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/WireType.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0a8403cbfeff31942997d1726a909e89 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/protobuf-net.csproj b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/protobuf-net.csproj new file mode 100644 index 0000000..e72f4ab --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/protobuf-net.csproj @@ -0,0 +1,86 @@ + + + protobuf-net + protobuf-net + Provides simple access to fast and efficient "Protocol Buffers" serialization from .NET applications + net20;net35;net452;netstandard2.0;netcoreapp3.1 + true + EMIT_ASSEMBLY_INFO + + True + + + net + true + true + true + true + true + Debug;Release;VS + + + + false + + + false + false + false + false + $(DefineConstants);COREFX;UAP + + + $(DefineConstants);COREFX + standard + true + false + + + $(DefineConstants);COREFX + none + true + false + + + + $(DefineConstants);FEAT_COMPILER + + + $(DefineConstants);FEAT_SERVICEMODEL + + + $(DefineConstants);FEAT_SERVICECONFIGMODEL + + + $(DefineConstants);PLAT_XMLSERIALIZER + + + $(DefineConstants);PLAT_BINARYFORMATTER + + + + + + + + + + + + + + + + + + + + + + + + all + runtime; build; native; contentfiles; analyzers + + + \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/protobuf-net.csproj.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/protobuf-net.csproj.meta new file mode 100644 index 0000000..0950983 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/Protobuf-net/protobuf-net.csproj.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 3b9128b665b538746a11489aee369030 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/WSocket.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/WSocket.meta new file mode 100644 index 0000000..d5dbe80 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/WSocket.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: fa968f65de2ed4f10a755c0646cde595 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/WSocket/Core.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/WSocket/Core.meta new file mode 100644 index 0000000..75a5349 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/WSocket/Core.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 8b3a2a8f55d4a47f599b1fa3ed612389 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/WSocket/Core/CloseEventArgs.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/WSocket/Core/CloseEventArgs.cs new file mode 100644 index 0000000..d0d5831 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/WSocket/Core/CloseEventArgs.cs @@ -0,0 +1,89 @@ +using System; + +namespace UnityWebSocket +{ + /// + /// Represents the event data for the event. + /// + /// + /// + /// That event occurs when the WebSocket connection has been closed. + /// + /// + /// If you would like to get the reason for the close, you should access + /// the or property. + /// + /// + public class CloseEventArgs : EventArgs + { + #region Internal Constructors + + internal CloseEventArgs() + { + } + + internal CloseEventArgs(ushort code) + : this(code, null) + { + } + + internal CloseEventArgs(CloseStatusCode code) + : this((ushort)code, null) + { + } + + internal CloseEventArgs(CloseStatusCode code, string reason) + : this((ushort)code, reason) + { + } + + internal CloseEventArgs(ushort code, string reason) + { + Code = code; + Reason = reason; + } + + #endregion + + #region Public Properties + + /// + /// Gets the status code for the close. + /// + /// + /// A that represents the status code for the close if any. + /// + public ushort Code { get; private set; } + + /// + /// Gets the reason for the close. + /// + /// + /// A that represents the reason for the close if any. + /// + public string Reason { get; private set; } + + /// + /// Gets a value indicating whether the connection has been closed cleanly. + /// + /// + /// true if the connection has been closed cleanly; otherwise, false. + /// + public bool WasClean { get; internal set; } + + /// + /// Enum value same as Code + /// + public CloseStatusCode StatusCode + { + get + { + if (Enum.IsDefined(typeof(CloseStatusCode), Code)) + return (CloseStatusCode)Code; + return CloseStatusCode.Unknown; + } + } + + #endregion + } +} diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/WSocket/Core/CloseEventArgs.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/WSocket/Core/CloseEventArgs.cs.meta new file mode 100644 index 0000000..6e2a928 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/WSocket/Core/CloseEventArgs.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 29b987d07ba15434cb1744135a7a5416 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/WSocket/Core/CloseStatusCode.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/WSocket/Core/CloseStatusCode.cs new file mode 100644 index 0000000..0da2ddb --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/WSocket/Core/CloseStatusCode.cs @@ -0,0 +1,91 @@ +namespace UnityWebSocket +{ + /// + /// Indicates the status code for the WebSocket connection close. + /// + /// + /// + /// The values of this enumeration are defined in + /// + /// Section 7.4 of RFC 6455. + /// + /// + /// "Reserved value" cannot be sent as a status code in + /// closing handshake by an endpoint. + /// + /// + public enum CloseStatusCode : ushort + { + Unknown = 65534, + /// + /// Equivalent to close status 1000. Indicates normal close. + /// + Normal = 1000, + /// + /// Equivalent to close status 1001. Indicates that an endpoint is + /// going away. + /// + Away = 1001, + /// + /// Equivalent to close status 1002. Indicates that an endpoint is + /// terminating the connection due to a protocol error. + /// + ProtocolError = 1002, + /// + /// Equivalent to close status 1003. Indicates that an endpoint is + /// terminating the connection because it has received a type of + /// data that it cannot accept. + /// + UnsupportedData = 1003, + /// + /// Equivalent to close status 1004. Still undefined. A Reserved value. + /// + Undefined = 1004, + /// + /// Equivalent to close status 1005. Indicates that no status code was + /// actually present. A Reserved value. + /// + NoStatus = 1005, + /// + /// Equivalent to close status 1006. Indicates that the connection was + /// closed abnormally. A Reserved value. + /// + Abnormal = 1006, + /// + /// Equivalent to close status 1007. Indicates that an endpoint is + /// terminating the connection because it has received a message that + /// contains data that is not consistent with the type of the message. + /// + InvalidData = 1007, + /// + /// Equivalent to close status 1008. Indicates that an endpoint is + /// terminating the connection because it has received a message that + /// violates its policy. + /// + PolicyViolation = 1008, + /// + /// Equivalent to close status 1009. Indicates that an endpoint is + /// terminating the connection because it has received a message that + /// is too big to process. + /// + TooBig = 1009, + /// + /// Equivalent to close status 1010. Indicates that a client is + /// terminating the connection because it has expected the server to + /// negotiate one or more extension, but the server did not return + /// them in the handshake response. + /// + MandatoryExtension = 1010, + /// + /// Equivalent to close status 1011. Indicates that a server is + /// terminating the connection because it has encountered an unexpected + /// condition that prevented it from fulfilling the request. + /// + ServerError = 1011, + /// + /// Equivalent to close status 1015. Indicates that the connection was + /// closed due to a failure to perform a TLS handshake. A Reserved value. + /// + TlsHandshakeFailure = 1015, + } +} diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/WSocket/Core/CloseStatusCode.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/WSocket/Core/CloseStatusCode.cs.meta new file mode 100644 index 0000000..48e9660 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/WSocket/Core/CloseStatusCode.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4e34ee317292e4225a10427cc35f85ec +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/WSocket/Core/ErrorEventArgs.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/WSocket/Core/ErrorEventArgs.cs new file mode 100644 index 0000000..cfb91b8 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/WSocket/Core/ErrorEventArgs.cs @@ -0,0 +1,59 @@ +using System; + +namespace UnityWebSocket +{ + /// + /// Represents the event data for the event. + /// + /// + /// + /// That event occurs when the gets an error. + /// + /// + /// If you would like to get the error message, you should access + /// the property. + /// + /// + /// And if the error is due to an exception, you can get it by accessing + /// the property. + /// + /// + public class ErrorEventArgs : EventArgs + { + #region Internal Constructors + + internal ErrorEventArgs(string message) + : this(message, null) + { + } + + internal ErrorEventArgs(string message, Exception exception) + { + this.Message = message; + this.Exception = exception; + } + + #endregion + + #region Public Properties + + /// + /// Gets the exception that caused the error. + /// + /// + /// An instance that represents the cause of + /// the error if it is due to an exception; otherwise, . + /// + public Exception Exception { get; private set; } + + /// + /// Gets the error message. + /// + /// + /// A that represents the error message. + /// + public string Message { get; private set; } + + #endregion + } +} diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/WSocket/Core/ErrorEventArgs.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/WSocket/Core/ErrorEventArgs.cs.meta new file mode 100644 index 0000000..47a5055 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/WSocket/Core/ErrorEventArgs.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 884e7db60b6444154b7200e0e436f2de +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/WSocket/Core/IWebSocket.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/WSocket/Core/IWebSocket.cs new file mode 100644 index 0000000..3e08d4b --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/WSocket/Core/IWebSocket.cs @@ -0,0 +1,143 @@ +using System; + +namespace UnityWebSocket +{ + /// + /// IWebSocket indicate a network connection. + /// It can be connecting, connected, closing or closed state. + /// You can send and receive messages by using it. + /// Register callbacks for handling messages. + /// ----------------------------------------------------------- + /// IWebSocket 表示一个网络连接, + /// 它可以是 connecting connected closing closed 状态, + /// 可以发送和接收消息, + /// 通过注册消息回调,来处理接收到的消息。 + /// + public interface IWebSocket + { + /// + /// Establishes a connection asynchronously. + /// + /// + /// + /// This method does not wait for the connect process to be complete. + /// + /// + /// This method does nothing if the connection has already been + /// established. + /// + /// + /// + /// + /// This instance is not a client. + /// + /// + /// -or- + /// + /// + /// The close process is in progress. + /// + /// + /// -or- + /// + /// + /// A series of reconnecting has failed. + /// + /// + void ConnectAsync(); + + /// + /// Closes the connection asynchronously. + /// + /// + /// + /// This method does not wait for the close to be complete. + /// + /// + /// This method does nothing if the current state of the connection is + /// Closing or Closed. + /// + /// + void CloseAsync(); + + /// + /// Sends the specified data asynchronously using the WebSocket connection. + /// + /// + /// This method does not wait for the send to be complete. + /// + /// + /// An array of that represents the binary data to send. + /// + /// + /// The current state of the connection is not Open. + /// + /// + /// is . + /// + void SendAsync(byte[] data); + + /// + /// Sends the specified data using the WebSocket connection. + /// + /// + /// A that represents the text data to send. + /// + /// + /// The current state of the connection is not Open. + /// + /// + /// is . + /// + /// + /// could not be UTF-8 encoded. + /// + void SendAsync(string text); + + /// + /// get the address which to connect. + /// + string Address { get; } + + /// + /// get sub protocols . + /// + string[] SubProtocols { get; } + + /// + /// Gets the current state of the connection. + /// + /// + /// + /// One of the enum values. + /// + /// + /// It indicates the current state of the connection. + /// + /// + /// The default value is . + /// + /// + WebSocketState ReadyState { get; } + + /// + /// Occurs when the WebSocket connection has been established. + /// + event EventHandler OnOpen; + + /// + /// Occurs when the WebSocket connection has been closed. + /// + event EventHandler OnClose; + + /// + /// Occurs when the gets an error. + /// + event EventHandler OnError; + + /// + /// Occurs when the receives a message. + /// + event EventHandler OnMessage; + } +} diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/WSocket/Core/IWebSocket.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/WSocket/Core/IWebSocket.cs.meta new file mode 100644 index 0000000..ae65825 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/WSocket/Core/IWebSocket.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 37ee2146eb8c34ffab8b081a632b05cf +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/WSocket/Core/MessageEventArgs.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/WSocket/Core/MessageEventArgs.cs new file mode 100644 index 0000000..a80fbae --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/WSocket/Core/MessageEventArgs.cs @@ -0,0 +1,115 @@ +using System; +using System.Text; + +namespace UnityWebSocket +{ + public class MessageEventArgs : EventArgs + { + private byte[] _rawData; + private string _data; + + internal MessageEventArgs(Opcode opcode, byte[] rawData) + { + Opcode = opcode; + _rawData = rawData; + } + + internal MessageEventArgs(Opcode opcode, string data) + { + Opcode = opcode; + _data = data; + } + + /// + /// Gets the opcode for the message. + /// + /// + /// , . + /// + internal Opcode Opcode { get; private set; } + + /// + /// Gets the message data as a . + /// + /// + /// A that represents the message data if its type is + /// text and if decoding it to a string has successfully done; + /// otherwise, . + /// + public string Data + { + get + { + SetData(); + return _data; + } + } + + /// + /// Gets the message data as an array of . + /// + /// + /// An array of that represents the message data. + /// + public byte[] RawData + { + get + { + SetRawData(); + return _rawData; + } + } + + /// + /// Gets a value indicating whether the message type is binary. + /// + /// + /// true if the message type is binary; otherwise, false. + /// + public bool IsBinary + { + get + { + return Opcode == Opcode.Binary; + } + } + + /// + /// Gets a value indicating whether the message type is text. + /// + /// + /// true if the message type is text; otherwise, false. + /// + public bool IsText + { + get + { + return Opcode == Opcode.Text; + } + } + + private void SetData() + { + if (_data != null) return; + + if (RawData == null) + { + return; + } + + _data = Encoding.UTF8.GetString(RawData); + } + + private void SetRawData() + { + if (_rawData != null) return; + + if (_data == null) + { + return; + } + + _rawData = Encoding.UTF8.GetBytes(_data); + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/WSocket/Core/MessageEventArgs.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/WSocket/Core/MessageEventArgs.cs.meta new file mode 100644 index 0000000..1c3a7d1 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/WSocket/Core/MessageEventArgs.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b44eda173b4924081bab76ae9d1b0a9c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/WSocket/Core/Opcode.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/WSocket/Core/Opcode.cs new file mode 100644 index 0000000..3e758e2 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/WSocket/Core/Opcode.cs @@ -0,0 +1,26 @@ +namespace UnityWebSocket +{ + /// + /// Indicates the WebSocket frame type. + /// + /// + /// The values of this enumeration are defined in + /// + /// Section 5.2 of RFC 6455. + /// + public enum Opcode : byte + { + /// + /// Equivalent to numeric value 1. Indicates text frame. + /// + Text = 0x1, + /// + /// Equivalent to numeric value 2. Indicates binary frame. + /// + Binary = 0x2, + /// + /// Equivalent to numeric value 8. Indicates connection close frame. + /// + Close = 0x8, + } +} diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/WSocket/Core/Opcode.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/WSocket/Core/Opcode.cs.meta new file mode 100644 index 0000000..a7ed802 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/WSocket/Core/Opcode.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: eeac0ef90273544ebbae046672caf362 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/WSocket/Core/OpenEventArgs.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/WSocket/Core/OpenEventArgs.cs new file mode 100644 index 0000000..fa84a33 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/WSocket/Core/OpenEventArgs.cs @@ -0,0 +1,11 @@ +using System; + +namespace UnityWebSocket +{ + public class OpenEventArgs : EventArgs + { + internal OpenEventArgs() + { + } + } +} diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/WSocket/Core/OpenEventArgs.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/WSocket/Core/OpenEventArgs.cs.meta new file mode 100644 index 0000000..0cfe2c2 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/WSocket/Core/OpenEventArgs.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 5fb6fd704bd4e4b8ba63cd0b28712955 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/WSocket/Core/Settings.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/WSocket/Core/Settings.cs new file mode 100644 index 0000000..f1646c5 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/WSocket/Core/Settings.cs @@ -0,0 +1,12 @@ +namespace UnityWebSocket +{ + public static class Settings + { + public const string GITHUB = "https://github.com/psygames/UnityWebSocket"; + public const string QQ_GROUP = "1126457634"; + public const string QQ_GROUP_LINK = "https://qm.qq.com/cgi-bin/qm/qr?k=KcexYJ9aYwogFXbj2aN0XHH5b2G7ICmd"; + public const string EMAIL = "799329256@qq.com"; + public const string AUHTOR = "psygames"; + public const string VERSION = "2.8.6"; + } +} diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/WSocket/Core/Settings.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/WSocket/Core/Settings.cs.meta new file mode 100644 index 0000000..e8e3622 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/WSocket/Core/Settings.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e268303c7a605e343b1b132e5559f01f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/WSocket/Core/WebSocketState.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/WSocket/Core/WebSocketState.cs new file mode 100644 index 0000000..796ab15 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/WSocket/Core/WebSocketState.cs @@ -0,0 +1,36 @@ +namespace UnityWebSocket +{ + /// + /// Reference html5 WebSocket ReadyState Properties + /// Indicates the state of a WebSocket connection. + /// + /// + /// The values of this enumeration are defined in + /// + /// The WebSocket API. + /// + public enum WebSocketState : ushort + { + /// + /// Equivalent to numeric value 0. Indicates that the connection has not + /// yet been established. + /// + Connecting = 0, + /// + /// Equivalent to numeric value 1. Indicates that the connection has + /// been established, and the communication is possible. + /// + Open = 1, + /// + /// Equivalent to numeric value 2. Indicates that the connection is + /// going through the closing handshake, or the close method has + /// been invoked. + /// + Closing = 2, + /// + /// Equivalent to numeric value 3. Indicates that the connection has + /// been closed or could not be established. + /// + Closed = 3 + } +} diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/WSocket/Core/WebSocketState.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/WSocket/Core/WebSocketState.cs.meta new file mode 100644 index 0000000..94877ec --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/WSocket/Core/WebSocketState.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 5f6567ad13cb147a59f8af784f1c5f60 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/WSocket/Implementation.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/WSocket/Implementation.meta new file mode 100644 index 0000000..abb1981 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/WSocket/Implementation.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 396c66b333d624d539153070900bb73b +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/WSocket/Implementation/NoWebGL.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/WSocket/Implementation/NoWebGL.meta new file mode 100644 index 0000000..dc70a45 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/WSocket/Implementation/NoWebGL.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 6c110a898ae8b0b41bcf4da49c2b0425 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/WSocket/Implementation/NoWebGL/WebSocket.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/WSocket/Implementation/NoWebGL/WebSocket.cs new file mode 100644 index 0000000..3054734 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/WSocket/Implementation/NoWebGL/WebSocket.cs @@ -0,0 +1,345 @@ +#if !NET_LEGACY && (UNITY_EDITOR || !UNITY_WEBGL) +using System; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using System.Net.WebSockets; +using System.IO; +using System.Collections.Concurrent; + +namespace UnityWebSocket +{ + public class WebSocket : IWebSocket + { + public string Address { get; private set; } + public string[] SubProtocols { get; private set; } + + public WebSocketState ReadyState + { + get + { + if (socket == null) + return WebSocketState.Closed; + switch (socket.State) + { + case System.Net.WebSockets.WebSocketState.Closed: + case System.Net.WebSockets.WebSocketState.None: + return WebSocketState.Closed; + case System.Net.WebSockets.WebSocketState.CloseReceived: + case System.Net.WebSockets.WebSocketState.CloseSent: + return WebSocketState.Closing; + case System.Net.WebSockets.WebSocketState.Connecting: + return WebSocketState.Connecting; + case System.Net.WebSockets.WebSocketState.Open: + return WebSocketState.Open; + } + return WebSocketState.Closed; + } + } + + public event EventHandler OnOpen; + public event EventHandler OnClose; + public event EventHandler OnError; + public event EventHandler OnMessage; + + private ClientWebSocket socket; + private bool isOpening => socket != null && socket.State == System.Net.WebSockets.WebSocketState.Open; + private ConcurrentQueue sendQueue = new ConcurrentQueue(); + private ConcurrentQueue eventQueue = new ConcurrentQueue(); + private bool closeProcessing; + private CancellationTokenSource cts = null; + + #region APIs + public WebSocket(string address) + { + this.Address = address; + } + + public WebSocket(string address, string subProtocol) + { + this.Address = address; + this.SubProtocols = new string[] { subProtocol }; + } + + public WebSocket(string address, string[] subProtocols) + { + this.Address = address; + this.SubProtocols = subProtocols; + } + + public void ConnectAsync() + { + if (socket != null) + { + HandleError(new Exception("Socket is busy.")); + return; + } + + WebSocketManager.Instance.Add(this); + + socket = new ClientWebSocket(); + cts = new CancellationTokenSource(); + + // support sub protocols + if (this.SubProtocols != null) + { + foreach (var protocol in this.SubProtocols) + { + if (string.IsNullOrEmpty(protocol)) continue; + Log($"Add Sub Protocol {protocol}"); + socket.Options.AddSubProtocol(protocol); + } + } + + Task.Run(ConnectTask); + } + + public void CloseAsync() + { + if (!isOpening) + { + return; + } + + closeProcessing = true; + } + + public void SendAsync(byte[] data, int offset, int len) + { + if (!isOpening) return; + var buffer = new SendBuffer(data, offset, len, WebSocketMessageType.Binary); + sendQueue.Enqueue(buffer); + } + + public void SendAsync(byte[] data) + { + if (!isOpening) return; + var buffer = new SendBuffer(data, 0, data.Length, WebSocketMessageType.Binary); + sendQueue.Enqueue(buffer); + } + + public void SendAsync(string text) + { + if (!isOpening) return; + var data = Encoding.UTF8.GetBytes(text); + var buffer = new SendBuffer(data, 0, data.Length, WebSocketMessageType.Text); + sendQueue.Enqueue(buffer); + } + #endregion + + class SendBuffer + { + public int offset; + public int len; + public byte[] data; + public WebSocketMessageType type; + public SendBuffer(byte[] data, int offset, int len, WebSocketMessageType type) + { + this.offset = offset; + this.len = len; + this.data = data; + this.type = type; + } + } + + private void CleanSendQueue() + { + while (sendQueue.TryDequeue(out var _)) ; + } + + private void CleanEventQueue() + { + while (eventQueue.TryDequeue(out var _)) ; + } + + private async Task ConnectTask() + { + Log("Connect Task Begin ..."); + + try + { + var uri = new Uri(Address); + await socket.ConnectAsync(uri, cts.Token); + } + catch (Exception e) + { + HandleError(e); + HandleClose((ushort)CloseStatusCode.Abnormal, e.Message); + return; + } + + HandleOpen(); + + Log("Connect Task Success !"); + + StartReceiveTask(); + StartSendTask(); + } + + private async void StartSendTask() + { + Log("Send Task Begin ..."); + + try + { + while (!closeProcessing && socket != null && cts != null && !cts.IsCancellationRequested) + { + while (!closeProcessing && sendQueue.Count > 0 && sendQueue.TryDequeue(out var buffer)) + { + Log($"Send, type: {buffer.type}, size: {buffer.data.Length}, queue left: {sendQueue.Count}"); + await socket.SendAsync(new ArraySegment(buffer.data,buffer.offset, buffer.len), buffer.type, true, cts.Token); + } + Thread.Sleep(3); + } + + if (closeProcessing && socket != null && cts != null && !cts.IsCancellationRequested) + { + CleanSendQueue(); + Log($"Close Send Begin ..."); + await socket.CloseOutputAsync(WebSocketCloseStatus.NormalClosure, "Normal Closure", cts.Token); + Log($"Close Send Success !"); + } + } + catch (Exception e) + { + HandleError(e); + } + finally + { + closeProcessing = false; + } + + Log("Send Task End !"); + } + + private async void StartReceiveTask() + { + Log("Receive Task Begin ..."); + + string closeReason = ""; + ushort closeCode = 0; + bool isClosed = false; + var segment = new ArraySegment(new byte[8192]); + var ms = new MemoryStream(); + + try + { + while (!isClosed && !cts.IsCancellationRequested) + { + var result = await socket.ReceiveAsync(segment, cts.Token); + ms.Write(segment.Array, 0, result.Count); + if (!result.EndOfMessage) continue; + var data = ms.ToArray(); + ms.SetLength(0); + switch (result.MessageType) + { + case WebSocketMessageType.Binary: + HandleMessage(Opcode.Binary, data); + break; + case WebSocketMessageType.Text: + HandleMessage(Opcode.Text, data); + break; + case WebSocketMessageType.Close: + isClosed = true; + closeCode = (ushort)result.CloseStatus; + closeReason = result.CloseStatusDescription; + break; + } + } + } + catch (Exception e) + { + HandleError(e); + closeCode = (ushort)CloseStatusCode.Abnormal; + closeReason = e.Message; + } + finally + { + ms.Close(); + } + + HandleClose(closeCode, closeReason); + + Log("Receive Task End !"); + } + + private void SocketDispose() + { + Log("Dispose"); + WebSocketManager.Instance.Remove(this); + CleanSendQueue(); + CleanEventQueue(); + socket.Dispose(); + socket = null; + cts.Dispose(); + cts = null; + } + + private void HandleOpen() + { + Log("OnOpen"); + eventQueue.Enqueue(new OpenEventArgs()); + } + + private void HandleMessage(Opcode opcode, byte[] rawData) + { + Log($"OnMessage, type: {opcode}, size: {rawData.Length}"); + eventQueue.Enqueue(new MessageEventArgs(opcode, rawData)); + } + + private void HandleClose(ushort code, string reason) + { + Log($"OnClose, code: {code}, reason: {reason}"); + eventQueue.Enqueue(new CloseEventArgs(code, reason)); + } + + private void HandleError(Exception exception) + { + Log("OnError, error: " + exception.Message); + eventQueue.Enqueue(new ErrorEventArgs(exception.Message)); + } + + internal void Update() + { + while (eventQueue.Count > 0 && eventQueue.TryDequeue(out var e)) + { + if (e is CloseEventArgs) + { + OnClose?.Invoke(this, e as CloseEventArgs); + SocketDispose(); + break; + } + else if (e is OpenEventArgs) + { + OnOpen?.Invoke(this, e as OpenEventArgs); + } + else if (e is MessageEventArgs) + { + OnMessage?.Invoke(this, e as MessageEventArgs); + } + else if (e is ErrorEventArgs) + { + OnError?.Invoke(this, e as ErrorEventArgs); + } + } + } + + internal void Abort() + { + Log("Abort"); + if (cts != null) + { + cts.Cancel(); + } + } + + [System.Diagnostics.Conditional("UNITY_WEB_SOCKET_LOG")] + static void Log(string msg) + { + var time = DateTime.Now.ToString("HH:mm:ss.fff"); + var thread = Thread.CurrentThread.ManagedThreadId; + UnityEngine.Debug.Log($"[{time}][UnityWebSocket][T-{thread:D3}] {msg}"); + } + } +} +#endif diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/WSocket/Implementation/NoWebGL/WebSocket.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/WSocket/Implementation/NoWebGL/WebSocket.cs.meta new file mode 100644 index 0000000..cbb5e53 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/WSocket/Implementation/NoWebGL/WebSocket.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d10f88a23641b4beb8df74460fb7f705 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/WSocket/Implementation/NoWebGL/WebSocketManager.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/WSocket/Implementation/NoWebGL/WebSocketManager.cs new file mode 100644 index 0000000..e3f82bd --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/WSocket/Implementation/NoWebGL/WebSocketManager.cs @@ -0,0 +1,72 @@ +#if !NET_LEGACY && (UNITY_EDITOR || !UNITY_WEBGL) +using System.Collections.Generic; +using UnityEngine; + +namespace UnityWebSocket +{ + [DisallowMultipleComponent] + [DefaultExecutionOrder(-10000)] + internal class WebSocketManager : MonoBehaviour + { + private const string rootName = "[UnityWebSocket]"; + private static WebSocketManager _instance; + public static WebSocketManager Instance + { + get + { + if (!_instance) CreateInstance(); + return _instance; + } + } + + private void Awake() + { + DontDestroyOnLoad(gameObject); + } + + public static void CreateInstance() + { + GameObject go = GameObject.Find("/" + rootName); + if (!go) go = new GameObject(rootName); + _instance = go.GetComponent(); + if (!_instance) _instance = go.AddComponent(); + } + + private readonly List sockets = new List(); + + public void Add(WebSocket socket) + { + if (!sockets.Contains(socket)) + sockets.Add(socket); + } + + public void Remove(WebSocket socket) + { + if (sockets.Contains(socket)) + sockets.Remove(socket); + } + + private void Update() + { + if (sockets.Count <= 0) return; + for (int i = sockets.Count - 1; i >= 0; i--) + { + sockets[i].Update(); + } + } + + private void OnDisable() + { + SocketAbort(); + } + + private void SocketAbort() + { + for (int i = sockets.Count - 1; i >= 0; i--) + { + sockets[i].Abort(); + } + } + } +} +#endif \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/WSocket/Implementation/NoWebGL/WebSocketManager.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/WSocket/Implementation/NoWebGL/WebSocketManager.cs.meta new file mode 100644 index 0000000..1e26dc8 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/WSocket/Implementation/NoWebGL/WebSocketManager.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 99157fb5def394c83a9e5342036c92b0 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/WSocket/Implementation/WebGL.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/WSocket/Implementation/WebGL.meta new file mode 100644 index 0000000..e9c4e7b --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/WSocket/Implementation/WebGL.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 1fb37927ec1ce4def9c5e7cff883f9f5 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/WSocket/Implementation/WebGL/WebSocket.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/WSocket/Implementation/WebGL/WebSocket.cs new file mode 100644 index 0000000..59a98b8 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/WSocket/Implementation/WebGL/WebSocket.cs @@ -0,0 +1,154 @@ +#if !UNITY_EDITOR && UNITY_WEBGL +using System; + +namespace UnityWebSocket +{ + public class WebSocket : IWebSocket + { + public string Address { get; private set; } + public string[] SubProtocols { get; private set; } + public WebSocketState ReadyState { get { return (WebSocketState)WebSocketManager.WebSocketGetState(instanceId); } } + + public event EventHandler OnOpen; + public event EventHandler OnClose; + public event EventHandler OnError; + public event EventHandler OnMessage; + + internal int instanceId = 0; + + public WebSocket(string address) + { + this.Address = address; + AllocateInstance(); + } + + public WebSocket(string address, string subProtocol) + { + this.Address = address; + this.SubProtocols = new string[] { subProtocol }; + AllocateInstance(); + } + + public WebSocket(string address, string[] subProtocols) + { + this.Address = address; + this.SubProtocols = subProtocols; + AllocateInstance(); + } + + internal void AllocateInstance() + { + instanceId = WebSocketManager.AllocateInstance(this.Address); + Log($"Allocate socket with instanceId: {instanceId}"); + if (this.SubProtocols == null) return; + foreach (var protocol in this.SubProtocols) + { + if (string.IsNullOrEmpty(protocol)) continue; + Log($"Add Sub Protocol {protocol}, with instanceId: {instanceId}"); + int code = WebSocketManager.WebSocketAddSubProtocol(instanceId, protocol); + if (code < 0) + { + HandleOnError(GetErrorMessageFromCode(code)); + break; + } + } + } + + ~WebSocket() + { + Log($"Free socket with instanceId: {instanceId}"); + WebSocketManager.WebSocketFree(instanceId); + } + + public void ConnectAsync() + { + Log($"Connect with instanceId: {instanceId}"); + WebSocketManager.Add(this); + int code = WebSocketManager.WebSocketConnect(instanceId); + if (code < 0) HandleOnError(GetErrorMessageFromCode(code)); + } + + public void CloseAsync() + { + Log($"Close with instanceId: {instanceId}"); + int code = WebSocketManager.WebSocketClose(instanceId, (int)CloseStatusCode.Normal, "Normal Closure"); + if (code < 0) HandleOnError(GetErrorMessageFromCode(code)); + } + + public void SendAsync(string text) + { + Log($"Send, type: {Opcode.Text}, size: {text.Length}"); + int code = WebSocketManager.WebSocketSendStr(instanceId, text); + if (code < 0) HandleOnError(GetErrorMessageFromCode(code)); + } + + public void SendAsync(byte[] data) + { + Log($"Send, type: {Opcode.Binary}, size: {data.Length}"); + int code = WebSocketManager.WebSocketSend(instanceId, data, 0, data.Length); + if (code < 0) HandleOnError(GetErrorMessageFromCode(code)); + } + + public void SendAsync(byte[] data, int offset, int len) + { + Log($"Send, type: {Opcode.Binary}, offset: {offset}, len: {len}, size: {data.Length}"); + int code = WebSocketManager.WebSocketSend(instanceId, data, offset, len); + if (code < 0) HandleOnError(GetErrorMessageFromCode(code)); + } + + internal void HandleOnOpen() + { + Log("OnOpen"); + OnOpen?.Invoke(this, new OpenEventArgs()); + } + + internal void HandleOnMessage(byte[] rawData) + { + Log($"OnMessage, type: {Opcode.Binary}, size: {rawData.Length}"); + OnMessage?.Invoke(this, new MessageEventArgs(Opcode.Binary, rawData)); + } + + internal void HandleOnMessageStr(string data) + { + Log($"OnMessage, type: {Opcode.Text}, size: {data.Length}"); + OnMessage?.Invoke(this, new MessageEventArgs(Opcode.Text, data)); + } + + internal void HandleOnClose(ushort code, string reason) + { + Log($"OnClose, code: {code}, reason: {reason}"); + OnClose?.Invoke(this, new CloseEventArgs(code, reason)); + WebSocketManager.Remove(instanceId); + } + + internal void HandleOnError(string msg) + { + Log("OnError, error: " + msg); + OnError?.Invoke(this, new ErrorEventArgs(msg)); + } + + internal static string GetErrorMessageFromCode(int errorCode) + { + switch (errorCode) + { + case -1: return "WebSocket instance not found."; + case -2: return "WebSocket is already connected or in connecting state."; + case -3: return "WebSocket is not connected."; + case -4: return "WebSocket is already closing."; + case -5: return "WebSocket is already closed."; + case -6: return "WebSocket is not in open state."; + case -7: return "Cannot close WebSocket, An invalid code was specified or reason is too long."; + case -8: return "Not support buffer slice. "; + default: return $"Unknown error code {errorCode}."; + } + } + + [System.Diagnostics.Conditional("UNITY_WEB_SOCKET_LOG")] + static void Log(string msg) + { + var time = DateTime.Now.ToString("HH:mm:ss.fff"); + UnityEngine.Debug.Log($"[{time}][UnityWebSocket] {msg}"); + } + } +} +#endif diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/WSocket/Implementation/WebGL/WebSocket.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/WSocket/Implementation/WebGL/WebSocket.cs.meta new file mode 100644 index 0000000..ffe47c7 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/WSocket/Implementation/WebGL/WebSocket.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 74a5b3c22251243d2a2f33e74741559d +timeCreated: 1466578513 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/WSocket/Implementation/WebGL/WebSocketManager.cs b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/WSocket/Implementation/WebGL/WebSocketManager.cs new file mode 100644 index 0000000..0a862a4 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/WSocket/Implementation/WebGL/WebSocketManager.cs @@ -0,0 +1,159 @@ +#if !UNITY_EDITOR && UNITY_WEBGL +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using AOT; + +namespace UnityWebSocket +{ + /// + /// Class providing static access methods to work with JSLIB WebSocket + /// + internal static class WebSocketManager + { + /* Map of websocket instances */ + private static Dictionary sockets = new Dictionary(); + + /* Delegates */ + public delegate void OnOpenCallback(int instanceId); + public delegate void OnMessageCallback(int instanceId, IntPtr msgPtr, int msgSize); + public delegate void OnMessageStrCallback(int instanceId, IntPtr msgStrPtr); + public delegate void OnErrorCallback(int instanceId, IntPtr errorPtr); + public delegate void OnCloseCallback(int instanceId, int closeCode, IntPtr reasonPtr); + + /* WebSocket JSLIB functions */ + [DllImport("__Internal")] + public static extern int WebSocketConnect(int instanceId); + + [DllImport("__Internal")] + public static extern int WebSocketClose(int instanceId, int code, string reason); + + [DllImport("__Internal")] + public static extern int WebSocketSend(int instanceId, byte[] dataPtr, int offset, int dataLength); + + [DllImport("__Internal")] + public static extern int WebSocketSendStr(int instanceId, string data); + + [DllImport("__Internal")] + public static extern int WebSocketGetState(int instanceId); + + /* WebSocket JSLIB callback setters and other functions */ + [DllImport("__Internal")] + public static extern int WebSocketAllocate(string url); + + [DllImport("__Internal")] + public static extern int WebSocketAddSubProtocol(int instanceId, string protocol); + + [DllImport("__Internal")] + public static extern void WebSocketFree(int instanceId); + + [DllImport("__Internal")] + public static extern void WebSocketSetOnOpen(OnOpenCallback callback); + + [DllImport("__Internal")] + public static extern void WebSocketSetOnMessage(OnMessageCallback callback); + + [DllImport("__Internal")] + public static extern void WebSocketSetOnMessageStr(OnMessageStrCallback callback); + + [DllImport("__Internal")] + public static extern void WebSocketSetOnError(OnErrorCallback callback); + + [DllImport("__Internal")] + public static extern void WebSocketSetOnClose(OnCloseCallback callback); + + [DllImport("__Internal")] + public static extern void WebSocketSetSupport6000(); + + /* If callbacks was initialized and set */ + private static bool isInitialized = false; + + /* Initialize WebSocket callbacks to JSLIB */ + private static void Initialize() + { + WebSocketSetOnOpen(DelegateOnOpenEvent); + WebSocketSetOnMessage(DelegateOnMessageEvent); + WebSocketSetOnMessageStr(DelegateOnMessageStrEvent); + WebSocketSetOnError(DelegateOnErrorEvent); + WebSocketSetOnClose(DelegateOnCloseEvent); +#if UNITY_6000_0_OR_NEWER + WebSocketSetSupport6000(); +#endif + + isInitialized = true; + } + + [MonoPInvokeCallback(typeof(OnOpenCallback))] + public static void DelegateOnOpenEvent(int instanceId) + { + if (sockets.TryGetValue(instanceId, out var socket)) + { + socket.HandleOnOpen(); + } + } + + [MonoPInvokeCallback(typeof(OnMessageCallback))] + public static void DelegateOnMessageEvent(int instanceId, IntPtr msgPtr, int msgSize) + { + if (sockets.TryGetValue(instanceId, out var socket)) + { + var bytes = new byte[msgSize]; + Marshal.Copy(msgPtr, bytes, 0, msgSize); + socket.HandleOnMessage(bytes); + } + } + + [MonoPInvokeCallback(typeof(OnMessageStrCallback))] + public static void DelegateOnMessageStrEvent(int instanceId, IntPtr msgStrPtr) + { + if (sockets.TryGetValue(instanceId, out var socket)) + { + string msgStr = Marshal.PtrToStringAuto(msgStrPtr); + socket.HandleOnMessageStr(msgStr); + } + } + + [MonoPInvokeCallback(typeof(OnErrorCallback))] + public static void DelegateOnErrorEvent(int instanceId, IntPtr errorPtr) + { + if (sockets.TryGetValue(instanceId, out var socket)) + { + string errorMsg = Marshal.PtrToStringAuto(errorPtr); + socket.HandleOnError(errorMsg); + } + } + + [MonoPInvokeCallback(typeof(OnCloseCallback))] + public static void DelegateOnCloseEvent(int instanceId, int closeCode, IntPtr reasonPtr) + { + if (sockets.TryGetValue(instanceId, out var socket)) + { + string reason = Marshal.PtrToStringAuto(reasonPtr); + socket.HandleOnClose((ushort)closeCode, reason); + } + } + + internal static int AllocateInstance(string address) + { + if (!isInitialized) Initialize(); + return WebSocketAllocate(address); + } + + internal static void Add(WebSocket socket) + { + if (!sockets.ContainsKey(socket.instanceId)) + { + sockets.Add(socket.instanceId, socket); + } + } + + internal static void Remove(int instanceId) + { + if (sockets.ContainsKey(instanceId)) + { + sockets.Remove(instanceId); + } + } + } +} +#endif diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/WSocket/Implementation/WebGL/WebSocketManager.cs.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/WSocket/Implementation/WebGL/WebSocketManager.cs.meta new file mode 100644 index 0000000..d0a16fe --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/WSocket/Implementation/WebGL/WebSocketManager.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 246cdc66a1e2047148371a8e56e17d3a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/WebGL.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/WebGL.meta new file mode 100644 index 0000000..404a7f6 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/WebGL.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: f1a1a6aea65cc413faf8fb4421138b29 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/WebGL/WebSocket.jslib b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/WebGL/WebSocket.jslib new file mode 100644 index 0000000..e669cd3 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/WebGL/WebSocket.jslib @@ -0,0 +1,392 @@ +var WebSocketLibrary = +{ + $webSocketManager: + { + /* + * Map of instances + * + * Instance structure: + * { + * url: string, + * ws: WebSocket, + * subProtocols: string[], + * } + */ + instances: {}, + + /* Last instance ID */ + lastId: 0, + + /* Event listeners */ + onOpen: null, + onMessage: null, + onMessageStr: null, + onError: null, + onClose: null, + + /* Support Unity 6000 */ + support6000: false + }, + + /** + * Support Unity 6000 + * + */ + WebSocketSetSupport6000: function() + { + webSocketManager.support6000 = true; + }, + + /** + * Set onOpen callback + * + * @param callback Reference to C# static function + */ + WebSocketSetOnOpen: function(callback) + { + webSocketManager.onOpen = callback; + }, + + /** + * Set onMessage callback + * + * @param callback Reference to C# static function + */ + WebSocketSetOnMessage: function(callback) + { + webSocketManager.onMessage = callback; + }, + + /** + * Set onMessageStr callback + * + * @param callback Reference to C# static function + */ + WebSocketSetOnMessageStr: function(callback) + { + webSocketManager.onMessageStr = callback; + }, + + /** + * Set onError callback + * + * @param callback Reference to C# static function + */ + WebSocketSetOnError: function(callback) + { + webSocketManager.onError = callback; + }, + + /** + * Set onClose callback + * + * @param callback Reference to C# static function + */ + WebSocketSetOnClose: function(callback) + { + webSocketManager.onClose = callback; + }, + + /** + * Allocate new WebSocket instance struct + * + * @param url Server URL + */ + WebSocketAllocate: function(urlPtr) + { + var url = UTF8ToString(urlPtr); + var id = ++webSocketManager.lastId; + webSocketManager.instances[id] = { + url: url, + ws: null, + }; + + return id; + }, + + /** + * Add Sub Protocol + * + * @param instanceId Instance ID + * @param protocol Sub Protocol + */ + WebSocketAddSubProtocol: function(instanceId, protocolPtr) + { + var instance = webSocketManager.instances[instanceId]; + if (!instance) return -1; + + var protocol = UTF8ToString(protocolPtr); + + if (instance.subProtocols == null) + instance.subProtocols = []; + + instance.subProtocols.push(protocol); + + return 0; + }, + + /** + * Remove reference to WebSocket instance + * + * If socket is not closed function will close it but onClose event will not be emitted because + * this function should be invoked by C# WebSocket destructor. + * + * @param instanceId Instance ID + */ + WebSocketFree: function(instanceId) + { + var instance = webSocketManager.instances[instanceId]; + if (!instance) return 0; + + // Close if not closed + if (instance.ws !== null && instance.ws.readyState < 2) + instance.ws.close(); + + // Remove reference + delete webSocketManager.instances[instanceId]; + + return 0; + }, + + /** + * Connect WebSocket to the server + * + * @param instanceId Instance ID + */ + WebSocketConnect: function(instanceId) + { + var instance = webSocketManager.instances[instanceId]; + if (!instance) return -1; + if (instance.ws !== null) return -2; + + if (instance.subProtocols != null) + instance.ws = new WebSocket(instance.url, instance.subProtocols); + else + instance.ws = new WebSocket(instance.url); + + instance.ws.onopen = function() + { + if (webSocketManager.support6000) + { + {{{ makeDynCall('vi', 'webSocketManager.onOpen') }}}(instanceId); + } + else + { + Module.dynCall_vi(webSocketManager.onOpen, instanceId); + } + }; + + instance.ws.onmessage = function(ev) + { + if (ev.data instanceof ArrayBuffer) + { + var array = new Uint8Array(ev.data); + var buffer = _malloc(array.length); + writeArrayToMemory(array, buffer); + try + { + if (webSocketManager.support6000) + { + {{{ makeDynCall('viii', 'webSocketManager.onMessage') }}}(instanceId, buffer, array.length); + } + else + { + Module.dynCall_viii(webSocketManager.onMessage, instanceId, buffer, array.length); + } + } + finally + { + _free(buffer); + } + } + else if (typeof ev.data == 'string') + { + var length = lengthBytesUTF8(ev.data) + 1; + var buffer = _malloc(length); + stringToUTF8(ev.data, buffer, length); + try + { + if (webSocketManager.support6000) + { + {{{ makeDynCall('vii', 'webSocketManager.onMessageStr') }}}(instanceId, buffer); + } + else + { + Module.dynCall_vii(webSocketManager.onMessageStr, instanceId, buffer); + } + } + finally + { + _free(buffer); + } + } + else if (typeof Blob !== 'undefined' && ev.data instanceof Blob) + { + var reader = new FileReader(); + reader.onload = function() + { + var array = new Uint8Array(reader.result); + var buffer = _malloc(array.length); + writeArrayToMemory(array, buffer); + try + { + if (webSocketManager.support6000) + { + {{{ makeDynCall('viii', 'webSocketManager.onMessage') }}}(instanceId, buffer, array.length); + } + else + { + Module.dynCall_viii(webSocketManager.onMessage, instanceId, buffer, array.length); + } + } + finally + { + reader = null; + _free(buffer); + } + }; + reader.readAsArrayBuffer(ev.data); + } + else + { + console.log("[JSLIB WebSocket] not support message type: ", (typeof ev.data)); + } + }; + + instance.ws.onerror = function(ev) + { + var msg = "WebSocket error."; + var length = lengthBytesUTF8(msg) + 1; + var buffer = _malloc(length); + stringToUTF8(msg, buffer, length); + try + { + if (webSocketManager.support6000) + { + {{{ makeDynCall('vii', 'webSocketManager.onError') }}}(instanceId, buffer); + } + else + { + Module.dynCall_vii(webSocketManager.onError, instanceId, buffer); + } + } + finally + { + _free(buffer); + } + }; + + instance.ws.onclose = function(ev) + { + var msg = ev.reason; + var length = lengthBytesUTF8(msg) + 1; + var buffer = _malloc(length); + stringToUTF8(msg, buffer, length); + try + { + if (webSocketManager.support6000) + { + {{{ makeDynCall('viii', 'webSocketManager.onClose') }}}(instanceId, ev.code, buffer); + } + else + { + Module.dynCall_viii(webSocketManager.onClose, instanceId, ev.code, buffer); + } + } + finally + { + _free(buffer); + } + instance.ws = null; + }; + + return 0; + }, + + /** + * Close WebSocket connection + * + * @param instanceId Instance ID + * @param code Close status code + * @param reasonPtr Pointer to reason string + */ + WebSocketClose: function(instanceId, code, reasonPtr) + { + var instance = webSocketManager.instances[instanceId]; + if (!instance) return -1; + if (instance.ws === null) return -3; + if (instance.ws.readyState === 2) return -4; + if (instance.ws.readyState === 3) return -5; + + var reason = ( reasonPtr ? UTF8ToString(reasonPtr) : undefined ); + try + { + instance.ws.close(code, reason); + } + catch (err) + { + return -7; + } + + return 0; + }, + + /** + * Send message over WebSocket + * + * @param instanceId Instance ID + * @param bufferPtr Pointer to the message buffer + * @param length Length of the message in the buffer + */ + WebSocketSend: function(instanceId, bufferPtr, offset, length) + { + var instance = webSocketManager.instances[instanceId]; + if (!instance) return -1; + if (instance.ws === null) return -3; + if (instance.ws.readyState !== 1) return -6; + + if (typeof HEAPU8 !== 'undefined') + instance.ws.send(HEAPU8.buffer.slice(bufferPtr + offset, bufferPtr + length)); + else if (typeof buffer !== 'undefined') + instance.ws.send(buffer.slice(bufferPtr + offset, bufferPtr + length)); + else + return -8; // not support buffer slice + + return 0; + }, + + /** + * Send message string over WebSocket + * + * @param instanceId Instance ID + * @param stringPtr Pointer to the message string + */ + WebSocketSendStr: function(instanceId, stringPtr) + { + var instance = webSocketManager.instances[instanceId]; + if (!instance) return -1; + if (instance.ws === null) return -3; + if (instance.ws.readyState !== 1) return -6; + + instance.ws.send(UTF8ToString(stringPtr)); + + return 0; + }, + + /** + * Return WebSocket readyState + * + * @param instanceId Instance ID + */ + WebSocketGetState: function(instanceId) + { + var instance = webSocketManager.instances[instanceId]; + if (!instance) return -1; + if (instance.ws === null) return 3; // socket null as closed + + return instance.ws.readyState; + } +}; + +autoAddDeps(WebSocketLibrary, '$webSocketManager'); +mergeInto(LibraryManager.library, WebSocketLibrary); diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/WebGL/WebSocket.jslib.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/WebGL/WebSocket.jslib.meta new file mode 100644 index 0000000..0d3f588 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/Runtime/Plugins/WebGL/WebSocket.jslib.meta @@ -0,0 +1,42 @@ +fileFormatVersion: 2 +guid: bd88770aa13fc47b08f87d2145e9ac6e +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + Any: + second: + enabled: 0 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + - first: + Facebook: WebGL + second: + enabled: 1 + settings: {} + - first: + WebGL: WebGL + second: + enabled: 1 + settings: {} + - first: + WeixinMiniGame: WeixinMiniGame + second: + enabled: 1 + settings: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/csc.rsp b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/csc.rsp new file mode 100644 index 0000000..84aeb38 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/csc.rsp @@ -0,0 +1,2 @@ +-define:FANTASY_UNITY +-r:System.Threading.Tasks.Extensions.dll \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/csc.rsp.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/csc.rsp.meta new file mode 100644 index 0000000..37b5f8e --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/csc.rsp.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 839059bf7dc694c46b95d545f4de03c9 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/package.json b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/package.json new file mode 100644 index 0000000..fd7395a --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/package.json @@ -0,0 +1,25 @@ +{ + "name": "com.fantasy.unity", + "version": "2024.2.24", + "displayName": "Fantasy.Unity", + "description": "Fantasy is a cross platform distributed server framework.", + "category": "Network Framework", + "documentationUrl": "https://www.code-fantasy.com/", + "changelogUrl": "https://www.code-fantasy.com/", + "licensesUrl": "https://www.code-fantasy.com/", + "keywords": [ + "Fantasy", + "Framework", + "hotfix", + "Server", + "Network" + ], + "author": { + "name": "Fantasy", + "email": "362946@qq.com", + "url": "https://www.code-fantasy.com/" + }, + "dependencies": { + "com.unity.nuget.newtonsoft-json": "3.2.1" + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/package.json.meta b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/package.json.meta new file mode 100644 index 0000000..fa5a5c1 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Fantasy.Unity/Fantasy.Unity/package.json.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: e2fcc306250504c38a18e633f5118933 +PackageManifestImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/物品和背包的完整代码/Packages/Fantasy/LICENSE b/物品和背包的完整代码/Packages/Fantasy/LICENSE new file mode 100644 index 0000000..24a69b2 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/LICENSE @@ -0,0 +1,14 @@ +MIT License + +Copyright (c) 2023 qq362946 + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +However, the following entity is explicitly prohibited from using, copying, modifying, or distributing the Software or any of its portions: + +泰课在线(https://www.taikr.com/) +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + diff --git a/物品和背包的完整代码/Packages/Fantasy/README.md b/物品和背包的完整代码/Packages/Fantasy/README.md new file mode 100644 index 0000000..acbdb43 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/README.md @@ -0,0 +1,55 @@ +# Fantasy +![Logo](Docs/Logo.png) +![Unity Ver](https://img.shields.io/badge/Unity%20Ver-2021.3.14++-blue.svg?style=flat-square) +![GitHub License](https://img.shields.io/github/license/qq362946/Fantasy) +![GitHub last commit](https://img.shields.io/github/last-commit/qq362946/Fantasy) +![GitHub Issues or Pull Requests](https://img.shields.io/github/issues/qq362946/Fantasy) +![GitHub top language](https://img.shields.io/github/languages/top/qq362946/Fantasy) +![GitHub code size in bytes](https://img.shields.io/github/languages/code-size/qq362946/Fantasy) +![GitHub Created At](https://img.shields.io/github/created-at/qq362946/Fantasy) +# Fantasy +#### Fantasy是基于.NET的高性能网络开发框架,支持主流协议,前后端分离。 +#### 支持Unity/Godot/WinFrom/WPF/Console等C#客户端接入。 +#### 框架支持TCP\KCP\WebSocket\http(支持Unity发布成H5)三种网络协议。 +#### 适合需要快速上手、可扩展、分布式全平台商业级解决方案的框架。 +## 导航 +* [Fantasy介绍网站](https://www.code-fantasy.com/) +* [Fantasy的API文档](https://www.code-fantasy.com/doc/api/Fantasy.html) +* [入门视频观看地址](https://space.bilibili.com/382126312) +## 快速上手 +* 01.快速入门 + * [1.1.获得Fantasy](https://www.code-fantasy.com/top/download-fantasy/) + * [1.2.配置文件](https://www.code-fantasy.com/top/config-file/) + * [1.3.Fantasy的网络](https://www.code-fantasy.com/top/use-network/) + * [1.4.Fantasy的配置文件](https://www.code-fantasy.com/top/config-file/) + * [1.5.Fantasy的命令行参数](https://www.code-fantasy.com/top/command-line-parameter/) + * [1.6.如何升级到最新版](https://www.code-fantasy.com/top/upgrade/) +* 02.网络通信 + * [2.1.配置网络协议](https://www.code-fantasy.com/network/network-protocols/) + * [2.2.客户端服务器之间发送消息](https://www.code-fantasy.com/network/session/) + * [2.3.服务器之间发送消息](https://www.code-fantasy.com/network/networkmessagingomponent/) + * [2.4.Route通信协议](https://www.code-fantasy.com/network/network-route/) + * [2.5.Addressable通信协议](https://www.code-fantasy.com/network/network-addressable/) +* 03.系统组件 + * [3.1.ECS系统](https://www.code-fantasy.com/core/ecs/) + * [3.2.事件系统](https://www.code-fantasy.com/core/event/) + * [3.3.任务系统](https://www.code-fantasy.com/core/task/) + * [3.4.异步协程锁](https://www.code-fantasy.com/core/lock/) + * [3.5.数据库](https://www.code-fantasy.com/core/db/) +* [更新日志](https://www.code-fantasy.com/changelog/) +* [API文档](https://www.code-fantasy.com/doc/api/Fantasy.html) +* [常见问题](https://www.code-fantasy.com/question/) + +## 优质开源项目推荐 +#### ET - ET框架是一整套完善的游戏开发框架。 +#### TEngine - TEngine是一个简单(新手友好开箱即用)且强大的Unity框架全平台解决方案。 +#### Legends-Of-Heroes - 一个LOL风格的球球大作战游戏,基于ET,使用状态同步。 +## 交流与讨论: +__讨论QQ群 : Fantasy服务器开发交流群 569888673 __ +## 特别鸣谢 + +感谢JetBrains公司提供的使用许可证! + +

+JetBrains的Logo

+ diff --git a/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/ConfigTable/CommandLine.dll b/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/ConfigTable/CommandLine.dll new file mode 100644 index 0000000..3eab2be Binary files /dev/null and b/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/ConfigTable/CommandLine.dll differ diff --git a/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/ConfigTable/EPPlus.Interfaces.dll b/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/ConfigTable/EPPlus.Interfaces.dll new file mode 100644 index 0000000..599a767 Binary files /dev/null and b/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/ConfigTable/EPPlus.Interfaces.dll differ diff --git a/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/ConfigTable/EPPlus.System.Drawing.dll b/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/ConfigTable/EPPlus.System.Drawing.dll new file mode 100644 index 0000000..8df125e Binary files /dev/null and b/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/ConfigTable/EPPlus.System.Drawing.dll differ diff --git a/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/ConfigTable/EPPlus.dll b/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/ConfigTable/EPPlus.dll new file mode 100644 index 0000000..b09ea77 Binary files /dev/null and b/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/ConfigTable/EPPlus.dll differ diff --git a/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/ConfigTable/ExporterSettings.json b/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/ConfigTable/ExporterSettings.json new file mode 100644 index 0000000..7499bd6 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/ConfigTable/ExporterSettings.json @@ -0,0 +1,44 @@ +{ + "Export": { + "ExcelProgramPath": { + "Value": "../../../Examples/Config/Excel/", + "Comment": "Excel文件夹的根目录" + }, + "ExcelVersionFile": { + "Value": "../../../Examples/Config/Excel/Version.txt", + "Comment": "Excel的Version文件位置、这个文件用于记录每次导出对比是否需要再次导出的文件" + }, + "ExcelServerFileDirectory": { + "Value": "../../../Examples/Server/Entity/Generate/ConfigTable/Entity/", + "Comment": "Excel生成的代码文件、在服务端文件夹位置" + }, + "ExcelClientFileDirectory": { + "Value": "../../../Examples/Client/Unity/Assets/Scripts/Hotfix/Generate/ConfigTable/Entity/", + "Comment": "Excel生成的代码文件、在客户端文件夹位置" + }, + "ExcelServerBinaryDirectory": { + "Value": "../../../Examples/Config/Binary/", + "Comment": "Excel生成服务器二进制数据文件夹位置" + }, + "ExcelClientBinaryDirectory": { + "Value": "../../../Examples/Client/Unity/Assets/Bundles/Config/", + "Comment": "Excel生成在客户端的二进制数据文件夹位置" + }, + "ExcelServerJsonDirectory": { + "Value": "../../../Examples/Config/Json/Server/", + "Comment": "Excel生成在服务端的Json数据文件夹位置" + }, + "ExcelClientJsonDirectory": { + "Value": "../../../Examples/Config/Json/Client/", + "Comment": "Excel生成在客户端的Json数据文件夹位置" + }, + "ServerCustomExportDirectory": { + "Value": "../../../Examples/Server/Entity/Generate/CustomExport/", + "Comment": "Excel在服务端生成自定义代码的文件夹位置" + }, + "ClientCustomExportDirectory": { + "Value": "../../../Examples/Client/Unity/Assets/Scripts/Hotfix/Generate/CustomExport", + "Comment": "Excel在客户端端生成自定义代码的文件夹位置" + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/ConfigTable/Fantasy.Tools.ConfigTable b/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/ConfigTable/Fantasy.Tools.ConfigTable new file mode 100644 index 0000000..351f187 Binary files /dev/null and b/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/ConfigTable/Fantasy.Tools.ConfigTable differ diff --git a/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/ConfigTable/Fantasy.Tools.ConfigTable.deps.json b/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/ConfigTable/Fantasy.Tools.ConfigTable.deps.json new file mode 100644 index 0000000..a7025c3 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/ConfigTable/Fantasy.Tools.ConfigTable.deps.json @@ -0,0 +1,508 @@ +{ + "runtimeTarget": { + "name": ".NETCoreApp,Version=v8.0", + "signature": "" + }, + "compilationOptions": {}, + "targets": { + ".NETCoreApp,Version=v8.0": { + "Fantasy.Tools.ConfigTable/1.0.0": { + "dependencies": { + "CommandLineParser": "2.9.1", + "EPPlus": "7.3.2", + "Microsoft.CodeAnalysis.CSharp": "4.11.0", + "Microsoft.Extensions.Configuration.Json": "8.0.0", + "Newtonsoft.Json": "13.0.3", + "protobuf-net": "3.2.30" + }, + "runtime": { + "Fantasy.Tools.ConfigTable.dll": {} + } + }, + "CommandLineParser/2.9.1": { + "runtime": { + "lib/netstandard2.0/CommandLine.dll": { + "assemblyVersion": "2.9.1.0", + "fileVersion": "2.9.1.0" + } + } + }, + "EPPlus/7.3.2": { + "dependencies": { + "EPPlus.System.Drawing": "6.1.1", + "Microsoft.Extensions.Configuration.Json": "8.0.0", + "Microsoft.IO.RecyclableMemoryStream": "3.0.1", + "System.ComponentModel.Annotations": "5.0.0", + "System.Formats.Asn1": "8.0.1", + "System.Security.Cryptography.Pkcs": "8.0.0", + "System.Text.Encoding.CodePages": "8.0.0", + "System.Text.Json": "8.0.4" + }, + "runtime": { + "lib/net8.0/EPPlus.dll": { + "assemblyVersion": "7.3.2.0", + "fileVersion": "7.3.2.0" + } + } + }, + "EPPlus.Interfaces/6.1.1": { + "runtime": { + "lib/net7.0/EPPlus.Interfaces.dll": { + "assemblyVersion": "6.1.1.0", + "fileVersion": "6.1.1.0" + } + } + }, + "EPPlus.System.Drawing/6.1.1": { + "dependencies": { + "EPPlus.Interfaces": "6.1.1", + "System.Drawing.Common": "7.0.0" + }, + "runtime": { + "lib/net7.0/EPPlus.System.Drawing.dll": { + "assemblyVersion": "6.1.1.0", + "fileVersion": "6.1.1.0" + } + } + }, + "Microsoft.CodeAnalysis.Analyzers/3.3.4": {}, + "Microsoft.CodeAnalysis.Common/4.11.0": { + "dependencies": { + "Microsoft.CodeAnalysis.Analyzers": "3.3.4", + "System.Collections.Immutable": "8.0.0", + "System.Reflection.Metadata": "8.0.0" + }, + "runtime": { + "lib/net8.0/Microsoft.CodeAnalysis.dll": { + "assemblyVersion": "4.11.0.0", + "fileVersion": "4.1100.24.37604" + } + } + }, + "Microsoft.CodeAnalysis.CSharp/4.11.0": { + "dependencies": { + "Microsoft.CodeAnalysis.Analyzers": "3.3.4", + "Microsoft.CodeAnalysis.Common": "4.11.0", + "System.Collections.Immutable": "8.0.0", + "System.Reflection.Metadata": "8.0.0" + }, + "runtime": { + "lib/net8.0/Microsoft.CodeAnalysis.CSharp.dll": { + "assemblyVersion": "4.11.0.0", + "fileVersion": "4.1100.24.37604" + } + } + }, + "Microsoft.Extensions.Configuration/8.0.0": { + "dependencies": { + "Microsoft.Extensions.Configuration.Abstractions": "8.0.0", + "Microsoft.Extensions.Primitives": "8.0.0" + }, + "runtime": { + "lib/net8.0/Microsoft.Extensions.Configuration.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.23.53103" + } + } + }, + "Microsoft.Extensions.Configuration.Abstractions/8.0.0": { + "dependencies": { + "Microsoft.Extensions.Primitives": "8.0.0" + }, + "runtime": { + "lib/net8.0/Microsoft.Extensions.Configuration.Abstractions.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.23.53103" + } + } + }, + "Microsoft.Extensions.Configuration.FileExtensions/8.0.0": { + "dependencies": { + "Microsoft.Extensions.Configuration": "8.0.0", + "Microsoft.Extensions.Configuration.Abstractions": "8.0.0", + "Microsoft.Extensions.FileProviders.Abstractions": "8.0.0", + "Microsoft.Extensions.FileProviders.Physical": "8.0.0", + "Microsoft.Extensions.Primitives": "8.0.0" + }, + "runtime": { + "lib/net8.0/Microsoft.Extensions.Configuration.FileExtensions.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.23.53103" + } + } + }, + "Microsoft.Extensions.Configuration.Json/8.0.0": { + "dependencies": { + "Microsoft.Extensions.Configuration": "8.0.0", + "Microsoft.Extensions.Configuration.Abstractions": "8.0.0", + "Microsoft.Extensions.Configuration.FileExtensions": "8.0.0", + "Microsoft.Extensions.FileProviders.Abstractions": "8.0.0", + "System.Text.Json": "8.0.4" + }, + "runtime": { + "lib/net8.0/Microsoft.Extensions.Configuration.Json.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.23.53103" + } + } + }, + "Microsoft.Extensions.FileProviders.Abstractions/8.0.0": { + "dependencies": { + "Microsoft.Extensions.Primitives": "8.0.0" + }, + "runtime": { + "lib/net8.0/Microsoft.Extensions.FileProviders.Abstractions.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.23.53103" + } + } + }, + "Microsoft.Extensions.FileProviders.Physical/8.0.0": { + "dependencies": { + "Microsoft.Extensions.FileProviders.Abstractions": "8.0.0", + "Microsoft.Extensions.FileSystemGlobbing": "8.0.0", + "Microsoft.Extensions.Primitives": "8.0.0" + }, + "runtime": { + "lib/net8.0/Microsoft.Extensions.FileProviders.Physical.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.23.53103" + } + } + }, + "Microsoft.Extensions.FileSystemGlobbing/8.0.0": { + "runtime": { + "lib/net8.0/Microsoft.Extensions.FileSystemGlobbing.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.23.53103" + } + } + }, + "Microsoft.Extensions.Primitives/8.0.0": { + "runtime": { + "lib/net8.0/Microsoft.Extensions.Primitives.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.23.53103" + } + } + }, + "Microsoft.IO.RecyclableMemoryStream/3.0.1": { + "runtime": { + "lib/net6.0/Microsoft.IO.RecyclableMemoryStream.dll": { + "assemblyVersion": "3.0.1.0", + "fileVersion": "3.0.1.0" + } + } + }, + "Microsoft.Win32.SystemEvents/7.0.0": { + "runtime": { + "lib/net7.0/Microsoft.Win32.SystemEvents.dll": { + "assemblyVersion": "7.0.0.0", + "fileVersion": "7.0.22.51805" + } + }, + "runtimeTargets": { + "runtimes/win/lib/net7.0/Microsoft.Win32.SystemEvents.dll": { + "rid": "win", + "assetType": "runtime", + "assemblyVersion": "7.0.0.0", + "fileVersion": "7.0.22.51805" + } + } + }, + "Newtonsoft.Json/13.0.3": { + "runtime": { + "lib/net6.0/Newtonsoft.Json.dll": { + "assemblyVersion": "13.0.0.0", + "fileVersion": "13.0.3.27908" + } + } + }, + "protobuf-net/3.2.30": { + "dependencies": { + "protobuf-net.Core": "3.2.30" + }, + "runtime": { + "lib/net6.0/protobuf-net.dll": { + "assemblyVersion": "3.0.0.0", + "fileVersion": "3.2.30.709" + } + } + }, + "protobuf-net.Core/3.2.30": { + "dependencies": { + "System.Collections.Immutable": "8.0.0" + }, + "runtime": { + "lib/net6.0/protobuf-net.Core.dll": { + "assemblyVersion": "3.0.0.0", + "fileVersion": "3.2.30.709" + } + } + }, + "System.Collections.Immutable/8.0.0": {}, + "System.ComponentModel.Annotations/5.0.0": {}, + "System.Drawing.Common/7.0.0": { + "dependencies": { + "Microsoft.Win32.SystemEvents": "7.0.0" + }, + "runtime": { + "lib/net7.0/System.Drawing.Common.dll": { + "assemblyVersion": "7.0.0.0", + "fileVersion": "7.0.22.51805" + } + }, + "runtimeTargets": { + "runtimes/win/lib/net7.0/System.Drawing.Common.dll": { + "rid": "win", + "assetType": "runtime", + "assemblyVersion": "7.0.0.0", + "fileVersion": "7.0.22.51805" + } + } + }, + "System.Formats.Asn1/8.0.1": {}, + "System.Reflection.Metadata/8.0.0": { + "dependencies": { + "System.Collections.Immutable": "8.0.0" + } + }, + "System.Security.Cryptography.Pkcs/8.0.0": { + "dependencies": { + "System.Formats.Asn1": "8.0.1" + }, + "runtime": { + "lib/net8.0/System.Security.Cryptography.Pkcs.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.23.53103" + } + }, + "runtimeTargets": { + "runtimes/win/lib/net8.0/System.Security.Cryptography.Pkcs.dll": { + "rid": "win", + "assetType": "runtime", + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.23.53103" + } + } + }, + "System.Text.Encoding.CodePages/8.0.0": {}, + "System.Text.Encodings.Web/8.0.0": {}, + "System.Text.Json/8.0.4": { + "dependencies": { + "System.Text.Encodings.Web": "8.0.0" + } + } + } + }, + "libraries": { + "Fantasy.Tools.ConfigTable/1.0.0": { + "type": "project", + "serviceable": false, + "sha512": "" + }, + "CommandLineParser/2.9.1": { + "type": "package", + "serviceable": true, + "sha512": "sha512-OE0sl1/sQ37bjVsPKKtwQlWDgqaxWgtme3xZz7JssWUzg5JpMIyHgCTY9MVMxOg48fJ1AgGT3tgdH5m/kQ5xhA==", + "path": "commandlineparser/2.9.1", + "hashPath": "commandlineparser.2.9.1.nupkg.sha512" + }, + "EPPlus/7.3.2": { + "type": "package", + "serviceable": true, + "sha512": "sha512-9DShQD2VuDZ7QLHp+map1r2HdI1G325YGkvRG+qs4N2fgeMF1Uq0TONCEL5gKCWMNDVGO0ZELJTAIzwNyOZQug==", + "path": "epplus/7.3.2", + "hashPath": "epplus.7.3.2.nupkg.sha512" + }, + "EPPlus.Interfaces/6.1.1": { + "type": "package", + "serviceable": true, + "sha512": "sha512-y7dkrOoE1ZR9Vgy1Jf2rEIaTf3SHlUjYt01NklP+F5Qh7S2ruPbzTcpYLRWMeXiG8XL8h2jqX4CyIkFt3NQGZw==", + "path": "epplus.interfaces/6.1.1", + "hashPath": "epplus.interfaces.6.1.1.nupkg.sha512" + }, + "EPPlus.System.Drawing/6.1.1": { + "type": "package", + "serviceable": true, + "sha512": "sha512-lRF5gHYrmkHOOiLMI0t6q8zNYjUrzRgAM5BCXumv5xiqXko8fx3AWI+HCNZfhEqVFGOop+42KfR5GiUcCoyoMw==", + "path": "epplus.system.drawing/6.1.1", + "hashPath": "epplus.system.drawing.6.1.1.nupkg.sha512" + }, + "Microsoft.CodeAnalysis.Analyzers/3.3.4": { + "type": "package", + "serviceable": true, + "sha512": "sha512-AxkxcPR+rheX0SmvpLVIGLhOUXAKG56a64kV9VQZ4y9gR9ZmPXnqZvHJnmwLSwzrEP6junUF11vuc+aqo5r68g==", + "path": "microsoft.codeanalysis.analyzers/3.3.4", + "hashPath": "microsoft.codeanalysis.analyzers.3.3.4.nupkg.sha512" + }, + "Microsoft.CodeAnalysis.Common/4.11.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-djf8ujmqYImFgB04UGtcsEhHrzVqzHowS+EEl/Yunc5LdrYrZhGBWUTXoCF0NzYXJxtfuD+UVQarWpvrNc94Qg==", + "path": "microsoft.codeanalysis.common/4.11.0", + "hashPath": "microsoft.codeanalysis.common.4.11.0.nupkg.sha512" + }, + "Microsoft.CodeAnalysis.CSharp/4.11.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-6XYi2EusI8JT4y2l/F3VVVS+ISoIX9nqHsZRaG6W5aFeJ5BEuBosHfT/ABb73FN0RZ1Z3cj2j7cL28SToJPXOw==", + "path": "microsoft.codeanalysis.csharp/4.11.0", + "hashPath": "microsoft.codeanalysis.csharp.4.11.0.nupkg.sha512" + }, + "Microsoft.Extensions.Configuration/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-0J/9YNXTMWSZP2p2+nvl8p71zpSwokZXZuJW+VjdErkegAnFdO1XlqtA62SJtgVYHdKu3uPxJHcMR/r35HwFBA==", + "path": "microsoft.extensions.configuration/8.0.0", + "hashPath": "microsoft.extensions.configuration.8.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.Configuration.Abstractions/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-3lE/iLSutpgX1CC0NOW70FJoGARRHbyKmG7dc0klnUZ9Dd9hS6N/POPWhKhMLCEuNN5nXEY5agmlFtH562vqhQ==", + "path": "microsoft.extensions.configuration.abstractions/8.0.0", + "hashPath": "microsoft.extensions.configuration.abstractions.8.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.Configuration.FileExtensions/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-McP+Lz/EKwvtCv48z0YImw+L1gi1gy5rHhNaNIY2CrjloV+XY8gydT8DjMR6zWeL13AFK+DioVpppwAuO1Gi1w==", + "path": "microsoft.extensions.configuration.fileextensions/8.0.0", + "hashPath": "microsoft.extensions.configuration.fileextensions.8.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.Configuration.Json/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-C2wqUoh9OmRL1akaCcKSTmRU8z0kckfImG7zLNI8uyi47Lp+zd5LWAD17waPQEqCz3ioWOCrFUo+JJuoeZLOBw==", + "path": "microsoft.extensions.configuration.json/8.0.0", + "hashPath": "microsoft.extensions.configuration.json.8.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.FileProviders.Abstractions/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-ZbaMlhJlpisjuWbvXr4LdAst/1XxH3vZ6A0BsgTphZ2L4PGuxRLz7Jr/S7mkAAnOn78Vu0fKhEgNF5JO3zfjqQ==", + "path": "microsoft.extensions.fileproviders.abstractions/8.0.0", + "hashPath": "microsoft.extensions.fileproviders.abstractions.8.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.FileProviders.Physical/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-UboiXxpPUpwulHvIAVE36Knq0VSHaAmfrFkegLyBZeaADuKezJ/AIXYAW8F5GBlGk/VaibN2k/Zn1ca8YAfVdA==", + "path": "microsoft.extensions.fileproviders.physical/8.0.0", + "hashPath": "microsoft.extensions.fileproviders.physical.8.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.FileSystemGlobbing/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-OK+670i7esqlQrPjdIKRbsyMCe9g5kSLpRRQGSr4Q58AOYEe/hCnfLZprh7viNisSUUQZmMrbbuDaIrP+V1ebQ==", + "path": "microsoft.extensions.filesystemglobbing/8.0.0", + "hashPath": "microsoft.extensions.filesystemglobbing.8.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.Primitives/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-bXJEZrW9ny8vjMF1JV253WeLhpEVzFo1lyaZu1vQ4ZxWUlVvknZ/+ftFgVheLubb4eZPSwwxBeqS1JkCOjxd8g==", + "path": "microsoft.extensions.primitives/8.0.0", + "hashPath": "microsoft.extensions.primitives.8.0.0.nupkg.sha512" + }, + "Microsoft.IO.RecyclableMemoryStream/3.0.1": { + "type": "package", + "serviceable": true, + "sha512": "sha512-s/s20YTVY9r9TPfTrN5g8zPF1YhwxyqO6PxUkrYTGI2B+OGPe9AdajWZrLhFqXIvqIW23fnUE4+ztrUWNU1+9g==", + "path": "microsoft.io.recyclablememorystream/3.0.1", + "hashPath": "microsoft.io.recyclablememorystream.3.0.1.nupkg.sha512" + }, + "Microsoft.Win32.SystemEvents/7.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-2nXPrhdAyAzir0gLl8Yy8S5Mnm/uBSQQA7jEsILOS1MTyS7DbmV1NgViMtvV1sfCD1ebITpNwb1NIinKeJgUVQ==", + "path": "microsoft.win32.systemevents/7.0.0", + "hashPath": "microsoft.win32.systemevents.7.0.0.nupkg.sha512" + }, + "Newtonsoft.Json/13.0.3": { + "type": "package", + "serviceable": true, + "sha512": "sha512-HrC5BXdl00IP9zeV+0Z848QWPAoCr9P3bDEZguI+gkLcBKAOxix/tLEAAHC+UvDNPv4a2d18lOReHMOagPa+zQ==", + "path": "newtonsoft.json/13.0.3", + "hashPath": "newtonsoft.json.13.0.3.nupkg.sha512" + }, + "protobuf-net/3.2.30": { + "type": "package", + "serviceable": true, + "sha512": "sha512-C/UTlmxEJHAHpqm8xQK1UyJKaIynVCSNG4mVrbLgnZ7ccH28nN49O8iMJvKEodTgVbnimvy+3mIiAdW6mATwnw==", + "path": "protobuf-net/3.2.30", + "hashPath": "protobuf-net.3.2.30.nupkg.sha512" + }, + "protobuf-net.Core/3.2.30": { + "type": "package", + "serviceable": true, + "sha512": "sha512-v2ZxxYrz+X212ukSx+uqkLuPu414bvmSAnTyf+PBUKR9ENJxO4P/csorA/27456MCp1JNoMssDj/f91RDiwBfQ==", + "path": "protobuf-net.core/3.2.30", + "hashPath": "protobuf-net.core.3.2.30.nupkg.sha512" + }, + "System.Collections.Immutable/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-AurL6Y5BA1WotzlEvVaIDpqzpIPvYnnldxru8oXJU2yFxFUy3+pNXjXd1ymO+RA0rq0+590Q8gaz2l3Sr7fmqg==", + "path": "system.collections.immutable/8.0.0", + "hashPath": "system.collections.immutable.8.0.0.nupkg.sha512" + }, + "System.ComponentModel.Annotations/5.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-dMkqfy2el8A8/I76n2Hi1oBFEbG1SfxD2l5nhwXV3XjlnOmwxJlQbYpJH4W51odnU9sARCSAgv7S3CyAFMkpYg==", + "path": "system.componentmodel.annotations/5.0.0", + "hashPath": "system.componentmodel.annotations.5.0.0.nupkg.sha512" + }, + "System.Drawing.Common/7.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-KIX+oBU38pxkKPxvLcLfIkOV5Ien8ReN78wro7OF5/erwcmortzeFx+iBswlh2Vz6gVne0khocQudGwaO1Ey6A==", + "path": "system.drawing.common/7.0.0", + "hashPath": "system.drawing.common.7.0.0.nupkg.sha512" + }, + "System.Formats.Asn1/8.0.1": { + "type": "package", + "serviceable": true, + "sha512": "sha512-XqKba7Mm/koKSjKMfW82olQdmfbI5yqeoLV/tidRp7fbh5rmHAQ5raDI/7SU0swTzv+jgqtUGkzmFxuUg0it1A==", + "path": "system.formats.asn1/8.0.1", + "hashPath": "system.formats.asn1.8.0.1.nupkg.sha512" + }, + "System.Reflection.Metadata/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-ptvgrFh7PvWI8bcVqG5rsA/weWM09EnthFHR5SCnS6IN+P4mj6rE1lBDC4U8HL9/57htKAqy4KQ3bBj84cfYyQ==", + "path": "system.reflection.metadata/8.0.0", + "hashPath": "system.reflection.metadata.8.0.0.nupkg.sha512" + }, + "System.Security.Cryptography.Pkcs/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-ULmp3xoOwNYjOYp4JZ2NK/6NdTgiN1GQXzVVN1njQ7LOZ0d0B9vyMnhyqbIi9Qw4JXj1JgCsitkTShboHRx7Eg==", + "path": "system.security.cryptography.pkcs/8.0.0", + "hashPath": "system.security.cryptography.pkcs.8.0.0.nupkg.sha512" + }, + "System.Text.Encoding.CodePages/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-OZIsVplFGaVY90G2SbpgU7EnCoOO5pw1t4ic21dBF3/1omrJFpAGoNAVpPyMVOC90/hvgkGG3VFqR13YgZMQfg==", + "path": "system.text.encoding.codepages/8.0.0", + "hashPath": "system.text.encoding.codepages.8.0.0.nupkg.sha512" + }, + "System.Text.Encodings.Web/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-yev/k9GHAEGx2Rg3/tU6MQh4HGBXJs70y7j1LaM1i/ER9po+6nnQ6RRqTJn1E7Xu0fbIFK80Nh5EoODxrbxwBQ==", + "path": "system.text.encodings.web/8.0.0", + "hashPath": "system.text.encodings.web.8.0.0.nupkg.sha512" + }, + "System.Text.Json/8.0.4": { + "type": "package", + "serviceable": true, + "sha512": "sha512-bAkhgDJ88XTsqczoxEMliSrpijKZHhbJQldhAmObj/RbrN3sU5dcokuXmWJWsdQAhiMJ9bTayWsL1C9fbbCRhw==", + "path": "system.text.json/8.0.4", + "hashPath": "system.text.json.8.0.4.nupkg.sha512" + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/ConfigTable/Fantasy.Tools.ConfigTable.dll b/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/ConfigTable/Fantasy.Tools.ConfigTable.dll new file mode 100644 index 0000000..816dfbb Binary files /dev/null and b/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/ConfigTable/Fantasy.Tools.ConfigTable.dll differ diff --git a/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/ConfigTable/Fantasy.Tools.ConfigTable.pdb b/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/ConfigTable/Fantasy.Tools.ConfigTable.pdb new file mode 100644 index 0000000..17add89 Binary files /dev/null and b/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/ConfigTable/Fantasy.Tools.ConfigTable.pdb differ diff --git a/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/ConfigTable/Fantasy.Tools.ConfigTable.runtimeconfig.json b/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/ConfigTable/Fantasy.Tools.ConfigTable.runtimeconfig.json new file mode 100644 index 0000000..becfaea --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/ConfigTable/Fantasy.Tools.ConfigTable.runtimeconfig.json @@ -0,0 +1,12 @@ +{ + "runtimeOptions": { + "tfm": "net8.0", + "framework": { + "name": "Microsoft.NETCore.App", + "version": "8.0.0" + }, + "configProperties": { + "System.Runtime.Serialization.EnableUnsafeBinaryFormatterSerialization": false + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/ConfigTable/Microsoft.CodeAnalysis.CSharp.dll b/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/ConfigTable/Microsoft.CodeAnalysis.CSharp.dll new file mode 100644 index 0000000..c23db48 Binary files /dev/null and b/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/ConfigTable/Microsoft.CodeAnalysis.CSharp.dll differ diff --git a/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/ConfigTable/Microsoft.CodeAnalysis.dll b/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/ConfigTable/Microsoft.CodeAnalysis.dll new file mode 100644 index 0000000..de7eadd Binary files /dev/null and b/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/ConfigTable/Microsoft.CodeAnalysis.dll differ diff --git a/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/ConfigTable/Microsoft.Extensions.Configuration.Abstractions.dll b/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/ConfigTable/Microsoft.Extensions.Configuration.Abstractions.dll new file mode 100644 index 0000000..a5ab313 Binary files /dev/null and b/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/ConfigTable/Microsoft.Extensions.Configuration.Abstractions.dll differ diff --git a/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/ConfigTable/Microsoft.Extensions.Configuration.FileExtensions.dll b/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/ConfigTable/Microsoft.Extensions.Configuration.FileExtensions.dll new file mode 100644 index 0000000..4efc1a5 Binary files /dev/null and b/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/ConfigTable/Microsoft.Extensions.Configuration.FileExtensions.dll differ diff --git a/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/ConfigTable/Microsoft.Extensions.Configuration.Json.dll b/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/ConfigTable/Microsoft.Extensions.Configuration.Json.dll new file mode 100644 index 0000000..296db6a Binary files /dev/null and b/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/ConfigTable/Microsoft.Extensions.Configuration.Json.dll differ diff --git a/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/ConfigTable/Microsoft.Extensions.Configuration.dll b/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/ConfigTable/Microsoft.Extensions.Configuration.dll new file mode 100644 index 0000000..d3e5c22 Binary files /dev/null and b/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/ConfigTable/Microsoft.Extensions.Configuration.dll differ diff --git a/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/ConfigTable/Microsoft.Extensions.FileProviders.Abstractions.dll b/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/ConfigTable/Microsoft.Extensions.FileProviders.Abstractions.dll new file mode 100644 index 0000000..f907206 Binary files /dev/null and b/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/ConfigTable/Microsoft.Extensions.FileProviders.Abstractions.dll differ diff --git a/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/ConfigTable/Microsoft.Extensions.FileProviders.Physical.dll b/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/ConfigTable/Microsoft.Extensions.FileProviders.Physical.dll new file mode 100644 index 0000000..6fb7f47 Binary files /dev/null and b/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/ConfigTable/Microsoft.Extensions.FileProviders.Physical.dll differ diff --git a/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/ConfigTable/Microsoft.Extensions.FileSystemGlobbing.dll b/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/ConfigTable/Microsoft.Extensions.FileSystemGlobbing.dll new file mode 100644 index 0000000..e590735 Binary files /dev/null and b/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/ConfigTable/Microsoft.Extensions.FileSystemGlobbing.dll differ diff --git a/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/ConfigTable/Microsoft.Extensions.Primitives.dll b/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/ConfigTable/Microsoft.Extensions.Primitives.dll new file mode 100644 index 0000000..c24f2a0 Binary files /dev/null and b/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/ConfigTable/Microsoft.Extensions.Primitives.dll differ diff --git a/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/ConfigTable/Microsoft.IO.RecyclableMemoryStream.dll b/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/ConfigTable/Microsoft.IO.RecyclableMemoryStream.dll new file mode 100644 index 0000000..6e0ea40 Binary files /dev/null and b/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/ConfigTable/Microsoft.IO.RecyclableMemoryStream.dll differ diff --git a/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/ConfigTable/Microsoft.Win32.SystemEvents.dll b/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/ConfigTable/Microsoft.Win32.SystemEvents.dll new file mode 100644 index 0000000..4f50adb Binary files /dev/null and b/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/ConfigTable/Microsoft.Win32.SystemEvents.dll differ diff --git a/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/ConfigTable/Newtonsoft.Json.dll b/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/ConfigTable/Newtonsoft.Json.dll new file mode 100644 index 0000000..d035c38 Binary files /dev/null and b/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/ConfigTable/Newtonsoft.Json.dll differ diff --git a/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/ConfigTable/Run.bat b/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/ConfigTable/Run.bat new file mode 100644 index 0000000..082d6b0 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/ConfigTable/Run.bat @@ -0,0 +1,33 @@ +@echo off + +echo Please select an option: +echo 1. Client Increment +echo 2. Client all +echo 3. Server Increment +echo 4. Server all +echo 5. Client and Server Increment +echo 6. Client and Server all + +set /p choice=Please select an option: + +if "%choice%"=="1" ( + echo Client Increment + dotnet Fantasy.Tools.ConfigTable.dll --p 1 --e 1 +) else if "%choice%"=="2" ( + echo Client all + dotnet Fantasy.Tools.ConfigTable.dll --p 1 --e 2 +) else if "%choice%"=="3" ( + echo Server Increment + dotnet Fantasy.Tools.ConfigTable.dll --p 2 --e 1 +) else if "%choice%"=="4" ( + echo Server all + dotnet Fantasy.Tools.ConfigTable.dll --p 2 --e 2 +) else if "%choice%"=="5" ( + echo Client and Server Increment + dotnet Fantasy.Tools.ConfigTable.dll --p 3 --e 1 +) else if "%choice%"=="6" ( + echo Client and Server all + dotnet Fantasy.Tools.ConfigTable.dll --p 3 --e 2 +) else ( + echo Invalid option +) diff --git a/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/ConfigTable/Run.sh b/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/ConfigTable/Run.sh new file mode 100644 index 0000000..7ac9f52 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/ConfigTable/Run.sh @@ -0,0 +1,34 @@ +#!/bin/bash + +echo "1. Client Increment" +echo "2. Client all" +echo "3. Server Increment" +echo "4. Server all" +echo "5. Client and Server Increment" +echo "6. Client and Server all" + +read -n 1 -p "Please select an option:" choice +echo "" +case $choice in + 1) + dotnet Fantasy.Tools.ConfigTable.dll --p 1 --e 1 + ;; + 2) + dotnet Fantasy.Tools.ConfigTable.dll --p 1 --e 2 + ;; + 3) + dotnet Fantasy.Tools.ConfigTable.dll --p 2 --e 1 + ;; + 4) + dotnet Fantasy.Tools.ConfigTable.dll --p 2 --e 2 + ;; + 5) + dotnet Fantasy.Tools.ConfigTable.dll --p 3 --e 1 + ;; + 6) + dotnet Fantasy.Tools.ConfigTable.dll --p 3 --e 2 + ;; + *) + echo "Invalid option" + ;; +esac diff --git a/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/ConfigTable/System.Drawing.Common.dll b/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/ConfigTable/System.Drawing.Common.dll new file mode 100644 index 0000000..310d5e8 Binary files /dev/null and b/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/ConfigTable/System.Drawing.Common.dll differ diff --git a/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/ConfigTable/System.Security.Cryptography.Pkcs.dll b/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/ConfigTable/System.Security.Cryptography.Pkcs.dll new file mode 100644 index 0000000..a76a14a Binary files /dev/null and b/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/ConfigTable/System.Security.Cryptography.Pkcs.dll differ diff --git a/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/ConfigTable/protobuf-net.Core.dll b/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/ConfigTable/protobuf-net.Core.dll new file mode 100644 index 0000000..845a840 Binary files /dev/null and b/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/ConfigTable/protobuf-net.Core.dll differ diff --git a/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/ConfigTable/protobuf-net.dll b/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/ConfigTable/protobuf-net.dll new file mode 100644 index 0000000..e4b6839 Binary files /dev/null and b/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/ConfigTable/protobuf-net.dll differ diff --git a/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/ConfigTable/runtimes/win/lib/net7.0/Microsoft.Win32.SystemEvents.dll b/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/ConfigTable/runtimes/win/lib/net7.0/Microsoft.Win32.SystemEvents.dll new file mode 100644 index 0000000..d40a926 Binary files /dev/null and b/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/ConfigTable/runtimes/win/lib/net7.0/Microsoft.Win32.SystemEvents.dll differ diff --git a/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/ConfigTable/runtimes/win/lib/net7.0/System.Drawing.Common.dll b/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/ConfigTable/runtimes/win/lib/net7.0/System.Drawing.Common.dll new file mode 100644 index 0000000..39493b4 Binary files /dev/null and b/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/ConfigTable/runtimes/win/lib/net7.0/System.Drawing.Common.dll differ diff --git a/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/ConfigTable/runtimes/win/lib/net8.0/System.Security.Cryptography.Pkcs.dll b/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/ConfigTable/runtimes/win/lib/net8.0/System.Security.Cryptography.Pkcs.dll new file mode 100644 index 0000000..cba73d0 Binary files /dev/null and b/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/ConfigTable/runtimes/win/lib/net8.0/System.Security.Cryptography.Pkcs.dll differ diff --git a/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/NetworkProtocol/CommandLine.dll b/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/NetworkProtocol/CommandLine.dll new file mode 100644 index 0000000..3eab2be Binary files /dev/null and b/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/NetworkProtocol/CommandLine.dll differ diff --git a/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/NetworkProtocol/ExporterSettings.json b/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/NetworkProtocol/ExporterSettings.json new file mode 100644 index 0000000..f093812 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/NetworkProtocol/ExporterSettings.json @@ -0,0 +1,29 @@ +{ + "Export": { + "NetworkProtocolDirectory": { + "Value": "../../../Examples/Config/NetworkProtocol/", + "Comment": "ProtoBuf文件所在的文件夹位置" + }, + "NetworkProtocolServerDirectory": { + "Value": "../../../Examples/Server/Entity/Generate/NetworkProtocol/", + "Comment": "ProtoBuf生成到服务端的文件夹位置" + }, + "NetworkProtocolClientDirectory": { + "Value": "../../../Examples/Client/Unity/Assets/Scripts/Hotfix/Generate/NetworkProtocol/", + "Comment": "ProtoBuf生成到客户端的文件夹位置" + }, + "Serializes": { + "Value": [ +// { +// "KeyIndex": 0, +// "NameSpace" : "MemoryPack", +// "SerializeName": "MemoryPack", +// "Attribute": "\t[MemoryPackable]", +// "Ignore": "\t\t[MemoryPackIgnore]", +// "Member": "MemoryPackOrder" +// } + ], + "Comment": "自定义序列化器" + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/NetworkProtocol/Fantasy.Tools.NetworkProtocol b/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/NetworkProtocol/Fantasy.Tools.NetworkProtocol new file mode 100644 index 0000000..25ceaf1 Binary files /dev/null and b/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/NetworkProtocol/Fantasy.Tools.NetworkProtocol differ diff --git a/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/NetworkProtocol/Fantasy.Tools.NetworkProtocol.deps.json b/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/NetworkProtocol/Fantasy.Tools.NetworkProtocol.deps.json new file mode 100644 index 0000000..3c053cb --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/NetworkProtocol/Fantasy.Tools.NetworkProtocol.deps.json @@ -0,0 +1,227 @@ +{ + "runtimeTarget": { + "name": ".NETCoreApp,Version=v8.0", + "signature": "" + }, + "compilationOptions": {}, + "targets": { + ".NETCoreApp,Version=v8.0": { + "Fantasy.Tools.NetworkProtocol/1.0.0": { + "dependencies": { + "CommandLineParser": "2.9.1", + "Microsoft.Extensions.Configuration.Json": "8.0.0", + "Newtonsoft.Json": "13.0.3" + }, + "runtime": { + "Fantasy.Tools.NetworkProtocol.dll": {} + } + }, + "CommandLineParser/2.9.1": { + "runtime": { + "lib/netstandard2.0/CommandLine.dll": { + "assemblyVersion": "2.9.1.0", + "fileVersion": "2.9.1.0" + } + } + }, + "Microsoft.Extensions.Configuration/8.0.0": { + "dependencies": { + "Microsoft.Extensions.Configuration.Abstractions": "8.0.0", + "Microsoft.Extensions.Primitives": "8.0.0" + }, + "runtime": { + "lib/net8.0/Microsoft.Extensions.Configuration.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.23.53103" + } + } + }, + "Microsoft.Extensions.Configuration.Abstractions/8.0.0": { + "dependencies": { + "Microsoft.Extensions.Primitives": "8.0.0" + }, + "runtime": { + "lib/net8.0/Microsoft.Extensions.Configuration.Abstractions.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.23.53103" + } + } + }, + "Microsoft.Extensions.Configuration.FileExtensions/8.0.0": { + "dependencies": { + "Microsoft.Extensions.Configuration": "8.0.0", + "Microsoft.Extensions.Configuration.Abstractions": "8.0.0", + "Microsoft.Extensions.FileProviders.Abstractions": "8.0.0", + "Microsoft.Extensions.FileProviders.Physical": "8.0.0", + "Microsoft.Extensions.Primitives": "8.0.0" + }, + "runtime": { + "lib/net8.0/Microsoft.Extensions.Configuration.FileExtensions.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.23.53103" + } + } + }, + "Microsoft.Extensions.Configuration.Json/8.0.0": { + "dependencies": { + "Microsoft.Extensions.Configuration": "8.0.0", + "Microsoft.Extensions.Configuration.Abstractions": "8.0.0", + "Microsoft.Extensions.Configuration.FileExtensions": "8.0.0", + "Microsoft.Extensions.FileProviders.Abstractions": "8.0.0", + "System.Text.Json": "8.0.0" + }, + "runtime": { + "lib/net8.0/Microsoft.Extensions.Configuration.Json.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.23.53103" + } + } + }, + "Microsoft.Extensions.FileProviders.Abstractions/8.0.0": { + "dependencies": { + "Microsoft.Extensions.Primitives": "8.0.0" + }, + "runtime": { + "lib/net8.0/Microsoft.Extensions.FileProviders.Abstractions.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.23.53103" + } + } + }, + "Microsoft.Extensions.FileProviders.Physical/8.0.0": { + "dependencies": { + "Microsoft.Extensions.FileProviders.Abstractions": "8.0.0", + "Microsoft.Extensions.FileSystemGlobbing": "8.0.0", + "Microsoft.Extensions.Primitives": "8.0.0" + }, + "runtime": { + "lib/net8.0/Microsoft.Extensions.FileProviders.Physical.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.23.53103" + } + } + }, + "Microsoft.Extensions.FileSystemGlobbing/8.0.0": { + "runtime": { + "lib/net8.0/Microsoft.Extensions.FileSystemGlobbing.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.23.53103" + } + } + }, + "Microsoft.Extensions.Primitives/8.0.0": { + "runtime": { + "lib/net8.0/Microsoft.Extensions.Primitives.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.23.53103" + } + } + }, + "Newtonsoft.Json/13.0.3": { + "runtime": { + "lib/net6.0/Newtonsoft.Json.dll": { + "assemblyVersion": "13.0.0.0", + "fileVersion": "13.0.3.27908" + } + } + }, + "System.Text.Encodings.Web/8.0.0": {}, + "System.Text.Json/8.0.0": { + "dependencies": { + "System.Text.Encodings.Web": "8.0.0" + } + } + } + }, + "libraries": { + "Fantasy.Tools.NetworkProtocol/1.0.0": { + "type": "project", + "serviceable": false, + "sha512": "" + }, + "CommandLineParser/2.9.1": { + "type": "package", + "serviceable": true, + "sha512": "sha512-OE0sl1/sQ37bjVsPKKtwQlWDgqaxWgtme3xZz7JssWUzg5JpMIyHgCTY9MVMxOg48fJ1AgGT3tgdH5m/kQ5xhA==", + "path": "commandlineparser/2.9.1", + "hashPath": "commandlineparser.2.9.1.nupkg.sha512" + }, + "Microsoft.Extensions.Configuration/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-0J/9YNXTMWSZP2p2+nvl8p71zpSwokZXZuJW+VjdErkegAnFdO1XlqtA62SJtgVYHdKu3uPxJHcMR/r35HwFBA==", + "path": "microsoft.extensions.configuration/8.0.0", + "hashPath": "microsoft.extensions.configuration.8.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.Configuration.Abstractions/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-3lE/iLSutpgX1CC0NOW70FJoGARRHbyKmG7dc0klnUZ9Dd9hS6N/POPWhKhMLCEuNN5nXEY5agmlFtH562vqhQ==", + "path": "microsoft.extensions.configuration.abstractions/8.0.0", + "hashPath": "microsoft.extensions.configuration.abstractions.8.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.Configuration.FileExtensions/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-McP+Lz/EKwvtCv48z0YImw+L1gi1gy5rHhNaNIY2CrjloV+XY8gydT8DjMR6zWeL13AFK+DioVpppwAuO1Gi1w==", + "path": "microsoft.extensions.configuration.fileextensions/8.0.0", + "hashPath": "microsoft.extensions.configuration.fileextensions.8.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.Configuration.Json/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-C2wqUoh9OmRL1akaCcKSTmRU8z0kckfImG7zLNI8uyi47Lp+zd5LWAD17waPQEqCz3ioWOCrFUo+JJuoeZLOBw==", + "path": "microsoft.extensions.configuration.json/8.0.0", + "hashPath": "microsoft.extensions.configuration.json.8.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.FileProviders.Abstractions/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-ZbaMlhJlpisjuWbvXr4LdAst/1XxH3vZ6A0BsgTphZ2L4PGuxRLz7Jr/S7mkAAnOn78Vu0fKhEgNF5JO3zfjqQ==", + "path": "microsoft.extensions.fileproviders.abstractions/8.0.0", + "hashPath": "microsoft.extensions.fileproviders.abstractions.8.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.FileProviders.Physical/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-UboiXxpPUpwulHvIAVE36Knq0VSHaAmfrFkegLyBZeaADuKezJ/AIXYAW8F5GBlGk/VaibN2k/Zn1ca8YAfVdA==", + "path": "microsoft.extensions.fileproviders.physical/8.0.0", + "hashPath": "microsoft.extensions.fileproviders.physical.8.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.FileSystemGlobbing/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-OK+670i7esqlQrPjdIKRbsyMCe9g5kSLpRRQGSr4Q58AOYEe/hCnfLZprh7viNisSUUQZmMrbbuDaIrP+V1ebQ==", + "path": "microsoft.extensions.filesystemglobbing/8.0.0", + "hashPath": "microsoft.extensions.filesystemglobbing.8.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.Primitives/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-bXJEZrW9ny8vjMF1JV253WeLhpEVzFo1lyaZu1vQ4ZxWUlVvknZ/+ftFgVheLubb4eZPSwwxBeqS1JkCOjxd8g==", + "path": "microsoft.extensions.primitives/8.0.0", + "hashPath": "microsoft.extensions.primitives.8.0.0.nupkg.sha512" + }, + "Newtonsoft.Json/13.0.3": { + "type": "package", + "serviceable": true, + "sha512": "sha512-HrC5BXdl00IP9zeV+0Z848QWPAoCr9P3bDEZguI+gkLcBKAOxix/tLEAAHC+UvDNPv4a2d18lOReHMOagPa+zQ==", + "path": "newtonsoft.json/13.0.3", + "hashPath": "newtonsoft.json.13.0.3.nupkg.sha512" + }, + "System.Text.Encodings.Web/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-yev/k9GHAEGx2Rg3/tU6MQh4HGBXJs70y7j1LaM1i/ER9po+6nnQ6RRqTJn1E7Xu0fbIFK80Nh5EoODxrbxwBQ==", + "path": "system.text.encodings.web/8.0.0", + "hashPath": "system.text.encodings.web.8.0.0.nupkg.sha512" + }, + "System.Text.Json/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-OdrZO2WjkiEG6ajEFRABTRCi/wuXQPxeV6g8xvUJqdxMvvuCCEk86zPla8UiIQJz3durtUEbNyY/3lIhS0yZvQ==", + "path": "system.text.json/8.0.0", + "hashPath": "system.text.json.8.0.0.nupkg.sha512" + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/NetworkProtocol/Fantasy.Tools.NetworkProtocol.dll b/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/NetworkProtocol/Fantasy.Tools.NetworkProtocol.dll new file mode 100644 index 0000000..918803d Binary files /dev/null and b/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/NetworkProtocol/Fantasy.Tools.NetworkProtocol.dll differ diff --git a/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/NetworkProtocol/Fantasy.Tools.NetworkProtocol.pdb b/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/NetworkProtocol/Fantasy.Tools.NetworkProtocol.pdb new file mode 100644 index 0000000..39d574a Binary files /dev/null and b/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/NetworkProtocol/Fantasy.Tools.NetworkProtocol.pdb differ diff --git a/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/NetworkProtocol/Fantasy.Tools.NetworkProtocol.runtimeconfig.json b/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/NetworkProtocol/Fantasy.Tools.NetworkProtocol.runtimeconfig.json new file mode 100644 index 0000000..becfaea --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/NetworkProtocol/Fantasy.Tools.NetworkProtocol.runtimeconfig.json @@ -0,0 +1,12 @@ +{ + "runtimeOptions": { + "tfm": "net8.0", + "framework": { + "name": "Microsoft.NETCore.App", + "version": "8.0.0" + }, + "configProperties": { + "System.Runtime.Serialization.EnableUnsafeBinaryFormatterSerialization": false + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/NetworkProtocol/Microsoft.Extensions.Configuration.Abstractions.dll b/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/NetworkProtocol/Microsoft.Extensions.Configuration.Abstractions.dll new file mode 100644 index 0000000..a5ab313 Binary files /dev/null and b/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/NetworkProtocol/Microsoft.Extensions.Configuration.Abstractions.dll differ diff --git a/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/NetworkProtocol/Microsoft.Extensions.Configuration.FileExtensions.dll b/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/NetworkProtocol/Microsoft.Extensions.Configuration.FileExtensions.dll new file mode 100644 index 0000000..4efc1a5 Binary files /dev/null and b/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/NetworkProtocol/Microsoft.Extensions.Configuration.FileExtensions.dll differ diff --git a/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/NetworkProtocol/Microsoft.Extensions.Configuration.Json.dll b/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/NetworkProtocol/Microsoft.Extensions.Configuration.Json.dll new file mode 100644 index 0000000..296db6a Binary files /dev/null and b/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/NetworkProtocol/Microsoft.Extensions.Configuration.Json.dll differ diff --git a/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/NetworkProtocol/Microsoft.Extensions.Configuration.dll b/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/NetworkProtocol/Microsoft.Extensions.Configuration.dll new file mode 100644 index 0000000..d3e5c22 Binary files /dev/null and b/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/NetworkProtocol/Microsoft.Extensions.Configuration.dll differ diff --git a/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/NetworkProtocol/Microsoft.Extensions.FileProviders.Abstractions.dll b/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/NetworkProtocol/Microsoft.Extensions.FileProviders.Abstractions.dll new file mode 100644 index 0000000..f907206 Binary files /dev/null and b/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/NetworkProtocol/Microsoft.Extensions.FileProviders.Abstractions.dll differ diff --git a/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/NetworkProtocol/Microsoft.Extensions.FileProviders.Physical.dll b/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/NetworkProtocol/Microsoft.Extensions.FileProviders.Physical.dll new file mode 100644 index 0000000..6fb7f47 Binary files /dev/null and b/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/NetworkProtocol/Microsoft.Extensions.FileProviders.Physical.dll differ diff --git a/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/NetworkProtocol/Microsoft.Extensions.FileSystemGlobbing.dll b/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/NetworkProtocol/Microsoft.Extensions.FileSystemGlobbing.dll new file mode 100644 index 0000000..e590735 Binary files /dev/null and b/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/NetworkProtocol/Microsoft.Extensions.FileSystemGlobbing.dll differ diff --git a/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/NetworkProtocol/Microsoft.Extensions.Primitives.dll b/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/NetworkProtocol/Microsoft.Extensions.Primitives.dll new file mode 100644 index 0000000..c24f2a0 Binary files /dev/null and b/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/NetworkProtocol/Microsoft.Extensions.Primitives.dll differ diff --git a/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/NetworkProtocol/Newtonsoft.Json.dll b/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/NetworkProtocol/Newtonsoft.Json.dll new file mode 100644 index 0000000..d035c38 Binary files /dev/null and b/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/NetworkProtocol/Newtonsoft.Json.dll differ diff --git a/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/NetworkProtocol/Run.bat b/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/NetworkProtocol/Run.bat new file mode 100644 index 0000000..af6e9e9 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/NetworkProtocol/Run.bat @@ -0,0 +1,21 @@ +@echo off + +echo Please select an option: +echo 1. Client +echo 2. Server +echo 3. All + +set /p choice=Please select an option: + +if "%choice%"=="1" ( + echo Client + dotnet Fantasy.Tools.NetworkProtocol.dll --p 1 +) else if "%choice%"=="2" ( + echo Server + dotnet Fantasy.Tools.NetworkProtocol.dll --p 2 +) else if "%choice%"=="3" ( + echo All + dotnet Fantasy.Tools.NetworkProtocol.dll --p 3 +) else ( + echo Invalid option +) diff --git a/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/NetworkProtocol/Run.sh b/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/NetworkProtocol/Run.sh new file mode 100644 index 0000000..015b119 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Tools/Exporter/NetworkProtocol/Run.sh @@ -0,0 +1,23 @@ +#!/bin/bash + +echo "1. Client" +echo "2. Server" +echo "3. All" + +read -n 1 -p "Please select an option:" choice +echo "" +echo "" +case $choice in + 1) + dotnet Fantasy.Tools.NetworkProtocol.dll --p 1 + ;; + 2) + dotnet Fantasy.Tools.NetworkProtocol.dll --p 2 + ;; + 3) + dotnet Fantasy.Tools.NetworkProtocol.dll --p 3 + ;; + *) + echo "Invalid option" + ;; +esac diff --git a/物品和背包的完整代码/Packages/Fantasy/Tools/NuGet/Fantasy.Tools.ExporterConfigTable/Fantasy-Net.Tools.ExporterConfigTable.targets b/物品和背包的完整代码/Packages/Fantasy/Tools/NuGet/Fantasy.Tools.ExporterConfigTable/Fantasy-Net.Tools.ExporterConfigTable.targets new file mode 100644 index 0000000..e8b9fad --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Tools/NuGet/Fantasy.Tools.ExporterConfigTable/Fantasy-Net.Tools.ExporterConfigTable.targets @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/物品和背包的完整代码/Packages/Fantasy/Tools/NuGet/Fantasy.Tools.ExporterConfigTable/Fantasy.Tools.ExporterConfigTable.csproj b/物品和背包的完整代码/Packages/Fantasy/Tools/NuGet/Fantasy.Tools.ExporterConfigTable/Fantasy.Tools.ExporterConfigTable.csproj new file mode 100644 index 0000000..4bd200c --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Tools/NuGet/Fantasy.Tools.ExporterConfigTable/Fantasy.Tools.ExporterConfigTable.csproj @@ -0,0 +1,31 @@ + + + + Fantasy-Net.Tools.ExporterConfigTable + 2024.2.0 + Fantasy-Net.Tools.ExporterConfigTable + qq362946 + qq362946 + ../../../nupkg + false + + Fantasy is a high-performance network development framework based on .NET, supporting mainstream protocols. It is designed for development teams or individuals needing a quick start, scalability, and a distributed, cross-platform solution at the commercial level. Fantasy aims to provide easy-to-use tools while ensuring high system performance and scalability. + Copyright 2026 qq362946 + https://www.code-fantasy.com/ + https://github.com/qq362946/Fantasy + git + Net, c#, Server, Game, GameServer, Fantasy , Network + icon.png + net8.0 + enable + enable + + + + + + + + + + diff --git a/物品和背包的完整代码/Packages/Fantasy/Tools/NuGet/Fantasy.Tools.ExporterConfigTable/icon.png b/物品和背包的完整代码/Packages/Fantasy/Tools/NuGet/Fantasy.Tools.ExporterConfigTable/icon.png new file mode 100644 index 0000000..8ae7488 Binary files /dev/null and b/物品和背包的完整代码/Packages/Fantasy/Tools/NuGet/Fantasy.Tools.ExporterConfigTable/icon.png differ diff --git a/物品和背包的完整代码/Packages/Fantasy/Tools/NuGet/Fantasy.Tools.ExporterNetworkProtocol/Fantasy-Net.Tools.ExporterNetworkProtocol.targets b/物品和背包的完整代码/Packages/Fantasy/Tools/NuGet/Fantasy.Tools.ExporterNetworkProtocol/Fantasy-Net.Tools.ExporterNetworkProtocol.targets new file mode 100644 index 0000000..d719402 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Tools/NuGet/Fantasy.Tools.ExporterNetworkProtocol/Fantasy-Net.Tools.ExporterNetworkProtocol.targets @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/物品和背包的完整代码/Packages/Fantasy/Tools/NuGet/Fantasy.Tools.ExporterNetworkProtocol/Fantasy.Tools.ExporterNetworkProtocol.csproj b/物品和背包的完整代码/Packages/Fantasy/Tools/NuGet/Fantasy.Tools.ExporterNetworkProtocol/Fantasy.Tools.ExporterNetworkProtocol.csproj new file mode 100644 index 0000000..9523891 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Tools/NuGet/Fantasy.Tools.ExporterNetworkProtocol/Fantasy.Tools.ExporterNetworkProtocol.csproj @@ -0,0 +1,31 @@ + + + + Fantasy-Net.Tools.ExporterNetworkProtocol + 2024.2.24 + Fantasy-Net.Tools.ExporterNetworkProtocol + qq362946 + qq362946 + ../../../nupkg + false + + Fantasy is a high-performance network development framework based on .NET, supporting mainstream protocols. It is designed for development teams or individuals needing a quick start, scalability, and a distributed, cross-platform solution at the commercial level. Fantasy aims to provide easy-to-use tools while ensuring high system performance and scalability. + Copyright 2026 qq362946 + https://www.code-fantasy.com/ + https://github.com/qq362946/Fantasy + git + Net, c#, Server, Game, GameServer, Fantasy , Network + icon.png + net8.0 + enable + enable + + + + + + + + + + diff --git a/物品和背包的完整代码/Packages/Fantasy/Tools/NuGet/Fantasy.Tools.ExporterNetworkProtocol/icon.png b/物品和背包的完整代码/Packages/Fantasy/Tools/NuGet/Fantasy.Tools.ExporterNetworkProtocol/icon.png new file mode 100644 index 0000000..8ae7488 Binary files /dev/null and b/物品和背包的完整代码/Packages/Fantasy/Tools/NuGet/Fantasy.Tools.ExporterNetworkProtocol/icon.png differ diff --git a/物品和背包的完整代码/Packages/Fantasy/Tools/SourceCode/Fantasy.Tools.ConfigTable/Core/Base/ExportType.cs b/物品和背包的完整代码/Packages/Fantasy/Tools/SourceCode/Fantasy.Tools.ConfigTable/Core/Base/ExportType.cs new file mode 100644 index 0000000..fa2b818 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Tools/SourceCode/Fantasy.Tools.ConfigTable/Core/Base/ExportType.cs @@ -0,0 +1,24 @@ +namespace Fantasy.Tools.ConfigTable; + +/// +/// 导出类型枚举,用于标识不同类型的导出操作。 +/// +public enum ExportType +{ + /// + /// 无导出类型。 + /// + None = 0, + /// + /// 所有数据的增量导出Excel类型。 + /// + AllExcelIncrement = 1, + /// + /// 所有数据的全量导出Excel类型。 + /// + AllExcel = 2, + /// + /// 导出类型枚举的最大值,一定要放在最后。 + /// + Max, +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Tools/SourceCode/Fantasy.Tools.ConfigTable/CustomExport/ConstValueToConst1.cs b/物品和背包的完整代码/Packages/Fantasy/Tools/SourceCode/Fantasy.Tools.ConfigTable/CustomExport/ConstValueToConst1.cs new file mode 100644 index 0000000..88e7197 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Tools/SourceCode/Fantasy.Tools.ConfigTable/CustomExport/ConstValueToConst1.cs @@ -0,0 +1,158 @@ +// using System; +// using System.Text; +// using Exporter.Excel; +// using Fantasy.Exporter; +// using OfficeOpenXml; +// +// namespace Exporter; +// +// public class ConstValueToConst : ACustomExport +// { +// public override void Run() +// { +// if (!ExcelExporter.LoadIgnoreExcel("#ConstValue", out var excelPackage)) +// { +// Log.Error("ConstValueToConst: Load Excel failed."); +// return; +// } +// +// var worksheet = excelPackage.Workbook.Worksheets[0]; +// +// var serverHotfixStrBuilder = new StringBuilder(); +// serverHotfixStrBuilder.AppendLine("namespace Fantasy\n{"); +// serverHotfixStrBuilder.AppendLine("\t// 生成器自动生成,请不要手动编辑,修改请在#ConstValue.xsl里。"); +// serverHotfixStrBuilder.AppendLine("\tpublic partial class ConstValueHotfix\n\t{"); +// +// var serverModelStrBuilder = new StringBuilder(); +// serverModelStrBuilder.AppendLine("namespace Fantasy\n{"); +// serverModelStrBuilder.AppendLine("\t// 生成器自动生成,请不要手动编辑。"); +// serverModelStrBuilder.AppendLine("\tpublic partial class ConstValue\n\t{"); +// +// var clientStrBuilder = new StringBuilder(); +// clientStrBuilder.AppendLine("namespace Fantasy\n{"); +// clientStrBuilder.AppendLine("\t// 生成器自动生成,请不要手动编辑。"); +// clientStrBuilder.AppendLine("\tpublic class ConstValue\n\t{"); +// +// for (var row = 2; row <= worksheet.Dimension.Rows; row++) +// { +// var first = worksheet.GetCellValue(row, 1); +// var second = worksheet.GetCellValue(row, 2); +// var lower = first?.ToLower() ?? ""; +// var isClient = lower.Contains("c"); +// var isServerModel = lower.Contains("sh"); +// var isServerHotfix = lower.Contains("sm"); +// +// if (string.IsNullOrEmpty(second)) +// { +// continue; +// } +// +// string str; +// +// if (second.StartsWith("#")) +// { +// str = $"\t\t// {second}"; +// clientStrBuilder.AppendLine(str); +// serverModelStrBuilder.AppendLine(str); +// serverHotfixStrBuilder.AppendLine(str); +// continue; +// } +// +// str = GetCodeStr(worksheet, row); +// +// if (isServerModel) +// { +// serverModelStrBuilder.AppendLine(str); +// } +// +// if (isServerHotfix) +// { +// serverHotfixStrBuilder.AppendLine(str); +// } +// +// if (isClient) +// { +// clientStrBuilder.AppendLine(str); +// } +// } +// +// clientStrBuilder.AppendLine("\t}\n}"); +// serverModelStrBuilder.AppendLine("\t}\n}"); +// serverHotfixStrBuilder.AppendLine("\t}\n}"); +// +// Write("ConstValue.cs", clientStrBuilder.ToString(), CustomExportType.Client); +// Write("ConstValue.cs", serverModelStrBuilder.ToString(), CustomExportType.Server); +// Write("ConstValueHotfix.cs", serverHotfixStrBuilder.ToString(),"../../Server/Hotfix/Generate/CustomExport123" ,CustomExportType.Server); +// } +// +// private static string GetCodeStr(ExcelWorksheet sheet, int row) +// { +// var typeStr = sheet.GetCellValue(row, 3); +// var name = sheet.GetCellValue(row, 2); +// var value = sheet.GetCellValue(row, 4); +// var desc = sheet.GetCellValue(row, 5); +// +// try +// { +// if (typeStr.Contains("[]") || typeStr.Contains("[,]")) +// { +// return $"\t\tpublic static readonly {typeStr} {name} = {DefaultValue(typeStr, value)}; // {desc}"; +// } +// +// if (typeStr.Contains("Vector")) +// { +// return $"\t\tpublic static readonly {typeStr} {name} = {DefaultValue(typeStr, value)}; // {desc}"; +// } +// +// return $"\t\tpublic const {typeStr} {name} = {DefaultValue(typeStr, value)}; // {desc}"; +// } +// catch (Exception e) +// { +// Log.Error($"{name} 常量导出异常 : {e}"); +// return ""; +// } +// } +// +// private static string DefaultValue(string type, string value) +// { +// switch (type) +// { +// case "byte[]": +// case "int[]": +// case "long[]": +// case "string[]": +// case "double[]": +// case "float[]": +// return $"new {type} {{{value}}}"; +// case "byte[,]": +// case "int[,]": +// case "long[,]": +// case "string[,]": +// case "float[,]": +// case "double[,]": +// return $"new {type} {{{value}}}"; +// case "int": +// case "bool": +// case "uint": +// case "long": +// case "double": +// return $"{value}"; +// case "float": +// return value[^1] == 'f' ? value : $"{value}f"; +// case "string": +// return $"\"{value}\""; +// case "Vector2": +// { +// var strings = value.Split(',', StringSplitOptions.TrimEntries); +// return $"new Vector2({strings[0]},{strings[1]})"; +// } +// case "Vector3": +// { +// var strings = value.Split(',', StringSplitOptions.TrimEntries); +// return $"new Vector3({strings[0]},{strings[1]},{strings[2]})"; +// } +// default: +// throw new Exception($"不支持此类型: {type}"); +// } +// } +// } \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Tools/SourceCode/Fantasy.Tools.ConfigTable/CustomExport/SceneTypeConfigToEnum.cs b/物品和背包的完整代码/Packages/Fantasy/Tools/SourceCode/Fantasy.Tools.ConfigTable/CustomExport/SceneTypeConfigToEnum.cs new file mode 100644 index 0000000..95904f4 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Tools/SourceCode/Fantasy.Tools.ConfigTable/CustomExport/SceneTypeConfigToEnum.cs @@ -0,0 +1,62 @@ +using System.Text; +using Fantasy.Tools.ConfigTable; +using System.Collections.Generic; + +namespace Exporter; + +/// +/// 将场景类型配置表转换为枚举和字典的自定义导出类。 +/// +public class SceneTypeConfigToEnum : ACustomExport +{ + public override void Run() + { + var sceneType = new Dictionary(); + // 获取场景配置表的完整路径 + if (!Worksheets.TryGetValue("SceneTypeConfig", out var sceneTypeConfig)) + { + return; + } + for (var row = 3; row <= sceneTypeConfig.Dimension.Rows; row++) + { + var sceneTypeId = sceneTypeConfig.GetCellValue(row, 1); + var sceneTypeStr = sceneTypeConfig.GetCellValue(row, 2); + + if (string.IsNullOrEmpty(sceneTypeId) || string.IsNullOrEmpty(sceneTypeStr)) + { + continue; + } + + sceneType.Add(sceneTypeId, sceneTypeStr); + } + // 如果存在场景类型或场景子类型,执行导出操作 + if (sceneType.Count > 0) + { + Write(CustomExportType.Server, sceneType); + } + } + + private void Write(CustomExportType customExportType, Dictionary sceneTypes) + { + var strBuilder = new StringBuilder(); + var dicBuilder = new StringBuilder(); + // 添加命名空间和注释头部 + strBuilder.AppendLine("namespace Fantasy\n{"); + strBuilder.AppendLine("\t// 生成器自动生成,请不要手动编辑。"); + // 生成场景类型的静态类 + strBuilder.AppendLine("\tpublic static class SceneType\n\t{"); + dicBuilder.AppendLine("\n\t\tpublic static readonly Dictionary SceneTypeDic = new Dictionary()\n\t\t{"); + // 遍历场景类型字典,生成场景类型的常量和字典项 + foreach (var (sceneTypeId, sceneTypeStr) in sceneTypes) + { + dicBuilder.AppendLine($"\t\t\t{{ \"{sceneTypeStr}\", {sceneTypeId} }},"); + strBuilder.AppendLine($"\t\tpublic const int {sceneTypeStr} = {sceneTypeId};"); + } + // 添加场景类型字典尾部,合并到主字符串构建器中 + dicBuilder.AppendLine("\t\t};"); + strBuilder.Append(dicBuilder); + strBuilder.AppendLine("\t}\n}"); + // 调用外部方法将生成的代码写入文件 + Write("SceneType.cs", strBuilder.ToString(), customExportType); + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Tools/SourceCode/Fantasy.Tools.ConfigTable/Exporter/ConfigTableHelper.cs b/物品和背包的完整代码/Packages/Fantasy/Tools/SourceCode/Fantasy.Tools.ConfigTable/Exporter/ConfigTableHelper.cs new file mode 100644 index 0000000..7a13fa9 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Tools/SourceCode/Fantasy.Tools.ConfigTable/Exporter/ConfigTableHelper.cs @@ -0,0 +1,13 @@ +using Fantasy.Serialize; + +#pragma warning disable CS8603 // Possible null reference return. + +namespace Fantasy; + +public static class ConfigTableHelper +{ + public static T Load() where T : ASerialize + { + return default; + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Tools/SourceCode/Fantasy.Tools.ConfigTable/Exporter/DynamicAssembly/DynamicAssembly.cs b/物品和背包的完整代码/Packages/Fantasy/Tools/SourceCode/Fantasy.Tools.ConfigTable/Exporter/DynamicAssembly/DynamicAssembly.cs new file mode 100644 index 0000000..2cf3b29 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Tools/SourceCode/Fantasy.Tools.ConfigTable/Exporter/DynamicAssembly/DynamicAssembly.cs @@ -0,0 +1,170 @@ +using System.Reflection; +using Fantasy.Exporter; +using Fantasy.Serialize; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using ProtoBuf; +#pragma warning disable CS8601 // Possible null reference assignment. + +namespace Exporter.Excel; + +/// +/// 动态程序集类,用于加载动态生成的程序集并获取动态信息。 +/// +public static class DynamicAssembly +{ + private static void MetadataReference(out string assemblyName, out List metadataReferenceList) + { + AssemblyMetadata assemblyMetadata; + MetadataReference metadataReference; + var currentDomain = AppDomain.CurrentDomain; + assemblyName = Path.GetRandomFileName(); + var assemblyArray = currentDomain.GetAssemblies(); + metadataReferenceList = new List(); + + // 注册引用 + + foreach (var domainAssembly in assemblyArray) + { + if (string.IsNullOrEmpty(domainAssembly.Location)) + { + continue; + } + + assemblyMetadata = AssemblyMetadata.CreateFromFile(domainAssembly.Location); + metadataReference = assemblyMetadata.GetReference(); + metadataReferenceList.Add(metadataReference); + } + + // 添加Proto支持 + + assemblyMetadata = AssemblyMetadata.CreateFromFile(typeof(ProtoMemberAttribute).Assembly.Location); + metadataReference = assemblyMetadata.GetReference(); + metadataReferenceList.Add(metadataReference); + + // 添加Fantasy支持 + + assemblyMetadata = AssemblyMetadata.CreateFromFile(typeof(ASerialize).Assembly.Location); + metadataReference = assemblyMetadata.GetReference(); + metadataReferenceList.Add(metadataReference); + } + + /// + /// 加载指定路径下的动态程序集。 + /// + /// 程序集文件路径。 + /// 加载的动态程序集。 + public static Assembly Load(string path) + { + var fileList = new List(); + + // 找到所有需要加载的CS文件 + + foreach (string file in Directory.GetFiles(path)) + { + if (Path.GetExtension(file) != ".cs") + { + continue; + } + + fileList.Add(file); + } + + var syntaxTreeList = new List(); + + foreach (var file in fileList) + { + using var fileStream = new StreamReader(file); + var cSharp = CSharpSyntaxTree.ParseText(fileStream.ReadToEnd()); + syntaxTreeList.Add(cSharp); + } + + // 注册程序集 + MetadataReference(out var assemblyName, out var metadataReferenceList); + var compilation = CSharpCompilation.Create(assemblyName, syntaxTreeList, metadataReferenceList, new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)); + using var ms = new MemoryStream(); + var result = compilation.Emit(ms); + if (!result.Success) + { + foreach (var resultDiagnostic in result.Diagnostics) + { + Log.Error(resultDiagnostic.GetMessage()); + } + + throw new Exception("failures"); + } + + ms.Seek(0, SeekOrigin.Begin); + return Assembly.Load(ms.ToArray()); + } + + /// + /// 获取动态程序集中指定表格的动态信息。 + /// + /// 动态程序集。 + /// 表格名称。 + /// 动态信息对象。 + public static DynamicConfigDataType GetDynamicInfo(Assembly dynamicAssembly, string tableName) + { + var dynamicConfigDataType = new DynamicConfigDataType + { + ConfigDataType = GetConfigType(dynamicAssembly, $"{tableName}Data"), + ConfigType = GetConfigType(dynamicAssembly, $"{tableName}") + }; + + dynamicConfigDataType.ConfigData = CreateInstance(dynamicConfigDataType.ConfigDataType); + + var listPropertyType = dynamicConfigDataType.ConfigDataType.GetProperty("List"); + + if (listPropertyType == null) + { + throw new Exception("No Property named Add was found"); + } + + dynamicConfigDataType.Obj = listPropertyType.GetValue(dynamicConfigDataType.ConfigData); + dynamicConfigDataType.Method = listPropertyType.PropertyType.GetMethod("Add"); + + if (dynamicConfigDataType.Method == null) + { + throw new Exception("No method named Add was found"); + } + + return dynamicConfigDataType; + } + + /// + /// 根据类型名称获取动态类型。 + /// + /// 动态程序集。 + /// 类型名称。 + /// 动态类型。 + private static Type GetConfigType(Assembly dynamicAssembly, string typeName) + { + var configType = dynamicAssembly.GetType($"Fantasy.{typeName}"); + + if (configType == null) + { + throw new FileNotFoundException($"Fantasy.{typeName} not found"); + } + + return configType; + // return dynamicAssembly.GetType($"Fantasy.{typeName}"); + } + + /// + /// 创建动态实例。 + /// + /// 动态类型。 + /// 动态实例。 + public static object CreateInstance(Type configType) + { + var config = Activator.CreateInstance(configType); + + if (config == null) + { + throw new Exception($"{configType.Name} is Activator.CreateInstance error"); + } + + return config; + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Tools/SourceCode/Fantasy.Tools.ConfigTable/Exporter/DynamicAssembly/DynamicConfigDataType.cs b/物品和背包的完整代码/Packages/Fantasy/Tools/SourceCode/Fantasy.Tools.ConfigTable/Exporter/DynamicAssembly/DynamicConfigDataType.cs new file mode 100644 index 0000000..6725f83 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Tools/SourceCode/Fantasy.Tools.ConfigTable/Exporter/DynamicAssembly/DynamicConfigDataType.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Text; +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. + +namespace Exporter.Excel; + +/// +/// 动态配置数据类型类,用于存储动态配置数据的相关信息。 +/// +public class DynamicConfigDataType +{ + /// + /// 配置数据对象,继承自 AProto 基类。 + /// + public object ConfigData; + /// + /// 配置数据类型。 + /// + public Type ConfigDataType; + /// + /// 配置类型。 + /// + public Type ConfigType; + /// + /// 反射方法信息,用于调用特定方法。 + /// + public MethodInfo Method; + /// + /// 配置数据对象实例。 + /// + public object Obj; + /// + /// 用于生成 JSON 格式数据的字符串构建器。 + /// + public StringBuilder Json = new StringBuilder(); +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Tools/SourceCode/Fantasy.Tools.ConfigTable/Exporter/DynamicAssembly/OneDynamicAssembly.cs b/物品和背包的完整代码/Packages/Fantasy/Tools/SourceCode/Fantasy.Tools.ConfigTable/Exporter/DynamicAssembly/OneDynamicAssembly.cs new file mode 100644 index 0000000..57de11e --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Tools/SourceCode/Fantasy.Tools.ConfigTable/Exporter/DynamicAssembly/OneDynamicAssembly.cs @@ -0,0 +1,70 @@ +using System.Reflection; +using Fantasy.Exporter; +using Fantasy.Serialize; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using ProtoBuf; + +namespace Exporter.Excel; + +public class OneDynamicAssembly +{ + private readonly List _syntaxTreeList = new List(); + + public void Load(string file) + { + using var fileStream = new StreamReader(file); + var cSharp = CSharpSyntaxTree.ParseText(fileStream.ReadToEnd()); + _syntaxTreeList.Add(cSharp); + } + + public Assembly Assembly + { + get + { + AssemblyMetadata assemblyMetadata; + MetadataReference metadataReference; + var currentDomain = AppDomain.CurrentDomain; + var assemblyName = Path.GetRandomFileName(); + var assemblyArray = currentDomain.GetAssemblies(); + var metadataReferenceList = new List(); + // 注册引用 + foreach (var domainAssembly in assemblyArray) + { + if (string.IsNullOrEmpty(domainAssembly.Location)) + { + continue; + } + + assemblyMetadata = AssemblyMetadata.CreateFromFile(domainAssembly.Location); + metadataReference = assemblyMetadata.GetReference(); + metadataReferenceList.Add(metadataReference); + } + // 添加ProtoEntity支持 + assemblyMetadata = AssemblyMetadata.CreateFromFile(typeof(ASerialize).Assembly.Location); + metadataReference = assemblyMetadata.GetReference(); + metadataReferenceList.Add(metadataReference); + // 添加MessagePack支持 + assemblyMetadata = AssemblyMetadata.CreateFromFile(typeof(ProtoMemberAttribute).Assembly.Location); + metadataReference = assemblyMetadata.GetReference(); + metadataReferenceList.Add(metadataReference); + CSharpCompilation compilation = CSharpCompilation.Create(assemblyName, _syntaxTreeList, metadataReferenceList, new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)); + + using var ms = new MemoryStream(); + var result = compilation.Emit(ms); + + if (!result.Success) + { + foreach (var resultDiagnostic in result.Diagnostics) + { + Log.Error(resultDiagnostic.GetMessage()); + } + + throw new Exception("failures"); + } + + ms.Seek(0, SeekOrigin.Begin); + return Assembly.Load(ms.ToArray()); + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Tools/SourceCode/Fantasy.Tools.ConfigTable/Exporter/ExcelExporter.cs b/物品和背包的完整代码/Packages/Fantasy/Tools/SourceCode/Fantasy.Tools.ConfigTable/Exporter/ExcelExporter.cs new file mode 100644 index 0000000..e4cdc92 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Tools/SourceCode/Fantasy.Tools.ConfigTable/Exporter/ExcelExporter.cs @@ -0,0 +1,1052 @@ +using System.Collections.Concurrent; +using System.Reflection; +using System.Runtime.Loader; +using System.Security.Cryptography; +using System.Text; +using System.Text.RegularExpressions; +using Exporter; +using Exporter.Excel; +using Fantasy; +using Fantasy.Assembly; +using Fantasy.ConfigTable; +using Fantasy.DataStructure.Collection; +using Fantasy.Exporter; +using Fantasy.Helper; +using Fantasy.Serialize; +using Microsoft.CodeAnalysis; +using Newtonsoft.Json; +using OfficeOpenXml; +using static System.String; +// ReSharper disable InconsistentNaming +#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. +#pragma warning disable CS8602 // Dereference of a possibly null reference. +#pragma warning disable CS8601 // Possible null reference assignment. +#pragma warning disable CS8604 // Possible null reference argument. +#pragma warning disable CS8600 // Converting null literal or possible null value to non-nullable type. + +namespace Fantasy.Tools.ConfigTable; +using TableDictionary = SortedDictionary>; +/// +/// Excel 数据导出器,用于从 Excel 文件导出数据到二进制格式和生成 C# 类文件。 +/// +public sealed class ExcelExporter +{ + public ExportType ExportType; + private readonly string _excelProgramPath; + private readonly string _versionFilePath; + private readonly string _excelClientFileDirectory; + private readonly string _excelServerFileDirectory; + public readonly string ClientCustomExportDirectory; + public readonly string ServerCustomExportDirectory; + private readonly string _excelServerBinaryDirectory; + private readonly string _excelClientBinaryDirectory; + private readonly string _excelServerJsonDirectory; + private readonly string _excelClientJsonDirectory; + public VersionInfo VersionInfo; // 存储 Excel 文件的版本信息。 + private readonly Regex _regexName = new Regex("^[a-zA-Z][a-zA-Z0-9_]*$"); // 用于验证 Excel 表名的正则表达式。 + private readonly HashSet _loadFiles = [".xlsx", ".xlsm", ".csv"]; // 加载的支持文件扩展名。 + private readonly OneToManyList _tables = new OneToManyList(); // 存储 Excel 表及其导出信息。 + private readonly ConcurrentDictionary _excelTables = new ConcurrentDictionary(); // 存储解析后的 Excel 表。 + public readonly ConcurrentDictionary Worksheets = new ConcurrentDictionary(); // 存储已加载的 Excel 工作表。 + public readonly Dictionary IgnoreTable = new Dictionary(); // 存储以#开头的的表和路径 + /// + /// 导表支持的数据类型集合。 + /// + public static readonly HashSet ColTypeSet = + [ + "", "0", "bool", "byte", "short", "ushort", "int", "uint", "long", "ulong", "float", "string", + "IntDictionaryConfig", "StringDictionaryConfig", + "short[]", "int[]", "long[]", "float[]", "string[]", "uint[]" + ]; + /// + /// 导出完成后自动删除的配置表代码文件。 + /// + private static readonly HashSet RemoveConfigSet = + [ + "WorldConfig.cs", "ServerConfig.cs", "SceneConfig.cs", "MachineConfig.cs", "ProcessConfig.cs" + ]; + static ExcelExporter() + { + ExcelPackage.LicenseContext = LicenseContext.NonCommercial; + } + /// + /// 根据指定的 exportType 初始化 ExcelExporter 类的新实例。 + /// + /// 要执行的导出类型(AllExcel 或 AllExcelIncrement)。 + public ExcelExporter(ExportType exportType) + { + ExportType = exportType; + + if (ExporterSettingsHelper.ExcelVersionFile == null || ExporterSettingsHelper.ExcelVersionFile.Trim() == "") + { + Log.Info($"ExcelVersionFile Can not be empty!"); + return; + } + + if (ExporterSettingsHelper.ExcelProgramPath == null || ExporterSettingsHelper.ExcelProgramPath.Trim() == "") + { + Log.Info($"ExcelProgramPath Can not be empty!"); + return; + } + + _excelProgramPath = FileHelper.GetFullPath(ExporterSettingsHelper.ExcelProgramPath); + _versionFilePath = FileHelper.GetFullPath(ExporterSettingsHelper.ExcelVersionFile); + + if (ExporterAges.Instance.ExportPlatform.HasFlag(ExportPlatform.Client)) + { + if (ExporterSettingsHelper.ExcelClientBinaryDirectory == null || + ExporterSettingsHelper.ExcelClientBinaryDirectory.Trim() == "") + { + Log.Info($"ExcelClientBinaryDirectory Can not be empty!"); + return; + } + + if (ExporterSettingsHelper.ExcelClientJsonDirectory == null || + ExporterSettingsHelper.ExcelClientJsonDirectory.Trim() == "") + { + Log.Info($"ExcelClientJsonDirectory Can not be empty!"); + return; + } + + if (ExporterSettingsHelper.ExcelClientFileDirectory == null || + ExporterSettingsHelper.ExcelClientFileDirectory.Trim() == "") + { + Log.Info($"ExcelServerFileDirectory Can not be empty!"); + return; + } + + if (ExporterSettingsHelper.ClientCustomExportDirectory == null || + ExporterSettingsHelper.ClientCustomExportDirectory.Trim() == "") + { + Log.Info($"ClientCustomExportDirectory Can not be empty!"); + return; + } + + _excelClientJsonDirectory = FileHelper.GetFullPath(ExporterSettingsHelper.ExcelClientJsonDirectory); + _excelClientBinaryDirectory = FileHelper.GetFullPath(ExporterSettingsHelper.ExcelClientBinaryDirectory); + ClientCustomExportDirectory = FileHelper.GetFullPath(ExporterSettingsHelper.ClientCustomExportDirectory); + _excelClientFileDirectory = FileHelper.GetFullPath(ExporterSettingsHelper.ExcelClientFileDirectory); + // FileHelper.ClearDirectoryFile(_excelClientFileDirectory); + } + + if (ExporterAges.Instance.ExportPlatform.HasFlag(ExportPlatform.Server)) + { + if (ExporterSettingsHelper.ExcelServerFileDirectory == null || ExporterSettingsHelper.ExcelServerFileDirectory.Trim() == "") + { + Log.Info($"ExcelServerFileDirectory Can not be empty!"); + return; + } + + if (ExporterSettingsHelper.ExcelServerJsonDirectory == null || ExporterSettingsHelper.ExcelServerJsonDirectory.Trim() == "") + { + Log.Info($"ExcelServerJsonDirectory Can not be empty!"); + return; + } + + if (ExporterSettingsHelper.ExcelServerBinaryDirectory == null || ExporterSettingsHelper.ExcelServerBinaryDirectory.Trim() == "") + { + Log.Info($"ExcelServerBinaryDirectory Can not be empty!"); + return; + } + + if (ExporterSettingsHelper.ServerCustomExportDirectory == null || ExporterSettingsHelper.ServerCustomExportDirectory.Trim() == "") + { + Log.Info($"ServerCustomExportDirectory Can not be empty!"); + return; + } + + _excelServerJsonDirectory = FileHelper.GetFullPath(ExporterSettingsHelper.ExcelServerJsonDirectory); + _excelServerBinaryDirectory = FileHelper.GetFullPath(ExporterSettingsHelper.ExcelServerBinaryDirectory); + ServerCustomExportDirectory = FileHelper.GetFullPath(ExporterSettingsHelper.ServerCustomExportDirectory); + _excelServerFileDirectory = FileHelper.GetFullPath(ExporterSettingsHelper.ExcelServerFileDirectory); + // FileHelper.ClearDirectoryFile(_excelServerFileDirectory); + } + + switch (ExportType) + { + case ExportType.AllExcelIncrement: + { + break; + } + case ExportType.AllExcel: + { + if (File.Exists(_versionFilePath)) + { + File.Delete(_versionFilePath); + } + + break; + } + } + + SerializerManager.Initialize(); + + } + + public void Run() + { + Find(); + Parsing(); + ExportToBinary(); + File.WriteAllText(_versionFilePath, JsonConvert.SerializeObject(VersionInfo)); + CustomExport(); + RemoveConfigCS(); + } + private static void RemoveConfigCS() + { + foreach (var removeConfigFile in RemoveConfigSet) + { + var serverFile = Path.Combine(ExporterSettingsHelper.ExcelServerFileDirectory, removeConfigFile); + var clientFile = Path.Combine(ExporterSettingsHelper.ExcelClientFileDirectory, removeConfigFile); + + if (File.Exists(serverFile)) + { + File.Delete(serverFile); + } + + if (File.Exists(clientFile)) + { + File.Delete(clientFile); + } + } + } + + private void CustomExport() + { + var task = new List(); + var excelWorksheets = new ExcelWorksheets(this); + var customConfigure = $"{_excelProgramPath}Custom.txt"; + + if (!File.Exists(customConfigure)) + { + using var streamWriter = File.CreateText(customConfigure); + var stringBuilder = new StringBuilder(); + stringBuilder.AppendLine("// 自定义导出配置文件,用于配置自定义导出自定义程序的路径,每行一个路径,路径是导表应用的相对路径。如:../../Config/Custom/1.cs"); + streamWriter.Write(stringBuilder); + return; + } + + var lineNumber = 0; + var oneDynamicAssembly = new OneDynamicAssembly(); + using var reader = new StreamReader(customConfigure); + + while (reader.ReadLine() is { } lineStr) + { + if (++lineNumber == 1 || string.IsNullOrEmpty(lineStr) || lineStr.StartsWith("#")) + { + continue; + } + + oneDynamicAssembly.Load(FileHelper.GetFullPath(lineStr)); + } + + long AssemblyIdentity(System.Reflection.Assembly assembly) + { + var assemblyName = assembly.GetName(); + var name = assemblyName.Name; + var version = assemblyName.Version.ToString(); + var culture = assemblyName.CultureInfo?.Name ?? "neutral"; + var publicKeyToken = BitConverter.ToString(assemblyName.GetPublicKeyToken()).Replace("-", string.Empty); + var assemblyIdentity = $"{name}|{version}|{culture}|{publicKeyToken}"; + var hashBytes = SHA256.HashData(Encoding.UTF8.GetBytes(assemblyIdentity)); + return BitConverter.ToInt64(hashBytes, 0); + } + + void AddCustomExportTask(System.Reflection.Assembly assembly) + { + var assemblyIdentity = AssemblyIdentity(assembly); + var assemblyInfo = new AssemblyInfo(assemblyIdentity); + assemblyInfo.Load(assembly); + + if (!assemblyInfo.AssemblyTypeGroupList.TryGetValue(typeof(ICustomExport), out var customExportList)) + { + return; + } + + foreach (var type in customExportList) + { + var customExport = (ICustomExport)Activator.CreateInstance(type); + + if (customExport != null) + { + customExport.Init(this, excelWorksheets); + task.Add(Task.Run(customExport.Run)); + } + } + } + + // 生成一个系统内置的自定义导出类 + var sceneTypeConfigToEnum = new SceneTypeConfigToEnum(); + sceneTypeConfigToEnum.Init(this, excelWorksheets); + task.Add(Task.Run(sceneTypeConfigToEnum.Run)); + // task.Add(Task.Run(constValueToConst.Run)); + // 加载自定义导出程序集 + AddCustomExportTask(oneDynamicAssembly.Assembly); + // 执行自定义导出任务 + Task.WaitAll(task.ToArray()); + } + + /// + /// 查找配置文件 + /// + private void Find() + { + VersionInfo = File.Exists(_versionFilePath) ? JsonConvert.DeserializeObject(File.ReadAllText(_versionFilePath)) : new VersionInfo(); + + var dir = new DirectoryInfo(_excelProgramPath); + var excelFiles = dir.GetFiles("*", SearchOption.AllDirectories); + + if (excelFiles.Length <= 0) + { + return; + } + + foreach (var excelFile in excelFiles) + { + // 过滤掉非指定后缀的文件 + + if (!_loadFiles.Contains(excelFile.Extension)) + { + continue; + } + + var lastIndexOf = excelFile.Name.LastIndexOf(".", StringComparison.Ordinal); + + if (lastIndexOf < 0) + { + continue; + } + + var fullName = excelFile.FullName; + var excelName = excelFile.Name.Substring(0, lastIndexOf); + var path = fullName.Substring(0, fullName.Length - excelFile.Name.Length); + + // 过滤~开头文件 + + if (excelName.StartsWith("~", StringComparison.Ordinal)) + { + continue; + } + + // 如果文件名以#开头,那么这个文件夹下的所有文件都不导出 + + if (excelName.StartsWith("#", StringComparison.Ordinal)) + { + IgnoreTable.Add(excelName, fullName); + continue; + } + + // 如果文件夹名包含#,那么这个文件夹下的所有文件都不导出 + + if (path.Contains("#", StringComparison.Ordinal)) + { + continue; + } + + if (!_regexName.IsMatch(excelName)) + { + Log.Info($"{excelName} 配置文件名非法"); + continue; + } + + var exportInfo = new ExportInfo() + { + Name = excelName, FileInfo = excelFile + }; + + _tables.Add(excelName.Split('_')[0], exportInfo); + } + + var removeTables = new List(); + + foreach (var (tableName, tableList) in _tables) + { + var isNeedExport = false; + + foreach (var exportInfo in tableList) + { + var timer = TimeHelper.Transition(exportInfo.FileInfo.LastWriteTime); + + if (!isNeedExport) + { + if (VersionInfo.Tables.TryGetValue(exportInfo.Name, out var lastWriteTime)) + { + isNeedExport = lastWriteTime != timer; + } + else + { + isNeedExport = true; + } + } + + VersionInfo.Tables[exportInfo.Name] = timer; + } + + if (!isNeedExport) + { + removeTables.Add(tableName); + } + } + + foreach (var removeTable in removeTables) + { + _tables.Remove(removeTable); + } + + foreach (var (_, exportInfo) in _tables) + { + exportInfo.Sort((x, y) => Compare(x.Name, y.Name, StringComparison.Ordinal)); + } + } + /// + /// 生成配置文件 + /// + private void Parsing() + { + var generateTasks = new List(); + + foreach (var (tableName, tableList) in _tables) + { + var task = Task.Run(() => + { + var writeToClassTask = new List(); + var excelTable = new ExcelTable(tableName); + + // 筛选需要导出的列 + + foreach (var exportInfo in tableList) + { + try + { + var serverColInfoList = new List(); + var clientColInfoList = new List(); + var worksheet = LoadExcel(exportInfo.FileInfo.FullName, true); + + for (var col = 3; col <= worksheet.Columns.EndColumn; col++) + { + // 列名字第一个字符是#不参与导出 + + var colName = worksheet.GetCellValue(5, col); + if (colName.StartsWith("#", StringComparison.Ordinal)) + { + continue; + } + + // 数值列不参与导出 + + var numericalCol = worksheet.GetCellValue(3, col); + if (numericalCol != "" && numericalCol != "0") + { + continue; + } + + var serverType = worksheet.GetCellValue(1, col); + var clientType = worksheet.GetCellValue(2, col); + var isExportServer = !IsNullOrEmpty(serverType) && serverType != "0"; + var isExportClient = !IsNullOrEmpty(clientType) && clientType != "0"; + + if (!isExportServer && !isExportClient) + { + continue; + } + + if (isExportServer && isExportClient & serverType != clientType) + { + Log.Info($"配置表 {exportInfo.Name} {col} 列 [{colName}] 客户端类型 {clientType} 和 服务端类型 {serverType} 不一致"); + continue; + } + + if (!ColTypeSet.Contains(serverType) || !ColTypeSet.Contains(clientType)) + { + Log.Info($"配置表 {exportInfo.Name} {col} 列 [{colName}] 客户端类型 {clientType}, 服务端类型 {serverType} 不合法"); + continue; + } + + if (!_regexName.IsMatch(colName)) + { + Log.Info($"配置表 {exportInfo.Name} {col} 列 [{colName}] 列名非法"); + continue; + } + + serverColInfoList.Add(col); + + if (isExportClient) + { + clientColInfoList.Add(col); + } + } + + if (clientColInfoList.Count > 0) + { + excelTable.ClientColInfos.Add(exportInfo.FileInfo.FullName, clientColInfoList); + } + + if (serverColInfoList.Count > 0) + { + excelTable.ServerColInfos.Add(exportInfo.FileInfo.FullName, serverColInfoList); + } + } + catch (Exception e) + { + Log.Error($"Config : {tableName}, Name : {exportInfo.Name}, Error : {e}"); + } + } + + // 生成cs文件 + + if (ExporterAges.Instance.ExportPlatform.HasFlag(ExportPlatform.Server)) + { + writeToClassTask.Add(Task.Run(() => + { + WriteToClass(excelTable.ServerColInfos, _excelServerFileDirectory, true); + })); + } + + if (ExporterAges.Instance.ExportPlatform.HasFlag(ExportPlatform.Client)) + { + writeToClassTask.Add(Task.Run(() => + { + WriteToClass(excelTable.ClientColInfos, _excelClientFileDirectory, false); + })); + } + + Task.WaitAll(writeToClassTask.ToArray()); + _excelTables.TryAdd(tableName, excelTable); + }); + + generateTasks.Add(task); + } + + Task.WaitAll(generateTasks.ToArray()); + } + /// + /// 把数据和实体类转换二进制导出到文件中 + /// + private void ExportToBinary() + { + System.Reflection.Assembly dynamicServerAssembly = null; + System.Reflection.Assembly dynamicClientAssembly = null; + var exportToBinaryTasks = new List(); + + if (ExporterAges.Instance.ExportPlatform.HasFlag(ExportPlatform.Server) && Directory.Exists(_excelServerFileDirectory)) + { + dynamicServerAssembly = DynamicAssembly.Load(_excelServerFileDirectory); + } + + if (ExporterAges.Instance.ExportPlatform.HasFlag(ExportPlatform.Client) && Directory.Exists(_excelClientFileDirectory)) + { + dynamicClientAssembly = DynamicAssembly.Load(_excelClientFileDirectory); + } + + foreach (var (tableName, tableList) in _tables) + { + var task = Task.Run(() => + { + DynamicConfigDataType serverDynamicInfo = null; + DynamicConfigDataType clientDynamicInfo = null; + + var idCheck = new HashSet(); + var excelTable = _excelTables[tableName]; + var csName = Path.GetFileNameWithoutExtension(tableName); + + if (ExporterAges.Instance.ExportPlatform.HasFlag(ExportPlatform.Server)) + { + var serverColInfoCount = excelTable.ServerColInfos.Sum(d => d.Value.Count); + serverDynamicInfo = serverColInfoCount == 0 ? null : DynamicAssembly.GetDynamicInfo(dynamicServerAssembly, csName); + } + + if (ExporterAges.Instance.ExportPlatform.HasFlag(ExportPlatform.Client)) + { + var clientColInfoCount = excelTable.ClientColInfos.Sum(d => d.Value.Count); + clientDynamicInfo = clientColInfoCount == 0 ? null : DynamicAssembly.GetDynamicInfo(dynamicClientAssembly, csName); + } + + for (var i = 0; i < tableList.Count; i++) + { + var tableListName = tableList[i]; + + try + { + var fileInfoFullName = tableListName.FileInfo.FullName; + var excelWorksheet = LoadExcel(fileInfoFullName, false); + var rows = excelWorksheet.Dimension.Rows; + excelTable.ServerColInfos.TryGetValue(fileInfoFullName, out var serverCols); + excelTable.ClientColInfos.TryGetValue(fileInfoFullName, out var clientCols); + + for (var row = 7; row <= rows; row++) + { + if (excelWorksheet.GetCellValue(row, 1).StartsWith("#", StringComparison.Ordinal)) + { + continue; + } + + var id = excelWorksheet.GetCellValue(row, 3); + + if (idCheck.Contains(id)) + { + Log.Info($"{tableListName.Name} 存在重复Id {id} 行号 {row}"); + continue; + } + + idCheck.Add(id); + var isLast = row == rows && (i == tableList.Count - 1); + + if (ExporterAges.Instance.ExportPlatform.HasFlag(ExportPlatform.Server)) + { + GenerateBinary(fileInfoFullName, excelWorksheet, serverDynamicInfo, serverCols, id, row, isLast, true); + } + + if (ExporterAges.Instance.ExportPlatform.HasFlag(ExportPlatform.Client)) + { + GenerateBinary(fileInfoFullName, excelWorksheet, clientDynamicInfo, clientCols, id, row, isLast, false); + } + } + } + catch (Exception e) + { + Log.Error($"Table:{tableListName} error! \n{e}"); + throw; + } + } + + if (serverDynamicInfo?.ConfigData != null) + { + var memoryStream = new MemoryStreamBuffer(); + SerializerManager.GetSerializer(FantasySerializerType.ProtoBuf).Serialize(serverDynamicInfo.ConfigData, memoryStream); + if (!Directory.Exists(_excelServerBinaryDirectory)) + { + Directory.CreateDirectory(_excelServerBinaryDirectory); + } + var asSpan = memoryStream.GetBuffer().AsSpan(0, (int)memoryStream.Position); + File.WriteAllBytes(Path.Combine(_excelServerBinaryDirectory, $"{csName}Data.bytes"), asSpan.ToArray()); + if (serverDynamicInfo.Json.Length > 0) + { + if (!Directory.Exists(_excelServerJsonDirectory)) + { + Directory.CreateDirectory(_excelServerJsonDirectory); + } + using var sw = new StreamWriter(Path.Combine(_excelServerJsonDirectory, $"{csName}Data.Json")); + sw.WriteLine("{\"List\":["); + sw.Write(serverDynamicInfo.Json.ToString()); + sw.WriteLine("]}"); + } + } + + if (clientDynamicInfo?.ConfigData != null) + { + var memoryStream = new MemoryStreamBuffer(); + SerializerManager.GetSerializer(FantasySerializerType.ProtoBuf).Serialize(clientDynamicInfo.ConfigData, memoryStream); + if (!Directory.Exists(_excelClientBinaryDirectory)) + { + Directory.CreateDirectory(_excelClientBinaryDirectory); + } + var asSpan = memoryStream.GetBuffer().AsSpan(0, (int)memoryStream.Position); + File.WriteAllBytes(Path.Combine(_excelClientBinaryDirectory, $"{csName}Data.bytes"), asSpan.ToArray()); + + if (clientDynamicInfo.Json.Length > 0) + { + if (!Directory.Exists(_excelClientJsonDirectory)) + { + Directory.CreateDirectory(_excelClientJsonDirectory); + } + using var sw = new StreamWriter(Path.Combine(_excelClientJsonDirectory, $"{csName}Data.Json")); + sw.WriteLine("{\"List\":["); + sw.Write(clientDynamicInfo.Json.ToString()); + sw.WriteLine("]}"); + } + } + }); + exportToBinaryTasks.Add(task); + } + + Task.WaitAll(exportToBinaryTasks.ToArray()); + } + private void GenerateBinary(string fileInfoFullName, ExcelWorksheet excelWorksheet, DynamicConfigDataType dynamicInfo, List cols, string id, int row, bool isLast, bool isServer) + { + if (cols == null || IsNullOrEmpty(id) || cols.Count <= 0 || dynamicInfo?.ConfigType == null) + { + return; + } + + var config = DynamicAssembly.CreateInstance(dynamicInfo.ConfigType); + + for (var i = 0; i < cols.Count; i++) + { + string colType; + var colIndex = cols[i]; + var colName = excelWorksheet.GetCellValue(5, colIndex); + var value = excelWorksheet.GetCellValue(row, colIndex); + + if (isServer) + { + colType = excelWorksheet.GetCellValue(1, colIndex); + + if (IsNullOrEmpty(colType) || colType == "0") + { + colType = excelWorksheet.GetCellValue(2, colIndex); + } + } + else + { + colType = excelWorksheet.GetCellValue(2, colIndex); + } + + try + { + SetNewValue(dynamicInfo.ConfigType.GetProperty(colName), config, colType, value); + } + catch (Exception e) + { + Log.Error($"Error Table {fileInfoFullName} Col:{colName} colType:{colType} Row:{row} value:{value} {e}"); + throw; + } + } + + dynamicInfo.Method.Invoke(dynamicInfo.Obj, new object[] {config}); + + var json = JsonConvert.SerializeObject(config); + + if (isLast) + { + dynamicInfo.Json.AppendLine(json); + } + else + { + dynamicInfo.Json.AppendLine($"{json},"); + } + } + /// + /// 从 Excel 文件加载工作表并返回 ExcelWorksheet 对象。 + /// + /// 工作表的名称或文件路径。 + /// 是否将加载的工作表添加到缓存字典中。 + /// 表示 Excel 工作表的 ExcelWorksheet 对象。 + public ExcelWorksheet LoadExcel(string name, bool isAddToDic) + { + if (Worksheets.TryGetValue(name, out var worksheet)) + { + return worksheet; + } + + var workbookWorksheets = ExcelHelper.LoadExcel(name).Workbook.Worksheets; + worksheet = workbookWorksheets[0]; + + if (isAddToDic) + { + Worksheets.TryAdd(name, worksheet); + + foreach (var workbookWorksheet in workbookWorksheets) + { + VersionInfo.WorksheetNames.Add(workbookWorksheet.Name); + Worksheets.TryAdd(workbookWorksheet.Name, workbookWorksheet); + } + } + + Log.Info(name); + return workbookWorksheets[0]; + } + /// + /// 写入到cs + /// + /// + /// + /// + private void WriteToClass(TableDictionary colInfos, string exportPath, bool isServer) + { + if (colInfos.Count <= 0) + { + return; + } + + var index = 0; + var fileBuilder = new StringBuilder(); + var colNameSet = new HashSet(); + + if (colInfos.Count == 0) + { + return; + } + + var csName = Path.GetFileNameWithoutExtension(colInfos.First().Key)?.Split('_')[0]; + + foreach (var (tableName, cols) in colInfos) + { + if (cols == null || cols.Count == 0) + { + continue; + } + + var excelWorksheet = LoadExcel(tableName, false); + + foreach (var colIndex in cols) + { + var colName = excelWorksheet.GetCellValue(5, colIndex); + + if (colNameSet.Contains(colName)) + { + continue; + } + + colNameSet.Add(colName); + + string colType; + + if (isServer) + { + colType = excelWorksheet.GetCellValue(1, colIndex); + + if (IsNullOrEmpty(colType) || colType == "0") + { + colType = excelWorksheet.GetCellValue(2, colIndex); + } + } + else + { + colType = excelWorksheet.GetCellValue(2, colIndex); + } + + var remarks = excelWorksheet.GetCellValue(4, colIndex); + + // 解决不同平台换行符不一致的问题 + + switch (Environment.OSVersion.Platform) + { + case PlatformID.Win32NT: + case PlatformID.Win32S: + case PlatformID.Win32Windows: + case PlatformID.WinCE: + { + fileBuilder.Append($"\r\n\t\t[ProtoMember({++index})]\r\n"); + break; + } + default: + { + fileBuilder.Append($"\n\t\t[ProtoMember({++index})]\n"); + break; + } + } + + fileBuilder.Append( + IsArray(colType,out var t) + ? $"\t\tpublic {colType} {colName} {{ get; set; }} = Array.Empty<{t}>(); // {remarks}" + : $"\t\tpublic {colType} {colName} {{ get; set; }} // {remarks}"); + } + } + + var template = ExcelTemplate.Template; + + if (fileBuilder.Length > 0) + { + if (!Directory.Exists(exportPath)) + { + FileHelper.CreateDirectory(exportPath); + } + + var content = template.Replace("(namespace)", "Fantasy") + .Replace("(ConfigName)", csName) + .Replace("(Fields)", fileBuilder.ToString()); + File.WriteAllText(Path.Combine(exportPath, $"{csName}.cs"), content); + } + } + private void SetNewValue(PropertyInfo propertyInfo, object config, string type, string value) + { + if (IsNullOrWhiteSpace(value)) + { + return; + } + + switch (type) + { + case "short": + { + propertyInfo.SetValue(config, Convert.ToInt16(value)); + return; + } + case "ushort": + { + propertyInfo.SetValue(config, Convert.ToUInt16(value)); + return; + } + case "uint": + { + propertyInfo.SetValue(config, Convert.ToUInt32(value)); + return; + } + case "int": + { + propertyInfo.SetValue(config, Convert.ToInt32(value)); + return; + } + case "decimal": + { + propertyInfo.SetValue(config, Convert.ToDecimal(value)); + return; + } + case "string": + { + try + { + propertyInfo.SetValue(config, value); + } + catch (Exception e) + { + Console.WriteLine(e); + throw; + } + + return; + } + case "bool": + { + // 空字符串 + + value = value.ToLower(); + + if (IsNullOrEmpty(value)) + { + propertyInfo.SetValue(config, false); + } + else if (bool.TryParse(value, out bool b)) + { + propertyInfo.SetValue(config, b); + } + else if (int.TryParse(value, out int v)) + { + propertyInfo.SetValue(config, v != 0); + } + else + { + propertyInfo.SetValue(config, false); + } + + return; + } + case "ulong": + { + propertyInfo.SetValue(config, Convert.ToUInt64(value)); + return; + } + case "long": + { + propertyInfo.SetValue(config, Convert.ToInt64(value)); + return; + } + case "double": + { + propertyInfo.SetValue(config, Convert.ToDouble(value)); + return; + } + case "float": + { + propertyInfo.SetValue(config, Convert.ToSingle(value)); + return; + } + case "int32[]": + case "int[]": + { + if (value != "0") + { + propertyInfo.SetValue(config, value.Split(",").Select(d => Convert.ToInt32(d)).ToArray()); + } + + return; + } + case "uint[]": + { + if (value != "0") + { + propertyInfo.SetValue(config, value.Split(",").Select(d => Convert.ToUInt32(d)).ToArray()); + } + return; + } + case "long[]": + { + if (value != "0") + { + propertyInfo.SetValue(config, value.Split(",").Select(d => Convert.ToInt64(d)).ToArray()); + } + + return; + } + case "double[]": + { + if (value != "0") + { + propertyInfo.SetValue(config, value.Split(",").Select(d => Convert.ToDouble(d)).ToArray()); + } + + return; + } + case "string[]": + { + if (value == "0") + { + return; + } + + var list = value.Split(",").ToArray(); + + for (var i = 0; i < list.Length; i++) + { + list[i] = list[i].Replace("\"", ""); + } + + propertyInfo.SetValue(config, value.Split(",").ToArray()); + + return; + } + case "float[]": + { + if (value != "0") + { + propertyInfo.SetValue(config, value.Split(",").Select(d => Convert.ToSingle(d)).ToArray()); + } + + return; + } + case "IntDictionaryConfig": + { + if (value.Trim() == "" || value.Trim() == "{}") + { + propertyInfo.SetValue(config, null); + return; + } + + var attr = new IntDictionaryConfig {Dic = JsonConvert.DeserializeObject>(value)}; + + propertyInfo.SetValue(config, attr); + + return; + } + case "StringDictionaryConfig": + { + if (value.Trim() == "" || value.Trim() == "{}") + { + propertyInfo.SetValue(config, null); + return; + } + + var attr = new StringDictionaryConfig {Dic = JsonConvert.DeserializeObject>(value)}; + + propertyInfo.SetValue(config, attr); + + return; + } + default: + throw new NotSupportedException($"不支持此类型: {type}"); + } + } + private bool IsArray(string type, out string t) + { + t = null; + var index = type.IndexOf("[]", StringComparison.Ordinal); + + if (index >= 0) + { + t = type.Remove(index, 2); + } + + return index >= 0; + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Tools/SourceCode/Fantasy.Tools.ConfigTable/Exporter/ExcelHelper.cs b/物品和背包的完整代码/Packages/Fantasy/Tools/SourceCode/Fantasy.Tools.ConfigTable/Exporter/ExcelHelper.cs new file mode 100644 index 0000000..05e63d5 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Tools/SourceCode/Fantasy.Tools.ConfigTable/Exporter/ExcelHelper.cs @@ -0,0 +1,47 @@ +using OfficeOpenXml; + +namespace Fantasy.Tools.ConfigTable; + +/// +/// 提供操作 Excel 文件的辅助方法。 +/// +public static class ExcelHelper +{ + /// + /// 加载 Excel 文件并返回 ExcelPackage 实例。 + /// + /// Excel 文件的路径。 + /// ExcelPackage 实例。 + public static ExcelPackage LoadExcel(string name) + { + return new ExcelPackage(name); + } + + /// + /// 获取指定工作表中指定行列位置的单元格值。 + /// + /// Excel 工作表。 + /// 行索引。 + /// 列索引。 + /// 单元格值。 + public static string GetCellValue(this ExcelWorksheet sheet, int row, int column) + { + ExcelRange cell = sheet.Cells[row, column]; + + try + { + if (cell.Value == null) + { + return ""; + } + + string s = cell.GetValue(); + + return s.Trim(); + } + catch (Exception e) + { + throw new Exception($"Rows {row} Columns {column} Content {cell.Text} {e}"); + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Tools/SourceCode/Fantasy.Tools.ConfigTable/Exporter/ExcelTable.cs b/物品和背包的完整代码/Packages/Fantasy/Tools/SourceCode/Fantasy.Tools.ConfigTable/Exporter/ExcelTable.cs new file mode 100644 index 0000000..9a645a8 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Tools/SourceCode/Fantasy.Tools.ConfigTable/Exporter/ExcelTable.cs @@ -0,0 +1,28 @@ +namespace Fantasy.Tools.ConfigTable; + +/// +/// Excel表格类,用于存储表格的名称和列信息。 +/// +public sealed class ExcelTable +{ + /// + /// 表格的名称。 + /// + public readonly string Name; + /// + /// 客户端列信息,使用排序字典存储列名和列索引列表。 + /// + public readonly SortedDictionary> ClientColInfos = new(); + /// + /// 服务器端列信息,使用排序字典存储列名和列索引列表。 + /// + public readonly SortedDictionary> ServerColInfos = new(); + /// + /// 构造函数,初始化Excel表格对象并设置表格名称。 + /// + /// 表格名称。 + public ExcelTable(string name) + { + Name = name; + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Tools/SourceCode/Fantasy.Tools.ConfigTable/Exporter/ExcelTemplate.cs b/物品和背包的完整代码/Packages/Fantasy/Tools/SourceCode/Fantasy.Tools.ConfigTable/Exporter/ExcelTemplate.cs new file mode 100644 index 0000000..3558e86 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Tools/SourceCode/Fantasy.Tools.ConfigTable/Exporter/ExcelTemplate.cs @@ -0,0 +1,98 @@ +namespace Fantasy.Tools.ConfigTable; + +public static class ExcelTemplate +{ + public static readonly string Template = """ + using System; + using ProtoBuf; + using Fantasy; + using System.Linq; + using System.Reflection; + using System.Collections.Generic; + using System.Collections.Concurrent; + using Fantasy.ConfigTable; + using Fantasy.Serialize; + // ReSharper disable CollectionNeverUpdated.Global + // ReSharper disable UnusedAutoPropertyAccessor.Global + #pragma warning disable CS1591 // Missing XML comment for publicly visible type or member + #pragma warning disable CS0169 + #pragma warning disable CS8618 + #pragma warning disable CS8625 + #pragma warning disable CS8603 + + namespace (namespace) + { + [ProtoContract] + public sealed partial class (ConfigName)Data : ASerialize, IConfigTable, IProto + { + [ProtoMember(1)] + public List<(ConfigName)> List { get; set; } = new List<(ConfigName)>(); + #if FANTASY_NET + [ProtoIgnore] + private readonly ConcurrentDictionary _configs = new ConcurrentDictionary(); + #else + [ProtoIgnore] + private readonly Dictionary _configs = new Dictionary(); + #endif + private static (ConfigName)Data _instance = null; + + public static (ConfigName)Data Instance + { + get { return _instance ??= ConfigTableHelper.Load<(ConfigName)Data>(); } + private set => _instance = value; + } + + public (ConfigName) Get(uint id, bool check = true) + { + if (_configs.ContainsKey(id)) + { + return _configs[id]; + } + + if (check) + { + throw new Exception($"(ConfigName) not find {id} Id"); + } + + return null; + } + public bool TryGet(uint id, out (ConfigName) config) + { + config = null; + + if (!_configs.ContainsKey(id)) + { + return false; + } + + config = _configs[id]; + return true; + } + public override void AfterDeserialization() + { + foreach (var config in List) + { + #if FANTASY_NET + _configs.TryAdd(config.Id, config); + #else + _configs.Add(config.Id, config); + #endif + config.AfterDeserialization(); + } + + EndInit(); + } + + public override void Dispose() + { + Instance = null; + } + } + + [ProtoContract] + public sealed partial class (ConfigName) : ASerialize, IProto + {(Fields) + } + } + """; +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Tools/SourceCode/Fantasy.Tools.ConfigTable/Exporter/ExcelWorksheets.cs b/物品和背包的完整代码/Packages/Fantasy/Tools/SourceCode/Fantasy.Tools.ConfigTable/Exporter/ExcelWorksheets.cs new file mode 100644 index 0000000..ba1a017 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Tools/SourceCode/Fantasy.Tools.ConfigTable/Exporter/ExcelWorksheets.cs @@ -0,0 +1,23 @@ +using Fantasy.Exporter; +using OfficeOpenXml; +#pragma warning disable CS8601 // Possible null reference assignment. + +namespace Fantasy.Tools.ConfigTable; + +public sealed class ExcelWorksheets(ExcelExporter excelExporter) +{ + public bool TryGetValue(string worksheetName, out ExcelWorksheet excelWorksheet) + { + if (excelExporter.Worksheets.TryGetValue(worksheetName, out excelWorksheet)) + { + return true; + } + + if (!excelExporter.VersionInfo.WorksheetNames.Contains(worksheetName)) + { + Log.Info($"{worksheetName} is not exist!"); + } + + return false; + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Tools/SourceCode/Fantasy.Tools.ConfigTable/Exporter/ExportInfo.cs b/物品和背包的完整代码/Packages/Fantasy/Tools/SourceCode/Fantasy.Tools.ConfigTable/Exporter/ExportInfo.cs new file mode 100644 index 0000000..d2150af --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Tools/SourceCode/Fantasy.Tools.ConfigTable/Exporter/ExportInfo.cs @@ -0,0 +1,17 @@ +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. +namespace Fantasy.Tools.ConfigTable; + +/// +/// 导出信息类,用于存储导出操作的名称和文件信息。 +/// +public class ExportInfo +{ + /// + /// 导出操作的名称。 + /// + public string Name; + /// + /// 导出操作生成的文件信息。 + /// + public FileInfo FileInfo; +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Tools/SourceCode/Fantasy.Tools.ConfigTable/Exporter/ICustomExport.cs b/物品和背包的完整代码/Packages/Fantasy/Tools/SourceCode/Fantasy.Tools.ConfigTable/Exporter/ICustomExport.cs new file mode 100644 index 0000000..0703eff --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Tools/SourceCode/Fantasy.Tools.ConfigTable/Exporter/ICustomExport.cs @@ -0,0 +1,148 @@ +using Fantasy.Exporter; +using Fantasy.Helper; +// ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. + +namespace Fantasy.Tools.ConfigTable; + +/// +/// 自定义导出接口 +/// +public interface ICustomExport +{ + /// + /// 执行导出操作 + /// + void Run(); + /// + /// 内部操作用于初始化、不明白原理不要修改这里和调用这个方法 + /// + /// + /// + void Init(ExcelExporter excelExporter, ExcelWorksheets worksheets); +} + +/// +/// 抽象自定义导出基类 +/// +public abstract class ACustomExport : ICustomExport +{ + protected ExcelExporter ExcelExporter; + protected ExcelWorksheets Worksheets; + + /// + /// 自定义导出类型枚举:客户端、服务器 + /// + protected enum CustomExportType + { + /// + /// 客户端 + /// + Client, + /// + /// 服务器 + /// + Server + } + + /// + /// 内部操作用于初始化、不明白原理不要修改这里 + /// + /// + /// + public void Init(ExcelExporter excelExporter, ExcelWorksheets worksheets) + { + ExcelExporter = excelExporter; + Worksheets = worksheets; + } + + /// + /// 执行导出操作的抽象方法 + /// + public abstract void Run(); + + /// + /// 写入文件内容到指定位置 + /// + /// 文件名 + /// 文件内容 + /// 相对的导出的目录 + /// 自定义导出类型 + protected void Write(string fileName, string fileContent, string filePath, CustomExportType customExportType) + { + if (filePath == null) + { + Log.Error($" {nameof(filePath)} is null"); + return; + } + + filePath = FileHelper.GetFullPath(filePath); + + if (!Directory.Exists(filePath)) + { + FileHelper.CreateDirectory(filePath); + } + + var combine = Path.Combine(filePath, fileName); + File.WriteAllText(combine, fileContent); + + switch (customExportType) + { + case CustomExportType.Client: + { + Log.Info($"导出客户端自定义文件:{filePath}/{fileName}"); + return; + } + case CustomExportType.Server: + { + Log.Info($"导出服务器自定义文件:{filePath}/{fileName}"); + return; + } + } + } + + /// + /// 写入文件内容到指定位置 + /// + /// 文件名 + /// 文件内容 + /// 自定义导出类型 + protected void Write(string fileName, string fileContent, CustomExportType customExportType) + { + switch (customExportType) + { + case CustomExportType.Client: + { + if (string.IsNullOrEmpty(ExcelExporter.ClientCustomExportDirectory)) + { + return; + } + + if (!Directory.Exists(ExcelExporter.ClientCustomExportDirectory)) + { + Directory.CreateDirectory(ExcelExporter.ClientCustomExportDirectory); + } + + File.WriteAllText($"{ExcelExporter.ClientCustomExportDirectory}/{fileName}", fileContent); + Log.Info($"导出客户端自定义文件:{ExcelExporter.ClientCustomExportDirectory}/{fileName}"); + return; + } + case CustomExportType.Server: + { + if (string.IsNullOrEmpty(ExcelExporter.ServerCustomExportDirectory)) + { + return; + } + + if (!Directory.Exists(ExcelExporter.ServerCustomExportDirectory)) + { + Directory.CreateDirectory(ExcelExporter.ServerCustomExportDirectory); + } + + File.WriteAllText($"{ExcelExporter.ServerCustomExportDirectory}/{fileName}", fileContent); + Log.Info($"导出服务器自定义文件:{ExcelExporter.ServerCustomExportDirectory}/{fileName}"); + return; + } + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Tools/SourceCode/Fantasy.Tools.ConfigTable/Exporter/VersionInfo.cs b/物品和背包的完整代码/Packages/Fantasy/Tools/SourceCode/Fantasy.Tools.ConfigTable/Exporter/VersionInfo.cs new file mode 100644 index 0000000..5d755be --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Tools/SourceCode/Fantasy.Tools.ConfigTable/Exporter/VersionInfo.cs @@ -0,0 +1,7 @@ +namespace Fantasy.Tools.ConfigTable; + +public class VersionInfo +{ + public List WorksheetNames = []; + public Dictionary Tables = new(); +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Tools/SourceCode/Fantasy.Tools.ConfigTable/ExporterAges.cs b/物品和背包的完整代码/Packages/Fantasy/Tools/SourceCode/Fantasy.Tools.ConfigTable/ExporterAges.cs new file mode 100644 index 0000000..5b712d0 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Tools/SourceCode/Fantasy.Tools.ConfigTable/ExporterAges.cs @@ -0,0 +1,21 @@ +using CommandLine; +using Fantasy.Tools.ConfigTable; + +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. + +namespace Fantasy.Tools; + +public class ExporterAges +{ + public static ExporterAges Instance; + /// + /// 导出目标平台枚举,用于标识导出到哪个平台 + /// + [Option('p',"ExportPlatform", Required = false, Default = ExportPlatform.None, HelpText = "Export target platform:\n/// Client target platform \nClient = 1\n/// Server target platform\nServer = 2\n/// Client and Server target platform\nAll = 3")] + public ExportPlatform ExportPlatform { get; set; } + /// + /// 导出类型 + /// + [Option('e',"ExportType", Required = false, Default = ExportType.None, HelpText = "Export Type:\n/// Incremental export of all data in Excel format.\nAllExcelIncrement = 1\n/// Export all data to Excel format.\nAllExcel = 2")] + public ExportType ExportType { get; set; } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Tools/SourceCode/Fantasy.Tools.ConfigTable/ExporterSettings.json b/物品和背包的完整代码/Packages/Fantasy/Tools/SourceCode/Fantasy.Tools.ConfigTable/ExporterSettings.json new file mode 100644 index 0000000..7499bd6 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Tools/SourceCode/Fantasy.Tools.ConfigTable/ExporterSettings.json @@ -0,0 +1,44 @@ +{ + "Export": { + "ExcelProgramPath": { + "Value": "../../../Examples/Config/Excel/", + "Comment": "Excel文件夹的根目录" + }, + "ExcelVersionFile": { + "Value": "../../../Examples/Config/Excel/Version.txt", + "Comment": "Excel的Version文件位置、这个文件用于记录每次导出对比是否需要再次导出的文件" + }, + "ExcelServerFileDirectory": { + "Value": "../../../Examples/Server/Entity/Generate/ConfigTable/Entity/", + "Comment": "Excel生成的代码文件、在服务端文件夹位置" + }, + "ExcelClientFileDirectory": { + "Value": "../../../Examples/Client/Unity/Assets/Scripts/Hotfix/Generate/ConfigTable/Entity/", + "Comment": "Excel生成的代码文件、在客户端文件夹位置" + }, + "ExcelServerBinaryDirectory": { + "Value": "../../../Examples/Config/Binary/", + "Comment": "Excel生成服务器二进制数据文件夹位置" + }, + "ExcelClientBinaryDirectory": { + "Value": "../../../Examples/Client/Unity/Assets/Bundles/Config/", + "Comment": "Excel生成在客户端的二进制数据文件夹位置" + }, + "ExcelServerJsonDirectory": { + "Value": "../../../Examples/Config/Json/Server/", + "Comment": "Excel生成在服务端的Json数据文件夹位置" + }, + "ExcelClientJsonDirectory": { + "Value": "../../../Examples/Config/Json/Client/", + "Comment": "Excel生成在客户端的Json数据文件夹位置" + }, + "ServerCustomExportDirectory": { + "Value": "../../../Examples/Server/Entity/Generate/CustomExport/", + "Comment": "Excel在服务端生成自定义代码的文件夹位置" + }, + "ClientCustomExportDirectory": { + "Value": "../../../Examples/Client/Unity/Assets/Scripts/Hotfix/Generate/CustomExport", + "Comment": "Excel在客户端端生成自定义代码的文件夹位置" + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Tools/SourceCode/Fantasy.Tools.ConfigTable/ExporterSettingsHelper.cs b/物品和背包的完整代码/Packages/Fantasy/Tools/SourceCode/Fantasy.Tools.ConfigTable/ExporterSettingsHelper.cs new file mode 100644 index 0000000..c39858c --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Tools/SourceCode/Fantasy.Tools.ConfigTable/ExporterSettingsHelper.cs @@ -0,0 +1,43 @@ +using Fantasy.Helper; +using Microsoft.Extensions.Configuration; +#pragma warning disable CS8604 // Possible null reference argument. + +namespace Fantasy.Tools.ConfigTable; + +public class ExporterSettingsHelper +{ + public static string? ExcelProgramPath { get; private set; } + public static string? ExcelVersionFile { get; private set; } + public static string? ExcelServerFileDirectory { get; private set; } + public static string? ExcelClientFileDirectory { get; private set; } + public static string? ExcelServerBinaryDirectory { get; private set; } + public static string? ExcelClientBinaryDirectory { get; private set; } + public static string? ExcelServerJsonDirectory { get; private set; } + public static string? ExcelClientJsonDirectory { get; private set; } + public static string? ServerCustomExportDirectory { get; private set; } + public static string? ClientCustomExportDirectory { get; private set; } + + public static void Initialize() + { + const string settingsName = "ExporterSettings.json"; + var currentDirectory = Directory.GetCurrentDirectory(); + + if (!File.Exists(Path.Combine(currentDirectory, settingsName))) + { + throw new FileNotFoundException($"not found {settingsName} in OutputDirectory"); + } + + var root = new ConfigurationBuilder().SetBasePath(Directory.GetCurrentDirectory()).AddJsonFile(settingsName).Build(); + + ExcelProgramPath = FileHelper.GetFullPath(root["Export:ExcelProgramPath:Value"]); + ExcelVersionFile = FileHelper.GetFullPath(root["Export:ExcelVersionFile:Value"]); + ExcelServerFileDirectory = FileHelper.GetFullPath(root["Export:ExcelServerFileDirectory:Value"]); + ExcelClientFileDirectory = FileHelper.GetFullPath(root["Export:ExcelClientFileDirectory:Value"]); + ExcelServerBinaryDirectory = FileHelper.GetFullPath(root["Export:ExcelServerBinaryDirectory:Value"]); + ExcelClientBinaryDirectory = FileHelper.GetFullPath(root["Export:ExcelClientBinaryDirectory:Value"]); + ExcelServerJsonDirectory = FileHelper.GetFullPath(root["Export:ExcelServerJsonDirectory:Value"]); + ExcelClientJsonDirectory = FileHelper.GetFullPath(root["Export:ExcelClientJsonDirectory:Value"]); + ServerCustomExportDirectory = FileHelper.GetFullPath(root["Export:ServerCustomExportDirectory:Value"]); + ClientCustomExportDirectory = FileHelper.GetFullPath(root["Export:ClientCustomExportDirectory:Value"]); + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Tools/SourceCode/Fantasy.Tools.ConfigTable/Fantasy.Tools.ConfigTable.csproj b/物品和背包的完整代码/Packages/Fantasy/Tools/SourceCode/Fantasy.Tools.ConfigTable/Fantasy.Tools.ConfigTable.csproj new file mode 100644 index 0000000..c73c8a1 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Tools/SourceCode/Fantasy.Tools.ConfigTable/Fantasy.Tools.ConfigTable.csproj @@ -0,0 +1,133 @@ + + + + Exe + net8.0 + enable + enable + 13 + + + + false + en + + + + true + TRACE;FANTASY_EXPORTER + ../../Exporter/ConfigTable/ + + + + true + TRACE;FANTASY_EXPORTER + ../../Exporter/ConfigTable/ + + + + + + + + + + + + + + CustomExport\ConstValueToConst.cs + + + CustomExport\ContainerConfigToEnum.cs + + + CustomExport\ErrorCodeToConst.cs + + + CustomExport\ItemTypeToEnum.cs + + + CustomExport\ItemUseEffectToEnum.cs + + + Core\Base\Pool.cs + + + Core\Dictionary\IntDictionaryConfig.cs + + + Core\Dictionary\StringDictionaryConfig.cs + + + Core\Interface\IConfigTable.cs + + + Core\Serialize\ProtoBufPackHelper\IProto.cs + + + Excel\Base\TimeHelper.cs + + + Excel\Base\IPool.cs + + + Excel\Base\AssemblyInfo.cs + + + Excel\Base\OneToManyList.cs + + + Core\ConsoleLog.cs + + + Core\ExportPlatform.cs + + + Core\FileHelper.cs + + + Core\HashCodeHelper.cs + + + Core\JsonHelper.cs + + + Core\Serialize\BsonPack\BsonPackHelperNet.cs + + + Core\Serialize\BsonPack\StructBsonSerialize.cs + + + Core\Serialize\BsonPack\SupportInitializeChecker.cs + + + Core\Serialize\Interface\ASerialize.cs + + + Core\Serialize\Interface\ISerialize.cs + + + Core\Serialize\SerializerManager.cs + + + Core\Serialize\ProtoBufPackHelper\ProtoBufPackHelperNet.cs + + + Excel\Base\MemoryStreamBuffer.cs + + + + + + Always + + + Always + + + Always + + + + diff --git a/物品和背包的完整代码/Packages/Fantasy/Tools/SourceCode/Fantasy.Tools.ConfigTable/Program.cs b/物品和背包的完整代码/Packages/Fantasy/Tools/SourceCode/Fantasy.Tools.ConfigTable/Program.cs new file mode 100644 index 0000000..7352d46 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Tools/SourceCode/Fantasy.Tools.ConfigTable/Program.cs @@ -0,0 +1,67 @@ +using System.Text; +using CommandLine; +using Fantasy.Exporter; +using Fantasy.Tools; +using Fantasy.Tools.ConfigTable; + +try +{ + Parser.Default.ParseArguments(Environment.GetCommandLineArgs()) + .WithNotParsed(error => throw new Exception("Command line format error!")) + .WithParsed(ages => ExporterAges.Instance = ages); + // 初始化配置 + ExporterSettingsHelper.Initialize(); + // 加载配置 + Console.OutputEncoding = Encoding.UTF8; + // 判断启动参数,如果没有选择目标平台就让用户选择 + if (ExporterAges.Instance.ExportPlatform == ExportPlatform.None) + { + Log.Info("请输入你想要导出的目标平台:"); + Log.Info("1:Client(客户端)"); + Log.Info("2:Server(服务器)"); + Log.Info("3:All(客户端和服务器)"); + var inputKeyChar = Console.ReadKey().KeyChar; + if (!int.TryParse(inputKeyChar.ToString(), out var exportPlatformKey) || exportPlatformKey is < 1 or >= (int)ExportPlatform.All) + { + Console.WriteLine(""); + Log.Error("无法识别的导出类型请,输入正确导出的目标平台。"); + return; + } + ExporterAges.Instance.ExportPlatform = (ExportPlatform)exportPlatformKey; + } + + var selectExportType = ExporterAges.Instance.ExportType; + + if (selectExportType == ExportType.None) + { + // 检查启动参数 + Log.Info("请输入你想要做的操作:"); + Log.Info("1:所有增量导出Excel(包含常量枚举)"); + Log.Info("2:所有全量导出Excel(包含常量枚举)"); + // 获取用户输入 + var keyChar = Console.ReadKey().KeyChar; + // 判断用户输入 + if (!int.TryParse(keyChar.ToString(), out var key) || key is < 1 or >= (int)ExportType.Max) + { + Console.WriteLine(""); + Log.Error("无法识别的导出类型请,输入正确的操作类型。"); + return; + } + + selectExportType = (ExportType)key; + } + Log.Info($"selectExportType:{selectExportType} ExportPlatform:{ExporterAges.Instance.ExportPlatform}"); + // 转换用户输入 + Log.Info(""); + new ExcelExporter(selectExportType).Run(); +} +catch (Exception e) +{ + Log.Error(e); +} +finally +{ + Log.Info("按任意键退出程序"); + Console.ReadKey(); + Environment.Exit(0); +} diff --git a/物品和背包的完整代码/Packages/Fantasy/Tools/SourceCode/Fantasy.Tools.ConfigTable/Properties/launchSettings.json b/物品和背包的完整代码/Packages/Fantasy/Tools/SourceCode/Fantasy.Tools.ConfigTable/Properties/launchSettings.json new file mode 100644 index 0000000..e468f8b --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Tools/SourceCode/Fantasy.Tools.ConfigTable/Properties/launchSettings.json @@ -0,0 +1,10 @@ +{ + "$schema": "http://json.schemastore.org/launchsettings.json", + "profiles": { + "Fantasy.Tools.ConfigTable": { + "commandName": "Project", + "environmentVariables": {}, + "commandLineArgs": "--ExportPlatform 3" + } + } +} diff --git a/物品和背包的完整代码/Packages/Fantasy/Tools/SourceCode/Fantasy.Tools.ConfigTable/Run.bat b/物品和背包的完整代码/Packages/Fantasy/Tools/SourceCode/Fantasy.Tools.ConfigTable/Run.bat new file mode 100644 index 0000000..082d6b0 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Tools/SourceCode/Fantasy.Tools.ConfigTable/Run.bat @@ -0,0 +1,33 @@ +@echo off + +echo Please select an option: +echo 1. Client Increment +echo 2. Client all +echo 3. Server Increment +echo 4. Server all +echo 5. Client and Server Increment +echo 6. Client and Server all + +set /p choice=Please select an option: + +if "%choice%"=="1" ( + echo Client Increment + dotnet Fantasy.Tools.ConfigTable.dll --p 1 --e 1 +) else if "%choice%"=="2" ( + echo Client all + dotnet Fantasy.Tools.ConfigTable.dll --p 1 --e 2 +) else if "%choice%"=="3" ( + echo Server Increment + dotnet Fantasy.Tools.ConfigTable.dll --p 2 --e 1 +) else if "%choice%"=="4" ( + echo Server all + dotnet Fantasy.Tools.ConfigTable.dll --p 2 --e 2 +) else if "%choice%"=="5" ( + echo Client and Server Increment + dotnet Fantasy.Tools.ConfigTable.dll --p 3 --e 1 +) else if "%choice%"=="6" ( + echo Client and Server all + dotnet Fantasy.Tools.ConfigTable.dll --p 3 --e 2 +) else ( + echo Invalid option +) diff --git a/物品和背包的完整代码/Packages/Fantasy/Tools/SourceCode/Fantasy.Tools.ConfigTable/Run.sh b/物品和背包的完整代码/Packages/Fantasy/Tools/SourceCode/Fantasy.Tools.ConfigTable/Run.sh new file mode 100644 index 0000000..7ac9f52 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Tools/SourceCode/Fantasy.Tools.ConfigTable/Run.sh @@ -0,0 +1,34 @@ +#!/bin/bash + +echo "1. Client Increment" +echo "2. Client all" +echo "3. Server Increment" +echo "4. Server all" +echo "5. Client and Server Increment" +echo "6. Client and Server all" + +read -n 1 -p "Please select an option:" choice +echo "" +case $choice in + 1) + dotnet Fantasy.Tools.ConfigTable.dll --p 1 --e 1 + ;; + 2) + dotnet Fantasy.Tools.ConfigTable.dll --p 1 --e 2 + ;; + 3) + dotnet Fantasy.Tools.ConfigTable.dll --p 2 --e 1 + ;; + 4) + dotnet Fantasy.Tools.ConfigTable.dll --p 2 --e 2 + ;; + 5) + dotnet Fantasy.Tools.ConfigTable.dll --p 3 --e 1 + ;; + 6) + dotnet Fantasy.Tools.ConfigTable.dll --p 3 --e 2 + ;; + *) + echo "Invalid option" + ;; +esac diff --git a/物品和背包的完整代码/Packages/Fantasy/Tools/SourceCode/Fantasy.Tools.NetworkProtocol/Core/Base/ConsoleLog.cs b/物品和背包的完整代码/Packages/Fantasy/Tools/SourceCode/Fantasy.Tools.NetworkProtocol/Core/Base/ConsoleLog.cs new file mode 100644 index 0000000..cbfc5a1 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Tools/SourceCode/Fantasy.Tools.NetworkProtocol/Core/Base/ConsoleLog.cs @@ -0,0 +1,176 @@ +using System.Diagnostics; + +namespace Fantasy.Exporter; + +/// +/// 定义日志记录功能的接口。 +/// +public interface ILog +{ + /// + /// 记录跟踪级别的日志消息。 + /// + /// 日志消息。 + void Trace(string message); + /// + /// 记录警告级别的日志消息。 + /// + /// 日志消息。 + void Warning(string message); + /// + /// 记录信息级别的日志消息。 + /// + /// 日志消息。 + void Info(string message); + /// + /// 记录调试级别的日志消息。 + /// + /// 日志消息。 + void Debug(string message); + /// + /// 记录错误级别的日志消息。 + /// + /// 日志消息。 + void Error(string message); + /// + /// 记录跟踪级别的格式化日志消息。 + /// + /// 日志消息模板。 + /// 格式化参数。 + void Trace(string message, params object[] args); + /// + /// 记录警告级别的格式化日志消息。 + /// + /// 日志消息模板。 + /// 格式化参数。 + void Warning(string message, params object[] args); + /// + /// 记录信息级别的格式化日志消息。 + /// + /// 日志消息模板。 + /// 格式化参数。 + void Info(string message, params object[] args); + /// + /// 记录调试级别的格式化日志消息。 + /// + /// 日志消息模板。 + /// 格式化参数。 + void Debug(string message, params object[] args); + /// + /// 记录错误级别的格式化日志消息。 + /// + /// 日志消息模板。 + /// 格式化参数。 + void Error(string message, params object[] args); +} + +public static class Log +{ + private static readonly ILog LogCore; + + static Log() + { + LogCore = new ConsoleLog(); + } + + /// + /// 记录信息级别的日志消息。 + /// + /// 日志消息。 + public static void Info(string msg) + { + LogCore.Info(msg); + } + + /// + /// 记录错误级别的日志消息,并附带调用栈信息。 + /// + /// 日志消息。 + public static void Error(string msg) + { + var st = new StackTrace(1, true); + LogCore.Error($"{msg}\n{st}"); + } + + /// + /// 记录异常的错误级别的日志消息,并附带调用栈信息。 + /// + /// 异常对象。 + public static void Error(Exception e) + { + if (e.Data.Contains("StackTrace")) + { + LogCore.Error($"{e.Data["StackTrace"]}\n{e}"); + return; + } + + var str = e.ToString(); + LogCore.Error(str); + } + + /// + /// 记录信息级别的格式化日志消息。 + /// + /// 日志消息模板。 + /// 格式化参数。 + public static void Info(string message, params object[] args) + { + LogCore.Info(string.Format(message, args)); + } +} + +public class ConsoleLog : ILog +{ + public void Info(string message) + { + Console.WriteLine(message); + } + + public void Error(string message) + { + ConsoleColor color = Console.ForegroundColor; + Console.ForegroundColor = ConsoleColor.Red; + Console.WriteLine($"{message}\n{new StackTrace(1, true)}"); + Console.ForegroundColor = color; + } + + public void Trace(string message) + { + throw new NotImplementedException(); + } + + public void Warning(string message) + { + throw new NotImplementedException(); + } + + public void Debug(string message) + { + throw new NotImplementedException(); + } + + public void Trace(string message, params object[] args) + { + throw new NotImplementedException(); + } + + public void Warning(string message, params object[] args) + { + throw new NotImplementedException(); + } + + public void Info(string message, params object[] args) + { + throw new NotImplementedException(); + } + + public void Debug(string message, params object[] args) + { + throw new NotImplementedException(); + } + + public void Error(string message, params object[] args) + { + throw new NotImplementedException(); + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Tools/SourceCode/Fantasy.Tools.NetworkProtocol/Core/Base/CustomSerialize.cs b/物品和背包的完整代码/Packages/Fantasy/Tools/SourceCode/Fantasy.Tools.NetworkProtocol/Core/Base/CustomSerialize.cs new file mode 100644 index 0000000..ec5bc60 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Tools/SourceCode/Fantasy.Tools.NetworkProtocol/Core/Base/CustomSerialize.cs @@ -0,0 +1,13 @@ +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. +namespace Fantasy.Tools.ProtocalExporter; + +public sealed class CustomSerialize +{ + public string NameSpace { get; set; } + public int KeyIndex { get; set; } + public string SerializeName { get; set; } + public string Attribute { get; set; } + public string Ignore { get; set; } + public string Member { get; set; } + public uint OpCodeType { get; set; } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Tools/SourceCode/Fantasy.Tools.NetworkProtocol/Core/Base/ExportPlatform.cs b/物品和背包的完整代码/Packages/Fantasy/Tools/SourceCode/Fantasy.Tools.NetworkProtocol/Core/Base/ExportPlatform.cs new file mode 100644 index 0000000..c7ed325 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Tools/SourceCode/Fantasy.Tools.NetworkProtocol/Core/Base/ExportPlatform.cs @@ -0,0 +1,13 @@ +namespace Fantasy.Tools; + +/// +/// 导出目标平台枚举,用于标识导出到哪个平台。 +/// +[Flags] +public enum ExportPlatform : byte +{ + None = 0, + Client = 1, + Server = 1 << 1, + All = Client | Server, +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Tools/SourceCode/Fantasy.Tools.NetworkProtocol/Exporter/NetworkProtocolTemplate.cs b/物品和背包的完整代码/Packages/Fantasy/Tools/SourceCode/Fantasy.Tools.NetworkProtocol/Exporter/NetworkProtocolTemplate.cs new file mode 100644 index 0000000..1c0519f --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Tools/SourceCode/Fantasy.Tools.NetworkProtocol/Exporter/NetworkProtocolTemplate.cs @@ -0,0 +1,40 @@ +namespace Fantasy.Tools.ProtocalExporter; + +public static class NetworkProtocolTemplate +{ + public static readonly string Template =""" + #if SERVER + using ProtoBuf; + (UsingNamespace) + using System.Collections.Generic; + using MongoDB.Bson.Serialization.Attributes; + using Fantasy; + using Fantasy.Network.Interface; + using Fantasy.Serialize; + // ReSharper disable InconsistentNaming + // ReSharper disable RedundantUsingDirective + // ReSharper disable RedundantOverriddenMember + // ReSharper disable PartialTypeWithSinglePart + // ReSharper disable UnusedAutoPropertyAccessor.Global + // ReSharper disable MemberCanBePrivate.Global + // ReSharper disable CheckNamespace + #pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. + #pragma warning disable CS8618 + + namespace Fantasy + { + #else + using ProtoBuf; + (UsingNamespace) + using System.Collections.Generic; + using Fantasy; + using Fantasy.Network.Interface; + using Fantasy.Serialize; + #pragma warning disable CS8618 + + namespace Fantasy + { + #endif + (Content)} + """; +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Tools/SourceCode/Fantasy.Tools.NetworkProtocol/Exporter/OpCodeCache.cs b/物品和背包的完整代码/Packages/Fantasy/Tools/SourceCode/Fantasy.Tools.NetworkProtocol/Exporter/OpCodeCache.cs new file mode 100644 index 0000000..6fd8af0 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Tools/SourceCode/Fantasy.Tools.NetworkProtocol/Exporter/OpCodeCache.cs @@ -0,0 +1,58 @@ +using Fantasy.Helper; + +namespace Fantasy.Tools.ProtocalExporter; + +internal class OpCodeCache +{ + private readonly List _opCodes = new List(); + private readonly Dictionary _opcodeCache; + private readonly Dictionary _saveOpCodeCache = new(); + private readonly string _opcodeCachePath = $"{ExporterSettingsHelper.NetworkProtocolDirectory}OpCode.Cache"; + + /// + /// 构造函数,用于初始化网络协议操作码缓存 + /// + public OpCodeCache(bool regenerate) + { + if (File.Exists(_opcodeCachePath) && !regenerate) + { + var readAllText = File.ReadAllText(_opcodeCachePath); + _opcodeCache = readAllText.Deserialize>(); + _opCodes.AddRange(_opcodeCache.Values); + } + else + { + _opcodeCache = new Dictionary(); + } + } + + /// + /// 保存网络协议操作码 + /// + public void Save() + { + File.WriteAllText(_opcodeCachePath, _saveOpCodeCache.ToJson()); + } + + /// + /// 根据className获得OpCode、如果是新增的会产生一个新的OpCode + /// + /// 协议名 + /// 操作码 + /// + public uint GetOpcodeCache(string className, ref uint opcode) + { + if (!_opcodeCache.TryGetValue(className, out var opCode)) + { + while (_opCodes.Contains(++opcode)) + { + + } + opCode = opcode; + _opCodes.Add(opCode); + } + + _saveOpCodeCache.Add(className, opCode); + return opCode; + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Tools/SourceCode/Fantasy.Tools.NetworkProtocol/Exporter/ProtocolExporter.cs b/物品和背包的完整代码/Packages/Fantasy/Tools/SourceCode/Fantasy.Tools.NetworkProtocol/Exporter/ProtocolExporter.cs new file mode 100644 index 0000000..887e494 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Tools/SourceCode/Fantasy.Tools.NetworkProtocol/Exporter/ProtocolExporter.cs @@ -0,0 +1,762 @@ +using System.Text; +using Fantasy.Exporter; +using Fantasy.Helper; +using Fantasy.Network; +using OpCode = Fantasy.Network.OpCode; +using OpCodeType = Fantasy.Network.OpCodeType; +#pragma warning disable CS8600 // Converting null literal or possible null value to non-nullable type. +#pragma warning disable CS8602 // Dereference of a possibly null reference. +// ReSharper disable PossibleNullReferenceException +// ReSharper disable ConditionIsAlwaysTrueOrFalse +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. +#pragma warning disable CS8604 // Possible null reference argument. + +namespace Fantasy.Tools.ProtocalExporter; +public enum NetworkProtocolOpCodeType +{ + None = 0, + Outer = 1, + Inner = 2, +} +public sealed class OpcodeInfo +{ + public uint Code; + public string Name; +} + +public sealed class ProtocolExporter +{ + private string _serverTemplate; + private string _clientTemplate; + private readonly List _opcodes = new(); + private static readonly char[] SplitChars = [' ', '\t']; + private readonly string _networkProtocolDirectory; + private readonly string _networkProtocolClientDirectory; + private readonly string _networkProtocolServerDirectory; + private readonly string _networkProtocolDirectoryOuter; + private readonly string _networkProtocolDirectoryInner; + + public ProtocolExporter() + { + Console.OutputEncoding = Encoding.UTF8; + + if (ExporterSettingsHelper.NetworkProtocolDirectory == null || ExporterSettingsHelper.NetworkProtocolDirectory.Trim() == "") + { + Log.Info($"NetworkProtocolDirectory Can not be empty!"); + return; + } + + _networkProtocolDirectory = FileHelper.GetFullPath(ExporterSettingsHelper.NetworkProtocolDirectory); + + if (ExporterAges.Instance.ExportPlatform.HasFlag(ExportPlatform.Client)) + { + if (ExporterSettingsHelper.NetworkProtocolClientDirectory?.Trim() == "") + { + Log.Info($"NetworkProtocolClientDirectory Can not be empty!"); + return; + } + + _networkProtocolClientDirectory = FileHelper.GetFullPath(ExporterSettingsHelper.NetworkProtocolClientDirectory); + + if (!Directory.Exists(_networkProtocolClientDirectory)) + { + Directory.CreateDirectory(_networkProtocolClientDirectory); + } + } + + if (ExporterAges.Instance.ExportPlatform.HasFlag(ExportPlatform.Server)) + { + if (ExporterSettingsHelper.NetworkProtocolServerDirectory?.Trim() == "") + { + Log.Info($"NetworkProtocolServerDirectory Can not be empty!"); + return; + } + + _networkProtocolServerDirectory = FileHelper.GetFullPath(ExporterSettingsHelper.NetworkProtocolServerDirectory); + + if (!Directory.Exists(_networkProtocolServerDirectory)) + { + Directory.CreateDirectory(_networkProtocolServerDirectory); + } + + _networkProtocolDirectoryInner = $"{_networkProtocolDirectory}Inner"; + + if (!Directory.Exists(_networkProtocolDirectoryInner)) + { + Directory.CreateDirectory(_networkProtocolDirectoryInner); + } + } + + _networkProtocolDirectoryOuter = $"{_networkProtocolDirectory}Outer"; + + if (!Directory.Exists(_networkProtocolDirectoryOuter)) + { + Directory.CreateDirectory(_networkProtocolDirectoryOuter); + } + } + + public void Run() + { + var tasks = new Task[2]; + tasks[0] = Task.Run(RouteType); + tasks[1] = Task.Run(async () => + { + LoadTemplate(); + await Start(NetworkProtocolOpCodeType.Outer); + if (ExporterAges.Instance.ExportPlatform.HasFlag(ExportPlatform.Server)) + { + await Start(NetworkProtocolOpCodeType.Inner); + } + }); + Task.WaitAll(tasks); + } + + private async Task Start(NetworkProtocolOpCodeType opCodeType) + { + var className = ""; + var opCodeName = ""; + var file = new StringBuilder(); + var messageStr = new StringBuilder(); + var disposeStr = new StringBuilder(); + var errorCodeStr = new StringBuilder(); + var usingNamespace = new HashSet(); + var saveDirectory = new Dictionary(); + + OpcodeInfo opcodeInfo = null; + ProtocolOpCode protocolOpCode = null; + string[] protocolFiles = null; + _opcodes.Clear(); + + switch (opCodeType) + { + case NetworkProtocolOpCodeType.Outer: + { + if (ExporterAges.Instance.ExportPlatform.HasFlag(ExportPlatform.Server)) + { + saveDirectory.Add(_networkProtocolServerDirectory, _serverTemplate); + } + + if (ExporterAges.Instance.ExportPlatform.HasFlag(ExportPlatform.Client)) + { + saveDirectory.Add(_networkProtocolClientDirectory, _clientTemplate); + } + + protocolOpCode = new ProtocolOpCode() + { + Message = OpCodeType.OuterMessage, + Request = OpCodeType.OuterRequest, + Response = OpCodeType.OuterResponse, + RouteMessage = 0, + RouteRequest = 0, + RouteResponse = 0, + AddressableMessage = OpCodeType.OuterAddressableMessage, + AddressableRequest = OpCodeType.OuterAddressableRequest, + AddressableResponse = OpCodeType.OuterAddressableResponse, + CustomRouteMessage = OpCodeType.OuterCustomRouteMessage, + CustomRouteRequest = OpCodeType.OuterCustomRouteRequest, + CustomRouteResponse = OpCodeType.OuterCustomRouteResponse, + }; + opCodeName = "OuterOpcode"; + protocolFiles = FileHelper.GetDirectoryFile(_networkProtocolDirectoryOuter, "*.proto", SearchOption.AllDirectories); + break; + } + case NetworkProtocolOpCodeType.Inner: + { + protocolOpCode = new ProtocolOpCode() + { + Message = OpCodeType.InnerMessage, + Request = OpCodeType.InnerRequest, + Response = OpCodeType.InnerResponse, + RouteMessage = OpCodeType.InnerRouteMessage, + RouteRequest = OpCodeType.InnerRouteRequest, + RouteResponse = OpCodeType.InnerRouteResponse, + AddressableMessage = OpCodeType.InnerAddressableMessage, + AddressableRequest = OpCodeType.InnerAddressableRequest, + AddressableResponse = OpCodeType.InnerAddressableResponse, + CustomRouteMessage = 0, + CustomRouteRequest = 0, + CustomRouteResponse = 0, + }; + opCodeName = "InnerOpcode"; + saveDirectory.Add(_networkProtocolServerDirectory, _serverTemplate); + protocolFiles = FileHelper.GetDirectoryFile(_networkProtocolDirectoryInner, "*.proto", SearchOption.AllDirectories); + break; + } + } + + if (protocolFiles == null || protocolFiles.Length == 0) + { + return; + } + + #region GenerateFiles + + foreach (var filePath in protocolFiles) + { + var keyIndex = 1; + var parameter = ""; + var hasOpCode = false; + var isMsgHead = false; + var isSetProtocol = false; + string responseTypeStr = null; + string customRouteType = null; + string protocolMember = "ProtoMember"; + string protocolType = "\t[ProtoContract]"; + string protocolIgnore = "\t\t[ProtoIgnore]"; + var protocolOpCodeType = OpCodeProtocolType.ProtoBuf; + var fileText = await File.ReadAllTextAsync(filePath); + + foreach (var line in fileText.Split('\n')) + { + var currentLine = line.Trim(); + + if (string.IsNullOrWhiteSpace(currentLine)) + { + continue; + } + + if (currentLine.StartsWith("///")) + { + messageStr.AppendFormat(" /// \r\n" + " /// {0}\r\n" + " /// \r\n", currentLine.Substring("///".Length)); + continue; + } + + if (currentLine.StartsWith("// Protocol")) + { + isSetProtocol = true; + var protocol = currentLine.Substring("// Protocol".Length).Trim(); + + switch (protocol) + { + case "ProtoBuf": + { + protocolType = "\t[ProtoContract]"; + protocolIgnore = "\t\t[ProtoIgnore]"; + protocolMember = "ProtoMember"; + protocolOpCodeType = OpCodeProtocolType.ProtoBuf; + break; + } + // case "MemoryPack": + // { + // keyIndex = 0; + // protocolType = "\t[MemoryPackable]"; + // protocolIgnore = "\t\t[MemoryPackIgnore]"; + // protocolMember = "MemoryPackOrder"; + // // protocolOpCodeType = OpCodeProtocolType.MemoryPack; + // break; + // } + case "Bson": + { + if (opCodeType == NetworkProtocolOpCodeType.Outer) + { + Log.Error("Under Outer, /// does not support the Bson protocol!"); + return; + } + protocolType = null; + protocolIgnore = "\t\t[BsonIgnore]"; + protocolMember = null; + protocolOpCodeType = OpCodeProtocolType.Bson; + break; + } + default: + { + if (!ExporterSettingsHelper.CustomSerializes.TryGetValue(protocol, out var customSerialize)) + { + Log.Error($"// Protocol {protocol} is not supported!"); + return; + } + + usingNamespace.Add(customSerialize.NameSpace); + keyIndex = customSerialize.KeyIndex; + protocolType = customSerialize.Attribute; + protocolIgnore = customSerialize.Ignore; + protocolMember = customSerialize.Member; + protocolOpCodeType = customSerialize.OpCodeType; + break; + } + } + } + + if (currentLine.StartsWith("message")) + { + isMsgHead = true; + className = currentLine.Split(SplitChars, StringSplitOptions.RemoveEmptyEntries)[1]; + var splits = currentLine.Split(new[] { "//" }, StringSplitOptions.RemoveEmptyEntries); + + if (isSetProtocol) + { + if (protocolType != null) + { + messageStr.AppendLine(protocolType); + } + } + else + { + messageStr.AppendLine("\t[ProtoContract]"); + } + + if (splits.Length > 1) + { + hasOpCode = true; + var parameterArray = currentLine.Split(new[] { "//" }, StringSplitOptions.RemoveEmptyEntries)[1].Trim().Split(','); + parameter = parameterArray[0].Trim(); + opcodeInfo = new OpcodeInfo() + { + Name = className + }; + switch (parameterArray.Length) + { + case 2: + { + if (parameter == "ICustomRouteMessage") + { + customRouteType = parameterArray[1].Trim(); + break; + } + + responseTypeStr = parameterArray[1].Trim(); + break; + } + case 3: + { + responseTypeStr = parameterArray[1].Trim(); + customRouteType = parameterArray[2].Trim(); + break; + } + } + } + else + { + parameter = ""; + hasOpCode = false; + } + + messageStr.Append(string.IsNullOrWhiteSpace(parameter) + ? $"\tpublic partial class {className} : AMessage" + : $"\tpublic partial class {className} : AMessage, {parameter}"); + if (protocolMember == "ProtoMember") + { + messageStr.Append(", IProto"); + } + continue; + } + + if (!isMsgHead) + { + continue; + } + + switch (currentLine) + { + case "{": + { + messageStr.AppendLine("\n\t{"); + messageStr.AppendLine($"\t\tpublic static {className} Create(Scene scene)"); + messageStr.AppendLine($"\t\t{{\n\t\t\treturn scene.MessagePoolComponent.Rent<{className}>();\n\t\t}}"); + messageStr.AppendLine($"\t\tpublic override void Dispose()"); + messageStr.AppendLine($"\t\t{{"); + messageStr.AppendLine($"<<<>>#if FANTASY_NET || FANTASY_UNITY\n\t\t\tGetScene().MessagePoolComponent.Return<{className}>(this);\n#endif"); + messageStr.AppendLine($"\t\t}}"); + + if (parameter == "IMessage") + { + opcodeInfo.Code = OpCode.Create(protocolOpCodeType, protocolOpCode.Message, protocolOpCode.AMessage++); + messageStr.AppendLine($"\t\tpublic uint OpCode() {{ return {opCodeName}.{className}; }}"); + } + else + { + if (responseTypeStr != null) + { + messageStr.AppendLine(protocolIgnore); + messageStr.AppendLine($"\t\tpublic {responseTypeStr} ResponseType {{ get; set; }}"); + responseTypeStr = null; + } + else + { + if (parameter.Contains("RouteRequest")) + { + Log.Error($"{opcodeInfo.Name} 没指定ResponseType"); + return; + } + } + + if (hasOpCode) + { + messageStr.AppendLine($"\t\tpublic uint OpCode() {{ return {opCodeName}.{className}; }}"); + } + + if (customRouteType != null) + { + messageStr.AppendLine(protocolIgnore); + messageStr.AppendLine($"\t\tpublic int RouteType => Fantasy.RouteType.{customRouteType};"); + customRouteType = null; + } + + switch (parameter) + { + case "IRequest": + { + opcodeInfo.Code = OpCode.Create(protocolOpCodeType, protocolOpCode.Request, protocolOpCode.ARequest++); + break; + } + case "IResponse": + { + opcodeInfo.Code = OpCode.Create(protocolOpCodeType, protocolOpCode.Response, protocolOpCode.AResponse++); + if (!string.IsNullOrEmpty(protocolMember)) + { + errorCodeStr.AppendLine($"\t\t[{protocolMember}(ErrorCodeKeyIndex)]"); + } + errorCodeStr.AppendLine("\t\tpublic uint ErrorCode { get; set; }"); + disposeStr.AppendLine($"\t\t\tErrorCode = default;"); + break; + } + default: + { + switch (parameter) + { + case "IAddressableRouteMessage": + { + opcodeInfo.Code = OpCode.Create(protocolOpCodeType, protocolOpCode.AddressableMessage, protocolOpCode.AAddressableMessage++); + break; + } + case "IAddressableRouteRequest": + { + opcodeInfo.Code = OpCode.Create(protocolOpCodeType, protocolOpCode.AddressableRequest, protocolOpCode.AAddressableRequest++); + break; + } + case "IAddressableRouteResponse": + { + opcodeInfo.Code = OpCode.Create(protocolOpCodeType, protocolOpCode.AddressableResponse, protocolOpCode.AAddressableResponse++); + if (!string.IsNullOrEmpty(protocolMember)) + { + errorCodeStr.AppendLine($"\t\t[{protocolMember}(ErrorCodeKeyIndex)]"); + } + errorCodeStr.AppendLine("\t\tpublic uint ErrorCode { get; set; }"); + disposeStr.AppendLine($"\t\t\tErrorCode = default;"); + break; + } + case "ICustomRouteMessage": + { + if (opCodeType == NetworkProtocolOpCodeType.Inner) + { + throw new NotSupportedException("Under Inner, /// does not support the ICustomRouteMessage!"); + } + opcodeInfo.Code = OpCode.Create(protocolOpCodeType, protocolOpCode.CustomRouteMessage, protocolOpCode.ACustomRouteMessage++); + break; + } + case "ICustomRouteRequest": + { + if (opCodeType == NetworkProtocolOpCodeType.Inner) + { + throw new NotSupportedException("Under Inner, /// does not support the ICustomRouteMessage!"); + } + opcodeInfo.Code = OpCode.Create(protocolOpCodeType, protocolOpCode.CustomRouteRequest, protocolOpCode.ACustomRouteRequest++); + break; + } + case "ICustomRouteResponse": + { + if (opCodeType == NetworkProtocolOpCodeType.Inner) + { + throw new NotSupportedException("Under Inner, /// does not support the ICustomRouteMessage!"); + } + opcodeInfo.Code = OpCode.Create(protocolOpCodeType, protocolOpCode.CustomRouteResponse, protocolOpCode.ACustomRouteResponse++); + if (!string.IsNullOrEmpty(protocolMember)) + { + errorCodeStr.AppendLine($"\t\t[{protocolMember}(ErrorCodeKeyIndex)]"); + } + errorCodeStr.AppendLine("\t\tpublic uint ErrorCode { get; set; }"); + disposeStr.AppendLine($"\t\t\tErrorCode = default;"); + break; + } + case "IRouteMessage": + { + if (opCodeType == NetworkProtocolOpCodeType.Outer) + { + throw new NotSupportedException("Under Inner, /// does not support the ICustomRouteMessage!"); + } + opcodeInfo.Code = OpCode.Create(protocolOpCodeType, protocolOpCode.RouteMessage, protocolOpCode.ARouteMessage++); + break; + } + case "IRouteRequest": + { + if (opCodeType == NetworkProtocolOpCodeType.Outer) + { + throw new NotSupportedException("Under Inner, /// does not support the ICustomRouteMessage!"); + } + opcodeInfo.Code = OpCode.Create(protocolOpCodeType, protocolOpCode.RouteRequest, protocolOpCode.ARouteRequest++); + break; + } + case "IRouteResponse": + { + if (opCodeType == NetworkProtocolOpCodeType.Outer) + { + throw new NotSupportedException("Under Inner, /// does not support the ICustomRouteMessage!"); + } + opcodeInfo.Code = OpCode.Create(protocolOpCodeType, protocolOpCode.RouteResponse, protocolOpCode.ARouteResponse++); + if (!string.IsNullOrEmpty(protocolMember)) + { + errorCodeStr.AppendLine($"\t\t[{protocolMember}(ErrorCodeKeyIndex)]"); + } + errorCodeStr.AppendLine("\t\tpublic uint ErrorCode { get; set; }"); + disposeStr.AppendLine($"\t\t\tErrorCode = default;"); + break; + } + } + + break; + } + } + } + + if (hasOpCode) + { + _opcodes.Add(opcodeInfo); + } + + continue; + } + case "}": + { + isMsgHead = false; + errorCodeStr = errorCodeStr.Replace("ErrorCodeKeyIndex", keyIndex.ToString()); + messageStr = messageStr.Replace("<<<>>", disposeStr.ToString()); + messageStr.Append(errorCodeStr); + messageStr.AppendLine("\t}"); + file.Append(messageStr); + messageStr.Clear(); + disposeStr.Clear(); + errorCodeStr.Clear(); + keyIndex = 1; + protocolType = "\t[ProtoContract]"; + protocolIgnore = "\t\t[ProtoIgnore]"; + protocolMember = "ProtoMember"; + protocolOpCodeType = OpCodeProtocolType.ProtoBuf; + continue; + } + case "": + { + continue; + } + } + + if (currentLine.StartsWith("//")) + { + messageStr.AppendFormat("\t\t///\r\n" + "\t\t/// {0}\r\n" + "\t\t///\r\n", currentLine.TrimStart('/', '/')); + continue; + } + + if (currentLine.StartsWith("repeated")) + { + Repeated(messageStr, disposeStr, currentLine, protocolMember, ref keyIndex); + } + else + { + Members(messageStr, disposeStr, currentLine, protocolMember, ref keyIndex); + } + } + + var namespaceBuilder = new StringBuilder(); + + foreach (var @namespace in usingNamespace) + { + namespaceBuilder.Append($"using {@namespace};\n"); + } + + var csName = $"{Path.GetFileNameWithoutExtension(filePath)}.cs"; + foreach (var (directory, template) in saveDirectory) + { + var csFile = Path.Combine(directory, csName); + var content = template.Replace("(Content)", file.ToString()); + content = content.Replace("(UsingNamespace)", namespaceBuilder.ToString()); + await File.WriteAllTextAsync(csFile, content); + } + file.Clear(); + } + + #endregion + + #region GenerateOpCode + + file.Clear(); + file.AppendLine("namespace Fantasy"); + file.AppendLine("{"); + file.AppendLine($"\tpublic static partial class {opCodeName}"); + file.AppendLine("\t{"); + + foreach (var opcode in _opcodes) + { + file.AppendLine($"\t\t public const uint {opcode.Name} = {opcode.Code};"); + } + + _opcodes.Clear(); + file.AppendLine("\t}"); + file.AppendLine("}"); + + foreach (var (directory, _) in saveDirectory) + { + var csFile = Path.Combine(directory, $"{opCodeName}.cs"); + await File.WriteAllTextAsync(csFile, file.ToString()); + } + #endregion + } + + private void Repeated(StringBuilder file, StringBuilder disposeStr, string newline, string protocolMember, ref int keyIndex) + { + try + { + var index = newline.IndexOf(";", StringComparison.Ordinal); + newline = newline.Remove(index); + var property = newline.Split(SplitChars, StringSplitOptions.RemoveEmptyEntries); + var type = property[1]; + var name = property[2]; + // var memberIndex = int.Parse(property[4]); + type = ConvertType(type); + + file.AppendLine($"\t\t[{protocolMember}({keyIndex++})]"); + file.AppendLine($"\t\tpublic List<{type}> {name} = new List<{type}>();"); + disposeStr.AppendLine($"\t\t\t{name}.Clear();"); + } + catch (Exception e) + { + Log.Error($"{newline}\n {e}"); + } + } + + private void Members(StringBuilder file, StringBuilder disposeStr, string currentLine, string protocolMember, ref int keyIndex) + { + try + { + var index = currentLine.IndexOf(";", StringComparison.Ordinal); + currentLine = currentLine.Remove(index); + var property = currentLine.Split(SplitChars, StringSplitOptions.RemoveEmptyEntries); + var type = property[0]; + var name = property[1]; + // var memberIndex = int.Parse(property[3]); + var typeCs = ConvertType(type); + if (protocolMember != null) + { + file.AppendLine($"\t\t[{protocolMember}({keyIndex++})]"); + } + file.AppendLine($"\t\tpublic {typeCs} {name} {{ get; set; }}"); + disposeStr.AppendLine($"\t\t\t{name} = default;"); + } + catch (Exception e) + { + Log.Error($"{currentLine}\n {e}"); + } + } + + private string ConvertType(string type) + { + return type switch + { + "int[]" => "int[] { }", + "int32[]" => "int[] { }", + "int64[]" => "long[] { }", + "int32" => "int", + "uint32" => "uint", + "int64" => "long", + "uint64" => "ulong", + _ => type + }; + } + + private async Task RouteType() + { + var routeTypeFile = $"{_networkProtocolDirectory}RouteType.Config"; + var protoFileText = await File.ReadAllTextAsync(routeTypeFile); + var routeTypeFileSb = new StringBuilder(); + routeTypeFileSb.AppendLine("namespace Fantasy\n{"); + routeTypeFileSb.AppendLine("\t// Route协议定义(需要定义1000以上、因为1000以内的框架预留)\t"); + routeTypeFileSb.AppendLine("\tpublic static class RouteType\n\t{"); + + foreach (var line in protoFileText.Split('\n')) + { + var currentLine = line.Trim(); + + if (currentLine.StartsWith("//")) + { + continue; + } + + var splits = currentLine.Split(new[] { "//" }, StringSplitOptions.RemoveEmptyEntries); + var routeTypeStr = splits[0].Split("=", StringSplitOptions.RemoveEmptyEntries); + routeTypeFileSb.Append($"\t\tpublic const int {routeTypeStr[0].Trim()} = {routeTypeStr[1].Trim()};"); + + if (splits.Length > 1) + { + routeTypeFileSb.Append($" // {splits[1].Trim()}\n"); + } + else + { + routeTypeFileSb.Append('\n'); + } + } + + routeTypeFileSb.AppendLine("\t}\n}"); + var file = routeTypeFileSb.ToString(); + + if (ExporterAges.Instance.ExportPlatform.HasFlag(ExportPlatform.Server)) + { + await File.WriteAllTextAsync($"{_networkProtocolServerDirectory}RouteType.cs", file); + } + + if (ExporterAges.Instance.ExportPlatform.HasFlag(ExportPlatform.Client)) + { + await File.WriteAllTextAsync($"{_networkProtocolClientDirectory}RouteType.cs", file); + } + } + + private void LoadTemplate() + { + string[] lines = NetworkProtocolTemplate.Template.Split(["\r\n", "\n"], StringSplitOptions.None); + + StringBuilder serverSb = new StringBuilder(); + StringBuilder clientSb = new StringBuilder(); + + int flag = 0; + foreach (string line in lines) + { + string trim = line.Trim(); + + if (trim.StartsWith("#if") && trim.Contains("SERVER")) + { + flag = 1; + continue; + } + else if (trim.StartsWith("#else")) + { + flag = 2; + continue; + } + else if (trim.StartsWith($"#endif")) + { + flag = 0; + continue; + } + + switch (flag) + { + case 1: // 服务端 + { + serverSb.AppendLine(line); + break; + } + case 2: // 客户端 + { + clientSb.AppendLine(line); + break; + } + default: // 双端 + { + serverSb.AppendLine(line); + clientSb.AppendLine(line); + break; + } + } + } + + _serverTemplate = serverSb.Replace("(NetworkProtocol)", "ProtoBuf").ToString(); + _clientTemplate = clientSb.Replace("(NetworkProtocol)", "ProtoBuf").ToString(); + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Tools/SourceCode/Fantasy.Tools.NetworkProtocol/Exporter/ProtocolOpCode.cs b/物品和背包的完整代码/Packages/Fantasy/Tools/SourceCode/Fantasy.Tools.NetworkProtocol/Exporter/ProtocolOpCode.cs new file mode 100644 index 0000000..ace739a --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Tools/SourceCode/Fantasy.Tools.NetworkProtocol/Exporter/ProtocolOpCode.cs @@ -0,0 +1,32 @@ +namespace Fantasy.Tools.ProtocalExporter; + +public class ProtocolOpCode +{ + private const int Start = 10001; + + public uint Message; + public uint Request; + public uint Response; + public uint RouteMessage; + public uint RouteRequest; + public uint RouteResponse; + public uint AddressableMessage; + public uint AddressableRequest; + public uint AddressableResponse; + public uint CustomRouteMessage; + public uint CustomRouteRequest; + public uint CustomRouteResponse; + + public uint AMessage = Start; + public uint ARequest = Start; + public uint AResponse = Start; + public uint ARouteMessage = Start; + public uint ARouteRequest = Start; + public uint ARouteResponse = Start; + public uint AAddressableMessage = Start; + public uint AAddressableRequest = Start; + public uint AAddressableResponse = Start; + public uint ACustomRouteMessage = Start; + public uint ACustomRouteRequest = Start; + public uint ACustomRouteResponse = Start; +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Tools/SourceCode/Fantasy.Tools.NetworkProtocol/ExporterAges.cs b/物品和背包的完整代码/Packages/Fantasy/Tools/SourceCode/Fantasy.Tools.NetworkProtocol/ExporterAges.cs new file mode 100644 index 0000000..c12f344 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Tools/SourceCode/Fantasy.Tools.NetworkProtocol/ExporterAges.cs @@ -0,0 +1,15 @@ +using CommandLine; + +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. + +namespace Fantasy.Tools; + +public class ExporterAges +{ + public static ExporterAges Instance; + /// + /// 导出目标平台枚举,用于标识导出到哪个平台 + /// + [Option('p',"ExportPlatform", Required = false, Default = ExportPlatform.None, HelpText = "Export target platform:\n/// Client target platform \nClient = 1\n/// Server target platform\nServer = 2\n/// Client and Server target platform\nAll = 3")] + public ExportPlatform ExportPlatform { get; set; } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Tools/SourceCode/Fantasy.Tools.NetworkProtocol/ExporterSettings.json b/物品和背包的完整代码/Packages/Fantasy/Tools/SourceCode/Fantasy.Tools.NetworkProtocol/ExporterSettings.json new file mode 100644 index 0000000..f093812 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Tools/SourceCode/Fantasy.Tools.NetworkProtocol/ExporterSettings.json @@ -0,0 +1,29 @@ +{ + "Export": { + "NetworkProtocolDirectory": { + "Value": "../../../Examples/Config/NetworkProtocol/", + "Comment": "ProtoBuf文件所在的文件夹位置" + }, + "NetworkProtocolServerDirectory": { + "Value": "../../../Examples/Server/Entity/Generate/NetworkProtocol/", + "Comment": "ProtoBuf生成到服务端的文件夹位置" + }, + "NetworkProtocolClientDirectory": { + "Value": "../../../Examples/Client/Unity/Assets/Scripts/Hotfix/Generate/NetworkProtocol/", + "Comment": "ProtoBuf生成到客户端的文件夹位置" + }, + "Serializes": { + "Value": [ +// { +// "KeyIndex": 0, +// "NameSpace" : "MemoryPack", +// "SerializeName": "MemoryPack", +// "Attribute": "\t[MemoryPackable]", +// "Ignore": "\t\t[MemoryPackIgnore]", +// "Member": "MemoryPackOrder" +// } + ], + "Comment": "自定义序列化器" + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Tools/SourceCode/Fantasy.Tools.NetworkProtocol/ExporterSettingsHelper.cs b/物品和背包的完整代码/Packages/Fantasy/Tools/SourceCode/Fantasy.Tools.NetworkProtocol/ExporterSettingsHelper.cs new file mode 100644 index 0000000..755e674 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Tools/SourceCode/Fantasy.Tools.NetworkProtocol/ExporterSettingsHelper.cs @@ -0,0 +1,58 @@ +using Fantasy.Helper; +using Microsoft.Extensions.Configuration; +#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. +#pragma warning disable CS8601 // Possible null reference assignment. +#pragma warning disable CS8604 // Possible null reference argument. + +namespace Fantasy.Tools.ProtocalExporter; + +public class ExporterSettingsHelper +{ + public static string? NetworkProtocolDirectory { get; private set; } + public static string NetworkProtocolServerDirectory { get; private set; } + public static string NetworkProtocolClientDirectory { get; private set; } + public static Dictionary CustomSerializes { get; private set; } + + public static void Initialize() + { + const string settingsName = "ExporterSettings.json"; + var currentDirectory = Directory.GetCurrentDirectory(); + + if (!File.Exists(Path.Combine(currentDirectory, settingsName))) + { + throw new FileNotFoundException($"not found {settingsName} in OutputDirectory"); + } + + var root = new ConfigurationBuilder().SetBasePath(Directory.GetCurrentDirectory()).AddJsonFile(settingsName).Build(); + + NetworkProtocolDirectory = FileHelper.GetFullPath(root["Export:NetworkProtocolDirectory:Value"]); + NetworkProtocolServerDirectory = FileHelper.GetFullPath(root["Export:NetworkProtocolServerDirectory:Value"]); + NetworkProtocolClientDirectory = FileHelper.GetFullPath(root["Export:NetworkProtocolClientDirectory:Value"]); + + CustomSerializes = []; + var sort = new SortedList(); + var arrayOfValuesSection = root.GetSection("Export:Serializes:Value"); + + foreach (var item in arrayOfValuesSection.GetChildren()) + { + var serializeItem = new CustomSerialize + { + KeyIndex = Convert.ToInt32(item.GetSection("KeyIndex").Value), + NameSpace = item.GetSection("NameSpace").Value, + SerializeName = item.GetSection("SerializeName").Value, + Attribute = item.GetSection("Attribute").Value, + Ignore = item.GetSection("Ignore").Value, + Member = item.GetSection("Member").Value + }; + + sort.Add(HashCodeHelper.ComputeHash64(serializeItem.SerializeName), serializeItem); + } + + for (var i = 0; i < sort.Count; i++) + { + var customSerialize = sort.GetValueAtIndex(i); + customSerialize.OpCodeType = (uint)(i + 2); + CustomSerializes.Add(customSerialize.SerializeName, customSerialize); + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Packages/Fantasy/Tools/SourceCode/Fantasy.Tools.NetworkProtocol/Fantasy.Tools.NetworkProtocol.csproj b/物品和背包的完整代码/Packages/Fantasy/Tools/SourceCode/Fantasy.Tools.NetworkProtocol/Fantasy.Tools.NetworkProtocol.csproj new file mode 100644 index 0000000..581ee09 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Tools/SourceCode/Fantasy.Tools.NetworkProtocol/Fantasy.Tools.NetworkProtocol.csproj @@ -0,0 +1,61 @@ + + + + Exe + net8.0 + enable + enable + + + + false + en + + + + true + ../../Exporter/NetworkProtocol/ + + + + true + ../../Exporter/NetworkProtocol/ + + + + + + + + + + + Core\FileHelper.cs + + + Core\HashCodeHelper.cs + + + Core\JsonHelper.cs + + + ProtocalExporter\OpCode.cs + + + Never + + + + + + Always + + + Always + + + Always + + + + diff --git a/物品和背包的完整代码/Packages/Fantasy/Tools/SourceCode/Fantasy.Tools.NetworkProtocol/Program.cs b/物品和背包的完整代码/Packages/Fantasy/Tools/SourceCode/Fantasy.Tools.NetworkProtocol/Program.cs new file mode 100644 index 0000000..7f83f0c --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Tools/SourceCode/Fantasy.Tools.NetworkProtocol/Program.cs @@ -0,0 +1,28 @@ +using System.Text; +using CommandLine; +using Fantasy.Exporter; +using Fantasy.Tools; +using Fantasy.Tools.ProtocalExporter; +// 解析命令行参数 +Parser.Default.ParseArguments(Environment.GetCommandLineArgs()) + .WithNotParsed(error => throw new Exception("Command line format error!")) + .WithParsed(ages => ExporterAges.Instance = ages); +try +{ + // 初始化配置 + ExporterSettingsHelper.Initialize(); + // 加载配置 + Console.OutputEncoding = Encoding.UTF8; + // 运行导出协议的代码 + new ProtocolExporter().Run(); +} +catch (Exception e) +{ + Log.Error(e); +} +finally +{ + Log.Info("按任意键退出程序"); + Console.ReadKey(); + Environment.Exit(0); +} diff --git a/物品和背包的完整代码/Packages/Fantasy/Tools/SourceCode/Fantasy.Tools.NetworkProtocol/Properties/launchSettings.json b/物品和背包的完整代码/Packages/Fantasy/Tools/SourceCode/Fantasy.Tools.NetworkProtocol/Properties/launchSettings.json new file mode 100644 index 0000000..02fbcba --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Tools/SourceCode/Fantasy.Tools.NetworkProtocol/Properties/launchSettings.json @@ -0,0 +1,10 @@ +{ + "$schema": "http://json.schemastore.org/launchsettings.json", + "profiles": { + "Fantasy.Tools.NetworkProtocol": { + "commandName": "Project", + "environmentVariables": {}, + "commandLineArgs": "--ExportPlatform 3" + } + } +} diff --git a/物品和背包的完整代码/Packages/Fantasy/Tools/SourceCode/Fantasy.Tools.NetworkProtocol/Run.bat b/物品和背包的完整代码/Packages/Fantasy/Tools/SourceCode/Fantasy.Tools.NetworkProtocol/Run.bat new file mode 100644 index 0000000..af6e9e9 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Tools/SourceCode/Fantasy.Tools.NetworkProtocol/Run.bat @@ -0,0 +1,21 @@ +@echo off + +echo Please select an option: +echo 1. Client +echo 2. Server +echo 3. All + +set /p choice=Please select an option: + +if "%choice%"=="1" ( + echo Client + dotnet Fantasy.Tools.NetworkProtocol.dll --p 1 +) else if "%choice%"=="2" ( + echo Server + dotnet Fantasy.Tools.NetworkProtocol.dll --p 2 +) else if "%choice%"=="3" ( + echo All + dotnet Fantasy.Tools.NetworkProtocol.dll --p 3 +) else ( + echo Invalid option +) diff --git a/物品和背包的完整代码/Packages/Fantasy/Tools/SourceCode/Fantasy.Tools.NetworkProtocol/Run.sh b/物品和背包的完整代码/Packages/Fantasy/Tools/SourceCode/Fantasy.Tools.NetworkProtocol/Run.sh new file mode 100644 index 0000000..015b119 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Tools/SourceCode/Fantasy.Tools.NetworkProtocol/Run.sh @@ -0,0 +1,23 @@ +#!/bin/bash + +echo "1. Client" +echo "2. Server" +echo "3. All" + +read -n 1 -p "Please select an option:" choice +echo "" +echo "" +case $choice in + 1) + dotnet Fantasy.Tools.NetworkProtocol.dll --p 1 + ;; + 2) + dotnet Fantasy.Tools.NetworkProtocol.dll --p 2 + ;; + 3) + dotnet Fantasy.Tools.NetworkProtocol.dll --p 3 + ;; + *) + echo "Invalid option" + ;; +esac diff --git a/物品和背包的完整代码/Packages/Fantasy/Tools/SourceCode/Fantasy.Tools.SourceCode.sln b/物品和背包的完整代码/Packages/Fantasy/Tools/SourceCode/Fantasy.Tools.SourceCode.sln new file mode 100644 index 0000000..47d417f --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Tools/SourceCode/Fantasy.Tools.SourceCode.sln @@ -0,0 +1,44 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Fantasy.Tools.NetworkProtocol", "Fantasy.Tools.NetworkProtocol\Fantasy.Tools.NetworkProtocol.csproj", "{72D45E2D-EF78-4D80-8BFC-ED95FA8543C7}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Fantasy.Tools.ConfigTable", "Fantasy.Tools.ConfigTable\Fantasy.Tools.ConfigTable.csproj", "{F01BD146-FDEA-46D6-9A08-F3CCF05D817E}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "NuGet", "NuGet", "{CCF6F6B1-50D8-4B0D-91B9-035CDCC4B1CA}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Fantasy.Tools.ExporterNetworkProtocol", "..\NuGet\Fantasy.Tools.ExporterNetworkProtocol\Fantasy.Tools.ExporterNetworkProtocol.csproj", "{E0F9231E-F057-4121-B167-7AC47D48E7E3}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Fantasy.Tools.ExporterConfigTable", "..\NuGet\Fantasy.Tools.ExporterConfigTable\Fantasy.Tools.ExporterConfigTable.csproj", "{5A236869-283F-4046-860B-E295963139AB}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SourceCode", "SourceCode", "{A402EB74-8BF8-4A53-82F2-F77E59D9F4C6}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {72D45E2D-EF78-4D80-8BFC-ED95FA8543C7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {72D45E2D-EF78-4D80-8BFC-ED95FA8543C7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {72D45E2D-EF78-4D80-8BFC-ED95FA8543C7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {72D45E2D-EF78-4D80-8BFC-ED95FA8543C7}.Release|Any CPU.Build.0 = Release|Any CPU + {F01BD146-FDEA-46D6-9A08-F3CCF05D817E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F01BD146-FDEA-46D6-9A08-F3CCF05D817E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F01BD146-FDEA-46D6-9A08-F3CCF05D817E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F01BD146-FDEA-46D6-9A08-F3CCF05D817E}.Release|Any CPU.Build.0 = Release|Any CPU + {E0F9231E-F057-4121-B167-7AC47D48E7E3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E0F9231E-F057-4121-B167-7AC47D48E7E3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E0F9231E-F057-4121-B167-7AC47D48E7E3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E0F9231E-F057-4121-B167-7AC47D48E7E3}.Release|Any CPU.Build.0 = Release|Any CPU + {5A236869-283F-4046-860B-E295963139AB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5A236869-283F-4046-860B-E295963139AB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5A236869-283F-4046-860B-E295963139AB}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5A236869-283F-4046-860B-E295963139AB}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {E0F9231E-F057-4121-B167-7AC47D48E7E3} = {CCF6F6B1-50D8-4B0D-91B9-035CDCC4B1CA} + {5A236869-283F-4046-860B-E295963139AB} = {CCF6F6B1-50D8-4B0D-91B9-035CDCC4B1CA} + {F01BD146-FDEA-46D6-9A08-F3CCF05D817E} = {A402EB74-8BF8-4A53-82F2-F77E59D9F4C6} + {72D45E2D-EF78-4D80-8BFC-ED95FA8543C7} = {A402EB74-8BF8-4A53-82F2-F77E59D9F4C6} + EndGlobalSection +EndGlobal diff --git a/物品和背包的完整代码/Packages/Fantasy/Tools/SourceCode/Fantasy.Tools.SourceCode.sln.DotSettings.user b/物品和背包的完整代码/Packages/Fantasy/Tools/SourceCode/Fantasy.Tools.SourceCode.sln.DotSettings.user new file mode 100644 index 0000000..b47a6d7 --- /dev/null +++ b/物品和背包的完整代码/Packages/Fantasy/Tools/SourceCode/Fantasy.Tools.SourceCode.sln.DotSettings.user @@ -0,0 +1,19 @@ + + ForceIncluded + ForceIncluded + ForceIncluded + ForceIncluded + ForceIncluded + ForceIncluded + ForceIncluded + ForceIncluded + ForceIncluded + ForceIncluded + ForceIncluded + ForceIncluded + ForceIncluded + ForceIncluded + ForceIncluded + <AssemblyExplorer> + <Assembly Path="/Users/sining/.nuget/packages/memorypack.core/1.21.1/lib/net8.0/MemoryPack.Core.dll" /> +</AssemblyExplorer> \ No newline at end of file diff --git a/物品和背包的完整代码/Server/.DS_Store b/物品和背包的完整代码/Server/.DS_Store new file mode 100644 index 0000000..2135ae7 Binary files /dev/null and b/物品和背包的完整代码/Server/.DS_Store differ diff --git a/物品和背包的完整代码/Server/Entity/.DS_Store b/物品和背包的完整代码/Server/Entity/.DS_Store new file mode 100644 index 0000000..e9d836b Binary files /dev/null and b/物品和背包的完整代码/Server/Entity/.DS_Store differ diff --git a/物品和背包的完整代码/Server/Entity/AssemblyHelper.cs b/物品和背包的完整代码/Server/Entity/AssemblyHelper.cs new file mode 100644 index 0000000..cac01c5 --- /dev/null +++ b/物品和背包的完整代码/Server/Entity/AssemblyHelper.cs @@ -0,0 +1,41 @@ +using System.Reflection; +using System.Runtime.Loader; + +namespace Fantasy +{ + public static class AssemblyHelper + { + private const string HotfixDll = "Hotfix"; + private static AssemblyLoadContext? _assemblyLoadContext = null; + + public static System.Reflection.Assembly[] Assemblies + { + get + { + var assemblies = new System.Reflection.Assembly[2]; + assemblies[0] = LoadEntityAssembly(); + assemblies[1] = LoadHotfixAssembly(); + return assemblies; + } + } + + private static System.Reflection.Assembly LoadEntityAssembly() + { + return typeof(AssemblyHelper).Assembly; + } + + private static System.Reflection.Assembly LoadHotfixAssembly() + { + if (_assemblyLoadContext != null) + { + _assemblyLoadContext.Unload(); + System.GC.Collect(); + } + + _assemblyLoadContext = new AssemblyLoadContext(HotfixDll, true); + var dllBytes = File.ReadAllBytes(Path.Combine(Environment.CurrentDirectory, $"{HotfixDll}.dll")); + var pdbBytes = File.ReadAllBytes(Path.Combine(Environment.CurrentDirectory, $"{HotfixDll}.pdb")); + return _assemblyLoadContext.LoadFromStream(new MemoryStream(dllBytes), new MemoryStream(pdbBytes)); + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Server/Entity/Entity.csproj b/物品和背包的完整代码/Server/Entity/Entity.csproj new file mode 100644 index 0000000..0541bbc --- /dev/null +++ b/物品和背包的完整代码/Server/Entity/Entity.csproj @@ -0,0 +1,19 @@ + + + + net8.0 + enable + enable + + + + + + + + + + + + + diff --git a/物品和背包的完整代码/Server/Entity/Gate/Components/BagComponent.cs b/物品和背包的完整代码/Server/Entity/Gate/Components/BagComponent.cs new file mode 100644 index 0000000..252c4d5 --- /dev/null +++ b/物品和背包的完整代码/Server/Entity/Gate/Components/BagComponent.cs @@ -0,0 +1,12 @@ +using Fantasy.Entitas; +using Fantasy.Entitas.Interface; +using MongoDB.Bson.Serialization.Attributes; +using MongoDB.Bson.Serialization.Options; + +namespace Fantasy; + +public class BagComponent : Entity, ISupportedDataBase +{ + [BsonDictionaryOptions(DictionaryRepresentation.ArrayOfArrays)] + public Dictionary Items = new Dictionary(); +} \ No newline at end of file diff --git a/物品和背包的完整代码/Server/Entity/Gate/Components/ItemUseComponent.cs b/物品和背包的完整代码/Server/Entity/Gate/Components/ItemUseComponent.cs new file mode 100644 index 0000000..8a55842 --- /dev/null +++ b/物品和背包的完整代码/Server/Entity/Gate/Components/ItemUseComponent.cs @@ -0,0 +1,240 @@ +using Fantasy.Assembly; +using Fantasy.Async; +using Fantasy.DataStructure.Collection; +using Fantasy.Entitas; +#pragma warning disable CS8604 // Possible null reference argument. +#pragma warning disable CS8600 // Converting null literal or possible null value to non-nullable type. + +namespace Fantasy; + +public class ItemUseComponent : Entity, IAssembly +{ + private readonly Dictionary _handlers = new Dictionary(); + private readonly OneToManyList _assemblyHandlers = new OneToManyList(); + + public override void Dispose() + { + base.Dispose(); + _handlers.Clear(); + _assemblyHandlers.Clear(); + } + + #region Assembly + + public async FTask Initialize() + { + await AssemblySystem.Register(this); + } + + public async FTask Load(long assemblyIdentity) + { + var tcs = FTask.Create(false); + Scene.ThreadSynchronizationContext.Post(() => + { + InnerLoad(assemblyIdentity); + tcs.SetResult(); + }); + await tcs; + } + + public async FTask ReLoad(long assemblyIdentity) + { + var tcs = FTask.Create(false); + Scene.ThreadSynchronizationContext.Post(() => + { + InnerUnLoad(assemblyIdentity); + InnerLoad(assemblyIdentity); + tcs.SetResult(); + }); + await tcs; + } + + public async FTask OnUnLoad(long assemblyIdentity) + { + var tcs = FTask.Create(false); + Scene.ThreadSynchronizationContext.Post(() => + { + InnerUnLoad(assemblyIdentity); + tcs.SetResult(); + }); + await tcs; + } + + private void InnerLoad(long assemblyIdentity) + { + foreach (var type in AssemblySystem.ForEach(assemblyIdentity,typeof(IItemUse))) + { + var customAttributes = type.GetCustomAttributes(typeof(ItemUseAttribute), false); + if (customAttributes.Length == 0) + { + Log.Warning($"type {type.FullName} Implemented the interface of IItemUse, requiring the implementation of ItemUseAttribute"); + continue; + } + var instance = (IItemUse)Activator.CreateInstance(type); + foreach (ItemUseAttribute customAttribute in customAttributes) + { + var customAttributeType = (int)customAttribute.Type; + _handlers.Add(customAttributeType, instance); + _assemblyHandlers.Add(assemblyIdentity, customAttributeType); + } + } + } + + private void InnerUnLoad(long assemblyIdentity) + { + if (!_assemblyHandlers.TryGetValue(assemblyIdentity, out var assemblyHandlers)) + { + return; + } + + foreach (var assemblyHandler in assemblyHandlers) + { + _handlers.Remove(assemblyHandler); + } + + _assemblyHandlers.RemoveByKey(assemblyIdentity); + } + + #endregion + + public uint CanUse(Account account, ItemConfig config, ref int count) + { + var itemUseEffect = (ItemUseEffect)config.Effect; + + if (itemUseEffect == ItemUseEffect.None) + { + Log.Error($"config.Effect is zero!"); + return 1; + } + + return CanUse(account, config, itemUseEffect, ref count); + } + + public void Use(Account account, ItemConfig config, ref int count) + { + var itemUseEffect = (ItemUseEffect)config.Effect; + + if (itemUseEffect == ItemUseEffect.None) + { + Log.Error($"config.Effect is zero!"); + return; + } + + if (!_handlers.TryGetValue((int)itemUseEffect, out var handler)) + { + return; + } + + handler.Use(account, config, ref count); + } + + public uint UseHandler(Account account, ItemConfig config, ref int count) + { + var itemUseEffect = (ItemUseEffect)config.Effect; + + if (itemUseEffect == ItemUseEffect.None) + { + Log.Error($"config.Effect is zero!"); + return 1; + } + + if (!_handlers.TryGetValue((int)itemUseEffect, out var handler)) + { + return 0; + } + + var canUse = handler.CanUse(account, config, ref count); + if (canUse != 0) + { + return canUse; + } + + handler.Use(account, config, ref count); + return 0; + } + + public uint CanUse(Account account, ItemConfig config, ItemUseEffect itemUseEffect, ref int count) + { + if (!_handlers.TryGetValue((int)itemUseEffect, out var handler)) + { + return 0; + } + + return handler.CanUse(account, config, ref count); + } + + public void Use(Account account, ItemConfig config, ItemUseEffect itemUseEffect, ref int count) + { + if (!_handlers.TryGetValue((int)itemUseEffect, out var handler)) + { + return; + } + + handler.Use(account, config, ref count); + } + + public uint UseHandler(Account account, ItemConfig config, ItemUseEffect itemUseEffect, ref int count) + { + if (!_handlers.TryGetValue((int)itemUseEffect, out var handler)) + { + return 0; + } + + var canUse = handler.CanUse(account, config, ref count); + if (canUse != 0) + { + return canUse; + } + + handler.Use(account, config, ref count); + return 0; + } +} + +// public static class ItemUseHelper +// { +// private static readonly Dictionary Handlers = new Dictionary(); +// +// public static void Init() +// { +// Handlers.Add((int)ItemType.Drug, new ItemUse_Drug()); +// Handlers.Add((int)ItemType.Equip , new ItemUse_Equip()); +// } +// +// public static uint CanUse(Account account, ItemConfig config, ref int count) +// { +// if (!Handlers.TryGetValue((int)config.Type, out var handler)) +// { +// return 0; +// } +// +// return handler.CanUse(account, config, ref count); +// } +// +// public static void Use(Account account, ItemConfig config, ref int count) +// { +// if (!Handlers.TryGetValue((int)config.Type, out var handler)) +// { +// return; +// } +// +// handler.Use(account, config, ref count); +// } +// +// public static uint UseHandler(Account account, ItemConfig config, ref int count) +// { +// if (!Handlers.TryGetValue((int)config.Type, out var handler)) +// { +// return 0; +// } +// +// var canUse = handler.CanUse(account, config, ref count); +// if (canUse != 0) +// { +// return canUse; +// } +// +// handler.CanUse(account, config, ref count); +// return 0; +// } +// } \ No newline at end of file diff --git a/物品和背包的完整代码/Server/Entity/Gate/Container/Container.cs b/物品和背包的完整代码/Server/Entity/Gate/Container/Container.cs new file mode 100644 index 0000000..f761ee2 --- /dev/null +++ b/物品和背包的完整代码/Server/Entity/Gate/Container/Container.cs @@ -0,0 +1,51 @@ +using Fantasy.DataStructure.Collection; +using Fantasy.Entitas; +using MongoDB.Bson.Serialization.Attributes; +using MongoDB.Bson.Serialization.Options; + +namespace Fantasy; + +/// +/// 代表一个容器的实体 +/// +public sealed class Container : Entity +{ + /// + /// 配置表ID + /// + public uint ConfigId; + /// + /// 账户的实体 + /// + [BsonIgnore] + public Account Account; + /// + /// 对应的Config配置文件 + /// + [BsonIgnore] + public ContainerConfig Config => ContainerConfigData.Instance.Get(ConfigId); + /// + /// 当前已经使用的格子的数量 + /// + public int CurrentCellCount; + /// + /// 容器内的物品 + /// + [BsonDictionaryOptions(DictionaryRepresentation.ArrayOfArrays)] + public Dictionary Items = new Dictionary(); + /// + /// 容器内的物品,按照格子进行存储 + /// + [BsonIgnore] + public Dictionary ItemsByCell = new Dictionary(); + /// + /// 容器内的物品,按照物品配置ID进行分组 + /// + [BsonIgnore] + public readonly OneToManyList ItemsByConfigId = new OneToManyListPool(); + /// + /// 容器内的物品,按照物品类型进行分组 + /// + [BsonIgnore] + public readonly OneToManyList ItemsByType = new OneToManyListPool(); +} \ No newline at end of file diff --git a/物品和背包的完整代码/Server/Entity/Gate/Container/ContainerComponent.cs b/物品和背包的完整代码/Server/Entity/Gate/Container/ContainerComponent.cs new file mode 100644 index 0000000..169ad8d --- /dev/null +++ b/物品和背包的完整代码/Server/Entity/Gate/Container/ContainerComponent.cs @@ -0,0 +1,34 @@ +using Fantasy.Entitas; +using Fantasy.Entitas.Interface; +using MongoDB.Bson.Serialization.Attributes; +using MongoDB.Bson.Serialization.Options; + +namespace Fantasy; + +/// +/// 把用户的所有容器都放在一个组件里,这样保存的时候也会存储在一个文档里。 +/// 如果物品数据过多,可能会超过数据库单条的限制。 +/// MongoDB的数据库的单个文档的最大大小限制为16MB。 +/// 所以这个几乎不会出现的,完全不需要考虑这个大小的问题了。因为几乎把玩家可能有16MB的物品。 +/// +public sealed class ContainerComponent : Entity, ISupportedDataBase +{ + [BsonDictionaryOptions(DictionaryRepresentation.ArrayOfArrays)] + public Dictionary Containers = new Dictionary(); +} +// 如果不放心,可以把每个容器单独做一个组件存起来 +// 例如下面 +/// +/// 背包容器组件 +/// +public sealed class BagContainerComponent : Entity, ISupportedDataBase +{ + public Container Container; +} +/// +/// 装备容器组件 +/// +public sealed class EquipContainerComponent : Entity, ISupportedDataBase +{ + public Container Container; +} \ No newline at end of file diff --git a/物品和背包的完整代码/Server/Entity/Gate/Container/Equip/EquipComponent.cs b/物品和背包的完整代码/Server/Entity/Gate/Container/Equip/EquipComponent.cs new file mode 100644 index 0000000..9d039df --- /dev/null +++ b/物品和背包的完整代码/Server/Entity/Gate/Container/Equip/EquipComponent.cs @@ -0,0 +1,54 @@ +using Fantasy.Entitas; +using Fantasy.Entitas.Interface; +using MongoDB.Bson.Serialization.Attributes; +using MongoDB.Bson.Serialization.Options; + +namespace Fantasy; +/// +/// 代表装备的某一个属性 +/// +public class EquipAttr : Entity +{ + [BsonElement("K")] + public int Key; // 属性数值对应的Key + [BsonElement("V")] + public int Value; // 属性对应额数值 + [BsonElement("S")] + public int SValue; // 附加或强化属性的对应数值 + [BsonIgnore] + public int ValidValue => Value + SValue; // 真实的数值 +} +/// +/// 挂载到Item下的组件,用来表示这个Item是一个装备 +/// +public class EquipComponent : Entity, ISupportedDataBase +{ + /// + /// 主属性 + /// + [BsonDictionaryOptions(DictionaryRepresentation.ArrayOfArrays)] + public Dictionary MainAttrs = new Dictionary(); + /// + /// 附加(副)属性 + /// + [BsonDictionaryOptions(DictionaryRepresentation.ArrayOfArrays)] + public Dictionary EntryAttrs = new Dictionary(); + /// + /// 词缀 + /// + public List Affixs = new List(); + public int DurableMax; // 耐久度上限 + public int Durable; // 耐久度 +} + +/* + * {"sdfsdfsdfsdf":111} + * {"s":111} + * 2000,100 = 150 - 50 = 100 + * 2001,200 + * + * 优化后的处理方式 + * 2000,100 ,50 = 100 + 50 = 150 + * 50 - 50 = 0 , 100 + 0 = 100 + * 力量 + 50 (+20) + */ \ No newline at end of file diff --git a/物品和背包的完整代码/Server/Entity/Gate/Container/Equip/EquipPosition.cs b/物品和背包的完整代码/Server/Entity/Gate/Container/Equip/EquipPosition.cs new file mode 100644 index 0000000..325c406 --- /dev/null +++ b/物品和背包的完整代码/Server/Entity/Gate/Container/Equip/EquipPosition.cs @@ -0,0 +1,30 @@ +namespace Fantasy; + +public enum EquipPosition +{ + None = 0, + /// + /// 武器 + /// + Weapon = 1, + /// + /// 头盔 + /// + Helmet = 2, + /// + /// 衣服 + /// + Clothing = 3, + /// + /// 护腿 + /// + Leggings = 4, + /// + /// 护腕 + /// + Bracer = 5, + /// + /// 鞋子 + /// + Shoe = 6, +} \ No newline at end of file diff --git a/物品和背包的完整代码/Server/Entity/Gate/Container/ItemReason.cs b/物品和背包的完整代码/Server/Entity/Gate/Container/ItemReason.cs new file mode 100644 index 0000000..06322d5 --- /dev/null +++ b/物品和背包的完整代码/Server/Entity/Gate/Container/ItemReason.cs @@ -0,0 +1,21 @@ +namespace Fantasy; + +/// +/// 物品操作原因 +/// +public enum ItemReason +{ + None = 0, + ContainerAdd = 1, // 容器初始化添加物品 + ContainerRemove = 2, // 容器移除物品 + ContainerSplit = 3, // 容器拆分物品 + Drop = 4, // 掉落物品 + Mail = 5, // 邮件领取物品 + Sort = 6, // 物品排序 + ItemUse = 7, // 物品使用扣除 + ItemTestAdd = 8, // 测试添加物品 + UnMountEquipAdd = 9, // 卸载装备添加(一般是装备容器移除,然后添加到背包容器中) + UnMountEquipRemove = 10, // 卸载装备移除(一般是在装备容器里移除掉) + MountEquipAdd = 11, // 装备添加(一般是在装备容器里添加) + MountEquipRemove = 12, // 装备移除(一般是在装备容器里添加,背包容器里移除) +} \ No newline at end of file diff --git a/物品和背包的完整代码/Server/Entity/Gate/Entity/Account.cs b/物品和背包的完整代码/Server/Entity/Gate/Entity/Account.cs new file mode 100644 index 0000000..faba9d4 --- /dev/null +++ b/物品和背包的完整代码/Server/Entity/Gate/Entity/Account.cs @@ -0,0 +1,16 @@ +using Fantasy.Entitas; +using Fantasy.Network; +using MongoDB.Bson.Serialization.Attributes; + +namespace Fantasy; + +public sealed class Account : Entity +{ + public string UserName; + public string Password; + public uint ConfigId; + [BsonIgnore] + public UnitConfig UnitConfig => UnitConfigData.Instance.Get(ConfigId); + [BsonIgnore] + public Session Session; +} \ No newline at end of file diff --git a/物品和背包的完整代码/Server/Entity/Gate/Entity/Item.cs b/物品和背包的完整代码/Server/Entity/Gate/Entity/Item.cs new file mode 100644 index 0000000..7dbd190 --- /dev/null +++ b/物品和背包的完整代码/Server/Entity/Gate/Entity/Item.cs @@ -0,0 +1,29 @@ +using Fantasy.Entitas; +using MongoDB.Bson.Serialization.Attributes; + +namespace Fantasy; + +/// +/// 代表游戏中的一个物品 +/// +public class Item : Entity +{ + public long CellId; // 格子Id x , y x | y = long + public int Count; // 数量(叠加) + public bool IsBind; // 是否绑定 + public uint ConfigId; // 配置表Id + [BsonIgnore] + public Container Container; + [BsonIgnore] + public ItemConfig Config => ItemConfigData.Instance.Get(ConfigId); +} + +/// +/// 用于创建Item使用 +/// +public struct ItemCreateParams +{ + public uint ConfigId; + public int Count; + public bool IsBind; +} \ No newline at end of file diff --git a/物品和背包的完整代码/Server/Entity/Gate/ItemUse/IItemUse.cs b/物品和背包的完整代码/Server/Entity/Gate/ItemUse/IItemUse.cs new file mode 100644 index 0000000..4e0319f --- /dev/null +++ b/物品和背包的完整代码/Server/Entity/Gate/ItemUse/IItemUse.cs @@ -0,0 +1,34 @@ +using Fantasy; + +namespace Fantasy; + +[AttributeUsage(AttributeTargets.Class, AllowMultiple = true,Inherited = false)] +public sealed class ItemUseAttribute : Attribute +{ + public ItemUseEffect Type { get; } + + public ItemUseAttribute(ItemUseEffect type) + { + Type = type; + } +} + +public interface IItemUse +{ + /// + /// 正常的情况下,应该是使用Unit,因为这个代表的是某一个单位。 + /// 由于课程中没有这个Unit,所以暂时用Account来代替。 + /// + /// + /// + /// + /// + uint CanUse(Account account, ItemConfig config, ref int count); + /// + /// 使用物品的逻辑。 + /// + /// + /// + /// + void Use(Account account, ItemConfig config, ref int count); +} \ No newline at end of file diff --git a/物品和背包的完整代码/Server/Entity/Generate/.DS_Store b/物品和背包的完整代码/Server/Entity/Generate/.DS_Store new file mode 100644 index 0000000..25e845f Binary files /dev/null and b/物品和背包的完整代码/Server/Entity/Generate/.DS_Store differ diff --git a/物品和背包的完整代码/Server/Entity/Generate/ConfigTable/Entity/ContainerConfig.cs b/物品和背包的完整代码/Server/Entity/Generate/ConfigTable/Entity/ContainerConfig.cs new file mode 100644 index 0000000..a144717 --- /dev/null +++ b/物品和背包的完整代码/Server/Entity/Generate/ConfigTable/Entity/ContainerConfig.cs @@ -0,0 +1,105 @@ +using System; +using ProtoBuf; +using Fantasy; +using System.Linq; +using System.Reflection; +using System.Collections.Generic; +using System.Collections.Concurrent; +using Fantasy.ConfigTable; +using Fantasy.Serialize; +// ReSharper disable CollectionNeverUpdated.Global +// ReSharper disable UnusedAutoPropertyAccessor.Global +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member +#pragma warning disable CS0169 +#pragma warning disable CS8618 +#pragma warning disable CS8625 +#pragma warning disable CS8603 + +namespace Fantasy +{ + [ProtoContract] + public sealed partial class ContainerConfigData : ASerialize, IConfigTable, IProto + { + [ProtoMember(1)] + public List List { get; set; } = new List(); +#if FANTASY_NET + [ProtoIgnore] + private readonly ConcurrentDictionary _configs = new ConcurrentDictionary(); +#else + [ProtoIgnore] + private readonly Dictionary _configs = new Dictionary(); +#endif + private static ContainerConfigData _instance = null; + + public static ContainerConfigData Instance + { + get { return _instance ??= ConfigTableHelper.Load(); } + private set => _instance = value; + } + + public ContainerConfig Get(uint id, bool check = true) + { + if (_configs.ContainsKey(id)) + { + return _configs[id]; + } + + if (check) + { + throw new Exception($"ContainerConfig not find {id} Id"); + } + + return null; + } + public bool TryGet(uint id, out ContainerConfig config) + { + config = null; + + if (!_configs.ContainsKey(id)) + { + return false; + } + + config = _configs[id]; + return true; + } + public override void AfterDeserialization() + { + foreach (var config in List) + { +#if FANTASY_NET + _configs.TryAdd(config.Id, config); +#else + _configs.Add(config.Id, config); +#endif + config.AfterDeserialization(); + } + + EndInit(); + } + + public override void Dispose() + { + Instance = null; + } + } + + [ProtoContract] + public sealed partial class ContainerConfig : ASerialize, IProto + { + [ProtoMember(1)] + public uint Id { get; set; } // Id + [ProtoMember(2)] + public string Name { get; set; } // 名字 + [ProtoMember(3)] + public int Type { get; set; } // 容器类型 + [ProtoMember(4)] + public int CellCountMax { get; set; } // 容器最大的格子数 + [ProtoMember(5)] + public int CellCount { get; set; } // 初始解锁格子 + [ProtoMember(6)] + public bool CanSort { get; set; } // 是否可以整理 + [ProtoMember(7)] + public int SortCD { get; set; } // 是否可以整理 + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Server/Entity/Generate/ConfigTable/Entity/EquipAffixConfig.cs b/物品和背包的完整代码/Server/Entity/Generate/ConfigTable/Entity/EquipAffixConfig.cs new file mode 100644 index 0000000..c771054 --- /dev/null +++ b/物品和背包的完整代码/Server/Entity/Generate/ConfigTable/Entity/EquipAffixConfig.cs @@ -0,0 +1,97 @@ +using System; +using ProtoBuf; +using Fantasy; +using System.Linq; +using System.Reflection; +using System.Collections.Generic; +using System.Collections.Concurrent; +using Fantasy.ConfigTable; +using Fantasy.Serialize; +// ReSharper disable CollectionNeverUpdated.Global +// ReSharper disable UnusedAutoPropertyAccessor.Global +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member +#pragma warning disable CS0169 +#pragma warning disable CS8618 +#pragma warning disable CS8625 +#pragma warning disable CS8603 + +namespace Fantasy +{ + [ProtoContract] + public sealed partial class EquipAffixConfigData : ASerialize, IConfigTable, IProto + { + [ProtoMember(1)] + public List List { get; set; } = new List(); +#if FANTASY_NET + [ProtoIgnore] + private readonly ConcurrentDictionary _configs = new ConcurrentDictionary(); +#else + [ProtoIgnore] + private readonly Dictionary _configs = new Dictionary(); +#endif + private static EquipAffixConfigData _instance = null; + + public static EquipAffixConfigData Instance + { + get { return _instance ??= ConfigTableHelper.Load(); } + private set => _instance = value; + } + + public EquipAffixConfig Get(uint id, bool check = true) + { + if (_configs.ContainsKey(id)) + { + return _configs[id]; + } + + if (check) + { + throw new Exception($"EquipAffixConfig not find {id} Id"); + } + + return null; + } + public bool TryGet(uint id, out EquipAffixConfig config) + { + config = null; + + if (!_configs.ContainsKey(id)) + { + return false; + } + + config = _configs[id]; + return true; + } + public override void AfterDeserialization() + { + foreach (var config in List) + { +#if FANTASY_NET + _configs.TryAdd(config.Id, config); +#else + _configs.Add(config.Id, config); +#endif + config.AfterDeserialization(); + } + + EndInit(); + } + + public override void Dispose() + { + Instance = null; + } + } + + [ProtoContract] + public sealed partial class EquipAffixConfig : ASerialize, IProto + { + [ProtoMember(1)] + public uint Id { get; set; } // Id + [ProtoMember(2)] + public uint BuffConfigId { get; set; } // 触发的Buff + [ProtoMember(3)] + public string Descride { get; set; } // 介绍 + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Server/Entity/Generate/ConfigTable/Entity/EquipEntryConfig.cs b/物品和背包的完整代码/Server/Entity/Generate/ConfigTable/Entity/EquipEntryConfig.cs new file mode 100644 index 0000000..bd2c1cd --- /dev/null +++ b/物品和背包的完整代码/Server/Entity/Generate/ConfigTable/Entity/EquipEntryConfig.cs @@ -0,0 +1,105 @@ +using System; +using ProtoBuf; +using Fantasy; +using System.Linq; +using System.Reflection; +using System.Collections.Generic; +using System.Collections.Concurrent; +using Fantasy.ConfigTable; +using Fantasy.Serialize; +// ReSharper disable CollectionNeverUpdated.Global +// ReSharper disable UnusedAutoPropertyAccessor.Global +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member +#pragma warning disable CS0169 +#pragma warning disable CS8618 +#pragma warning disable CS8625 +#pragma warning disable CS8603 + +namespace Fantasy +{ + [ProtoContract] + public sealed partial class EquipEntryConfigData : ASerialize, IConfigTable, IProto + { + [ProtoMember(1)] + public List List { get; set; } = new List(); +#if FANTASY_NET + [ProtoIgnore] + private readonly ConcurrentDictionary _configs = new ConcurrentDictionary(); +#else + [ProtoIgnore] + private readonly Dictionary _configs = new Dictionary(); +#endif + private static EquipEntryConfigData _instance = null; + + public static EquipEntryConfigData Instance + { + get { return _instance ??= ConfigTableHelper.Load(); } + private set => _instance = value; + } + + public EquipEntryConfig Get(uint id, bool check = true) + { + if (_configs.ContainsKey(id)) + { + return _configs[id]; + } + + if (check) + { + throw new Exception($"EquipEntryConfig not find {id} Id"); + } + + return null; + } + public bool TryGet(uint id, out EquipEntryConfig config) + { + config = null; + + if (!_configs.ContainsKey(id)) + { + return false; + } + + config = _configs[id]; + return true; + } + public override void AfterDeserialization() + { + foreach (var config in List) + { +#if FANTASY_NET + _configs.TryAdd(config.Id, config); +#else + _configs.Add(config.Id, config); +#endif + config.AfterDeserialization(); + } + + EndInit(); + } + + public override void Dispose() + { + Instance = null; + } + } + + [ProtoContract] + public sealed partial class EquipEntryConfig : ASerialize, IProto + { + [ProtoMember(1)] + public uint Id { get; set; } // Id + [ProtoMember(2)] + public int Min { get; set; } // 词条最小数 + [ProtoMember(3)] + public int Max { get; set; } // 词条最大数 + [ProtoMember(4)] + public int AffixMin { get; set; } // 词缀最小数 + [ProtoMember(5)] + public int AffixMax { get; set; } // 词缀最大数 + [ProtoMember(6)] + public uint[] Affix { get; set; } = Array.Empty(); // 词缀列表 + [ProtoMember(7)] + public int[] Attrs { get; set; } = Array.Empty(); // 属性数组 + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Server/Entity/Generate/ConfigTable/Entity/EquipValueConfig.cs b/物品和背包的完整代码/Server/Entity/Generate/ConfigTable/Entity/EquipValueConfig.cs new file mode 100644 index 0000000..e8d5112 --- /dev/null +++ b/物品和背包的完整代码/Server/Entity/Generate/ConfigTable/Entity/EquipValueConfig.cs @@ -0,0 +1,101 @@ +using System; +using ProtoBuf; +using Fantasy; +using System.Linq; +using System.Reflection; +using System.Collections.Generic; +using System.Collections.Concurrent; +using Fantasy.ConfigTable; +using Fantasy.Serialize; +// ReSharper disable CollectionNeverUpdated.Global +// ReSharper disable UnusedAutoPropertyAccessor.Global +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member +#pragma warning disable CS0169 +#pragma warning disable CS8618 +#pragma warning disable CS8625 +#pragma warning disable CS8603 + +namespace Fantasy +{ + [ProtoContract] + public sealed partial class EquipValueConfigData : ASerialize, IConfigTable, IProto + { + [ProtoMember(1)] + public List List { get; set; } = new List(); +#if FANTASY_NET + [ProtoIgnore] + private readonly ConcurrentDictionary _configs = new ConcurrentDictionary(); +#else + [ProtoIgnore] + private readonly Dictionary _configs = new Dictionary(); +#endif + private static EquipValueConfigData _instance = null; + + public static EquipValueConfigData Instance + { + get { return _instance ??= ConfigTableHelper.Load(); } + private set => _instance = value; + } + + public EquipValueConfig Get(uint id, bool check = true) + { + if (_configs.ContainsKey(id)) + { + return _configs[id]; + } + + if (check) + { + throw new Exception($"EquipValueConfig not find {id} Id"); + } + + return null; + } + public bool TryGet(uint id, out EquipValueConfig config) + { + config = null; + + if (!_configs.ContainsKey(id)) + { + return false; + } + + config = _configs[id]; + return true; + } + public override void AfterDeserialization() + { + foreach (var config in List) + { +#if FANTASY_NET + _configs.TryAdd(config.Id, config); +#else + _configs.Add(config.Id, config); +#endif + config.AfterDeserialization(); + } + + EndInit(); + } + + public override void Dispose() + { + Instance = null; + } + } + + [ProtoContract] + public sealed partial class EquipValueConfig : ASerialize, IProto + { + [ProtoMember(1)] + public uint Id { get; set; } // Id + [ProtoMember(2)] + public uint ItemConfigId { get; set; } // ItemConfigId + [ProtoMember(3)] + public uint EquipEntryConfigId { get; set; } // EquipEntryConfigId + [ProtoMember(4)] + public int Quality { get; set; } // 品质 + [ProtoMember(5)] + public IntDictionaryConfig MainAttrs { get; set; } // 法术强度 + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Server/Entity/Generate/ConfigTable/Entity/ErrorCode.cs b/物品和背包的完整代码/Server/Entity/Generate/ConfigTable/Entity/ErrorCode.cs new file mode 100644 index 0000000..22c5440 --- /dev/null +++ b/物品和背包的完整代码/Server/Entity/Generate/ConfigTable/Entity/ErrorCode.cs @@ -0,0 +1,97 @@ +using System; +using ProtoBuf; +using Fantasy; +using System.Linq; +using System.Reflection; +using System.Collections.Generic; +using System.Collections.Concurrent; +using Fantasy.ConfigTable; +using Fantasy.Serialize; +// ReSharper disable CollectionNeverUpdated.Global +// ReSharper disable UnusedAutoPropertyAccessor.Global +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member +#pragma warning disable CS0169 +#pragma warning disable CS8618 +#pragma warning disable CS8625 +#pragma warning disable CS8603 + +namespace Fantasy +{ + [ProtoContract] + public sealed partial class ErrorCodeData : ASerialize, IConfigTable, IProto + { + [ProtoMember(1)] + public List List { get; set; } = new List(); +#if FANTASY_NET + [ProtoIgnore] + private readonly ConcurrentDictionary _configs = new ConcurrentDictionary(); +#else + [ProtoIgnore] + private readonly Dictionary _configs = new Dictionary(); +#endif + private static ErrorCodeData _instance = null; + + public static ErrorCodeData Instance + { + get { return _instance ??= ConfigTableHelper.Load(); } + private set => _instance = value; + } + + public ErrorCode Get(uint id, bool check = true) + { + if (_configs.ContainsKey(id)) + { + return _configs[id]; + } + + if (check) + { + throw new Exception($"ErrorCode not find {id} Id"); + } + + return null; + } + public bool TryGet(uint id, out ErrorCode config) + { + config = null; + + if (!_configs.ContainsKey(id)) + { + return false; + } + + config = _configs[id]; + return true; + } + public override void AfterDeserialization() + { + foreach (var config in List) + { +#if FANTASY_NET + _configs.TryAdd(config.Id, config); +#else + _configs.Add(config.Id, config); +#endif + config.AfterDeserialization(); + } + + EndInit(); + } + + public override void Dispose() + { + Instance = null; + } + } + + [ProtoContract] + public sealed partial class ErrorCode : ASerialize, IProto + { + [ProtoMember(1)] + public uint Id { get; set; } // Id + [ProtoMember(2)] + public string Name { get; set; } // 名称 + [ProtoMember(3)] + public string Text { get; set; } // 文本内容 + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Server/Entity/Generate/ConfigTable/Entity/ItemConfig.cs b/物品和背包的完整代码/Server/Entity/Generate/ConfigTable/Entity/ItemConfig.cs new file mode 100644 index 0000000..f7f6e27 --- /dev/null +++ b/物品和背包的完整代码/Server/Entity/Generate/ConfigTable/Entity/ItemConfig.cs @@ -0,0 +1,123 @@ +using System; +using ProtoBuf; +using Fantasy; +using System.Linq; +using System.Reflection; +using System.Collections.Generic; +using System.Collections.Concurrent; +using Fantasy.ConfigTable; +using Fantasy.Serialize; +// ReSharper disable CollectionNeverUpdated.Global +// ReSharper disable UnusedAutoPropertyAccessor.Global +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member +#pragma warning disable CS0169 +#pragma warning disable CS8618 +#pragma warning disable CS8625 +#pragma warning disable CS8603 + +namespace Fantasy +{ + [ProtoContract] + public sealed partial class ItemConfigData : ASerialize, IConfigTable, IProto + { + [ProtoMember(1)] + public List List { get; set; } = new List(); +#if FANTASY_NET + [ProtoIgnore] + private readonly ConcurrentDictionary _configs = new ConcurrentDictionary(); +#else + [ProtoIgnore] + private readonly Dictionary _configs = new Dictionary(); +#endif + private static ItemConfigData _instance = null; + + public static ItemConfigData Instance + { + get { return _instance ??= ConfigTableHelper.Load(); } + private set => _instance = value; + } + + public ItemConfig Get(uint id, bool check = true) + { + if (_configs.ContainsKey(id)) + { + return _configs[id]; + } + + if (check) + { + throw new Exception($"ItemConfig not find {id} Id"); + } + + return null; + } + public bool TryGet(uint id, out ItemConfig config) + { + config = null; + + if (!_configs.ContainsKey(id)) + { + return false; + } + + config = _configs[id]; + return true; + } + public override void AfterDeserialization() + { + foreach (var config in List) + { +#if FANTASY_NET + _configs.TryAdd(config.Id, config); +#else + _configs.Add(config.Id, config); +#endif + config.AfterDeserialization(); + } + + EndInit(); + } + + public override void Dispose() + { + Instance = null; + } + } + + [ProtoContract] + public sealed partial class ItemConfig : ASerialize, IProto + { + [ProtoMember(1)] + public uint Id { get; set; } // Id + [ProtoMember(2)] + public string Name { get; set; } // 名称 + [ProtoMember(3)] + public string Descride { get; set; } // 描述 + [ProtoMember(4)] + public int Weight { get; set; } // 排序权重 + [ProtoMember(5)] + public string Model2D { get; set; } // 对应模型 + [ProtoMember(6)] + public bool Superposed { get; set; } // 是否可以叠加 + [ProtoMember(7)] + public uint SuperposedMax { get; set; } // 叠加 + [ProtoMember(8)] + public uint Type { get; set; } // 类型 + [ProtoMember(9)] + public bool IsDeal { get; set; } // 是否可以交易 + [ProtoMember(10)] + public bool IsSell { get; set; } // 是否可以出售 + [ProtoMember(11)] + public int[] Sell { get; set; } = Array.Empty(); // 出售价格 + [ProtoMember(12)] + public int Effect { get; set; } // 使用效果 + [ProtoMember(13)] + public string[] Params { get; set; } = Array.Empty(); // 效果参数 + [ProtoMember(14)] + public int Durable { get; set; } // 耐久度 + [ProtoMember(15)] + public int Quality { get; set; } // 品质 + [ProtoMember(16)] + public int Position { get; set; } // 装备位置 + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Server/Entity/Generate/ConfigTable/Entity/LevelConfig.cs b/物品和背包的完整代码/Server/Entity/Generate/ConfigTable/Entity/LevelConfig.cs new file mode 100644 index 0000000..e3cb9f6 --- /dev/null +++ b/物品和背包的完整代码/Server/Entity/Generate/ConfigTable/Entity/LevelConfig.cs @@ -0,0 +1,99 @@ +using System; +using ProtoBuf; +using Fantasy; +using System.Linq; +using System.Reflection; +using System.Collections.Generic; +using System.Collections.Concurrent; +using Fantasy.ConfigTable; +using Fantasy.Serialize; +// ReSharper disable CollectionNeverUpdated.Global +// ReSharper disable UnusedAutoPropertyAccessor.Global +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member +#pragma warning disable CS0169 +#pragma warning disable CS8618 +#pragma warning disable CS8625 +#pragma warning disable CS8603 + +namespace Fantasy +{ + [ProtoContract] + public sealed partial class LevelConfigData : ASerialize, IConfigTable, IProto + { + [ProtoMember(1)] + public List List { get; set; } = new List(); +#if FANTASY_NET + [ProtoIgnore] + private readonly ConcurrentDictionary _configs = new ConcurrentDictionary(); +#else + [ProtoIgnore] + private readonly Dictionary _configs = new Dictionary(); +#endif + private static LevelConfigData _instance = null; + + public static LevelConfigData Instance + { + get { return _instance ??= ConfigTableHelper.Load(); } + private set => _instance = value; + } + + public LevelConfig Get(uint id, bool check = true) + { + if (_configs.ContainsKey(id)) + { + return _configs[id]; + } + + if (check) + { + throw new Exception($"LevelConfig not find {id} Id"); + } + + return null; + } + public bool TryGet(uint id, out LevelConfig config) + { + config = null; + + if (!_configs.ContainsKey(id)) + { + return false; + } + + config = _configs[id]; + return true; + } + public override void AfterDeserialization() + { + foreach (var config in List) + { +#if FANTASY_NET + _configs.TryAdd(config.Id, config); +#else + _configs.Add(config.Id, config); +#endif + config.AfterDeserialization(); + } + + EndInit(); + } + + public override void Dispose() + { + Instance = null; + } + } + + [ProtoContract] + public sealed partial class LevelConfig : ASerialize, IProto + { + [ProtoMember(1)] + public uint Id { get; set; } // Id + [ProtoMember(2)] + public string Name { get; set; } // 名称 + [ProtoMember(3)] + public string Model { get; set; } // 数据库类型 + [ProtoMember(4)] + public uint Group { get; set; } // 分组 + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Server/Entity/Generate/ConfigTable/Entity/UnitConfig.cs b/物品和背包的完整代码/Server/Entity/Generate/ConfigTable/Entity/UnitConfig.cs new file mode 100644 index 0000000..48d72e8 --- /dev/null +++ b/物品和背包的完整代码/Server/Entity/Generate/ConfigTable/Entity/UnitConfig.cs @@ -0,0 +1,109 @@ +using System; +using ProtoBuf; +using Fantasy; +using System.Linq; +using System.Reflection; +using System.Collections.Generic; +using System.Collections.Concurrent; +using Fantasy.ConfigTable; +using Fantasy.Serialize; +// ReSharper disable CollectionNeverUpdated.Global +// ReSharper disable UnusedAutoPropertyAccessor.Global +#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member +#pragma warning disable CS0169 +#pragma warning disable CS8618 +#pragma warning disable CS8625 +#pragma warning disable CS8603 + +namespace Fantasy +{ + [ProtoContract] + public sealed partial class UnitConfigData : ASerialize, IConfigTable, IProto + { + [ProtoMember(1)] + public List List { get; set; } = new List(); +#if FANTASY_NET + [ProtoIgnore] + private readonly ConcurrentDictionary _configs = new ConcurrentDictionary(); +#else + [ProtoIgnore] + private readonly Dictionary _configs = new Dictionary(); +#endif + private static UnitConfigData _instance = null; + + public static UnitConfigData Instance + { + get { return _instance ??= ConfigTableHelper.Load(); } + private set => _instance = value; + } + + public UnitConfig Get(uint id, bool check = true) + { + if (_configs.ContainsKey(id)) + { + return _configs[id]; + } + + if (check) + { + throw new Exception($"UnitConfig not find {id} Id"); + } + + return null; + } + public bool TryGet(uint id, out UnitConfig config) + { + config = null; + + if (!_configs.ContainsKey(id)) + { + return false; + } + + config = _configs[id]; + return true; + } + public override void AfterDeserialization() + { + foreach (var config in List) + { +#if FANTASY_NET + _configs.TryAdd(config.Id, config); +#else + _configs.Add(config.Id, config); +#endif + config.AfterDeserialization(); + } + + EndInit(); + } + + public override void Dispose() + { + Instance = null; + } + } + + [ProtoContract] + public sealed partial class UnitConfig : ASerialize, IProto + { + [ProtoMember(1)] + public uint Id { get; set; } // Id + [ProtoMember(2)] + public string Name { get; set; } // 名称 + [ProtoMember(3)] + public string Model { get; set; } // 数据库类型 + [ProtoMember(4)] + public uint Type { get; set; } // 类型 + [ProtoMember(5)] + public uint MonsterPRange { get; set; } // 怪物追击范围 + [ProtoMember(6)] + public uint TalkConfigId { get; set; } // NPC对话列表Id + [ProtoMember(7)] + public uint Camp { get; set; } // 玩家阵营 + [ProtoMember(8)] + public uint[] MountContainer { get; set; } = Array.Empty(); // 挂载的容器列表 + [ProtoMember(9)] + public uint[] Items { get; set; } = Array.Empty(); // 容器物品初始列表 + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Server/Entity/Generate/ConfigTable/Partial/ContainerConfigData.cs b/物品和背包的完整代码/Server/Entity/Generate/ConfigTable/Partial/ContainerConfigData.cs new file mode 100644 index 0000000..09b28a0 --- /dev/null +++ b/物品和背包的完整代码/Server/Entity/Generate/ConfigTable/Partial/ContainerConfigData.cs @@ -0,0 +1,38 @@ +#pragma warning disable CS8601 // Possible null reference assignment. +#pragma warning disable CS8603 // Possible null reference return. +namespace Fantasy; + +public sealed partial class ContainerConfigData +{ + private readonly Dictionary _configsByType = new Dictionary(); + + public override void EndInit() + { + foreach (var containerConfig in List) + { + _configsByType.Add(containerConfig.Type, containerConfig); + } + } + + public ContainerConfig GetConfig(ContainerType containerType) + { + if (!_configsByType.TryGetValue((int)containerType, out var config)) + { + Log.Error($"containerType {containerType} not found!"); + return null; + } + + return config; + } + + public bool TryGetConfig(ContainerType containerType, out ContainerConfig containerConfig) + { + if (!_configsByType.TryGetValue((int)containerType, out containerConfig)) + { + Log.Error($"containerType {containerType} not found!"); + return false; + } + + return true; + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Server/Entity/Generate/ConfigTable/Partial/EquipValueConfigData.cs b/物品和背包的完整代码/Server/Entity/Generate/ConfigTable/Partial/EquipValueConfigData.cs new file mode 100644 index 0000000..0411c07 --- /dev/null +++ b/物品和背包的完整代码/Server/Entity/Generate/ConfigTable/Partial/EquipValueConfigData.cs @@ -0,0 +1,33 @@ +#pragma warning disable CS8601 // Possible null reference assignment. +namespace Fantasy; + +public partial class EquipValueConfigData +{ + private readonly Dictionary _equipValueDic = new Dictionary(); + public override void EndInit() + { + foreach (var equipValueConfig in List) + { + var equipValueKey = GetEquipValueKey(equipValueConfig.ItemConfigId, equipValueConfig.Quality); + _equipValueDic.Add(equipValueKey, equipValueConfig); + } + } + + public bool TryGetValue(uint itemConfigId, int quality, out EquipValueConfig value) + { + var equipValueKey = GetEquipValueKey(itemConfigId, quality); + + if (!_equipValueDic.TryGetValue(equipValueKey, out value)) + { + Log.Error($"itemConfigId: {itemConfigId} and quality: {quality} not found in EquipValueConfig!"); + return false; + } + + return true; + } + + private ulong GetEquipValueKey(uint itemConfigId, int quality) + { + return ((ulong)itemConfigId << 32) | (uint)quality; + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Server/Entity/Generate/CustomExport/ConstValue.cs b/物品和背包的完整代码/Server/Entity/Generate/CustomExport/ConstValue.cs new file mode 100644 index 0000000..252bbf1 --- /dev/null +++ b/物品和背包的完整代码/Server/Entity/Generate/CustomExport/ConstValue.cs @@ -0,0 +1,27 @@ +namespace Fantasy +{ + // 生成器自动生成,请不要手动编辑,修改请在#ConstValue.xsl里。 + public partial class ConstValue + { + /// + /// 游戏版本 + /// + public const string Version = "v202501"; + /// + /// JWT令牌加密密钥 + /// + public const string JWTSecret = "6666"; + /// + /// 客户端使用的网络类型 + /// + public const string Network = "KCP"; + /// + /// 客户端发送心跳的时间(毫秒单位) + /// + public const int Heartbeat = 2000; + /// + /// 服务器最大容纳玩家人数 + /// + public const int PlayerCount = 5000; + } +} diff --git a/物品和背包的完整代码/Server/Entity/Generate/CustomExport/ContainerType.cs b/物品和背包的完整代码/Server/Entity/Generate/CustomExport/ContainerType.cs new file mode 100644 index 0000000..63102b2 --- /dev/null +++ b/物品和背包的完整代码/Server/Entity/Generate/CustomExport/ContainerType.cs @@ -0,0 +1,16 @@ +using System; + +namespace Fantasy +{ + // 生成器自动生成,请不要手动编辑,修改请在ContainerConfig.xsl里。 + [Flags] + public enum ContainerType : byte + { + None = 0, + Bag = 1,// 背包 + Equip = 2,// 装备栏 + Trade = 4,// 交易 + Cell = Equip | Trade,// 按格子存储的容器 + Normal = Bag,// 正常的容器 + } +} diff --git a/物品和背包的完整代码/Server/Entity/Generate/CustomExport/ErrorCode.cs b/物品和背包的完整代码/Server/Entity/Generate/CustomExport/ErrorCode.cs new file mode 100644 index 0000000..7029507 --- /dev/null +++ b/物品和背包的完整代码/Server/Entity/Generate/CustomExport/ErrorCode.cs @@ -0,0 +1,15 @@ +namespace Fantasy +{ + // 生成器自动生成,请不要手动编辑,修改请在ErrorCode.xsl里。 + public partial class ErrorCode + { + /// + /// 登陆失败 + /// + public const uint LoingError = 1; + /// + /// 角色登陆失败 + /// + public const uint LoginRoleError = 2; + } +} diff --git a/物品和背包的完整代码/Server/Entity/Generate/CustomExport/ItemType.cs b/物品和背包的完整代码/Server/Entity/Generate/CustomExport/ItemType.cs new file mode 100644 index 0000000..32a7fe7 --- /dev/null +++ b/物品和背包的完整代码/Server/Entity/Generate/CustomExport/ItemType.cs @@ -0,0 +1,12 @@ +namespace Fantasy +{ + // 生成器自动生成,请不要手动编辑,修改请在#ItemType.xsl里。 + public enum ItemType + { + None = 0, + Drug = 1,// 药品 + Equip = 2,// 装备 + Prop = 3,// 道具 + Garbage = 4,// 垃圾 + } +} diff --git a/物品和背包的完整代码/Server/Entity/Generate/CustomExport/ItemUseEffect.cs b/物品和背包的完整代码/Server/Entity/Generate/CustomExport/ItemUseEffect.cs new file mode 100644 index 0000000..cbcc3c0 --- /dev/null +++ b/物品和背包的完整代码/Server/Entity/Generate/CustomExport/ItemUseEffect.cs @@ -0,0 +1,12 @@ +namespace Fantasy +{ + // 生成器自动生成,请不要手动编辑,修改请在#ItemUseEffect.xsl里。 + public enum ItemUseEffect + { + None = 0, + Equip = 1,// 装备到身上 + UnEquip = 2,// 从身上卸下 + AddAttr = 3,// 增加属性 + CutAttr = 4,// 减少属性 + } +} diff --git a/物品和背包的完整代码/Server/Entity/Generate/CustomExport/SceneType.cs b/物品和背包的完整代码/Server/Entity/Generate/CustomExport/SceneType.cs new file mode 100644 index 0000000..de34ed9 --- /dev/null +++ b/物品和背包的完整代码/Server/Entity/Generate/CustomExport/SceneType.cs @@ -0,0 +1,27 @@ +namespace Fantasy +{ + // 生成器自动生成,请不要手动编辑。 + public static class SceneType + { + public const int Authentication = 1; + public const int Addressable = 2; + public const int Gate = 3; + public const int Map = 4; + public const int CopyDispatcher = 5; + public const int CopyManager = 6; + public const int Copy = 7; + public const int Chat = 8; + + public static readonly Dictionary SceneTypeDic = new Dictionary() + { + { "Authentication", 1 }, + { "Addressable", 2 }, + { "Gate", 3 }, + { "Map", 4 }, + { "CopyDispatcher", 5 }, + { "CopyManager", 6 }, + { "Copy", 7 }, + { "Chat", 8 }, + }; + } +} diff --git a/物品和背包的完整代码/Server/Entity/Generate/NetworkProtocol/InnerMessage.cs b/物品和背包的完整代码/Server/Entity/Generate/NetworkProtocol/InnerMessage.cs new file mode 100644 index 0000000..b4368a8 --- /dev/null +++ b/物品和背包的完整代码/Server/Entity/Generate/NetworkProtocol/InnerMessage.cs @@ -0,0 +1,73 @@ +using ProtoBuf; + +using System.Collections.Generic; +using MongoDB.Bson.Serialization.Attributes; +using Fantasy; +using Fantasy.Network.Interface; +using Fantasy.Serialize; +// ReSharper disable InconsistentNaming +// ReSharper disable RedundantUsingDirective +// ReSharper disable RedundantOverriddenMember +// ReSharper disable PartialTypeWithSinglePart +// ReSharper disable UnusedAutoPropertyAccessor.Global +// ReSharper disable MemberCanBePrivate.Global +// ReSharper disable CheckNamespace +#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. +#pragma warning disable CS8618 + +namespace Fantasy +{ + [ProtoContract] + public partial class G2A_TestMessage : AMessage, IRouteMessage, IProto + { + public static G2A_TestMessage Create(Scene scene) + { + return scene.MessagePoolComponent.Rent(); + } + public override void Dispose() + { + Tag = default; +#if FANTASY_NET || FANTASY_UNITY + GetScene().MessagePoolComponent.Return(this); +#endif + } + public uint OpCode() { return InnerOpcode.G2A_TestMessage; } + [ProtoMember(1)] + public string Tag { get; set; } + } + [ProtoContract] + public partial class G2A_TestRequest : AMessage, IRouteRequest, IProto + { + public static G2A_TestRequest Create(Scene scene) + { + return scene.MessagePoolComponent.Rent(); + } + public override void Dispose() + { +#if FANTASY_NET || FANTASY_UNITY + GetScene().MessagePoolComponent.Return(this); +#endif + } + [ProtoIgnore] + public G2A_TestResponse ResponseType { get; set; } + public uint OpCode() { return InnerOpcode.G2A_TestRequest; } + } + [ProtoContract] + public partial class G2A_TestResponse : AMessage, IRouteResponse, IProto + { + public static G2A_TestResponse Create(Scene scene) + { + return scene.MessagePoolComponent.Rent(); + } + public override void Dispose() + { + ErrorCode = default; +#if FANTASY_NET || FANTASY_UNITY + GetScene().MessagePoolComponent.Return(this); +#endif + } + public uint OpCode() { return InnerOpcode.G2A_TestResponse; } + [ProtoMember(1)] + public uint ErrorCode { get; set; } + } +} diff --git a/物品和背包的完整代码/Server/Entity/Generate/NetworkProtocol/InnerOpcode.cs b/物品和背包的完整代码/Server/Entity/Generate/NetworkProtocol/InnerOpcode.cs new file mode 100644 index 0000000..5c02193 --- /dev/null +++ b/物品和背包的完整代码/Server/Entity/Generate/NetworkProtocol/InnerOpcode.cs @@ -0,0 +1,9 @@ +namespace Fantasy +{ + public static partial class InnerOpcode + { + public const uint G2A_TestMessage = 939534097; + public const uint G2A_TestRequest = 1073751825; + public const uint G2A_TestResponse = 1207969553; + } +} diff --git a/物品和背包的完整代码/Server/Entity/Generate/NetworkProtocol/OuterMessage.cs b/物品和背包的完整代码/Server/Entity/Generate/NetworkProtocol/OuterMessage.cs new file mode 100644 index 0000000..d159956 --- /dev/null +++ b/物品和背包的完整代码/Server/Entity/Generate/NetworkProtocol/OuterMessage.cs @@ -0,0 +1,350 @@ +using ProtoBuf; + +using System.Collections.Generic; +using MongoDB.Bson.Serialization.Attributes; +using Fantasy; +using Fantasy.Network.Interface; +using Fantasy.Serialize; +// ReSharper disable InconsistentNaming +// ReSharper disable RedundantUsingDirective +// ReSharper disable RedundantOverriddenMember +// ReSharper disable PartialTypeWithSinglePart +// ReSharper disable UnusedAutoPropertyAccessor.Global +// ReSharper disable MemberCanBePrivate.Global +// ReSharper disable CheckNamespace +#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. +#pragma warning disable CS8618 + +namespace Fantasy +{ + /// + /// 客户端登陆到服务器 + /// + [ProtoContract] + public partial class C2G_LoginRequest : AMessage, IRequest, IProto + { + public static C2G_LoginRequest Create(Scene scene) + { + return scene.MessagePoolComponent.Rent(); + } + public override void Dispose() + { + UserName = default; + PassWord = default; +#if FANTASY_NET || FANTASY_UNITY + GetScene().MessagePoolComponent.Return(this); +#endif + } + [ProtoIgnore] + public G2C_LoginResponse ResponseType { get; set; } + public uint OpCode() { return OuterOpcode.C2G_LoginRequest; } + [ProtoMember(1)] + public string UserName { get; set; } + [ProtoMember(2)] + public string PassWord { get; set; } + } + /// + /// 服务器返回登陆状态给客户端 + /// + [ProtoContract] + public partial class G2C_LoginResponse : AMessage, IResponse, IProto + { + public static G2C_LoginResponse Create(Scene scene) + { + return scene.MessagePoolComponent.Rent(); + } + public override void Dispose() + { + ErrorCode = default; +#if FANTASY_NET || FANTASY_UNITY + GetScene().MessagePoolComponent.Return(this); +#endif + } + public uint OpCode() { return OuterOpcode.G2C_LoginResponse; } + [ProtoMember(1)] + public uint ErrorCode { get; set; } + } + /// + /// 客户端请求服务器使用物品 + /// + [ProtoContract] + public partial class C2G_UseItemRequest : AMessage, IRequest, IProto + { + public static C2G_UseItemRequest Create(Scene scene) + { + return scene.MessagePoolComponent.Rent(); + } + public override void Dispose() + { + ItemId = default; + Count = default; + ContainerType = default; +#if FANTASY_NET || FANTASY_UNITY + GetScene().MessagePoolComponent.Return(this); +#endif + } + [ProtoIgnore] + public G2C_UseItemResponse ResponseType { get; set; } + public uint OpCode() { return OuterOpcode.C2G_UseItemRequest; } + [ProtoMember(1)] + public long ItemId { get; set; } + [ProtoMember(2)] + public int Count { get; set; } + [ProtoMember(3)] + public int ContainerType { get; set; } + } + [ProtoContract] + public partial class G2C_UseItemResponse : AMessage, IResponse, IProto + { + public static G2C_UseItemResponse Create(Scene scene) + { + return scene.MessagePoolComponent.Rent(); + } + public override void Dispose() + { + ErrorCode = default; +#if FANTASY_NET || FANTASY_UNITY + GetScene().MessagePoolComponent.Return(this); +#endif + } + public uint OpCode() { return OuterOpcode.G2C_UseItemResponse; } + [ProtoMember(1)] + public uint ErrorCode { get; set; } + } + /// + /// 装备基础信息类 + /// + [ProtoContract] + public partial class EquipInfo : AMessage, IProto + { + public static EquipInfo Create(Scene scene) + { + return scene.MessagePoolComponent.Rent(); + } + public override void Dispose() + { + Durable = default; + DurableMax = default; + MainKeys.Clear(); + EquipAttrKeys.Clear(); + EquipAttrValues.Clear(); + EquipAttrSValues.Clear(); +#if FANTASY_NET || FANTASY_UNITY + GetScene().MessagePoolComponent.Return(this); +#endif + } + [ProtoMember(1)] + public int Durable { get; set; } + [ProtoMember(2)] + public int DurableMax { get; set; } + [ProtoMember(3)] + public List MainKeys = new List(); + [ProtoMember(4)] + public List EquipAttrKeys = new List(); + [ProtoMember(5)] + public List EquipAttrValues = new List(); + [ProtoMember(6)] + public List EquipAttrSValues = new List(); + /// + /// 比如强化等级,副属性,词缀等。都可以在这里添加 + /// + } + /// + /// 物品基础信息类 + /// + [ProtoContract] + public partial class ItemInfo : AMessage, IProto + { + public static ItemInfo Create(Scene scene) + { + return scene.MessagePoolComponent.Rent(); + } + public override void Dispose() + { + ItemId = default; + Container = default; + ConfigId = default; + CellId = default; + Count = default; + IsBind = default; + EquipInfo = default; +#if FANTASY_NET || FANTASY_UNITY + GetScene().MessagePoolComponent.Return(this); +#endif + } + [ProtoMember(1)] + public long ItemId { get; set; } + [ProtoMember(2)] + public int Container { get; set; } + [ProtoMember(3)] + public int ConfigId { get; set; } + [ProtoMember(4)] + public long CellId { get; set; } + [ProtoMember(5)] + public int Count { get; set; } + [ProtoMember(6)] + public bool IsBind { get; set; } + [ProtoMember(7)] + public EquipInfo EquipInfo { get; set; } + /// + /// 后面可能会有装备词条 也会在这里定义的,现在没有所以就是先不管了 + /// + } + /// + /// 容器信息类 + /// + [ProtoContract] + public partial class ContainerInfo : AMessage, IProto + { + public static ContainerInfo Create(Scene scene) + { + return scene.MessagePoolComponent.Rent(); + } + public override void Dispose() + { + CurrentCellCount = default; + ConfigId = default; + Items.Clear(); +#if FANTASY_NET || FANTASY_UNITY + GetScene().MessagePoolComponent.Return(this); +#endif + } + [ProtoMember(1)] + public int CurrentCellCount { get; set; } + [ProtoMember(2)] + public int ConfigId { get; set; } + [ProtoMember(3)] + public List Items = new List(); + } + /// + /// 物品变更协议(服务器推送给客户端) + /// + [ProtoContract] + public partial class G2C_UpdateItems : AMessage, IMessage, IProto + { + public static G2C_UpdateItems Create(Scene scene) + { + return scene.MessagePoolComponent.Rent(); + } + public override void Dispose() + { + ItemReason = default; + Items.Clear(); +#if FANTASY_NET || FANTASY_UNITY + GetScene().MessagePoolComponent.Return(this); +#endif + } + public uint OpCode() { return OuterOpcode.G2C_UpdateItems; } + [ProtoMember(1)] + public int ItemReason { get; set; } + [ProtoMember(2)] + public List Items = new List(); + } + /// + /// 通知服务器客户端初始化完成 + /// + [ProtoContract] + public partial class C2G_GameInitCompleteRequest : AMessage, IRequest, IProto + { + public static C2G_GameInitCompleteRequest Create(Scene scene) + { + return scene.MessagePoolComponent.Rent(); + } + public override void Dispose() + { + PushContainer = default; + PushUnitInfo = default; + Aoi = default; +#if FANTASY_NET || FANTASY_UNITY + GetScene().MessagePoolComponent.Return(this); +#endif + } + [ProtoIgnore] + public G2C_GameInitCompleteResponse ResponseType { get; set; } + public uint OpCode() { return OuterOpcode.C2G_GameInitCompleteRequest; } + [ProtoMember(1)] + public bool PushContainer { get; set; } + [ProtoMember(2)] + public bool PushUnitInfo { get; set; } + [ProtoMember(3)] + public bool Aoi { get; set; } + } + [ProtoContract] + public partial class G2C_GameInitCompleteResponse : AMessage, IResponse, IProto + { + public static G2C_GameInitCompleteResponse Create(Scene scene) + { + return scene.MessagePoolComponent.Rent(); + } + public override void Dispose() + { + ErrorCode = default; +#if FANTASY_NET || FANTASY_UNITY + GetScene().MessagePoolComponent.Return(this); +#endif + } + public uint OpCode() { return OuterOpcode.G2C_GameInitCompleteResponse; } + [ProtoMember(1)] + public uint ErrorCode { get; set; } + } + /// + /// 推送所有容器数据给客户端 + /// + [ProtoContract] + public partial class G2C_PushAllContainerInfo : AMessage, IMessage, IProto + { + public static G2C_PushAllContainerInfo Create(Scene scene) + { + return scene.MessagePoolComponent.Rent(); + } + public override void Dispose() + { + Containers.Clear(); +#if FANTASY_NET || FANTASY_UNITY + GetScene().MessagePoolComponent.Return(this); +#endif + } + public uint OpCode() { return OuterOpcode.G2C_PushAllContainerInfo; } + [ProtoMember(1)] + public List Containers = new List(); + } + /// + /// 推送单个的容器数据给客户端 + /// + [ProtoContract] + public partial class G2C_PushContainerInfo : AMessage, IMessage, IProto + { + public static G2C_PushContainerInfo Create(Scene scene) + { + return scene.MessagePoolComponent.Rent(); + } + public override void Dispose() + { + Container = default; +#if FANTASY_NET || FANTASY_UNITY + GetScene().MessagePoolComponent.Return(this); +#endif + } + public uint OpCode() { return OuterOpcode.G2C_PushContainerInfo; } + [ProtoMember(1)] + public ContainerInfo Container { get; set; } + } + /// + /// 通知服务器创建一个物品到背包容器中。 + /// + [ProtoContract] + public partial class C2G_StartCreateItem : AMessage, IMessage, IProto + { + public static C2G_StartCreateItem Create(Scene scene) + { + return scene.MessagePoolComponent.Rent(); + } + public override void Dispose() + { +#if FANTASY_NET || FANTASY_UNITY + GetScene().MessagePoolComponent.Return(this); +#endif + } + public uint OpCode() { return OuterOpcode.C2G_StartCreateItem; } + } +} diff --git a/物品和背包的完整代码/Server/Entity/Generate/NetworkProtocol/OuterOpcode.cs b/物品和背包的完整代码/Server/Entity/Generate/NetworkProtocol/OuterOpcode.cs new file mode 100644 index 0000000..913f8a0 --- /dev/null +++ b/物品和背包的完整代码/Server/Entity/Generate/NetworkProtocol/OuterOpcode.cs @@ -0,0 +1,16 @@ +namespace Fantasy +{ + public static partial class OuterOpcode + { + public const uint C2G_LoginRequest = 268445457; + public const uint G2C_LoginResponse = 402663185; + public const uint C2G_UseItemRequest = 268445458; + public const uint G2C_UseItemResponse = 402663186; + public const uint G2C_UpdateItems = 134227729; + public const uint C2G_GameInitCompleteRequest = 268445459; + public const uint G2C_GameInitCompleteResponse = 402663187; + public const uint G2C_PushAllContainerInfo = 134227730; + public const uint G2C_PushContainerInfo = 134227731; + public const uint C2G_StartCreateItem = 134227732; + } +} diff --git a/物品和背包的完整代码/Server/Entity/Generate/NetworkProtocol/RouteType.cs b/物品和背包的完整代码/Server/Entity/Generate/NetworkProtocol/RouteType.cs new file mode 100644 index 0000000..cdd0df0 --- /dev/null +++ b/物品和背包的完整代码/Server/Entity/Generate/NetworkProtocol/RouteType.cs @@ -0,0 +1,9 @@ +namespace Fantasy +{ + // Route协议定义(需要定义1000以上、因为1000以内的框架预留) + public static class RouteType + { + public const int GateRoute = 1001; // Gate + public const int ChatRoute = 1002; // Chat + } +} diff --git a/物品和背包的完整代码/Server/Entity/bin/Debug/net8.0/Entity.deps.json b/物品和背包的完整代码/Server/Entity/bin/Debug/net8.0/Entity.deps.json new file mode 100644 index 0000000..dac35c0 --- /dev/null +++ b/物品和背包的完整代码/Server/Entity/bin/Debug/net8.0/Entity.deps.json @@ -0,0 +1,361 @@ +{ + "runtimeTarget": { + "name": ".NETCoreApp,Version=v8.0", + "signature": "" + }, + "compilationOptions": {}, + "targets": { + ".NETCoreApp,Version=v8.0": { + "Entity/1.0.0": { + "dependencies": { + "Fantasy-Net": "2024.2.24", + "Fantasy-Net.ConfigTable": "2024.2.0", + "Fantasy-Net.ConfigTable.Reference": "1.0.0.0", + "Fantasy-Net.Reference": "1.0.0.0" + }, + "runtime": { + "Entity.dll": {} + } + }, + "CommandLineParser/2.9.1": { + "runtime": { + "lib/netstandard2.0/CommandLine.dll": { + "assemblyVersion": "2.9.1.0", + "fileVersion": "2.9.1.0" + } + } + }, + "DnsClient/1.6.1": { + "dependencies": { + "Microsoft.Win32.Registry": "5.0.0" + }, + "runtime": { + "lib/net5.0/DnsClient.dll": { + "assemblyVersion": "1.6.1.0", + "fileVersion": "1.6.1.0" + } + } + }, + "Microsoft.Extensions.Logging.Abstractions/2.0.0": {}, + "Microsoft.NETCore.Platforms/5.0.0": {}, + "Microsoft.Win32.Registry/5.0.0": { + "dependencies": { + "System.Security.AccessControl": "5.0.0", + "System.Security.Principal.Windows": "5.0.0" + } + }, + "MongoDB.Bson/3.1.0": { + "dependencies": { + "System.Memory": "4.5.5", + "System.Runtime.CompilerServices.Unsafe": "5.0.0" + }, + "runtime": { + "lib/net6.0/MongoDB.Bson.dll": { + "assemblyVersion": "3.1.0.0", + "fileVersion": "3.1.0.0" + } + } + }, + "MongoDB.Driver/3.1.0": { + "dependencies": { + "DnsClient": "1.6.1", + "Microsoft.Extensions.Logging.Abstractions": "2.0.0", + "MongoDB.Bson": "3.1.0", + "SharpCompress": "0.30.1", + "Snappier": "1.0.0", + "System.Buffers": "4.5.1", + "ZstdSharp.Port": "0.7.3" + }, + "runtime": { + "lib/net6.0/MongoDB.Driver.dll": { + "assemblyVersion": "3.1.0.0", + "fileVersion": "3.1.0.0" + } + } + }, + "Newtonsoft.Json/13.0.3": { + "runtime": { + "lib/net6.0/Newtonsoft.Json.dll": { + "assemblyVersion": "13.0.0.0", + "fileVersion": "13.0.3.27908" + } + } + }, + "protobuf-net/3.2.45": { + "dependencies": { + "protobuf-net.Core": "3.2.45" + }, + "runtime": { + "lib/net6.0/protobuf-net.dll": { + "assemblyVersion": "3.0.0.0", + "fileVersion": "3.2.45.36865" + } + } + }, + "protobuf-net.Core/3.2.45": { + "dependencies": { + "System.Collections.Immutable": "7.0.0" + }, + "runtime": { + "lib/net6.0/protobuf-net.Core.dll": { + "assemblyVersion": "3.0.0.0", + "fileVersion": "3.2.45.36865" + } + } + }, + "SharpCompress/0.30.1": { + "runtime": { + "lib/net5.0/SharpCompress.dll": { + "assemblyVersion": "0.30.1.0", + "fileVersion": "0.30.1.0" + } + } + }, + "Snappier/1.0.0": { + "runtime": { + "lib/net5.0/Snappier.dll": { + "assemblyVersion": "1.0.0.0", + "fileVersion": "1.0.0.0" + } + } + }, + "System.Buffers/4.5.1": {}, + "System.Collections.Immutable/7.0.0": {}, + "System.IO.Pipelines/9.0.0": { + "runtime": { + "lib/net8.0/System.IO.Pipelines.dll": { + "assemblyVersion": "9.0.0.0", + "fileVersion": "9.0.24.52809" + } + } + }, + "System.Memory/4.5.5": {}, + "System.Runtime.CompilerServices.Unsafe/5.0.0": {}, + "System.Security.AccessControl/5.0.0": { + "dependencies": { + "Microsoft.NETCore.Platforms": "5.0.0", + "System.Security.Principal.Windows": "5.0.0" + } + }, + "System.Security.Principal.Windows/5.0.0": {}, + "ZstdSharp.Port/0.7.3": { + "runtime": { + "lib/net7.0/ZstdSharp.dll": { + "assemblyVersion": "0.7.3.0", + "fileVersion": "0.7.3.0" + } + } + }, + "Fantasy-Net/2024.2.24": { + "dependencies": { + "CommandLineParser": "2.9.1", + "MongoDB.Bson": "3.1.0", + "MongoDB.Driver": "3.1.0", + "Newtonsoft.Json": "13.0.3", + "System.IO.Pipelines": "9.0.0", + "protobuf-net": "3.2.45" + }, + "runtime": { + "Fantasy-Net.dll": { + "assemblyVersion": "2024.2.24", + "fileVersion": "" + } + } + }, + "Fantasy-Net.ConfigTable/2024.2.0": { + "dependencies": { + "Fantasy-Net": "2024.2.24" + }, + "runtime": { + "Fantasy-Net.ConfigTable.dll": { + "assemblyVersion": "2024.2.0", + "fileVersion": "" + } + } + }, + "Fantasy-Net.ConfigTable.Reference/1.0.0.0": { + "runtime": { + "Fantasy-Net.ConfigTable.dll": { + "assemblyVersion": "1.0.0.0", + "fileVersion": "1.0.0.0" + } + } + }, + "Fantasy-Net.Reference/1.0.0.0": { + "runtime": { + "Fantasy-Net.dll": { + "assemblyVersion": "1.0.0.0", + "fileVersion": "1.0.0.0" + } + } + } + } + }, + "libraries": { + "Entity/1.0.0": { + "type": "project", + "serviceable": false, + "sha512": "" + }, + "CommandLineParser/2.9.1": { + "type": "package", + "serviceable": true, + "sha512": "sha512-OE0sl1/sQ37bjVsPKKtwQlWDgqaxWgtme3xZz7JssWUzg5JpMIyHgCTY9MVMxOg48fJ1AgGT3tgdH5m/kQ5xhA==", + "path": "commandlineparser/2.9.1", + "hashPath": "commandlineparser.2.9.1.nupkg.sha512" + }, + "DnsClient/1.6.1": { + "type": "package", + "serviceable": true, + "sha512": "sha512-4H/f2uYJOZ+YObZjpY9ABrKZI+JNw3uizp6oMzTXwDw6F+2qIPhpRl/1t68O/6e98+vqNiYGu+lswmwdYUy3gg==", + "path": "dnsclient/1.6.1", + "hashPath": "dnsclient.1.6.1.nupkg.sha512" + }, + "Microsoft.Extensions.Logging.Abstractions/2.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-6ZCllUYGFukkymSTx3Yr0G/ajRxoNJp7/FqSxSB4fGISST54ifBhgu4Nc0ItGi3i6DqwuNd8SUyObmiC++AO2Q==", + "path": "microsoft.extensions.logging.abstractions/2.0.0", + "hashPath": "microsoft.extensions.logging.abstractions.2.0.0.nupkg.sha512" + }, + "Microsoft.NETCore.Platforms/5.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-VyPlqzH2wavqquTcYpkIIAQ6WdenuKoFN0BdYBbCWsclXacSOHNQn66Gt4z5NBqEYW0FAPm5rlvki9ZiCij5xQ==", + "path": "microsoft.netcore.platforms/5.0.0", + "hashPath": "microsoft.netcore.platforms.5.0.0.nupkg.sha512" + }, + "Microsoft.Win32.Registry/5.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-dDoKi0PnDz31yAyETfRntsLArTlVAVzUzCIvvEDsDsucrl33Dl8pIJG06ePTJTI3tGpeyHS9Cq7Foc/s4EeKcg==", + "path": "microsoft.win32.registry/5.0.0", + "hashPath": "microsoft.win32.registry.5.0.0.nupkg.sha512" + }, + "MongoDB.Bson/3.1.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-3dhaZhz18B5vUoEP13o2j8A6zQfkHdZhwBvLZEjDJum4BTLLv1/Z8bt25UQEtpqvYwLgde4R6ekWZ7XAYUMxuw==", + "path": "mongodb.bson/3.1.0", + "hashPath": "mongodb.bson.3.1.0.nupkg.sha512" + }, + "MongoDB.Driver/3.1.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-+O7lKaIl7VUHptE0hqTd7UY1G5KDp/o8S4upG7YL4uChMNKD/U6tz9i17nMGHaD/L2AiPLgaJcaDe2XACsegGA==", + "path": "mongodb.driver/3.1.0", + "hashPath": "mongodb.driver.3.1.0.nupkg.sha512" + }, + "Newtonsoft.Json/13.0.3": { + "type": "package", + "serviceable": true, + "sha512": "sha512-HrC5BXdl00IP9zeV+0Z848QWPAoCr9P3bDEZguI+gkLcBKAOxix/tLEAAHC+UvDNPv4a2d18lOReHMOagPa+zQ==", + "path": "newtonsoft.json/13.0.3", + "hashPath": "newtonsoft.json.13.0.3.nupkg.sha512" + }, + "protobuf-net/3.2.45": { + "type": "package", + "serviceable": true, + "sha512": "sha512-5UZ/ukUHcGbFSl7vNMrHsfjqdxusdd9w7w0fCEXzf3UUtsrGNVCzV5SmF+sCHAbnRV2qPcD1ixiDP7Aj8lX/HA==", + "path": "protobuf-net/3.2.45", + "hashPath": "protobuf-net.3.2.45.nupkg.sha512" + }, + "protobuf-net.Core/3.2.45": { + "type": "package", + "serviceable": true, + "sha512": "sha512-PMWatW2NrT1uTXD7etJ4VdQ0wWZLFrIfdRGppD2QX7nzZ0+kIzqhq551u6ZiXJHWJgG4hWFEkSnUnt2aB6posg==", + "path": "protobuf-net.core/3.2.45", + "hashPath": "protobuf-net.core.3.2.45.nupkg.sha512" + }, + "SharpCompress/0.30.1": { + "type": "package", + "serviceable": true, + "sha512": "sha512-XqD4TpfyYGa7QTPzaGlMVbcecKnXy4YmYLDWrU+JIj7IuRNl7DH2END+Ll7ekWIY8o3dAMWLFDE1xdhfIWD1nw==", + "path": "sharpcompress/0.30.1", + "hashPath": "sharpcompress.0.30.1.nupkg.sha512" + }, + "Snappier/1.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-rFtK2KEI9hIe8gtx3a0YDXdHOpedIf9wYCEYtBEmtlyiWVX3XlCNV03JrmmAi/Cdfn7dxK+k0sjjcLv4fpHnqA==", + "path": "snappier/1.0.0", + "hashPath": "snappier.1.0.0.nupkg.sha512" + }, + "System.Buffers/4.5.1": { + "type": "package", + "serviceable": true, + "sha512": "sha512-Rw7ijyl1qqRS0YQD/WycNst8hUUMgrMH4FCn1nNm27M4VxchZ1js3fVjQaANHO5f3sN4isvP4a+Met9Y4YomAg==", + "path": "system.buffers/4.5.1", + "hashPath": "system.buffers.4.5.1.nupkg.sha512" + }, + "System.Collections.Immutable/7.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-dQPcs0U1IKnBdRDBkrCTi1FoajSTBzLcVTpjO4MBCMC7f4pDOIPzgBoX8JjG7X6uZRJ8EBxsi8+DR1JuwjnzOQ==", + "path": "system.collections.immutable/7.0.0", + "hashPath": "system.collections.immutable.7.0.0.nupkg.sha512" + }, + "System.IO.Pipelines/9.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-eA3cinogwaNB4jdjQHOP3Z3EuyiDII7MT35jgtnsA4vkn0LUrrSHsU0nzHTzFzmaFYeKV7MYyMxOocFzsBHpTw==", + "path": "system.io.pipelines/9.0.0", + "hashPath": "system.io.pipelines.9.0.0.nupkg.sha512" + }, + "System.Memory/4.5.5": { + "type": "package", + "serviceable": true, + "sha512": "sha512-XIWiDvKPXaTveaB7HVganDlOCRoj03l+jrwNvcge/t8vhGYKvqV+dMv6G4SAX2NoNmN0wZfVPTAlFwZcZvVOUw==", + "path": "system.memory/4.5.5", + "hashPath": "system.memory.4.5.5.nupkg.sha512" + }, + "System.Runtime.CompilerServices.Unsafe/5.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-ZD9TMpsmYJLrxbbmdvhwt9YEgG5WntEnZ/d1eH8JBX9LBp+Ju8BSBhUGbZMNVHHomWo2KVImJhTDl2hIgw/6MA==", + "path": "system.runtime.compilerservices.unsafe/5.0.0", + "hashPath": "system.runtime.compilerservices.unsafe.5.0.0.nupkg.sha512" + }, + "System.Security.AccessControl/5.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-dagJ1mHZO3Ani8GH0PHpPEe/oYO+rVdbQjvjJkBRNQkX4t0r1iaeGn8+/ybkSLEan3/slM0t59SVdHzuHf2jmw==", + "path": "system.security.accesscontrol/5.0.0", + "hashPath": "system.security.accesscontrol.5.0.0.nupkg.sha512" + }, + "System.Security.Principal.Windows/5.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-t0MGLukB5WAVU9bO3MGzvlGnyJPgUlcwerXn1kzBRjwLKixT96XV0Uza41W49gVd8zEMFu9vQEFlv0IOrytICA==", + "path": "system.security.principal.windows/5.0.0", + "hashPath": "system.security.principal.windows.5.0.0.nupkg.sha512" + }, + "ZstdSharp.Port/0.7.3": { + "type": "package", + "serviceable": true, + "sha512": "sha512-U9Ix4l4cl58Kzz1rJzj5hoVTjmbx1qGMwzAcbv1j/d3NzrFaESIurQyg+ow4mivCgkE3S413y+U9k4WdnEIkRA==", + "path": "zstdsharp.port/0.7.3", + "hashPath": "zstdsharp.port.0.7.3.nupkg.sha512" + }, + "Fantasy-Net/2024.2.24": { + "type": "project", + "serviceable": false, + "sha512": "" + }, + "Fantasy-Net.ConfigTable/2024.2.0": { + "type": "project", + "serviceable": false, + "sha512": "" + }, + "Fantasy-Net.ConfigTable.Reference/1.0.0.0": { + "type": "reference", + "serviceable": false, + "sha512": "" + }, + "Fantasy-Net.Reference/1.0.0.0": { + "type": "reference", + "serviceable": false, + "sha512": "" + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Server/Entity/bin/Debug/net8.0/Entity.dll b/物品和背包的完整代码/Server/Entity/bin/Debug/net8.0/Entity.dll new file mode 100644 index 0000000..56f7ee8 Binary files /dev/null and b/物品和背包的完整代码/Server/Entity/bin/Debug/net8.0/Entity.dll differ diff --git a/物品和背包的完整代码/Server/Entity/bin/Debug/net8.0/Entity.pdb b/物品和背包的完整代码/Server/Entity/bin/Debug/net8.0/Entity.pdb new file mode 100644 index 0000000..dc622c0 Binary files /dev/null and b/物品和背包的完整代码/Server/Entity/bin/Debug/net8.0/Entity.pdb differ diff --git a/物品和背包的完整代码/Server/Entity/bin/Debug/net8.0/Fantasy-Net.ConfigTable.dll b/物品和背包的完整代码/Server/Entity/bin/Debug/net8.0/Fantasy-Net.ConfigTable.dll new file mode 100644 index 0000000..fce9289 Binary files /dev/null and b/物品和背包的完整代码/Server/Entity/bin/Debug/net8.0/Fantasy-Net.ConfigTable.dll differ diff --git a/物品和背包的完整代码/Server/Entity/bin/Debug/net8.0/Fantasy-Net.ConfigTable.pdb b/物品和背包的完整代码/Server/Entity/bin/Debug/net8.0/Fantasy-Net.ConfigTable.pdb new file mode 100644 index 0000000..60e4fcc Binary files /dev/null and b/物品和背包的完整代码/Server/Entity/bin/Debug/net8.0/Fantasy-Net.ConfigTable.pdb differ diff --git a/物品和背包的完整代码/Server/Entity/bin/Debug/net8.0/Fantasy-Net.dll b/物品和背包的完整代码/Server/Entity/bin/Debug/net8.0/Fantasy-Net.dll new file mode 100644 index 0000000..a5e915f Binary files /dev/null and b/物品和背包的完整代码/Server/Entity/bin/Debug/net8.0/Fantasy-Net.dll differ diff --git a/物品和背包的完整代码/Server/Entity/bin/Debug/net8.0/Fantasy-Net.pdb b/物品和背包的完整代码/Server/Entity/bin/Debug/net8.0/Fantasy-Net.pdb new file mode 100644 index 0000000..fdff803 Binary files /dev/null and b/物品和背包的完整代码/Server/Entity/bin/Debug/net8.0/Fantasy-Net.pdb differ diff --git a/物品和背包的完整代码/Server/Entity/obj/Debug/net8.0/.NETCoreApp,Version=v8.0.AssemblyAttributes.cs b/物品和背包的完整代码/Server/Entity/obj/Debug/net8.0/.NETCoreApp,Version=v8.0.AssemblyAttributes.cs new file mode 100644 index 0000000..2217181 --- /dev/null +++ b/物品和背包的完整代码/Server/Entity/obj/Debug/net8.0/.NETCoreApp,Version=v8.0.AssemblyAttributes.cs @@ -0,0 +1,4 @@ +// +using System; +using System.Reflection; +[assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute(".NETCoreApp,Version=v8.0", FrameworkDisplayName = ".NET 8.0")] diff --git a/物品和背包的完整代码/Server/Entity/obj/Debug/net8.0/Entity.AssemblyInfo.cs b/物品和背包的完整代码/Server/Entity/obj/Debug/net8.0/Entity.AssemblyInfo.cs new file mode 100644 index 0000000..b1f9a04 --- /dev/null +++ b/物品和背包的完整代码/Server/Entity/obj/Debug/net8.0/Entity.AssemblyInfo.cs @@ -0,0 +1,22 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +using System; +using System.Reflection; + +[assembly: System.Reflection.AssemblyCompanyAttribute("Entity")] +[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")] +[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")] +[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0")] +[assembly: System.Reflection.AssemblyProductAttribute("Entity")] +[assembly: System.Reflection.AssemblyTitleAttribute("Entity")] +[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")] + +// 由 MSBuild WriteCodeFragment 类生成。 + diff --git a/物品和背包的完整代码/Server/Entity/obj/Debug/net8.0/Entity.AssemblyInfoInputs.cache b/物品和背包的完整代码/Server/Entity/obj/Debug/net8.0/Entity.AssemblyInfoInputs.cache new file mode 100644 index 0000000..b4d28d5 --- /dev/null +++ b/物品和背包的完整代码/Server/Entity/obj/Debug/net8.0/Entity.AssemblyInfoInputs.cache @@ -0,0 +1 @@ +b7ceabf79c524d6ee0475da740239235018950a5f2c92d51c77f832004e64e6c diff --git a/物品和背包的完整代码/Server/Entity/obj/Debug/net8.0/Entity.GeneratedMSBuildEditorConfig.editorconfig b/物品和背包的完整代码/Server/Entity/obj/Debug/net8.0/Entity.GeneratedMSBuildEditorConfig.editorconfig new file mode 100644 index 0000000..6ec23ea --- /dev/null +++ b/物品和背包的完整代码/Server/Entity/obj/Debug/net8.0/Entity.GeneratedMSBuildEditorConfig.editorconfig @@ -0,0 +1,15 @@ +is_global = true +build_property.TargetFramework = net8.0 +build_property.TargetPlatformMinVersion = +build_property.UsingMicrosoftNETSdkWeb = +build_property.ProjectTypeGuids = +build_property.InvariantGlobalization = +build_property.PlatformNeutralAssembly = +build_property.EnforceExtendedAnalyzerRules = +build_property._SupportedPlatformList = Linux,macOS,Windows +build_property.RootNamespace = Entity +build_property.ProjectDir = /Users/fantasy/Movies/物品背包开发之旅/B/Server/Entity/ +build_property.EnableComHosting = +build_property.EnableGeneratedComInterfaceComImportInterop = +build_property.EffectiveAnalysisLevelStyle = 8.0 +build_property.EnableCodeStyleSeverity = diff --git a/物品和背包的完整代码/Server/Entity/obj/Debug/net8.0/Entity.GlobalUsings.g.cs b/物品和背包的完整代码/Server/Entity/obj/Debug/net8.0/Entity.GlobalUsings.g.cs new file mode 100644 index 0000000..8578f3d --- /dev/null +++ b/物品和背包的完整代码/Server/Entity/obj/Debug/net8.0/Entity.GlobalUsings.g.cs @@ -0,0 +1,8 @@ +// +global using global::System; +global using global::System.Collections.Generic; +global using global::System.IO; +global using global::System.Linq; +global using global::System.Net.Http; +global using global::System.Threading; +global using global::System.Threading.Tasks; diff --git a/物品和背包的完整代码/Server/Entity/obj/Debug/net8.0/Entity.assets.cache b/物品和背包的完整代码/Server/Entity/obj/Debug/net8.0/Entity.assets.cache new file mode 100644 index 0000000..a00be98 Binary files /dev/null and b/物品和背包的完整代码/Server/Entity/obj/Debug/net8.0/Entity.assets.cache differ diff --git a/物品和背包的完整代码/Server/Entity/obj/Debug/net8.0/Entity.csproj.AssemblyReference.cache b/物品和背包的完整代码/Server/Entity/obj/Debug/net8.0/Entity.csproj.AssemblyReference.cache new file mode 100644 index 0000000..b5e014e Binary files /dev/null and b/物品和背包的完整代码/Server/Entity/obj/Debug/net8.0/Entity.csproj.AssemblyReference.cache differ diff --git a/物品和背包的完整代码/Server/Entity/obj/Debug/net8.0/Entity.csproj.CoreCompileInputs.cache b/物品和背包的完整代码/Server/Entity/obj/Debug/net8.0/Entity.csproj.CoreCompileInputs.cache new file mode 100644 index 0000000..ebe8f35 --- /dev/null +++ b/物品和背包的完整代码/Server/Entity/obj/Debug/net8.0/Entity.csproj.CoreCompileInputs.cache @@ -0,0 +1 @@ +e04100643a4962db8226f14c87608f61ef350431fd0164f615b9a90d5f481444 diff --git a/物品和背包的完整代码/Server/Entity/obj/Debug/net8.0/Entity.csproj.FileListAbsolute.txt b/物品和背包的完整代码/Server/Entity/obj/Debug/net8.0/Entity.csproj.FileListAbsolute.txt new file mode 100644 index 0000000..d609562 --- /dev/null +++ b/物品和背包的完整代码/Server/Entity/obj/Debug/net8.0/Entity.csproj.FileListAbsolute.txt @@ -0,0 +1,17 @@ +/Users/fantasy/Movies/物品背包开发之旅/B/Server/Entity/bin/Debug/net8.0/Entity.deps.json +/Users/fantasy/Movies/物品背包开发之旅/B/Server/Entity/bin/Debug/net8.0/Entity.dll +/Users/fantasy/Movies/物品背包开发之旅/B/Server/Entity/bin/Debug/net8.0/Entity.pdb +/Users/fantasy/Movies/物品背包开发之旅/B/Server/Entity/obj/Debug/net8.0/Entity.GeneratedMSBuildEditorConfig.editorconfig +/Users/fantasy/Movies/物品背包开发之旅/B/Server/Entity/obj/Debug/net8.0/Entity.AssemblyInfoInputs.cache +/Users/fantasy/Movies/物品背包开发之旅/B/Server/Entity/obj/Debug/net8.0/Entity.AssemblyInfo.cs +/Users/fantasy/Movies/物品背包开发之旅/B/Server/Entity/obj/Debug/net8.0/Entity.csproj.CoreCompileInputs.cache +/Users/fantasy/Movies/物品背包开发之旅/B/Server/Entity/obj/Debug/net8.0/Entity.dll +/Users/fantasy/Movies/物品背包开发之旅/B/Server/Entity/obj/Debug/net8.0/refint/Entity.dll +/Users/fantasy/Movies/物品背包开发之旅/B/Server/Entity/obj/Debug/net8.0/Entity.pdb +/Users/fantasy/Movies/物品背包开发之旅/B/Server/Entity/obj/Debug/net8.0/ref/Entity.dll +/Users/fantasy/Movies/物品背包开发之旅/B/Server/Entity/bin/Debug/net8.0/Fantasy-Net.dll +/Users/fantasy/Movies/物品背包开发之旅/B/Server/Entity/bin/Debug/net8.0/Fantasy-Net.pdb +/Users/fantasy/Movies/物品背包开发之旅/B/Server/Entity/obj/Debug/net8.0/Entity.csproj.AssemblyReference.cache +/Users/fantasy/Movies/物品背包开发之旅/B/Server/Entity/obj/Debug/net8.0/Entity.csproj.Up2Date +/Users/fantasy/Movies/物品背包开发之旅/B/Server/Entity/bin/Debug/net8.0/Fantasy-Net.ConfigTable.dll +/Users/fantasy/Movies/物品背包开发之旅/B/Server/Entity/bin/Debug/net8.0/Fantasy-Net.ConfigTable.pdb diff --git a/物品和背包的完整代码/Server/Entity/obj/Debug/net8.0/Entity.csproj.Up2Date b/物品和背包的完整代码/Server/Entity/obj/Debug/net8.0/Entity.csproj.Up2Date new file mode 100644 index 0000000..e69de29 diff --git a/物品和背包的完整代码/Server/Entity/obj/Debug/net8.0/Entity.dll b/物品和背包的完整代码/Server/Entity/obj/Debug/net8.0/Entity.dll new file mode 100644 index 0000000..56f7ee8 Binary files /dev/null and b/物品和背包的完整代码/Server/Entity/obj/Debug/net8.0/Entity.dll differ diff --git a/物品和背包的完整代码/Server/Entity/obj/Debug/net8.0/Entity.pdb b/物品和背包的完整代码/Server/Entity/obj/Debug/net8.0/Entity.pdb new file mode 100644 index 0000000..dc622c0 Binary files /dev/null and b/物品和背包的完整代码/Server/Entity/obj/Debug/net8.0/Entity.pdb differ diff --git a/物品和背包的完整代码/Server/Entity/obj/Debug/net8.0/ref/Entity.dll b/物品和背包的完整代码/Server/Entity/obj/Debug/net8.0/ref/Entity.dll new file mode 100644 index 0000000..637315b Binary files /dev/null and b/物品和背包的完整代码/Server/Entity/obj/Debug/net8.0/ref/Entity.dll differ diff --git a/物品和背包的完整代码/Server/Entity/obj/Debug/net8.0/refint/Entity.dll b/物品和背包的完整代码/Server/Entity/obj/Debug/net8.0/refint/Entity.dll new file mode 100644 index 0000000..637315b Binary files /dev/null and b/物品和背包的完整代码/Server/Entity/obj/Debug/net8.0/refint/Entity.dll differ diff --git a/物品和背包的完整代码/Server/Entity/obj/Entity.csproj.nuget.dgspec.json b/物品和背包的完整代码/Server/Entity/obj/Entity.csproj.nuget.dgspec.json new file mode 100644 index 0000000..ac48626 --- /dev/null +++ b/物品和背包的完整代码/Server/Entity/obj/Entity.csproj.nuget.dgspec.json @@ -0,0 +1,282 @@ +{ + "format": 1, + "restore": { + "/Users/fantasy/Movies/物品背包开发之旅/B/Server/Entity/Entity.csproj": {} + }, + "projects": { + "/Users/fantasy/Movies/物品背包开发之旅/B/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Fantasy.Net.csproj": { + "version": "2024.2.24", + "restore": { + "projectUniqueName": "/Users/fantasy/Movies/物品背包开发之旅/B/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Fantasy.Net.csproj", + "projectName": "Fantasy-Net", + "projectPath": "/Users/fantasy/Movies/物品背包开发之旅/B/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Fantasy.Net.csproj", + "packagesPath": "/Users/fantasy/.nuget/packages/", + "outputPath": "/Users/fantasy/Movies/物品背包开发之旅/B/Packages/Fantasy/Fantasy.Net/Fantasy.Net/obj/", + "projectStyle": "PackageReference", + "crossTargeting": true, + "configFilePaths": [ + "/Users/fantasy/.nuget/NuGet/NuGet.Config" + ], + "originalTargetFrameworks": [ + "net8.0", + "net9.0" + ], + "sources": { + "/usr/local/share/dotnet/library-packs": {}, + "https://api.nuget.org/v3/index.json": {} + }, + "frameworks": { + "net8.0": { + "targetAlias": "net8.0", + "projectReferences": {} + }, + "net9.0": { + "targetAlias": "net9.0", + "projectReferences": {} + } + }, + "warningProperties": { + "allWarningsAsErrors": true, + "warnAsError": [ + "NU1605" + ] + }, + "restoreAuditProperties": { + "enableAudit": "true", + "auditLevel": "low", + "auditMode": "all" + }, + "SdkAnalysisLevel": "9.0.100" + }, + "frameworks": { + "net8.0": { + "targetAlias": "net8.0", + "dependencies": { + "CommandLineParser": { + "target": "Package", + "version": "[2.9.1, )" + }, + "MongoDB.Bson": { + "target": "Package", + "version": "[3.1.0, )" + }, + "MongoDB.Driver": { + "target": "Package", + "version": "[3.1.0, )" + }, + "Newtonsoft.Json": { + "target": "Package", + "version": "[13.0.3, )" + }, + "System.IO.Pipelines": { + "target": "Package", + "version": "[9.0.0, )" + }, + "protobuf-net": { + "target": "Package", + "version": "[3.2.45, )" + } + }, + "imports": [ + "net461", + "net462", + "net47", + "net471", + "net472", + "net48", + "net481" + ], + "assetTargetFallback": true, + "warn": true, + "frameworkReferences": { + "Microsoft.AspNetCore.App": { + "privateAssets": "none" + }, + "Microsoft.NETCore.App": { + "privateAssets": "all" + } + }, + "runtimeIdentifierGraphPath": "/usr/local/share/dotnet/sdk/9.0.100/PortableRuntimeIdentifierGraph.json" + }, + "net9.0": { + "targetAlias": "net9.0", + "dependencies": { + "CommandLineParser": { + "target": "Package", + "version": "[2.9.1, )" + }, + "MongoDB.Bson": { + "target": "Package", + "version": "[3.1.0, )" + }, + "MongoDB.Driver": { + "target": "Package", + "version": "[3.1.0, )" + }, + "Newtonsoft.Json": { + "target": "Package", + "version": "[13.0.3, )" + }, + "protobuf-net": { + "target": "Package", + "version": "[3.2.45, )" + } + }, + "imports": [ + "net461", + "net462", + "net47", + "net471", + "net472", + "net48", + "net481" + ], + "assetTargetFallback": true, + "warn": true, + "frameworkReferences": { + "Microsoft.AspNetCore.App": { + "privateAssets": "none" + }, + "Microsoft.NETCore.App": { + "privateAssets": "all" + } + }, + "runtimeIdentifierGraphPath": "/usr/local/share/dotnet/sdk/9.0.100/PortableRuntimeIdentifierGraph.json" + } + } + }, + "/Users/fantasy/Movies/物品背包开发之旅/B/Packages/Fantasy/Fantasy.Packages/Fantasy.ConfigTable/Net/Fantasy.ConfigTable.csproj": { + "version": "2024.2.0", + "restore": { + "projectUniqueName": "/Users/fantasy/Movies/物品背包开发之旅/B/Packages/Fantasy/Fantasy.Packages/Fantasy.ConfigTable/Net/Fantasy.ConfigTable.csproj", + "projectName": "Fantasy-Net.ConfigTable", + "projectPath": "/Users/fantasy/Movies/物品背包开发之旅/B/Packages/Fantasy/Fantasy.Packages/Fantasy.ConfigTable/Net/Fantasy.ConfigTable.csproj", + "packagesPath": "/Users/fantasy/.nuget/packages/", + "outputPath": "/Users/fantasy/Movies/物品背包开发之旅/B/Packages/Fantasy/Fantasy.Packages/Fantasy.ConfigTable/Net/obj/", + "projectStyle": "PackageReference", + "configFilePaths": [ + "/Users/fantasy/.nuget/NuGet/NuGet.Config" + ], + "originalTargetFrameworks": [ + "net8.0" + ], + "sources": { + "/usr/local/share/dotnet/library-packs": {}, + "https://api.nuget.org/v3/index.json": {} + }, + "frameworks": { + "net8.0": { + "targetAlias": "net8.0", + "projectReferences": {} + } + }, + "warningProperties": { + "warnAsError": [ + "NU1605" + ] + }, + "restoreAuditProperties": { + "enableAudit": "true", + "auditLevel": "low", + "auditMode": "all" + }, + "SdkAnalysisLevel": "9.0.100" + }, + "frameworks": { + "net8.0": { + "targetAlias": "net8.0", + "dependencies": { + "Fantasy-Net": { + "target": "Package", + "version": "[2024.2.22, )" + } + }, + "imports": [ + "net461", + "net462", + "net47", + "net471", + "net472", + "net48", + "net481" + ], + "assetTargetFallback": true, + "warn": true, + "frameworkReferences": { + "Microsoft.NETCore.App": { + "privateAssets": "all" + } + }, + "runtimeIdentifierGraphPath": "/usr/local/share/dotnet/sdk/9.0.100/PortableRuntimeIdentifierGraph.json" + } + } + }, + "/Users/fantasy/Movies/物品背包开发之旅/B/Server/Entity/Entity.csproj": { + "version": "1.0.0", + "restore": { + "projectUniqueName": "/Users/fantasy/Movies/物品背包开发之旅/B/Server/Entity/Entity.csproj", + "projectName": "Entity", + "projectPath": "/Users/fantasy/Movies/物品背包开发之旅/B/Server/Entity/Entity.csproj", + "packagesPath": "/Users/fantasy/.nuget/packages/", + "outputPath": "/Users/fantasy/Movies/物品背包开发之旅/B/Server/Entity/obj/", + "projectStyle": "PackageReference", + "configFilePaths": [ + "/Users/fantasy/.nuget/NuGet/NuGet.Config" + ], + "originalTargetFrameworks": [ + "net8.0" + ], + "sources": { + "/usr/local/share/dotnet/library-packs": {}, + "https://api.nuget.org/v3/index.json": {} + }, + "frameworks": { + "net8.0": { + "targetAlias": "net8.0", + "projectReferences": { + "/Users/fantasy/Movies/物品背包开发之旅/B/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Fantasy.Net.csproj": { + "projectPath": "/Users/fantasy/Movies/物品背包开发之旅/B/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Fantasy.Net.csproj" + }, + "/Users/fantasy/Movies/物品背包开发之旅/B/Packages/Fantasy/Fantasy.Packages/Fantasy.ConfigTable/Net/Fantasy.ConfigTable.csproj": { + "projectPath": "/Users/fantasy/Movies/物品背包开发之旅/B/Packages/Fantasy/Fantasy.Packages/Fantasy.ConfigTable/Net/Fantasy.ConfigTable.csproj" + } + } + } + }, + "warningProperties": { + "warnAsError": [ + "NU1605" + ] + }, + "restoreAuditProperties": { + "enableAudit": "true", + "auditLevel": "low", + "auditMode": "all" + }, + "SdkAnalysisLevel": "9.0.100" + }, + "frameworks": { + "net8.0": { + "targetAlias": "net8.0", + "imports": [ + "net461", + "net462", + "net47", + "net471", + "net472", + "net48", + "net481" + ], + "assetTargetFallback": true, + "warn": true, + "frameworkReferences": { + "Microsoft.NETCore.App": { + "privateAssets": "all" + } + }, + "runtimeIdentifierGraphPath": "/usr/local/share/dotnet/sdk/9.0.100/PortableRuntimeIdentifierGraph.json" + } + } + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Server/Entity/obj/Entity.csproj.nuget.g.props b/物品和背包的完整代码/Server/Entity/obj/Entity.csproj.nuget.g.props new file mode 100644 index 0000000..f402062 --- /dev/null +++ b/物品和背包的完整代码/Server/Entity/obj/Entity.csproj.nuget.g.props @@ -0,0 +1,15 @@ + + + + True + NuGet + $(MSBuildThisFileDirectory)project.assets.json + /Users/fantasy/.nuget/packages/ + /Users/fantasy/.nuget/packages/ + PackageReference + 6.12.2 + + + + + \ No newline at end of file diff --git a/物品和背包的完整代码/Server/Entity/obj/Entity.csproj.nuget.g.targets b/物品和背包的完整代码/Server/Entity/obj/Entity.csproj.nuget.g.targets new file mode 100644 index 0000000..3dc06ef --- /dev/null +++ b/物品和背包的完整代码/Server/Entity/obj/Entity.csproj.nuget.g.targets @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/物品和背包的完整代码/Server/Entity/obj/project.assets.json b/物品和背包的完整代码/Server/Entity/obj/project.assets.json new file mode 100644 index 0000000..7674d78 --- /dev/null +++ b/物品和背包的完整代码/Server/Entity/obj/project.assets.json @@ -0,0 +1,956 @@ +{ + "version": 3, + "targets": { + "net8.0": { + "CommandLineParser/2.9.1": { + "type": "package", + "compile": { + "lib/netstandard2.0/CommandLine.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netstandard2.0/CommandLine.dll": { + "related": ".xml" + } + } + }, + "DnsClient/1.6.1": { + "type": "package", + "dependencies": { + "Microsoft.Win32.Registry": "5.0.0" + }, + "compile": { + "lib/net5.0/DnsClient.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net5.0/DnsClient.dll": { + "related": ".xml" + } + } + }, + "Microsoft.Extensions.Logging.Abstractions/2.0.0": { + "type": "package", + "compile": { + "lib/netstandard2.0/Microsoft.Extensions.Logging.Abstractions.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netstandard2.0/Microsoft.Extensions.Logging.Abstractions.dll": { + "related": ".xml" + } + } + }, + "Microsoft.NETCore.Platforms/5.0.0": { + "type": "package", + "compile": { + "lib/netstandard1.0/_._": {} + }, + "runtime": { + "lib/netstandard1.0/_._": {} + } + }, + "Microsoft.Win32.Registry/5.0.0": { + "type": "package", + "dependencies": { + "System.Security.AccessControl": "5.0.0", + "System.Security.Principal.Windows": "5.0.0" + }, + "compile": { + "ref/netstandard2.0/Microsoft.Win32.Registry.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netstandard2.0/Microsoft.Win32.Registry.dll": { + "related": ".xml" + } + }, + "runtimeTargets": { + "runtimes/win/lib/netstandard2.0/Microsoft.Win32.Registry.dll": { + "assetType": "runtime", + "rid": "win" + } + } + }, + "MongoDB.Bson/3.1.0": { + "type": "package", + "dependencies": { + "System.Memory": "4.5.5", + "System.Runtime.CompilerServices.Unsafe": "5.0.0" + }, + "compile": { + "lib/net6.0/MongoDB.Bson.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net6.0/MongoDB.Bson.dll": { + "related": ".xml" + } + } + }, + "MongoDB.Driver/3.1.0": { + "type": "package", + "dependencies": { + "DnsClient": "1.6.1", + "Microsoft.Extensions.Logging.Abstractions": "2.0.0", + "MongoDB.Bson": "3.1.0", + "SharpCompress": "0.30.1", + "Snappier": "1.0.0", + "System.Buffers": "4.5.1", + "ZstdSharp.Port": "0.7.3" + }, + "compile": { + "lib/net6.0/MongoDB.Driver.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net6.0/MongoDB.Driver.dll": { + "related": ".xml" + } + } + }, + "Newtonsoft.Json/13.0.3": { + "type": "package", + "compile": { + "lib/net6.0/Newtonsoft.Json.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net6.0/Newtonsoft.Json.dll": { + "related": ".xml" + } + } + }, + "protobuf-net/3.2.45": { + "type": "package", + "dependencies": { + "protobuf-net.Core": "3.2.45" + }, + "compile": { + "lib/net6.0/protobuf-net.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net6.0/protobuf-net.dll": { + "related": ".xml" + } + } + }, + "protobuf-net.Core/3.2.45": { + "type": "package", + "dependencies": { + "System.Collections.Immutable": "7.0.0" + }, + "compile": { + "lib/net6.0/protobuf-net.Core.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net6.0/protobuf-net.Core.dll": { + "related": ".xml" + } + } + }, + "SharpCompress/0.30.1": { + "type": "package", + "compile": { + "lib/net5.0/SharpCompress.dll": {} + }, + "runtime": { + "lib/net5.0/SharpCompress.dll": {} + } + }, + "Snappier/1.0.0": { + "type": "package", + "compile": { + "lib/net5.0/Snappier.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net5.0/Snappier.dll": { + "related": ".xml" + } + } + }, + "System.Buffers/4.5.1": { + "type": "package", + "compile": { + "ref/netcoreapp2.0/_._": {} + }, + "runtime": { + "lib/netcoreapp2.0/_._": {} + } + }, + "System.Collections.Immutable/7.0.0": { + "type": "package", + "compile": { + "lib/net7.0/System.Collections.Immutable.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net7.0/System.Collections.Immutable.dll": { + "related": ".xml" + } + }, + "build": { + "buildTransitive/net6.0/_._": {} + } + }, + "System.IO.Pipelines/9.0.0": { + "type": "package", + "compile": { + "lib/net8.0/System.IO.Pipelines.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net8.0/System.IO.Pipelines.dll": { + "related": ".xml" + } + }, + "build": { + "buildTransitive/net8.0/_._": {} + } + }, + "System.Memory/4.5.5": { + "type": "package", + "compile": { + "ref/netcoreapp2.1/_._": {} + }, + "runtime": { + "lib/netcoreapp2.1/_._": {} + } + }, + "System.Runtime.CompilerServices.Unsafe/5.0.0": { + "type": "package", + "compile": { + "ref/netstandard2.1/System.Runtime.CompilerServices.Unsafe.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netcoreapp2.0/System.Runtime.CompilerServices.Unsafe.dll": { + "related": ".xml" + } + } + }, + "System.Security.AccessControl/5.0.0": { + "type": "package", + "dependencies": { + "Microsoft.NETCore.Platforms": "5.0.0", + "System.Security.Principal.Windows": "5.0.0" + }, + "compile": { + "ref/netstandard2.0/System.Security.AccessControl.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netstandard2.0/System.Security.AccessControl.dll": { + "related": ".xml" + } + }, + "runtimeTargets": { + "runtimes/win/lib/netcoreapp2.0/System.Security.AccessControl.dll": { + "assetType": "runtime", + "rid": "win" + } + } + }, + "System.Security.Principal.Windows/5.0.0": { + "type": "package", + "compile": { + "ref/netcoreapp3.0/System.Security.Principal.Windows.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netstandard2.0/System.Security.Principal.Windows.dll": { + "related": ".xml" + } + }, + "runtimeTargets": { + "runtimes/unix/lib/netcoreapp2.1/System.Security.Principal.Windows.dll": { + "assetType": "runtime", + "rid": "unix" + }, + "runtimes/win/lib/netcoreapp2.1/System.Security.Principal.Windows.dll": { + "assetType": "runtime", + "rid": "win" + } + } + }, + "ZstdSharp.Port/0.7.3": { + "type": "package", + "compile": { + "lib/net7.0/ZstdSharp.dll": {} + }, + "runtime": { + "lib/net7.0/ZstdSharp.dll": {} + } + }, + "Fantasy-Net/2024.2.24": { + "type": "project", + "framework": ".NETCoreApp,Version=v8.0", + "dependencies": { + "CommandLineParser": "2.9.1", + "MongoDB.Bson": "3.1.0", + "MongoDB.Driver": "3.1.0", + "Newtonsoft.Json": "13.0.3", + "System.IO.Pipelines": "9.0.0", + "protobuf-net": "3.2.45" + }, + "compile": { + "bin/placeholder/Fantasy-Net.dll": {} + }, + "runtime": { + "bin/placeholder/Fantasy-Net.dll": {} + }, + "frameworkReferences": [ + "Microsoft.AspNetCore.App" + ] + }, + "Fantasy-Net.ConfigTable/2024.2.0": { + "type": "project", + "framework": ".NETCoreApp,Version=v8.0", + "dependencies": { + "Fantasy-Net": "2024.2.22" + }, + "compile": { + "bin/placeholder/Fantasy-Net.ConfigTable.dll": {} + }, + "runtime": { + "bin/placeholder/Fantasy-Net.ConfigTable.dll": {} + } + } + } + }, + "libraries": { + "CommandLineParser/2.9.1": { + "sha512": "OE0sl1/sQ37bjVsPKKtwQlWDgqaxWgtme3xZz7JssWUzg5JpMIyHgCTY9MVMxOg48fJ1AgGT3tgdH5m/kQ5xhA==", + "type": "package", + "path": "commandlineparser/2.9.1", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "CommandLine20.png", + "License.md", + "README.md", + "commandlineparser.2.9.1.nupkg.sha512", + "commandlineparser.nuspec", + "lib/net40/CommandLine.dll", + "lib/net40/CommandLine.xml", + "lib/net45/CommandLine.dll", + "lib/net45/CommandLine.xml", + "lib/net461/CommandLine.dll", + "lib/net461/CommandLine.xml", + "lib/netstandard2.0/CommandLine.dll", + "lib/netstandard2.0/CommandLine.xml" + ] + }, + "DnsClient/1.6.1": { + "sha512": "4H/f2uYJOZ+YObZjpY9ABrKZI+JNw3uizp6oMzTXwDw6F+2qIPhpRl/1t68O/6e98+vqNiYGu+lswmwdYUy3gg==", + "type": "package", + "path": "dnsclient/1.6.1", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "dnsclient.1.6.1.nupkg.sha512", + "dnsclient.nuspec", + "icon.png", + "lib/net45/DnsClient.dll", + "lib/net45/DnsClient.xml", + "lib/net471/DnsClient.dll", + "lib/net471/DnsClient.xml", + "lib/net5.0/DnsClient.dll", + "lib/net5.0/DnsClient.xml", + "lib/netstandard1.3/DnsClient.dll", + "lib/netstandard1.3/DnsClient.xml", + "lib/netstandard2.0/DnsClient.dll", + "lib/netstandard2.0/DnsClient.xml", + "lib/netstandard2.1/DnsClient.dll", + "lib/netstandard2.1/DnsClient.xml" + ] + }, + "Microsoft.Extensions.Logging.Abstractions/2.0.0": { + "sha512": "6ZCllUYGFukkymSTx3Yr0G/ajRxoNJp7/FqSxSB4fGISST54ifBhgu4Nc0ItGi3i6DqwuNd8SUyObmiC++AO2Q==", + "type": "package", + "path": "microsoft.extensions.logging.abstractions/2.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "lib/netstandard2.0/Microsoft.Extensions.Logging.Abstractions.dll", + "lib/netstandard2.0/Microsoft.Extensions.Logging.Abstractions.xml", + "microsoft.extensions.logging.abstractions.2.0.0.nupkg.sha512", + "microsoft.extensions.logging.abstractions.nuspec" + ] + }, + "Microsoft.NETCore.Platforms/5.0.0": { + "sha512": "VyPlqzH2wavqquTcYpkIIAQ6WdenuKoFN0BdYBbCWsclXacSOHNQn66Gt4z5NBqEYW0FAPm5rlvki9ZiCij5xQ==", + "type": "package", + "path": "microsoft.netcore.platforms/5.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "LICENSE.TXT", + "THIRD-PARTY-NOTICES.TXT", + "lib/netstandard1.0/_._", + "microsoft.netcore.platforms.5.0.0.nupkg.sha512", + "microsoft.netcore.platforms.nuspec", + "runtime.json", + "useSharedDesignerContext.txt", + "version.txt" + ] + }, + "Microsoft.Win32.Registry/5.0.0": { + "sha512": "dDoKi0PnDz31yAyETfRntsLArTlVAVzUzCIvvEDsDsucrl33Dl8pIJG06ePTJTI3tGpeyHS9Cq7Foc/s4EeKcg==", + "type": "package", + "path": "microsoft.win32.registry/5.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "LICENSE.TXT", + "THIRD-PARTY-NOTICES.TXT", + "lib/net46/Microsoft.Win32.Registry.dll", + "lib/net461/Microsoft.Win32.Registry.dll", + "lib/net461/Microsoft.Win32.Registry.xml", + "lib/netstandard1.3/Microsoft.Win32.Registry.dll", + "lib/netstandard2.0/Microsoft.Win32.Registry.dll", + "lib/netstandard2.0/Microsoft.Win32.Registry.xml", + "microsoft.win32.registry.5.0.0.nupkg.sha512", + "microsoft.win32.registry.nuspec", + "ref/net46/Microsoft.Win32.Registry.dll", + "ref/net461/Microsoft.Win32.Registry.dll", + "ref/net461/Microsoft.Win32.Registry.xml", + "ref/netstandard1.3/Microsoft.Win32.Registry.dll", + "ref/netstandard1.3/Microsoft.Win32.Registry.xml", + "ref/netstandard1.3/de/Microsoft.Win32.Registry.xml", + "ref/netstandard1.3/es/Microsoft.Win32.Registry.xml", + "ref/netstandard1.3/fr/Microsoft.Win32.Registry.xml", + "ref/netstandard1.3/it/Microsoft.Win32.Registry.xml", + "ref/netstandard1.3/ja/Microsoft.Win32.Registry.xml", + "ref/netstandard1.3/ko/Microsoft.Win32.Registry.xml", + "ref/netstandard1.3/ru/Microsoft.Win32.Registry.xml", + "ref/netstandard1.3/zh-hans/Microsoft.Win32.Registry.xml", + "ref/netstandard1.3/zh-hant/Microsoft.Win32.Registry.xml", + "ref/netstandard2.0/Microsoft.Win32.Registry.dll", + "ref/netstandard2.0/Microsoft.Win32.Registry.xml", + "runtimes/win/lib/net46/Microsoft.Win32.Registry.dll", + "runtimes/win/lib/net461/Microsoft.Win32.Registry.dll", + "runtimes/win/lib/net461/Microsoft.Win32.Registry.xml", + "runtimes/win/lib/netstandard1.3/Microsoft.Win32.Registry.dll", + "runtimes/win/lib/netstandard2.0/Microsoft.Win32.Registry.dll", + "runtimes/win/lib/netstandard2.0/Microsoft.Win32.Registry.xml", + "useSharedDesignerContext.txt", + "version.txt" + ] + }, + "MongoDB.Bson/3.1.0": { + "sha512": "3dhaZhz18B5vUoEP13o2j8A6zQfkHdZhwBvLZEjDJum4BTLLv1/Z8bt25UQEtpqvYwLgde4R6ekWZ7XAYUMxuw==", + "type": "package", + "path": "mongodb.bson/3.1.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "README.md", + "lib/net472/MongoDB.Bson.dll", + "lib/net472/MongoDB.Bson.xml", + "lib/net6.0/MongoDB.Bson.dll", + "lib/net6.0/MongoDB.Bson.xml", + "lib/netstandard2.1/MongoDB.Bson.dll", + "lib/netstandard2.1/MongoDB.Bson.xml", + "mongodb.bson.3.1.0.nupkg.sha512", + "mongodb.bson.nuspec", + "packageIcon.png" + ] + }, + "MongoDB.Driver/3.1.0": { + "sha512": "+O7lKaIl7VUHptE0hqTd7UY1G5KDp/o8S4upG7YL4uChMNKD/U6tz9i17nMGHaD/L2AiPLgaJcaDe2XACsegGA==", + "type": "package", + "path": "mongodb.driver/3.1.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "README.md", + "lib/net472/MongoDB.Driver.dll", + "lib/net472/MongoDB.Driver.xml", + "lib/net6.0/MongoDB.Driver.dll", + "lib/net6.0/MongoDB.Driver.xml", + "lib/netstandard2.1/MongoDB.Driver.dll", + "lib/netstandard2.1/MongoDB.Driver.xml", + "mongodb.driver.3.1.0.nupkg.sha512", + "mongodb.driver.nuspec", + "packageIcon.png" + ] + }, + "Newtonsoft.Json/13.0.3": { + "sha512": "HrC5BXdl00IP9zeV+0Z848QWPAoCr9P3bDEZguI+gkLcBKAOxix/tLEAAHC+UvDNPv4a2d18lOReHMOagPa+zQ==", + "type": "package", + "path": "newtonsoft.json/13.0.3", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "LICENSE.md", + "README.md", + "lib/net20/Newtonsoft.Json.dll", + "lib/net20/Newtonsoft.Json.xml", + "lib/net35/Newtonsoft.Json.dll", + "lib/net35/Newtonsoft.Json.xml", + "lib/net40/Newtonsoft.Json.dll", + "lib/net40/Newtonsoft.Json.xml", + "lib/net45/Newtonsoft.Json.dll", + "lib/net45/Newtonsoft.Json.xml", + "lib/net6.0/Newtonsoft.Json.dll", + "lib/net6.0/Newtonsoft.Json.xml", + "lib/netstandard1.0/Newtonsoft.Json.dll", + "lib/netstandard1.0/Newtonsoft.Json.xml", + "lib/netstandard1.3/Newtonsoft.Json.dll", + "lib/netstandard1.3/Newtonsoft.Json.xml", + "lib/netstandard2.0/Newtonsoft.Json.dll", + "lib/netstandard2.0/Newtonsoft.Json.xml", + "newtonsoft.json.13.0.3.nupkg.sha512", + "newtonsoft.json.nuspec", + "packageIcon.png" + ] + }, + "protobuf-net/3.2.45": { + "sha512": "5UZ/ukUHcGbFSl7vNMrHsfjqdxusdd9w7w0fCEXzf3UUtsrGNVCzV5SmF+sCHAbnRV2qPcD1ixiDP7Aj8lX/HA==", + "type": "package", + "path": "protobuf-net/3.2.45", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "lib/net462/protobuf-net.dll", + "lib/net462/protobuf-net.xml", + "lib/net6.0/protobuf-net.dll", + "lib/net6.0/protobuf-net.xml", + "lib/netstandard2.0/protobuf-net.dll", + "lib/netstandard2.0/protobuf-net.xml", + "lib/netstandard2.1/protobuf-net.dll", + "lib/netstandard2.1/protobuf-net.xml", + "protobuf-net.3.2.45.nupkg.sha512", + "protobuf-net.nuspec", + "protobuf-net.png", + "readme.md" + ] + }, + "protobuf-net.Core/3.2.45": { + "sha512": "PMWatW2NrT1uTXD7etJ4VdQ0wWZLFrIfdRGppD2QX7nzZ0+kIzqhq551u6ZiXJHWJgG4hWFEkSnUnt2aB6posg==", + "type": "package", + "path": "protobuf-net.core/3.2.45", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "lib/net462/protobuf-net.Core.dll", + "lib/net462/protobuf-net.Core.xml", + "lib/net6.0/protobuf-net.Core.dll", + "lib/net6.0/protobuf-net.Core.xml", + "lib/netstandard2.0/protobuf-net.Core.dll", + "lib/netstandard2.0/protobuf-net.Core.xml", + "lib/netstandard2.1/protobuf-net.Core.dll", + "lib/netstandard2.1/protobuf-net.Core.xml", + "protobuf-net.core.3.2.45.nupkg.sha512", + "protobuf-net.core.nuspec", + "protobuf-net.png", + "readme.md" + ] + }, + "SharpCompress/0.30.1": { + "sha512": "XqD4TpfyYGa7QTPzaGlMVbcecKnXy4YmYLDWrU+JIj7IuRNl7DH2END+Ll7ekWIY8o3dAMWLFDE1xdhfIWD1nw==", + "type": "package", + "path": "sharpcompress/0.30.1", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "lib/net461/SharpCompress.dll", + "lib/net5.0/SharpCompress.dll", + "lib/netcoreapp3.1/SharpCompress.dll", + "lib/netstandard2.0/SharpCompress.dll", + "lib/netstandard2.1/SharpCompress.dll", + "sharpcompress.0.30.1.nupkg.sha512", + "sharpcompress.nuspec" + ] + }, + "Snappier/1.0.0": { + "sha512": "rFtK2KEI9hIe8gtx3a0YDXdHOpedIf9wYCEYtBEmtlyiWVX3XlCNV03JrmmAi/Cdfn7dxK+k0sjjcLv4fpHnqA==", + "type": "package", + "path": "snappier/1.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "COPYING.txt", + "lib/net5.0/Snappier.dll", + "lib/net5.0/Snappier.xml", + "lib/netcoreapp3.0/Snappier.dll", + "lib/netcoreapp3.0/Snappier.xml", + "lib/netstandard2.0/Snappier.dll", + "lib/netstandard2.0/Snappier.xml", + "lib/netstandard2.1/Snappier.dll", + "lib/netstandard2.1/Snappier.xml", + "snappier.1.0.0.nupkg.sha512", + "snappier.nuspec" + ] + }, + "System.Buffers/4.5.1": { + "sha512": "Rw7ijyl1qqRS0YQD/WycNst8hUUMgrMH4FCn1nNm27M4VxchZ1js3fVjQaANHO5f3sN4isvP4a+Met9Y4YomAg==", + "type": "package", + "path": "system.buffers/4.5.1", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "LICENSE.TXT", + "THIRD-PARTY-NOTICES.TXT", + "lib/net461/System.Buffers.dll", + "lib/net461/System.Buffers.xml", + "lib/netcoreapp2.0/_._", + "lib/netstandard1.1/System.Buffers.dll", + "lib/netstandard1.1/System.Buffers.xml", + "lib/netstandard2.0/System.Buffers.dll", + "lib/netstandard2.0/System.Buffers.xml", + "lib/uap10.0.16299/_._", + "ref/net45/System.Buffers.dll", + "ref/net45/System.Buffers.xml", + "ref/netcoreapp2.0/_._", + "ref/netstandard1.1/System.Buffers.dll", + "ref/netstandard1.1/System.Buffers.xml", + "ref/netstandard2.0/System.Buffers.dll", + "ref/netstandard2.0/System.Buffers.xml", + "ref/uap10.0.16299/_._", + "system.buffers.4.5.1.nupkg.sha512", + "system.buffers.nuspec", + "useSharedDesignerContext.txt", + "version.txt" + ] + }, + "System.Collections.Immutable/7.0.0": { + "sha512": "dQPcs0U1IKnBdRDBkrCTi1FoajSTBzLcVTpjO4MBCMC7f4pDOIPzgBoX8JjG7X6uZRJ8EBxsi8+DR1JuwjnzOQ==", + "type": "package", + "path": "system.collections.immutable/7.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "LICENSE.TXT", + "README.md", + "THIRD-PARTY-NOTICES.TXT", + "buildTransitive/net461/System.Collections.Immutable.targets", + "buildTransitive/net462/_._", + "buildTransitive/net6.0/_._", + "buildTransitive/netcoreapp2.0/System.Collections.Immutable.targets", + "lib/net462/System.Collections.Immutable.dll", + "lib/net462/System.Collections.Immutable.xml", + "lib/net6.0/System.Collections.Immutable.dll", + "lib/net6.0/System.Collections.Immutable.xml", + "lib/net7.0/System.Collections.Immutable.dll", + "lib/net7.0/System.Collections.Immutable.xml", + "lib/netstandard2.0/System.Collections.Immutable.dll", + "lib/netstandard2.0/System.Collections.Immutable.xml", + "system.collections.immutable.7.0.0.nupkg.sha512", + "system.collections.immutable.nuspec", + "useSharedDesignerContext.txt" + ] + }, + "System.IO.Pipelines/9.0.0": { + "sha512": "eA3cinogwaNB4jdjQHOP3Z3EuyiDII7MT35jgtnsA4vkn0LUrrSHsU0nzHTzFzmaFYeKV7MYyMxOocFzsBHpTw==", + "type": "package", + "path": "system.io.pipelines/9.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "LICENSE.TXT", + "PACKAGE.md", + "THIRD-PARTY-NOTICES.TXT", + "buildTransitive/net461/System.IO.Pipelines.targets", + "buildTransitive/net462/_._", + "buildTransitive/net8.0/_._", + "buildTransitive/netcoreapp2.0/System.IO.Pipelines.targets", + "lib/net462/System.IO.Pipelines.dll", + "lib/net462/System.IO.Pipelines.xml", + "lib/net8.0/System.IO.Pipelines.dll", + "lib/net8.0/System.IO.Pipelines.xml", + "lib/net9.0/System.IO.Pipelines.dll", + "lib/net9.0/System.IO.Pipelines.xml", + "lib/netstandard2.0/System.IO.Pipelines.dll", + "lib/netstandard2.0/System.IO.Pipelines.xml", + "system.io.pipelines.9.0.0.nupkg.sha512", + "system.io.pipelines.nuspec", + "useSharedDesignerContext.txt" + ] + }, + "System.Memory/4.5.5": { + "sha512": "XIWiDvKPXaTveaB7HVganDlOCRoj03l+jrwNvcge/t8vhGYKvqV+dMv6G4SAX2NoNmN0wZfVPTAlFwZcZvVOUw==", + "type": "package", + "path": "system.memory/4.5.5", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "LICENSE.TXT", + "THIRD-PARTY-NOTICES.TXT", + "lib/net461/System.Memory.dll", + "lib/net461/System.Memory.xml", + "lib/netcoreapp2.1/_._", + "lib/netstandard1.1/System.Memory.dll", + "lib/netstandard1.1/System.Memory.xml", + "lib/netstandard2.0/System.Memory.dll", + "lib/netstandard2.0/System.Memory.xml", + "ref/netcoreapp2.1/_._", + "system.memory.4.5.5.nupkg.sha512", + "system.memory.nuspec", + "useSharedDesignerContext.txt", + "version.txt" + ] + }, + "System.Runtime.CompilerServices.Unsafe/5.0.0": { + "sha512": "ZD9TMpsmYJLrxbbmdvhwt9YEgG5WntEnZ/d1eH8JBX9LBp+Ju8BSBhUGbZMNVHHomWo2KVImJhTDl2hIgw/6MA==", + "type": "package", + "path": "system.runtime.compilerservices.unsafe/5.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "LICENSE.TXT", + "THIRD-PARTY-NOTICES.TXT", + "lib/net45/System.Runtime.CompilerServices.Unsafe.dll", + "lib/net45/System.Runtime.CompilerServices.Unsafe.xml", + "lib/netcoreapp2.0/System.Runtime.CompilerServices.Unsafe.dll", + "lib/netcoreapp2.0/System.Runtime.CompilerServices.Unsafe.xml", + "lib/netstandard1.0/System.Runtime.CompilerServices.Unsafe.dll", + "lib/netstandard1.0/System.Runtime.CompilerServices.Unsafe.xml", + "lib/netstandard2.0/System.Runtime.CompilerServices.Unsafe.dll", + "lib/netstandard2.0/System.Runtime.CompilerServices.Unsafe.xml", + "ref/net461/System.Runtime.CompilerServices.Unsafe.dll", + "ref/net461/System.Runtime.CompilerServices.Unsafe.xml", + "ref/netstandard1.0/System.Runtime.CompilerServices.Unsafe.dll", + "ref/netstandard1.0/System.Runtime.CompilerServices.Unsafe.xml", + "ref/netstandard2.0/System.Runtime.CompilerServices.Unsafe.dll", + "ref/netstandard2.0/System.Runtime.CompilerServices.Unsafe.xml", + "ref/netstandard2.1/System.Runtime.CompilerServices.Unsafe.dll", + "ref/netstandard2.1/System.Runtime.CompilerServices.Unsafe.xml", + "system.runtime.compilerservices.unsafe.5.0.0.nupkg.sha512", + "system.runtime.compilerservices.unsafe.nuspec", + "useSharedDesignerContext.txt", + "version.txt" + ] + }, + "System.Security.AccessControl/5.0.0": { + "sha512": "dagJ1mHZO3Ani8GH0PHpPEe/oYO+rVdbQjvjJkBRNQkX4t0r1iaeGn8+/ybkSLEan3/slM0t59SVdHzuHf2jmw==", + "type": "package", + "path": "system.security.accesscontrol/5.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "LICENSE.TXT", + "THIRD-PARTY-NOTICES.TXT", + "lib/net46/System.Security.AccessControl.dll", + "lib/net461/System.Security.AccessControl.dll", + "lib/net461/System.Security.AccessControl.xml", + "lib/netstandard1.3/System.Security.AccessControl.dll", + "lib/netstandard2.0/System.Security.AccessControl.dll", + "lib/netstandard2.0/System.Security.AccessControl.xml", + "lib/uap10.0.16299/_._", + "ref/net46/System.Security.AccessControl.dll", + "ref/net461/System.Security.AccessControl.dll", + "ref/net461/System.Security.AccessControl.xml", + "ref/netstandard1.3/System.Security.AccessControl.dll", + "ref/netstandard1.3/System.Security.AccessControl.xml", + "ref/netstandard1.3/de/System.Security.AccessControl.xml", + "ref/netstandard1.3/es/System.Security.AccessControl.xml", + "ref/netstandard1.3/fr/System.Security.AccessControl.xml", + "ref/netstandard1.3/it/System.Security.AccessControl.xml", + "ref/netstandard1.3/ja/System.Security.AccessControl.xml", + "ref/netstandard1.3/ko/System.Security.AccessControl.xml", + "ref/netstandard1.3/ru/System.Security.AccessControl.xml", + "ref/netstandard1.3/zh-hans/System.Security.AccessControl.xml", + "ref/netstandard1.3/zh-hant/System.Security.AccessControl.xml", + "ref/netstandard2.0/System.Security.AccessControl.dll", + "ref/netstandard2.0/System.Security.AccessControl.xml", + "ref/uap10.0.16299/_._", + "runtimes/win/lib/net46/System.Security.AccessControl.dll", + "runtimes/win/lib/net461/System.Security.AccessControl.dll", + "runtimes/win/lib/net461/System.Security.AccessControl.xml", + "runtimes/win/lib/netcoreapp2.0/System.Security.AccessControl.dll", + "runtimes/win/lib/netcoreapp2.0/System.Security.AccessControl.xml", + "runtimes/win/lib/netstandard1.3/System.Security.AccessControl.dll", + "runtimes/win/lib/uap10.0.16299/_._", + "system.security.accesscontrol.5.0.0.nupkg.sha512", + "system.security.accesscontrol.nuspec", + "useSharedDesignerContext.txt", + "version.txt" + ] + }, + "System.Security.Principal.Windows/5.0.0": { + "sha512": "t0MGLukB5WAVU9bO3MGzvlGnyJPgUlcwerXn1kzBRjwLKixT96XV0Uza41W49gVd8zEMFu9vQEFlv0IOrytICA==", + "type": "package", + "path": "system.security.principal.windows/5.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "LICENSE.TXT", + "THIRD-PARTY-NOTICES.TXT", + "lib/net46/System.Security.Principal.Windows.dll", + "lib/net461/System.Security.Principal.Windows.dll", + "lib/net461/System.Security.Principal.Windows.xml", + "lib/netstandard1.3/System.Security.Principal.Windows.dll", + "lib/netstandard2.0/System.Security.Principal.Windows.dll", + "lib/netstandard2.0/System.Security.Principal.Windows.xml", + "lib/uap10.0.16299/_._", + "ref/net46/System.Security.Principal.Windows.dll", + "ref/net461/System.Security.Principal.Windows.dll", + "ref/net461/System.Security.Principal.Windows.xml", + "ref/netcoreapp3.0/System.Security.Principal.Windows.dll", + "ref/netcoreapp3.0/System.Security.Principal.Windows.xml", + "ref/netstandard1.3/System.Security.Principal.Windows.dll", + "ref/netstandard1.3/System.Security.Principal.Windows.xml", + "ref/netstandard1.3/de/System.Security.Principal.Windows.xml", + "ref/netstandard1.3/es/System.Security.Principal.Windows.xml", + "ref/netstandard1.3/fr/System.Security.Principal.Windows.xml", + "ref/netstandard1.3/it/System.Security.Principal.Windows.xml", + "ref/netstandard1.3/ja/System.Security.Principal.Windows.xml", + "ref/netstandard1.3/ko/System.Security.Principal.Windows.xml", + "ref/netstandard1.3/ru/System.Security.Principal.Windows.xml", + "ref/netstandard1.3/zh-hans/System.Security.Principal.Windows.xml", + "ref/netstandard1.3/zh-hant/System.Security.Principal.Windows.xml", + "ref/netstandard2.0/System.Security.Principal.Windows.dll", + "ref/netstandard2.0/System.Security.Principal.Windows.xml", + "ref/uap10.0.16299/_._", + "runtimes/unix/lib/netcoreapp2.0/System.Security.Principal.Windows.dll", + "runtimes/unix/lib/netcoreapp2.0/System.Security.Principal.Windows.xml", + "runtimes/unix/lib/netcoreapp2.1/System.Security.Principal.Windows.dll", + "runtimes/unix/lib/netcoreapp2.1/System.Security.Principal.Windows.xml", + "runtimes/win/lib/net46/System.Security.Principal.Windows.dll", + "runtimes/win/lib/net461/System.Security.Principal.Windows.dll", + "runtimes/win/lib/net461/System.Security.Principal.Windows.xml", + "runtimes/win/lib/netcoreapp2.0/System.Security.Principal.Windows.dll", + "runtimes/win/lib/netcoreapp2.0/System.Security.Principal.Windows.xml", + "runtimes/win/lib/netcoreapp2.1/System.Security.Principal.Windows.dll", + "runtimes/win/lib/netcoreapp2.1/System.Security.Principal.Windows.xml", + "runtimes/win/lib/netstandard1.3/System.Security.Principal.Windows.dll", + "runtimes/win/lib/uap10.0.16299/_._", + "system.security.principal.windows.5.0.0.nupkg.sha512", + "system.security.principal.windows.nuspec", + "useSharedDesignerContext.txt", + "version.txt" + ] + }, + "ZstdSharp.Port/0.7.3": { + "sha512": "U9Ix4l4cl58Kzz1rJzj5hoVTjmbx1qGMwzAcbv1j/d3NzrFaESIurQyg+ow4mivCgkE3S413y+U9k4WdnEIkRA==", + "type": "package", + "path": "zstdsharp.port/0.7.3", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "lib/net461/ZstdSharp.dll", + "lib/net5.0/ZstdSharp.dll", + "lib/net6.0/ZstdSharp.dll", + "lib/net7.0/ZstdSharp.dll", + "lib/netcoreapp3.1/ZstdSharp.dll", + "lib/netstandard2.0/ZstdSharp.dll", + "lib/netstandard2.1/ZstdSharp.dll", + "zstdsharp.port.0.7.3.nupkg.sha512", + "zstdsharp.port.nuspec" + ] + }, + "Fantasy-Net/2024.2.24": { + "type": "project", + "path": "../../Packages/Fantasy/Fantasy.Net/Fantasy.Net/Fantasy.Net.csproj", + "msbuildProject": "../../Packages/Fantasy/Fantasy.Net/Fantasy.Net/Fantasy.Net.csproj" + }, + "Fantasy-Net.ConfigTable/2024.2.0": { + "type": "project", + "path": "../../Packages/Fantasy/Fantasy.Packages/Fantasy.ConfigTable/Net/Fantasy.ConfigTable.csproj", + "msbuildProject": "../../Packages/Fantasy/Fantasy.Packages/Fantasy.ConfigTable/Net/Fantasy.ConfigTable.csproj" + } + }, + "projectFileDependencyGroups": { + "net8.0": [ + "Fantasy-Net >= 2024.2.24", + "Fantasy-Net.ConfigTable >= 2024.2.0" + ] + }, + "packageFolders": { + "/Users/fantasy/.nuget/packages/": {} + }, + "project": { + "version": "1.0.0", + "restore": { + "projectUniqueName": "/Users/fantasy/Movies/物品背包开发之旅/B/Server/Entity/Entity.csproj", + "projectName": "Entity", + "projectPath": "/Users/fantasy/Movies/物品背包开发之旅/B/Server/Entity/Entity.csproj", + "packagesPath": "/Users/fantasy/.nuget/packages/", + "outputPath": "/Users/fantasy/Movies/物品背包开发之旅/B/Server/Entity/obj/", + "projectStyle": "PackageReference", + "configFilePaths": [ + "/Users/fantasy/.nuget/NuGet/NuGet.Config" + ], + "originalTargetFrameworks": [ + "net8.0" + ], + "sources": { + "/usr/local/share/dotnet/library-packs": {}, + "https://api.nuget.org/v3/index.json": {} + }, + "frameworks": { + "net8.0": { + "targetAlias": "net8.0", + "projectReferences": { + "/Users/fantasy/Movies/物品背包开发之旅/B/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Fantasy.Net.csproj": { + "projectPath": "/Users/fantasy/Movies/物品背包开发之旅/B/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Fantasy.Net.csproj" + }, + "/Users/fantasy/Movies/物品背包开发之旅/B/Packages/Fantasy/Fantasy.Packages/Fantasy.ConfigTable/Net/Fantasy.ConfigTable.csproj": { + "projectPath": "/Users/fantasy/Movies/物品背包开发之旅/B/Packages/Fantasy/Fantasy.Packages/Fantasy.ConfigTable/Net/Fantasy.ConfigTable.csproj" + } + } + } + }, + "warningProperties": { + "warnAsError": [ + "NU1605" + ] + }, + "restoreAuditProperties": { + "enableAudit": "true", + "auditLevel": "low", + "auditMode": "all" + }, + "SdkAnalysisLevel": "9.0.100" + }, + "frameworks": { + "net8.0": { + "targetAlias": "net8.0", + "imports": [ + "net461", + "net462", + "net47", + "net471", + "net472", + "net48", + "net481" + ], + "assetTargetFallback": true, + "warn": true, + "frameworkReferences": { + "Microsoft.NETCore.App": { + "privateAssets": "all" + } + }, + "runtimeIdentifierGraphPath": "/usr/local/share/dotnet/sdk/9.0.100/PortableRuntimeIdentifierGraph.json" + } + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Server/Entity/obj/project.nuget.cache b/物品和背包的完整代码/Server/Entity/obj/project.nuget.cache new file mode 100644 index 0000000..dbe47bc --- /dev/null +++ b/物品和背包的完整代码/Server/Entity/obj/project.nuget.cache @@ -0,0 +1,30 @@ +{ + "version": 2, + "dgSpecHash": "3mbwUg3kjU0=", + "success": true, + "projectFilePath": "/Users/fantasy/Movies/物品背包开发之旅/B/Server/Entity/Entity.csproj", + "expectedPackageFiles": [ + "/Users/fantasy/.nuget/packages/commandlineparser/2.9.1/commandlineparser.2.9.1.nupkg.sha512", + "/Users/fantasy/.nuget/packages/dnsclient/1.6.1/dnsclient.1.6.1.nupkg.sha512", + "/Users/fantasy/.nuget/packages/microsoft.extensions.logging.abstractions/2.0.0/microsoft.extensions.logging.abstractions.2.0.0.nupkg.sha512", + "/Users/fantasy/.nuget/packages/microsoft.netcore.platforms/5.0.0/microsoft.netcore.platforms.5.0.0.nupkg.sha512", + "/Users/fantasy/.nuget/packages/microsoft.win32.registry/5.0.0/microsoft.win32.registry.5.0.0.nupkg.sha512", + "/Users/fantasy/.nuget/packages/mongodb.bson/3.1.0/mongodb.bson.3.1.0.nupkg.sha512", + "/Users/fantasy/.nuget/packages/mongodb.driver/3.1.0/mongodb.driver.3.1.0.nupkg.sha512", + "/Users/fantasy/.nuget/packages/newtonsoft.json/13.0.3/newtonsoft.json.13.0.3.nupkg.sha512", + "/Users/fantasy/.nuget/packages/protobuf-net/3.2.45/protobuf-net.3.2.45.nupkg.sha512", + "/Users/fantasy/.nuget/packages/protobuf-net.core/3.2.45/protobuf-net.core.3.2.45.nupkg.sha512", + "/Users/fantasy/.nuget/packages/sharpcompress/0.30.1/sharpcompress.0.30.1.nupkg.sha512", + "/Users/fantasy/.nuget/packages/snappier/1.0.0/snappier.1.0.0.nupkg.sha512", + "/Users/fantasy/.nuget/packages/system.buffers/4.5.1/system.buffers.4.5.1.nupkg.sha512", + "/Users/fantasy/.nuget/packages/system.collections.immutable/7.0.0/system.collections.immutable.7.0.0.nupkg.sha512", + "/Users/fantasy/.nuget/packages/system.io.pipelines/9.0.0/system.io.pipelines.9.0.0.nupkg.sha512", + "/Users/fantasy/.nuget/packages/system.memory/4.5.5/system.memory.4.5.5.nupkg.sha512", + "/Users/fantasy/.nuget/packages/system.runtime.compilerservices.unsafe/5.0.0/system.runtime.compilerservices.unsafe.5.0.0.nupkg.sha512", + "/Users/fantasy/.nuget/packages/system.security.accesscontrol/5.0.0/system.security.accesscontrol.5.0.0.nupkg.sha512", + "/Users/fantasy/.nuget/packages/system.security.principal.windows/5.0.0/system.security.principal.windows.5.0.0.nupkg.sha512", + "/Users/fantasy/.nuget/packages/zstdsharp.port/0.7.3/zstdsharp.port.0.7.3.nupkg.sha512", + "/Users/fantasy/.nuget/packages/fantasy-net/2024.2.24/fantasy-net.2024.2.24.nupkg.sha512" + ], + "logs": [] +} \ No newline at end of file diff --git a/物品和背包的完整代码/Server/Entity/obj/project.packagespec.json b/物品和背包的完整代码/Server/Entity/obj/project.packagespec.json new file mode 100644 index 0000000..983c2ab --- /dev/null +++ b/物品和背包的完整代码/Server/Entity/obj/project.packagespec.json @@ -0,0 +1 @@ +"restore":{"projectUniqueName":"/Users/fantasy/Movies/物品背包开发之旅/B/Server/Entity/Entity.csproj","projectName":"Entity","projectPath":"/Users/fantasy/Movies/物品背包开发之旅/B/Server/Entity/Entity.csproj","outputPath":"/Users/fantasy/Movies/物品背包开发之旅/B/Server/Entity/obj/","projectStyle":"PackageReference","originalTargetFrameworks":["net8.0"],"sources":{"/usr/local/share/dotnet/library-packs":{},"https://api.nuget.org/v3/index.json":{}},"frameworks":{"net8.0":{"targetAlias":"net8.0","projectReferences":{"/Users/fantasy/Movies/物品背包开发之旅/B/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Fantasy.Net.csproj":{"projectPath":"/Users/fantasy/Movies/物品背包开发之旅/B/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Fantasy.Net.csproj"},"/Users/fantasy/Movies/物品背包开发之旅/B/Packages/Fantasy/Fantasy.Packages/Fantasy.ConfigTable/Net/Fantasy.ConfigTable.csproj":{"projectPath":"/Users/fantasy/Movies/物品背包开发之旅/B/Packages/Fantasy/Fantasy.Packages/Fantasy.ConfigTable/Net/Fantasy.ConfigTable.csproj"}}}},"warningProperties":{"warnAsError":["NU1605"]},"restoreAuditProperties":{"enableAudit":"true","auditLevel":"low","auditMode":"all"},"SdkAnalysisLevel":"9.0.100"}"frameworks":{"net8.0":{"targetAlias":"net8.0","imports":["net461","net462","net47","net471","net472","net48","net481"],"assetTargetFallback":true,"warn":true,"frameworkReferences":{"Microsoft.NETCore.App":{"privateAssets":"all"}},"runtimeIdentifierGraphPath":"/usr/local/share/dotnet/sdk/9.0.100/PortableRuntimeIdentifierGraph.json"}} \ No newline at end of file diff --git a/物品和背包的完整代码/Server/Entity/obj/rider.project.model.nuget.info b/物品和背包的完整代码/Server/Entity/obj/rider.project.model.nuget.info new file mode 100644 index 0000000..4eb4dc8 --- /dev/null +++ b/物品和背包的完整代码/Server/Entity/obj/rider.project.model.nuget.info @@ -0,0 +1 @@ +17428701567253007 \ No newline at end of file diff --git a/物品和背包的完整代码/Server/Entity/obj/rider.project.restore.info b/物品和背包的完整代码/Server/Entity/obj/rider.project.restore.info new file mode 100644 index 0000000..4eb4dc8 --- /dev/null +++ b/物品和背包的完整代码/Server/Entity/obj/rider.project.restore.info @@ -0,0 +1 @@ +17428701567253007 \ No newline at end of file diff --git a/物品和背包的完整代码/Server/Hotfix/Gate/Components/BagComponentSystem.cs b/物品和背包的完整代码/Server/Hotfix/Gate/Components/BagComponentSystem.cs new file mode 100644 index 0000000..a26a92a --- /dev/null +++ b/物品和背包的完整代码/Server/Hotfix/Gate/Components/BagComponentSystem.cs @@ -0,0 +1,16 @@ +namespace Fantasy; + +public static class BagComponentSystem +{ + public static uint AddItem(this BagComponent self, Item item) + { + self.Items.Add(item.Id, item); + Log.Debug($"add item:{item.Id}"); + return 0; + } + + public static bool TryGetItem(this BagComponent self, long itemId, out Item item) + { + return self.Items.TryGetValue(itemId, out item); + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Server/Hotfix/Gate/Components/ItemUseComponentSystem.cs b/物品和背包的完整代码/Server/Hotfix/Gate/Components/ItemUseComponentSystem.cs new file mode 100644 index 0000000..1884df5 --- /dev/null +++ b/物品和背包的完整代码/Server/Hotfix/Gate/Components/ItemUseComponentSystem.cs @@ -0,0 +1,58 @@ +// using Fantasy.Entitas.Interface; +// +// namespace Fantasy; +// +// public sealed class ItemUseComponentDestroySystem : DestroySystem +// { +// protected override void Destroy(ItemUseComponent self) +// { +// self.Dispose(); +// self.Handlers.Clear(); +// } +// } +// +// public static class ItemUseComponentSystem +// { +// public static void Init(this ItemUseComponent self) +// { +// self.Handlers.Add((int)ItemType.Drug, new ItemUse_Drug()); +// self.Handlers.Add((int)ItemType.Equip , new ItemUse_Equip()); +// } +// +// public static uint CanUse(this ItemUseComponent self, Account account, ItemConfig config, ref int count) +// { +// if (!self.Handlers.TryGetValue((int)config.Type, out var handler)) +// { +// return 0; +// } +// +// return handler.CanUse(account, config, ref count); +// } +// +// public static void Use(this ItemUseComponent self, Account account, ItemConfig config, ref int count) +// { +// if (!self.Handlers.TryGetValue((int)config.Type, out var handler)) +// { +// return; +// } +// +// handler.Use(account, config, ref count); +// } +// +// public static uint UseHandler(this ItemUseComponent self, Account account, ItemConfig config, ref int count) +// { +// if (!self.Handlers.TryGetValue((int)config.Type, out var handler)) +// { +// return 0; +// } +// +// var canUse = handler.CanUse(account, config, ref count); +// if (canUse != 0) +// { +// return canUse; +// } +// +// handler.CanUse(account, config, ref count); +// return 0; +// } +// } \ No newline at end of file diff --git a/物品和背包的完整代码/Server/Hotfix/Gate/Container/ContainerComponentSystem.cs b/物品和背包的完整代码/Server/Hotfix/Gate/Container/ContainerComponentSystem.cs new file mode 100644 index 0000000..ec38e8b --- /dev/null +++ b/物品和背包的完整代码/Server/Hotfix/Gate/Container/ContainerComponentSystem.cs @@ -0,0 +1,82 @@ +using Fantasy.Entitas.Interface; +// ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract + +namespace Fantasy; + +public sealed class ContainerComponentDestroySystem : DestroySystem +{ + protected override void Destroy(ContainerComponent self) + { + foreach (var (_, container) in self.Containers) + { + container.Dispose(); + } + + self.Containers.Clear(); + } +} + +public sealed class ContainerComponentDeserializeSystem : DeserializeSystem +{ + protected override void Deserialize(ContainerComponent self) + { + var account = self.GetParent(); + foreach (var (key, container) in self.Containers) + { + container.Deserialize(self.Scene); + container.Account = account; + } + } +} + +public sealed class ContainerComponentAwakeSystem : AwakeSystem +{ + protected override void Awake(ContainerComponent self) + { + var account = self.GetParent(); + var unitConfig = account.UnitConfig; + // 根据角色的配置文件创建容器。 + foreach (var containerConfigId in unitConfig.MountContainer) + { + if (!ContainerConfigData.Instance.TryGet(containerConfigId, out var containerConfig)) + { + Log.Error($"containerConfigId : {containerConfigId} not found"); + return; + } + + ContainerHelper.Create(account, (ContainerType)containerConfig.Type); + } + // 创建初始化物品到容器中。 + var unitConfigItems = unitConfig.Items; + for (var itemArgs = 0; itemArgs < unitConfigItems.Length; itemArgs += 3) + { + try + { + var containerType = unitConfigItems[itemArgs]; + var itemConfigId = unitConfigItems[itemArgs + 1]; + var itemCount = (int)unitConfigItems[itemArgs + 2]; + var item = ItemFactory.Create(self.Scene, itemConfigId, itemCount, true); + if (item == null) + { + // 这里创建物品失败,可以选择跳过这个物品,继续下一个创建。 + // 也可以直接停止全部的物品创建。 + continue; + } + // 添加物品到容器中。 + var addItemErrorCode = ContainerHelper.AddItem(account, (ContainerType)containerType, item, ItemReason.ContainerAdd, false); + if (addItemErrorCode != 0) + { + Log.Error($"cant add item to container errorCode:{addItemErrorCode}"); + continue; + } + } + catch + { + Log.Error($"unitConfig :{unitConfig.Id} items参数不正确,要求是3个一组。"); + // 你可以选择如果有一个出错了,跳过、继续下一个创建。 + // 你还可以选择如果出错了,直接终止跳出。 + break; + } + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Server/Hotfix/Gate/Container/ContainerHelper.cs b/物品和背包的完整代码/Server/Hotfix/Gate/Container/ContainerHelper.cs new file mode 100644 index 0000000..e992f50 --- /dev/null +++ b/物品和背包的完整代码/Server/Hotfix/Gate/Container/ContainerHelper.cs @@ -0,0 +1,291 @@ +// ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract + +using Fantasy.Entitas; +using Fantasy.Network; + +#pragma warning disable CS8601 // Possible null reference assignment. +#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. + +#pragma warning disable CS8603 // Possible null reference return. +namespace Fantasy; + +public static class ContainerHelper +{ + #region Container + + public static Container Create(Account account, ContainerType containerType) + { + if (!ContainerConfigData.Instance.TryGetConfig(containerType, out var containerConfig)) + { + return null; + } + + var containerComponent = account.GetComponent(); + + if (containerComponent == null) + { + Log.Error($"account {account.Id} not found ContainerComponent!"); + return null; + } + + var containerTypeInt = (int)containerType; + + if (containerComponent.Containers.ContainsKey(containerTypeInt)) + { + Log.Error($"account {account.Id} containerType {containerType} already exists!"); + return null; + } + + var container = Entity.Create(account.Scene, true, true); + container.ConfigId = containerConfig.Id; + container.Account = account; + container.CurrentCellCount = 0; + containerComponent.Containers.Add(containerTypeInt, container); + return container; + } + + public static uint TryGetContainer(Account account, ContainerType containerType, out Container container) + { + container = null; + var containerComponent = account.GetComponent(); + + if (containerComponent == null) + { + // 没有找到容器组件的错误码。 + return 1; + } + + if (!containerComponent.Containers.TryGetValue((int)containerType, out container)) + { + // 在容器组件中没有找到该容器的错误码。 + return 2; + } + + return 0; + } + + #endregion + + #region GetItem + + public static bool GetItemById(Account account, ContainerType containerType, long id, out Item item) + { + if (TryGetContainer(account, containerType, out var container) != 0) + { + item = null; + return false; + } + + return container.GetItemById(id, out item); + } + + public static bool GetItemByCell(Account account, ContainerType containerType, long cell, out Item item) + { + if (TryGetContainer(account, containerType, out var container) != 0) + { + item = null; + return false; + } + + return container.GetItemByCell(cell, out item); + } + + public static void GetItemsByConfigId(Account account, ContainerType containerType, uint configId, List items) + { + if (TryGetContainer(account, containerType, out var container) != 0) + { + return; + } + + container.GetItemsByConfigId(configId, items); + } + + public static void GetItemsByType(Account account, ContainerType containerType, ItemType itemType, List items) + { + if (TryGetContainer(account, containerType, out var container) != 0) + { + return; + } + + container.GetItemsByType(itemType, items); + } + + public static bool IsFull(Account account, ContainerType containerType) + { + if (TryGetContainer(account, containerType, out var container) != 0) + { + // 这里的可以返回False,因为容器组件中可能这个容器。 + // 但是也可以返回true,是因为这个函数的语义是判断容器已满,如果找不到容器,也可以认为是满的。 + return true; + } + + return container.IsFull(); + } + + public static int GetItemCount(Account account, ContainerType containerType, uint configId) + { + if (TryGetContainer(account, containerType, out var container) != 0) + { + return 0; + } + + return container.GetItemCount(configId); + } + + #endregion + + #region AddItem + + public static uint AddItem(Account account, ContainerType containerType, Item item, ItemReason itemReason, bool isSendClient) + { + var tryGetContainer = TryGetContainer(account, containerType, out var container); + + if (tryGetContainer != 0) + { + return tryGetContainer; + } + + return container.AddItem(item, itemReason, isSendClient); + } + + public static uint AddItem(Account account, ContainerType containerType, Item item, long cellId, ItemReason itemReason, bool isSendClient) + { + var tryGetContainer = TryGetContainer(account, containerType, out var container); + + if (tryGetContainer != 0) + { + return tryGetContainer; + } + + return container.AddItem(item, cellId, itemReason, isSendClient); + } + + #endregion + + #region SplitItem + + public static uint SplitItem(Account account, ContainerType containerType, long itemId, int count, out Item splitItem) + { + var tryGetContainer = TryGetContainer(account, containerType, out var container); + + if (tryGetContainer != 0) + { + splitItem = null; + return tryGetContainer; + } + + return container.SplitItem(itemId, count, out splitItem); + } + + #endregion + + #region RemoveItem + + public static uint RemoveItem(Account account, ContainerType containerType, long itemId, ItemReason itemReason, bool isSendClient, bool isDispose = true) + { + var tryGetContainer = TryGetContainer(account, containerType, out var container); + + if (tryGetContainer != 0) + { + return tryGetContainer; + } + + return container.RemoveItem(itemId, itemReason, isSendClient, isDispose); + } + + public static uint RemoveItem(Account account, ContainerType containerType, long itemId, int count, ItemReason itemReason, bool isSendClient, bool isDispose = true) + { + var tryGetContainer = TryGetContainer(account, containerType, out var container); + + if (tryGetContainer != 0) + { + return tryGetContainer; + } + + return container.RemoveItem(itemId, count, itemReason, isSendClient, isDispose); + } + + public static uint RemoveItemByCell(Account account, ContainerType containerType, long cellId, ItemReason itemReason, bool isSendClient, bool isDispose = true) + { + var tryGetContainer = TryGetContainer(account, containerType, out var container); + + if (tryGetContainer != 0) + { + return tryGetContainer; + } + + return container.RemoveItemByCell(cellId, itemReason, isSendClient, isDispose); + } + + #endregion + + #region Sort + + public static void Sort(Account account, ContainerType containerType) + { + if (TryGetContainer(account, containerType, out var container) != 0) + { + return; + } + + container.Sort(); + } + + #endregion + + #region ToProto + + public static bool TryGetContainerInfo(Account account, ContainerType containerType, out ContainerInfo containerInfo) + { + var tryGetContainer = TryGetContainer(account, containerType, out var container); + + if (tryGetContainer != 0) + { + containerInfo = null; + return false; + } + + containerInfo = container.ToContainerInfo(); + return true; + } + + public static void SendAllContainerInfo(Account account) + { + var containerComponent = account.GetComponent(); + + if (containerComponent == null) + { + Log.Error($"account {account.Id} not found ContainerComponent!"); + return; + } + + var g2CPushAllContainerInfo = new G2C_PushAllContainerInfo(); + foreach (var (_, container) in containerComponent.Containers) + { + g2CPushAllContainerInfo.Containers.Add(container.ToContainerInfo()); + } + // 推送容器数据给客户端 + account.Session.Send(g2CPushAllContainerInfo); + } + + // public static void SendAllContainerInfo(Account account) + // { + // var containerComponent = account.GetComponent(); + // + // if (containerComponent == null) + // { + // Log.Error($"account {account.Id} not found ContainerComponent!"); + // return; + // } + // + // foreach (var (_, container) in containerComponent.Containers) + // { + // account.Session.Send(new G2C_PushContainerInfo() + // { + // Container = container.ToContainerInfo() + // }); + // } + // } + + #endregion +} \ No newline at end of file diff --git a/物品和背包的完整代码/Server/Hotfix/Gate/Container/ContainerSystem.cs b/物品和背包的完整代码/Server/Hotfix/Gate/Container/ContainerSystem.cs new file mode 100644 index 0000000..9dd4bb3 --- /dev/null +++ b/物品和背包的完整代码/Server/Hotfix/Gate/Container/ContainerSystem.cs @@ -0,0 +1,470 @@ +using Fantasy.DataStructure.Collection; +using Fantasy.Entitas.Interface; +using Fantasy.Helper; +using Fantasy.Network; +using Fantasy.Network.Interface; + +#pragma warning disable CS8602 // Dereference of a possibly null reference. +#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. +#pragma warning disable CS8601 // Possible null reference assignment. + +namespace Fantasy; + +public sealed class ContainerDestroySystem : DestroySystem +{ + protected override void Destroy(Container self) + { + self.Account = null; + self.ConfigId = 0; + self.CurrentCellCount = 0; + + foreach (var (_, item) in self.Items) + { + item.Dispose(); + } + + self.Items.Clear(); + self.ItemsByCell.Clear(); + self.ItemsByConfigId.Clear(); + self.ItemsByType.Clear(); + } +} + +public sealed class ContainerDeserializeSystem : DeserializeSystem +{ + protected override void Deserialize(Container self) + { + foreach (var (_, item) in self.Items) + { + item.Deserialize(self.Scene); + item.Container = self; + + if (item.CellId > 0) + { + self.ItemsByCell.Add(item.CellId, item); + } + + self.ItemsByConfigId.Add(item.ConfigId, item); + self.ItemsByType.Add(item.Config.Type, item); + } + } +} + +public static class ContainerSystem +{ + #region Get + + public static bool GetItemById(this Container self, long id, out Item item) + { + return self.Items.TryGetValue(id, out item); + } + + public static bool GetItemByCell(this Container self, long cell, out Item item) + { + return self.ItemsByCell.TryGetValue(cell, out item); + } + + public static void GetItemsByConfigId(this Container self, uint configId, List items) + { + if (!self.ItemsByConfigId.TryGetValue(configId, out var itemList)) + { + return; + } + + items.AddRange(itemList); + } + + public static void GetItemsByType(this Container self, ItemType itemType, List items) + { + if (!self.ItemsByType.TryGetValue((uint)itemType, out var itemList)) + { + return; + } + + items.AddRange(itemList); + } + + public static bool IsFull(this Container self) + { + return self.CurrentCellCount >= self.Config.CellCount; + } + + public static int GetItemCount(this Container self, uint configId) + { + if (!self.ItemsByConfigId.TryGetValue(configId, out var itemList)) + { + return 0; + } + + var count = 0; + foreach (var item in itemList) + { + count += item.Count; + } + // return itemList.Sum(x => x.Count); + return count; + } + + #endregion + + #region Add + + public static uint AddItem(this Container self, Item item, ItemReason itemReason, bool isSendClient) + { + var containerConfig = self.Config; + if (!ContainerType.Normal.HasFlag((ContainerType)containerConfig.Type)) + { + Log.Error($"{self.GetType().Name} is not normal container"); + return 1; + } + + var count = item.Count; + var itemConfig = item.Config; + var g2CUpdateItems = new G2C_UpdateItems(); + g2CUpdateItems.ItemReason = (int)itemReason; + if (itemConfig.Superposed) + { + var superposedMax = (int)itemConfig.SuperposedMax; + if (self.ItemsByConfigId.TryGetValue(itemConfig.Id, out var itemList)) + { + var availableCount = superposedMax * itemList.Count; + // 计算当前物品可以叠加的数量 + foreach (var haveItem in itemList) + { + availableCount -= haveItem.Count; + } + // 检查当前容器中是否还有空位。 + if (item.Count > availableCount && self.IsFull()) + { + // 当前背包已满,无法添加该物品的错误码。 + // 无法叠加的数量大于物品的数量,那就表示当前物品不可以叠加到其他物品中了。 + return 2; + } + foreach (var haveItem in itemList) + { + var haveItemCount = superposedMax - haveItem.Count; + // 如果当前物品叠加数量已经满了,那就直接找下一个同配置Id的物品。 + if (haveItemCount <= 0) + { + continue; + } + + if (item.Count > haveItemCount) + { + // 如果添加的物品数量大于当前物品的可叠加数量,那就把可叠加的数量减去。 + item.Count -= haveItemCount; + } + else + { + // 如果添加的物品数量小于当前物品的可叠加数量,那就表示当前物品可以把添加物品的全部叠加到当前物品中了。 + // 这样的话,只需要记录下添加物品的数量就可以了 + haveItemCount = item.Count; + item.Count = 0; + } + + haveItem.Count += haveItemCount; + g2CUpdateItems.Items.Add(haveItem.ToItemInfo()); + if (item.Count <= 0) + { + break; + } + } + } + } + else + { + if (self.IsFull()) + { + // 当前背包已满,无法添加该物品的错误码。 + return 2; + } + } + + if (item.Count <= 0) + { + item.Dispose(); + } + else + { + item.Container = self; + self.CurrentCellCount++; + self.Items.Add(item.Id, item); + self.ItemsByType.Add(itemConfig.Type, item); + self.ItemsByConfigId.Add(itemConfig.Id, item); + g2CUpdateItems.Items.Add(item.ToItemInfo()); + } + + if (isSendClient) + { + self.SendClient(g2CUpdateItems); + } + + Log.Debug($"AddItem itemReason:{itemReason} itemConfigId:{itemConfig.Id} Count:{count}"); + return 0; + } + + public static uint AddItem(this Container self, Item item, long cellId, ItemReason itemReason, bool isSendClient) + { + var containerConfig = self.Config; + if (!ContainerType.Cell.HasFlag((ContainerType)containerConfig.Type)) + { + Log.Error($"{self.GetType().Name} is not cell container"); + return 1; + } + + if (self.IsFull()) + { + // 当前背包已满,无法添加该物品的错误码。 + return 2; + } + + if (self.ItemsByCell.ContainsKey(cellId)) + { + // 该Cell已经存在物品了。 + return 3; + } + + var g2CUpdateItems = new G2C_UpdateItems(); + g2CUpdateItems.ItemReason = (int)itemReason; + + var itemConfig = item.Config; + var count = item.Count; + item.CellId = cellId; + item.Container = self; + self.CurrentCellCount++; + + self.Items.Add(item.Id, item); + self.ItemsByCell.Add(cellId, item); + self.ItemsByType.Add(itemConfig.Type, item); + self.ItemsByConfigId.Add(item.ConfigId, item); + + g2CUpdateItems.Items.Add(item.ToItemInfo()); + + if (isSendClient) + { + self.SendClient(g2CUpdateItems); + } + Log.Debug($"AddItem itemReason:{itemReason} itemConfigId:{itemConfig.Id} Count:{count}"); + return 0; + } + + #endregion + + #region Split + + public static uint SplitItem(this Container self, long itemId, int count, out Item splitItem) + { + splitItem = null; + + if (count <= 0) + { + // 要拆分的道具数量不可以小于等于0的错误码。 + return 2; + } + + if (self.Items.TryGetValue(itemId, out var item)) + { + // 没有找到物品的错误码。 + return 1; + } + + if (item.Count == count) + { + // 要拆分的物品数量不可以和物品的数量相同的错误码。 + return 3; + } + + if (item.Count < count) + { + // 要拆分的物品数量不可以大于物品的数量的错误码。 + return 4; + } + + item.Count -= count; + splitItem = ItemFactory.Create(self.Scene, item.ConfigId, count, item.IsBind); + return 0; + } + + #endregion + + #region Remove + + public static uint RemoveItem(this Container self, Item item, ItemReason itemReason, bool isSendClient, bool isDispose = true) + { + var count = item.Count; + var itemConfig = item.Config; + self.Items.Remove(item.Id); + self.ItemsByConfigId.RemoveValue(item.ConfigId,item); + self.ItemsByType.RemoveValue(itemConfig.Type, item); + var containerConfig = self.Config; + if (ContainerType.Cell.HasFlag((ContainerType)containerConfig.Type)) + { + self.ItemsByCell.Remove(item.CellId); + } + + var g2CUpdateItems = new G2C_UpdateItems(); + g2CUpdateItems.ItemReason = (int)itemReason; + g2CUpdateItems.Items.Add(item.ToItemInfo()); + + if (isDispose) + { + item.Dispose(); + } + + self.CurrentCellCount--; + + if (isSendClient) + { + self.SendClient(g2CUpdateItems); + } + Log.Debug($"RemoveItem itemReason:{itemReason} itemConfigId:{itemConfig.Id} Count:{count}"); + return 0; + } + + public static uint RemoveItem(this Container self, long itemId, ItemReason itemReason, bool isSendClient, bool isDispose = true) + { + if (!self.Items.TryGetValue(itemId, out var item)) + { + // 移除的时候,容器里找不到该物品的错误码。 + return 1; + } + + return self.RemoveItem(item, itemReason, isSendClient, isDispose); + } + + public static uint RemoveItem(this Container self, long itemId, int count, ItemReason itemReason, bool isSendClient, bool isDispose = true) + { + if (!self.Items.TryGetValue(itemId, out var item)) + { + // 移除的时候,容器里找不到该物品的错误码。 + return 1; + } + + if (item.Count < count) + { + // 要移除的物品数量不足的错误码。 + return 2; + } + + if (count < 1) + { + // 要移除物品的数量不能小于1的错误码。 + return 3; + } + + item.Count -= count; + + if (item.Count <= 0) + { + return self.RemoveItem(item, itemReason, isSendClient, isDispose); + } + else + { + if (isSendClient) + { + var g2CUpdateItems = new G2C_UpdateItems(); + g2CUpdateItems.ItemReason = (int)itemReason; + g2CUpdateItems.Items.Add(item.ToItemInfo()); + self.SendClient(g2CUpdateItems); + } + Log.Debug($"RemoveItem itemReason:{itemReason} itemConfigId:{item.ConfigId} Count:{count}"); + } + + return 0; + } + + public static uint RemoveItemByCell(this Container self, long cellId, ItemReason itemReason, bool isSendClient, bool isDispose = true) + { + if (!self.ItemsByCell.TryGetValue(cellId, out var item)) + { + // 移除的时候,容器里找不到该物品的错误码。 + return 1; + } + + return self.RemoveItem(item, itemReason, isSendClient, isDispose); + } + + #endregion + + #region Sort + + public static void Sort(this Container self) + { + // 这里排序一般服务器不会排序,也可以说是很少用排序. + // 一般都是让客户端做好这个排序。 + // 如果用服务器排序会出现如下几种情况: + // 1、排序好了后,要下发给客户端,很有可能会把当前容器里的所有物品全部下发给客户端。 + // 2、如果频繁排序的话,服务器的压力就会很大。 + // 3、因为移动端很少有那种格子空一个然后再有物品的情况,所以可以不用考虑空格子的情况。 + // 如果是PC端,需要格子有空位的,这时候服务器可以考虑排序了。 + using (var list = ListPool.Create()) + { + list.AddRange(self.Items.Values); + list.Sort(SortCompare); + self.Items.Clear(); + for (var i = 0; i < list.Count; i++) + { + var item = list[i]; + self.Items.Add(item.Id,item); + } + } + } + + private static int SortCompare(Item a, Item b) + { + // 升序排列(从小到大) + // 3 1 2 排序后就是1 2 3 + // < 0 那就是a 在 b 的前面 + // = 0 那就是a 和 b 相等,顺序不变 + // > 0 那就 a 在 b 的后面 + var aConfig = a.Config; + var bConfig = b.Config; + var aWeight = aConfig.Weight; + var bWeight = bConfig.Weight; + // 这里还可以增加一些自定义的逻辑 + // 比如:按照物品创建时间、是否绑定、出售价格等等。 + // 这里的话就按照需求自己扩展把。 + if (a.IsBind != b.IsBind) + { + // 比如这里要做一个需求是绑定的排在前面. + return a.IsBind ? -1 : 1; + } + if (aWeight == bWeight) + { + return 0; + } + + if (aWeight > bWeight) + { + return -1; + } + return 1; + } + + #endregion + + #region ToProto + + public static ContainerInfo ToContainerInfo(this Container self) + { + var containerInfo = new ContainerInfo() + { + ConfigId = (int)self.ConfigId, + CurrentCellCount = self.CurrentCellCount + }; + + foreach (var (_, item) in self.Items) + { + containerInfo.Items.Add(item.ToItemInfo()); + } + + return containerInfo; + } + + #endregion + + private static void SendClient(this Container self, IMessage message) + { + self.Account.GetParent().Send(message); + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Server/Hotfix/Gate/Container/Equip/EquipComponentSystem.cs b/物品和背包的完整代码/Server/Hotfix/Gate/Container/Equip/EquipComponentSystem.cs new file mode 100644 index 0000000..bbaa5d3 --- /dev/null +++ b/物品和背包的完整代码/Server/Hotfix/Gate/Container/Equip/EquipComponentSystem.cs @@ -0,0 +1,162 @@ +using Fantasy.Entitas; +using Fantasy.Entitas.Interface; +using Fantasy.Helper; + +namespace Fantasy.Equip; + +public class EquipComponentAwakeSystem : AwakeSystem +{ + protected override void Awake(EquipComponent self) + { + self.Awake(); + } +} + +public sealed class EquipComponentDestroySystem : DestroySystem +{ + protected override void Destroy(EquipComponent self) + { + foreach (var (_, value) in self.MainAttrs) + { + value.Dispose(); + } + foreach (var (_, value) in self.EntryAttrs) + { + value.Dispose(); + } + self.Affixs.Clear(); + self.MainAttrs.Clear(); + self.EntryAttrs.Clear(); + self.Durable = 0; + self.DurableMax = 0; + } +} + +public sealed class EquipAttrDestroySystem : DestroySystem +{ + protected override void Destroy(EquipAttr self) + { + self.Key = 0; + self.Value = 0; + self.SValue = 0; + } +} + +public static class EquipComponentSystem +{ + public static void Awake(this EquipComponent self) + { + var item = self.GetParent(); + var itemConfig = item.Config; + // 设置装备的耐久 + self.Durable = itemConfig.Durable; + self.DurableMax = self.Durable; + // 获取装备品质主属性方案 + if (!EquipValueConfigData.Instance.TryGetValue(itemConfig.Id, itemConfig.Quality, out var equipValueConfig)) + { + // 没有找到主属性方案,需要检查代码或配置表是否正确。 + // 到这里的话就不需要继续执行了。 + return; + } + // 设置主属性 + self.InitMainAttrs(itemConfig, equipValueConfig); + // 设置附加(副)属性 + self.InitEntryAttrs(itemConfig, equipValueConfig); + // 设置词缀 + self.InitAffix(itemConfig, equipValueConfig); + } + + private static void InitMainAttrs(this EquipComponent self, ItemConfig itemConfig, EquipValueConfig equipValueConfig) + { + self.MainAttrs.Clear(); + // 循环遍历主属性。 + foreach (var (key, value) in equipValueConfig.MainAttrs.Dic) + { + var equipAttr = Entity.Create(self.Scene, true, true); + equipAttr.Key = key; + equipAttr.Value = value; + self.MainAttrs.Add(key, equipAttr); + } + // 这里还可以加一些其他的需求。 + } + + private static void InitEntryAttrs(this EquipComponent self, ItemConfig itemConfig, EquipValueConfig equipValueConfig) + { + var equipEntryConfigId = equipValueConfig.EquipEntryConfigId; + // 很有可能当前的装备没有附加(副)属性,所以如果为默认值的情况下就不进行下面的逻辑。 + if (equipEntryConfigId == 0) + { + return; + } + // 还有一种可能是设置的副(附加)属性不存在,一般这样的情况下都是策划配置的错误,这里的话也不进行下面的逻辑了。 + if (!EquipEntryConfigData.Instance.TryGet(equipEntryConfigId, out var equipEntryConfig)) + { + // 也可以在这里打印出一个错误,方便排查,找到这个错误告诉策划,让策划修改下。 + // (推荐做法)也可以一个单独的Scene,在这里Scene里把这些所有配置加载出来,按个的排查,如果有错误就打印出来。 + return; + } + self.EntryAttrs.Clear(); + // 这里可以用权重来控制随机的数量和属性,但是这里就不演示的。 + // 这里就是用直接的随机来做来了。 + var entryCount = RandomHelper.RandomNumber(equipEntryConfig.Min, equipEntryConfig.Max); + // 获得当前随机附加属性的列表 + var configAttrs = equipEntryConfig.Attrs; + var entryIndex = 0; + for (var i = 0; i < entryCount; i++) + { + var equipAttr = Entity.Create(self.Scene, true, true); + equipAttr.Key = configAttrs[entryIndex]; + equipAttr.Value = RandomHelper.RandomNumber(configAttrs[entryIndex + 1], configAttrs[entryIndex + 2]); + self.EntryAttrs.Add(equipAttr.Key, equipAttr); + } + } + + private static void InitAffix(this EquipComponent self, ItemConfig itemConfig, EquipValueConfig equipValueConfig) + { + var equipEntryConfigId = equipValueConfig.EquipEntryConfigId; + + if (equipEntryConfigId == 0) + { + return; + } + + if (!EquipEntryConfigData.Instance.TryGet(equipEntryConfigId, out var equipEntryConfig)) + { + // 也可以在这里打印出一个错误,方便排查,找到这个错误告诉策划,让策划修改下。 + // (推荐做法)也可以一个单独的Scene,在这里Scene里把这些所有配置加载出来,按个的排查,如果有错误就打印出来。 + return; + } + + if (equipEntryConfig.Affix.Length == 0) + { + // 有可能没有词缀,所以这里就不进行下面的逻辑了。 + return; + } + + // 随机词缀的数量 + // 这里还是只做最简单的随机,如果想加权重的随机,可以自己实现下。 + var configAffix = equipEntryConfig.Affix; + var affixCount = RandomHelper.RandomNumber(equipEntryConfig.AffixMin, equipEntryConfig.AffixMax); + for (var i = 0; i < affixCount; i++) + { + self.Affixs.Add(configAffix[i]); + } + } + + public static EquipInfo ToEquipInfo(this EquipComponent self) + { + var equipInfo = new EquipInfo(); + equipInfo.Durable = self.Durable; + equipInfo.DurableMax = self.DurableMax; + + foreach (var (key,equipAttr) in self.MainAttrs) + { + equipInfo.MainKeys.Add(key); + equipInfo.EquipAttrKeys.Add(key); + equipInfo.EquipAttrValues.Add(equipAttr.Value); + equipInfo.EquipAttrSValues.Add(equipAttr.SValue); + } + + return equipInfo; + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Server/Hotfix/Gate/Container/Equip/EquipHelper.cs b/物品和背包的完整代码/Server/Hotfix/Gate/Container/Equip/EquipHelper.cs new file mode 100644 index 0000000..35ddadd --- /dev/null +++ b/物品和背包的完整代码/Server/Hotfix/Gate/Container/Equip/EquipHelper.cs @@ -0,0 +1,137 @@ +namespace Fantasy; + +public static class EquipHelper +{ + /// + /// 装载一个装备 + /// + /// + /// + /// + public static uint MountEquip(Account account, Item mountEquipItem) + { + var itemConfig = mountEquipItem.Config; + + if (!itemConfig.IsEquip()) + { + // 这里返回的是不是装备的错误码。 + return 1; + } + + if (mountEquipItem.Container.Config.Type != (int)ContainerType.Bag) + { + // 只有在背包里的物品才可以装备到装备栏里的错误码。 + return 2; + } + + var mountEquipPosition = itemConfig.Position; + // 如果在目标装备栏上有装备,那就先卸载装备。 + UnMountEquip(account, (EquipPosition)mountEquipPosition, true); + // 下面要执行把装备添加到装备栏上。 + // 先在背包中移除该装备,因为已经得到了装备了,所以可以直接通过物品拿到背包的容器。 + var removeItem = mountEquipItem.Container.RemoveItem(mountEquipItem, ItemReason.MountEquipRemove, true, false); + if (removeItem != 0) + { + // 移除装备的时候,发生了错误,直接返回错误码。 + return removeItem; + } + // 把装备添加到对应的装备栏上。 + var addItem = ContainerHelper.AddItem(account, ContainerType.Equip, mountEquipItem, mountEquipPosition, + ItemReason.MountEquipAdd, true); + if (addItem != 0) + { + // 添加装备的时候,发生了错误,直接返回错误码。 + return addItem; + } + // 这里要执行添加装备后,因为装备有增加属性或词缀Buff,所以需要在添加的时候把这些也要给添加下。 + // 因为本课程胡总没有数值系统和Buff系统,所以这里就不处理了。 + Log.Debug($"执行了装备装备的效果逻辑。"); + Log.Debug($"装载装备完成。mountEquipItem:{mountEquipItem.Id}"); + // 可以合包优化下这个协议的数量,优化成一个,能节省流量。 + return 0; + } + + /// + /// 卸载一个装备 + /// + /// + /// + /// + /// + public static uint UnMountEquip(Account account, EquipPosition equipPosition, bool isSendClient) + { + if (!ContainerHelper.GetItemByCell(account, ContainerType.Equip, (long)equipPosition, out var unMountEquipItem)) + { + // 没有找到该位置的装备的错误码。 + return 1; + } + + return UnMountEquip(account, unMountEquipItem, isSendClient); + } + + /// + /// 卸载一个装备 + /// + /// + /// + /// + /// + public static uint UnMountEquip(Account account, Item unMountEquipItem, bool isSendClient) + { + // 首先在装备栏容器中移除装备。 + var removeItem = unMountEquipItem.Container.RemoveItem(unMountEquipItem, ItemReason.UnMountEquipRemove, isSendClient, false); + if (removeItem != 0) + { + // 移除失败了,要返回错误码,就不要执行后面的程序了。 + return removeItem; + } + // 这里要执行移除装备后,因为装备有增加属性或词缀Buff,所以需要在移除的时候把这些也要给移除下。 + // 因为本课程胡总没有数值系统和Buff系统,所以这里就不处理了。 + // 把移除成功的装备再次添加到背包容器中。 + Log.Debug("执行了装备卸载的效果逻辑。"); + return ContainerHelper.AddItem(account, ContainerType.Bag, unMountEquipItem, ItemReason.UnMountEquipAdd, isSendClient); + } + + /// + /// 根据装备的位置获取装备 + /// + /// + /// + /// + /// + public static bool GetEquipItem(Account account, EquipPosition equipPosition, out Item item) + { + return ContainerHelper.GetItemByCell(account, ContainerType.Equip, (long)equipPosition, out item); + } + + /// + /// 是否是装备 + /// + /// + /// + public static bool IsEquip(this Item item) + { + return item.Config.IsEquip(); + } + + /// + /// 获得装备所在的装备栏位置 + /// + /// + /// + public static EquipPosition GetEquipPosition(this Item item) + { + return (EquipPosition)item.GetEquipPositionInt(); + } + + private static int GetEquipPositionInt(this Item item) + { + return item.Config.Position; + } + + private static bool IsEquip(this ItemConfig itemConfig) + { + var configType = (ItemType)itemConfig.Type; + return configType == ItemType.Equip; + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Server/Hotfix/Gate/Container/ItemSystem.cs b/物品和背包的完整代码/Server/Hotfix/Gate/Container/ItemSystem.cs new file mode 100644 index 0000000..bbb96e6 --- /dev/null +++ b/物品和背包的完整代码/Server/Hotfix/Gate/Container/ItemSystem.cs @@ -0,0 +1,44 @@ +using Fantasy.Entitas.Interface; +using Fantasy.Equip; +// ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract +#pragma warning disable CS8601 // Possible null reference assignment. + +#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. + +namespace Fantasy; + +public sealed class ItemDestroySystem : DestroySystem +{ + protected override void Destroy(Item self) + { + self.CellId = 0; + self.Count = 0; + self.ConfigId = 0; + self.Container = null; + self.IsBind = false; + } +} + +public static class ItemSystem +{ + public static ItemInfo ToItemInfo(this Item self) + { + // 创建基础的物品信息 + var mItemInfo = new ItemInfo() + { + ItemId = self.Id, + CellId = self.CellId, + Count = self.Count, + IsBind = self.IsBind, + ConfigId = (int)self.ConfigId, + Container = self.Container.Config.Type + }; + // 添加装备信息 + var equipComponent = self.GetComponent(); + if (equipComponent != null) + { + mItemInfo.EquipInfo = equipComponent.ToEquipInfo(); + } + return mItemInfo; + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Server/Hotfix/Gate/Container/ItemUseHelper.cs b/物品和背包的完整代码/Server/Hotfix/Gate/Container/ItemUseHelper.cs new file mode 100644 index 0000000..77057a5 --- /dev/null +++ b/物品和背包的完整代码/Server/Hotfix/Gate/Container/ItemUseHelper.cs @@ -0,0 +1,73 @@ +#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. +namespace Fantasy; + +public static class ItemUseHelper +{ + public static uint UseBagItem(Account account, long itemId, int count) + { + return UseItem(account, ContainerType.Bag, itemId, count); + } + + public static uint CanUseBagItem(Account account, long itemId, int count, out Container container, out ItemConfig itemConfig, out ItemUseComponent itemUseComponent) + { + return CanUseItem(account, ContainerType.Bag, itemId, count, out container, out itemConfig, out itemUseComponent); + } + + public static uint UseItem(Account account, ContainerType containerType, long itemId, int count) + { + var errorCode = CanUseItem(account, containerType, itemId, count, out var container, out var itemConfig, out var itemUseComponent); + + if (errorCode != 0) + { + return errorCode; + } + + errorCode = container.RemoveItem(itemId, count, ItemReason.ItemUse, true); + + if (errorCode != 0) + { + return errorCode; + } + + itemUseComponent.Use(account, itemConfig, ref count); + return 0; + } + + public static uint CanUseItem(Account account, ContainerType containerType, long itemId, int count, out Container container, out ItemConfig itemConfig, out ItemUseComponent itemUseComponent) + { + itemConfig = null; + itemUseComponent = null; + var errorCode = ContainerHelper.TryGetContainer(account, containerType, out container); + + if (errorCode != 0) + { + return errorCode; + } + + if (!container.GetItemById(itemId, out var item)) + { + // 这里是找不到该物品的错误码。 + return 1; + } + + if (item.Count < count) + { + // 这里是物品数量不足的错误码。 + return 2; + } + + itemConfig = item.Config; + + if (itemConfig.Params.Length <= 0) + { + // 这里是物品没有配置参数的错误码。 + return 3; + } + + // 这里还可以增加一些其他的判定,比如物品是否过期,物品是否被锁定等。 + // 甚至还有物品使用的CD。 + // 使用物品效果来判定 + itemUseComponent = account.Scene.GetComponent(); + return itemUseComponent.CanUse(account, item.Config, ref count); + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Server/Hotfix/Gate/Entity/AccountSystem.cs b/物品和背包的完整代码/Server/Hotfix/Gate/Entity/AccountSystem.cs new file mode 100644 index 0000000..11380cb --- /dev/null +++ b/物品和背包的完整代码/Server/Hotfix/Gate/Entity/AccountSystem.cs @@ -0,0 +1,14 @@ +using Fantasy.Entitas.Interface; + +namespace Fantasy.Gate.Entity; + +public sealed class AccountSystemDestroySystem : DestroySystem +{ + protected override void Destroy(Account self) + { + self.Session = null; + self.UserName = null; + self.Password = null; + self.ConfigId = 0; + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Server/Hotfix/Gate/Helper/ItemFactory.cs b/物品和背包的完整代码/Server/Hotfix/Gate/Helper/ItemFactory.cs new file mode 100644 index 0000000..7f65ba7 --- /dev/null +++ b/物品和背包的完整代码/Server/Hotfix/Gate/Helper/ItemFactory.cs @@ -0,0 +1,116 @@ +using Fantasy.Entitas; +#pragma warning disable CS8603 // Possible null reference return. + +namespace Fantasy; + +public static class ItemFactory +{ + /// + /// 创建一个物品 + /// + /// + /// + /// + /// + /// + public static Item Create(Scene scene, uint configId, int count, bool isBind) + { + var itemConfig = ItemConfigData.Instance.Get(configId); + + if (itemConfig.Superposed) + { + if (itemConfig.SuperposedMax < count) + { + Log.Error($"物品{itemConfig.Name} 最大叠加数量为{itemConfig.SuperposedMax},不能超过{count}"); + return null; + } + } + else + { + if (count > 1) + { + Log.Error($"物品{itemConfig.Name} 不支持叠加,不能超过1个"); + return null; + } + } + + var item = Entity.Create(scene, true, true); + item.ConfigId = configId; + item.Count = count; + item.IsBind = isBind; + + // 根据物品的类型单独的做一些处理 + + switch ((ItemType)itemConfig.Type) + { + case ItemType.Drug: + { + break; + } + case ItemType.Equip: + { + // 装备的要挂载装备组件。 + item.AddComponent(); + break; + } + case ItemType.Prop: + { + break; + } + case ItemType.Garbage: + { + break; + } + } + + return item; + } + + /// + /// 批量创建物品 + /// + /// + /// + /// + public static void Create(Scene scene, List itemCreateParamsList, List items) + { + // 也可以用Foreach,但是性能会差一点点。 + // for和Foreach性能差距非常小,尤其是在现在的CPU用,但如果在高频繁使用的场景下,for提升会明显一些。 + // 不要纠结到底是用for还是Foreach,因为两者性能差距非常小,而且Foreach更简洁。 + // 以下是一个简单性能对比(处理 1000 万元素的 List): + // for 循环 ~50 ms + // foreach 循环 ~70 ms + // for 循环快约 20-30%(因硬件和 .NET 版本而异)。 + + // 为什么 for 更快? + // 直接索引访问:List 底层是数组,索引访问是 O(1) 操作。 + // 避免迭代器开销:foreach 需要调用 MoveNext() 和 Current,隐含版本检查(防止遍历时集合被修改)。 + + // 什么时候用 foreach? + // 代码简洁性优先:不需要索引时,foreach 更易读。 + // 复杂集合类型:对于非 List 的集合(如 IEnumerable 或字典),foreach 可能更高效,因为某些集合的索引访问是 O(n)(如 LinkedList)。 + + // 优化建议 + // 优先选择 for:如果性能敏感且需要高频遍历大规模数据。 + // 使用 foreach:如果代码可读性更重要,或遍历非数组结构的集合。 + // 避免在 List 中使用 foreach 的陷阱: + // 如果遍历过程中修改集合(如增删元素),会触发 InvalidOperationException。 + // 对值类型集合(如 List),foreach 可能涉及装箱(但 List 的 Enumerator 是结构体,不会发生装箱)。 + + // 高级场景 + // Span 或数组:对于 Span 或原生数组,for 循环可以进一步优化为 SIMD 指令。 + + // for (var index = 0; index < itemCreateParamsList.Count; index++) + // { + // var itemCreateParams = itemCreateParamsList[index]; + // var item = Create(scene, itemCreateParams.ConfigId, itemCreateParams.Count, itemCreateParams.IsBind); + // items.Add(item); + // } + + foreach (var itemCreateParams in itemCreateParamsList) + { + var item = Create(scene, itemCreateParams.ConfigId, itemCreateParams.Count, itemCreateParams.IsBind); + items.Add(item); + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Server/Hotfix/Gate/Helper/UnitFactory.cs b/物品和背包的完整代码/Server/Hotfix/Gate/Helper/UnitFactory.cs new file mode 100644 index 0000000..a6e5b46 --- /dev/null +++ b/物品和背包的完整代码/Server/Hotfix/Gate/Helper/UnitFactory.cs @@ -0,0 +1,25 @@ +using Fantasy.Entitas; + +namespace Fantasy; + +public static class UnitFactory +{ + public static Account CreatePlayer(Scene scene, uint configId, string userName, string password) + { + var account = Entity.Create(scene, true, true); + account.ConfigId = configId; + account.UserName = userName; + account.Password = password; + // 挂载容器组件 + account.AddComponent(); + return account; + } + + public static Account CreateMonster(Scene scene, uint configId) + { + var account = Entity.Create(scene, true, true); + // 挂载容器组件 + account.AddComponent(); + return account; + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Server/Hotfix/Gate/ItemUseEffect/ItemUse_Drug.cs b/物品和背包的完整代码/Server/Hotfix/Gate/ItemUseEffect/ItemUse_Drug.cs new file mode 100644 index 0000000..5f27287 --- /dev/null +++ b/物品和背包的完整代码/Server/Hotfix/Gate/ItemUseEffect/ItemUse_Drug.cs @@ -0,0 +1,27 @@ +namespace Fantasy; + +[ItemUse(ItemUseEffect.AddAttr)] +public class ItemUse_Drug_AddAttr : IItemUse +{ + public uint CanUse(Account account, ItemConfig config, ref int count) + { + if (config.Params.Length < 2) + { + Log.Error($"configId:{config.Id} config.Params.Length({config.Params.Length}) < 2"); + return 1; + } + + Log.Debug($"CanUse 使用了药品增加属性 configId:{config.Id} count:{count}"); + return 0; + } + + public void Use(Account account, ItemConfig config, ref int count) + { + for (int i = 0; i < config.Params.Length; i += 2) + { + var attrKey = config.Params[i]; + var attrValue = config.Params[i + 1]; + Log.Debug($"Use 使用了药品增加属性 configId:{config.Id} attrKey:{attrKey} attrValue:{attrValue}"); + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Server/Hotfix/Gate/ItemUseEffect/ItemUse_Equip.cs b/物品和背包的完整代码/Server/Hotfix/Gate/ItemUseEffect/ItemUse_Equip.cs new file mode 100644 index 0000000..605a081 --- /dev/null +++ b/物品和背包的完整代码/Server/Hotfix/Gate/ItemUseEffect/ItemUse_Equip.cs @@ -0,0 +1,16 @@ +namespace Fantasy; + +[ItemUse(ItemUseEffect.Equip)] +public class ItemUse_Equip_Equip : IItemUse +{ + public uint CanUse(Account account, ItemConfig config, ref int count) + { + Log.Debug($"CanUse 使用了装备装备到身上 configId:{config.Id} count:{count}"); + return 0; + } + + public void Use(Account account, ItemConfig config, ref int count) + { + Log.Debug($"Use 使用了装备装备到身上 configId:{config.Id} count:{count}"); + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Server/Hotfix/Handler/C2G_GameInitCompleteRequestHandler.cs b/物品和背包的完整代码/Server/Hotfix/Handler/C2G_GameInitCompleteRequestHandler.cs new file mode 100644 index 0000000..3ece918 --- /dev/null +++ b/物品和背包的完整代码/Server/Hotfix/Handler/C2G_GameInitCompleteRequestHandler.cs @@ -0,0 +1,26 @@ +using Fantasy.Async; +using Fantasy.Network; +using Fantasy.Network.Interface; + +namespace Fantasy; + +public sealed class C2G_GameInitCompleteRequestHandler : MessageRPC +{ + protected override async FTask Run(Session session, C2G_GameInitCompleteRequest request, G2C_GameInitCompleteResponse response, Action reply) + { + var account = session.GetComponent(); + var requestPushContainer = request.PushContainer; + var requestPushUnitInfo = request.PushUnitInfo; + var requestAoi = request.Aoi; + // 当调用reply方法的时候,就会马上返回G2C_GameInitCompleteResponse消息给客户端了。 + // 这时候客户端await等待就会继续执行。 + reply(); + // 比如这个代码就是推送给客户端的。 + if (requestPushContainer) + { + // 推送容器的数据给客户端。 + ContainerHelper.SendAllContainerInfo(account); + } + await FTask.CompletedTask; + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Server/Hotfix/Handler/C2G_LoginRequestHandler.cs b/物品和背包的完整代码/Server/Hotfix/Handler/C2G_LoginRequestHandler.cs new file mode 100644 index 0000000..d51c42f --- /dev/null +++ b/物品和背包的完整代码/Server/Hotfix/Handler/C2G_LoginRequestHandler.cs @@ -0,0 +1,41 @@ +using Fantasy.Async; +using Fantasy.Entitas; +using Fantasy.Network; +using Fantasy.Network.Interface; + +namespace Fantasy; + +public class C2G_LoginRequestHandler : MessageRPC +{ + protected override async FTask Run(Session session, C2G_LoginRequest request, G2C_LoginResponse response, Action reply) + { + // 由于本课程中,主要讲解的是物品和背包的内容,所以这里就简单的创建了一个登陆逻辑。 + // 这个登陆逻辑,并不能用于商用,只是为了当前的课程服务的临时。 + // 如果想学习完整的注册登陆的流程,建议关注下我的注册登陆的课程。 + var scene = session.Scene; + // 再数据库中查询用户名和密码是否存在。 + var account = await scene.World.DataBase.First(d => + d.UserName == request.UserName && d.Password == request.PassWord, true); + if (account == null) + { + // 如果没有就创建一个新的实体,并且保存到数据库中。 + account = UnitFactory.CreatePlayer(scene, 1, request.UserName, request.PassWord); + // account = Entity.Create(scene, true, true); + // account.UserName = request.UserName; + // account.Password = request.PassWord; + // // 增加背包组件 + // var bagComponent = account.AddComponent(); + // // 创建一个临时物品,并且放入到临时背包中 + // var item = ItemFactory.Create(scene, 1, 1, true); + // bagComponent.AddItem(item); + // 把实体保存到数据库中。 + await scene.World.DataBase.Save(account); + } + // 把当前账号添加到Session下,好处有下面的几个方面: + // 1、客在Session下很方便的获得到当前账号。 + // 2、当Session断开了,也就是客户端跟服务器断开连接了,会自动执行小伙这个Account。 + account.Session = session; + session.AddComponent(account); + Log.Debug($"登陆成功 UserName:{request.UserName} Password:{request.PassWord}"); + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Server/Hotfix/Handler/C2G_StartCreateItemHandler.cs b/物品和背包的完整代码/Server/Hotfix/Handler/C2G_StartCreateItemHandler.cs new file mode 100644 index 0000000..ae8c6c8 --- /dev/null +++ b/物品和背包的完整代码/Server/Hotfix/Handler/C2G_StartCreateItemHandler.cs @@ -0,0 +1,42 @@ +using Fantasy.Async; +using Fantasy.Network; +using Fantasy.Network.Interface; +// ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract + +namespace Fantasy; + +public sealed class C2G_StartCreateItemHandler : Message +{ + // protected override async FTask Run(Session session, C2G_StartCreateItem message) + // { + // var account = session.GetComponent(); + // + // if (account == null) + // { + // session.Dispose(); + // return; + // } + // + // var item = ItemFactory.Create(session.Scene, 1000001, 1, true); + // var addItemErrorCode = ContainerHelper.AddItem(account, ContainerType.Bag, item, ItemReason.ItemTestAdd, true); + // Log.Debug($"addItemErrorCode:{addItemErrorCode}"); + // await session.Scene.World.DataBase.Save(account); + // await FTask.CompletedTask; + // } + + protected override async FTask Run(Session session, C2G_StartCreateItem message) + { + var account = session.GetComponent(); + + if (account == null) + { + session.Dispose(); + return; + } + + var items = new List(); + ContainerHelper.GetItemsByConfigId(account, ContainerType.Bag, 1000001, items); + Log.Debug($"MountEquip:{EquipHelper.MountEquip(account, items[0])}"); + await session.Scene.World.DataBase.Save(account); + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Server/Hotfix/Handler/C2G_UseItemRequestHandler.cs b/物品和背包的完整代码/Server/Hotfix/Handler/C2G_UseItemRequestHandler.cs new file mode 100644 index 0000000..8e15748 --- /dev/null +++ b/物品和背包的完整代码/Server/Hotfix/Handler/C2G_UseItemRequestHandler.cs @@ -0,0 +1,23 @@ +using Fantasy.Async; +using Fantasy.Network; +using Fantasy.Network.Interface; +// ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract + +namespace Fantasy; + +public class C2G_UseItemRequestHandler : MessageRPC +{ + protected override async FTask Run(Session session, C2G_UseItemRequest request, G2C_UseItemResponse response, Action reply) + { + var account = session.GetComponent(); + + if (account == null) + { + session.Dispose(); + return; + } + + response.ErrorCode = ItemUseHelper.UseItem(account, (ContainerType)request.ContainerType, request.ItemId, request.Count); + await FTask.CompletedTask; + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Server/Hotfix/Hotfix.csproj b/物品和背包的完整代码/Server/Hotfix/Hotfix.csproj new file mode 100644 index 0000000..4f09b61 --- /dev/null +++ b/物品和背包的完整代码/Server/Hotfix/Hotfix.csproj @@ -0,0 +1,13 @@ + + + + net8.0 + enable + enable + + + + + + + diff --git a/物品和背包的完整代码/Server/Hotfix/OnCreateScene_Init.cs b/物品和背包的完整代码/Server/Hotfix/OnCreateScene_Init.cs new file mode 100644 index 0000000..5a1f087 --- /dev/null +++ b/物品和背包的完整代码/Server/Hotfix/OnCreateScene_Init.cs @@ -0,0 +1,25 @@ +using Fantasy.Async; +using Fantasy.Event; + +namespace Fantasy; + +public sealed class OnCreateScene_Init : AsyncEventSystem +{ + protected override async FTask Handler(OnCreateScene self) + { + var scene = self.Scene; + switch (scene.SceneType) + { + case SceneType.Gate: + { + // 添加物品使用分发的组件 + await scene.AddComponent().Initialize(); + break; + } + case SceneType.Chat: + { + break; + } + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Server/Hotfix/bin/Debug/net8.0/Entity.dll b/物品和背包的完整代码/Server/Hotfix/bin/Debug/net8.0/Entity.dll new file mode 100644 index 0000000..56f7ee8 Binary files /dev/null and b/物品和背包的完整代码/Server/Hotfix/bin/Debug/net8.0/Entity.dll differ diff --git a/物品和背包的完整代码/Server/Hotfix/bin/Debug/net8.0/Entity.pdb b/物品和背包的完整代码/Server/Hotfix/bin/Debug/net8.0/Entity.pdb new file mode 100644 index 0000000..dc622c0 Binary files /dev/null and b/物品和背包的完整代码/Server/Hotfix/bin/Debug/net8.0/Entity.pdb differ diff --git a/物品和背包的完整代码/Server/Hotfix/bin/Debug/net8.0/Fantasy-Net.ConfigTable.dll b/物品和背包的完整代码/Server/Hotfix/bin/Debug/net8.0/Fantasy-Net.ConfigTable.dll new file mode 100644 index 0000000..fce9289 Binary files /dev/null and b/物品和背包的完整代码/Server/Hotfix/bin/Debug/net8.0/Fantasy-Net.ConfigTable.dll differ diff --git a/物品和背包的完整代码/Server/Hotfix/bin/Debug/net8.0/Fantasy-Net.ConfigTable.pdb b/物品和背包的完整代码/Server/Hotfix/bin/Debug/net8.0/Fantasy-Net.ConfigTable.pdb new file mode 100644 index 0000000..60e4fcc Binary files /dev/null and b/物品和背包的完整代码/Server/Hotfix/bin/Debug/net8.0/Fantasy-Net.ConfigTable.pdb differ diff --git a/物品和背包的完整代码/Server/Hotfix/bin/Debug/net8.0/Fantasy-Net.dll b/物品和背包的完整代码/Server/Hotfix/bin/Debug/net8.0/Fantasy-Net.dll new file mode 100644 index 0000000..a5e915f Binary files /dev/null and b/物品和背包的完整代码/Server/Hotfix/bin/Debug/net8.0/Fantasy-Net.dll differ diff --git a/物品和背包的完整代码/Server/Hotfix/bin/Debug/net8.0/Fantasy-Net.pdb b/物品和背包的完整代码/Server/Hotfix/bin/Debug/net8.0/Fantasy-Net.pdb new file mode 100644 index 0000000..fdff803 Binary files /dev/null and b/物品和背包的完整代码/Server/Hotfix/bin/Debug/net8.0/Fantasy-Net.pdb differ diff --git a/物品和背包的完整代码/Server/Hotfix/bin/Debug/net8.0/Hotfix.deps.json b/物品和背包的完整代码/Server/Hotfix/bin/Debug/net8.0/Hotfix.deps.json new file mode 100644 index 0000000..d3c9b0d --- /dev/null +++ b/物品和背包的完整代码/Server/Hotfix/bin/Debug/net8.0/Hotfix.deps.json @@ -0,0 +1,377 @@ +{ + "runtimeTarget": { + "name": ".NETCoreApp,Version=v8.0", + "signature": "" + }, + "compilationOptions": {}, + "targets": { + ".NETCoreApp,Version=v8.0": { + "Hotfix/1.0.0": { + "dependencies": { + "Entity": "1.0.0", + "Fantasy-Net.ConfigTable.Reference": "1.0.0.0", + "Fantasy-Net.Reference": "1.0.0.0" + }, + "runtime": { + "Hotfix.dll": {} + } + }, + "CommandLineParser/2.9.1": { + "runtime": { + "lib/netstandard2.0/CommandLine.dll": { + "assemblyVersion": "2.9.1.0", + "fileVersion": "2.9.1.0" + } + } + }, + "DnsClient/1.6.1": { + "dependencies": { + "Microsoft.Win32.Registry": "5.0.0" + }, + "runtime": { + "lib/net5.0/DnsClient.dll": { + "assemblyVersion": "1.6.1.0", + "fileVersion": "1.6.1.0" + } + } + }, + "Microsoft.Extensions.Logging.Abstractions/2.0.0": {}, + "Microsoft.NETCore.Platforms/5.0.0": {}, + "Microsoft.Win32.Registry/5.0.0": { + "dependencies": { + "System.Security.AccessControl": "5.0.0", + "System.Security.Principal.Windows": "5.0.0" + } + }, + "MongoDB.Bson/3.1.0": { + "dependencies": { + "System.Memory": "4.5.5", + "System.Runtime.CompilerServices.Unsafe": "5.0.0" + }, + "runtime": { + "lib/net6.0/MongoDB.Bson.dll": { + "assemblyVersion": "3.1.0.0", + "fileVersion": "3.1.0.0" + } + } + }, + "MongoDB.Driver/3.1.0": { + "dependencies": { + "DnsClient": "1.6.1", + "Microsoft.Extensions.Logging.Abstractions": "2.0.0", + "MongoDB.Bson": "3.1.0", + "SharpCompress": "0.30.1", + "Snappier": "1.0.0", + "System.Buffers": "4.5.1", + "ZstdSharp.Port": "0.7.3" + }, + "runtime": { + "lib/net6.0/MongoDB.Driver.dll": { + "assemblyVersion": "3.1.0.0", + "fileVersion": "3.1.0.0" + } + } + }, + "Newtonsoft.Json/13.0.3": { + "runtime": { + "lib/net6.0/Newtonsoft.Json.dll": { + "assemblyVersion": "13.0.0.0", + "fileVersion": "13.0.3.27908" + } + } + }, + "protobuf-net/3.2.45": { + "dependencies": { + "protobuf-net.Core": "3.2.45" + }, + "runtime": { + "lib/net6.0/protobuf-net.dll": { + "assemblyVersion": "3.0.0.0", + "fileVersion": "3.2.45.36865" + } + } + }, + "protobuf-net.Core/3.2.45": { + "dependencies": { + "System.Collections.Immutable": "7.0.0" + }, + "runtime": { + "lib/net6.0/protobuf-net.Core.dll": { + "assemblyVersion": "3.0.0.0", + "fileVersion": "3.2.45.36865" + } + } + }, + "SharpCompress/0.30.1": { + "runtime": { + "lib/net5.0/SharpCompress.dll": { + "assemblyVersion": "0.30.1.0", + "fileVersion": "0.30.1.0" + } + } + }, + "Snappier/1.0.0": { + "runtime": { + "lib/net5.0/Snappier.dll": { + "assemblyVersion": "1.0.0.0", + "fileVersion": "1.0.0.0" + } + } + }, + "System.Buffers/4.5.1": {}, + "System.Collections.Immutable/7.0.0": {}, + "System.IO.Pipelines/9.0.0": { + "runtime": { + "lib/net8.0/System.IO.Pipelines.dll": { + "assemblyVersion": "9.0.0.0", + "fileVersion": "9.0.24.52809" + } + } + }, + "System.Memory/4.5.5": {}, + "System.Runtime.CompilerServices.Unsafe/5.0.0": {}, + "System.Security.AccessControl/5.0.0": { + "dependencies": { + "Microsoft.NETCore.Platforms": "5.0.0", + "System.Security.Principal.Windows": "5.0.0" + } + }, + "System.Security.Principal.Windows/5.0.0": {}, + "ZstdSharp.Port/0.7.3": { + "runtime": { + "lib/net7.0/ZstdSharp.dll": { + "assemblyVersion": "0.7.3.0", + "fileVersion": "0.7.3.0" + } + } + }, + "Entity/1.0.0": { + "dependencies": { + "Fantasy-Net": "2024.2.24", + "Fantasy-Net.ConfigTable": "2024.2.0" + }, + "runtime": { + "Entity.dll": { + "assemblyVersion": "1.0.0", + "fileVersion": "1.0.0.0" + } + } + }, + "Fantasy-Net/2024.2.24": { + "dependencies": { + "CommandLineParser": "2.9.1", + "MongoDB.Bson": "3.1.0", + "MongoDB.Driver": "3.1.0", + "Newtonsoft.Json": "13.0.3", + "System.IO.Pipelines": "9.0.0", + "protobuf-net": "3.2.45" + }, + "runtime": { + "Fantasy-Net.dll": { + "assemblyVersion": "2024.2.24", + "fileVersion": "" + } + } + }, + "Fantasy-Net.ConfigTable/2024.2.0": { + "dependencies": { + "Fantasy-Net": "2024.2.24" + }, + "runtime": { + "Fantasy-Net.ConfigTable.dll": { + "assemblyVersion": "2024.2.0", + "fileVersion": "" + } + } + }, + "Fantasy-Net.ConfigTable.Reference/1.0.0.0": { + "runtime": { + "Fantasy-Net.ConfigTable.dll": { + "assemblyVersion": "1.0.0.0", + "fileVersion": "1.0.0.0" + } + } + }, + "Fantasy-Net.Reference/1.0.0.0": { + "runtime": { + "Fantasy-Net.dll": { + "assemblyVersion": "1.0.0.0", + "fileVersion": "1.0.0.0" + } + } + } + } + }, + "libraries": { + "Hotfix/1.0.0": { + "type": "project", + "serviceable": false, + "sha512": "" + }, + "CommandLineParser/2.9.1": { + "type": "package", + "serviceable": true, + "sha512": "sha512-OE0sl1/sQ37bjVsPKKtwQlWDgqaxWgtme3xZz7JssWUzg5JpMIyHgCTY9MVMxOg48fJ1AgGT3tgdH5m/kQ5xhA==", + "path": "commandlineparser/2.9.1", + "hashPath": "commandlineparser.2.9.1.nupkg.sha512" + }, + "DnsClient/1.6.1": { + "type": "package", + "serviceable": true, + "sha512": "sha512-4H/f2uYJOZ+YObZjpY9ABrKZI+JNw3uizp6oMzTXwDw6F+2qIPhpRl/1t68O/6e98+vqNiYGu+lswmwdYUy3gg==", + "path": "dnsclient/1.6.1", + "hashPath": "dnsclient.1.6.1.nupkg.sha512" + }, + "Microsoft.Extensions.Logging.Abstractions/2.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-6ZCllUYGFukkymSTx3Yr0G/ajRxoNJp7/FqSxSB4fGISST54ifBhgu4Nc0ItGi3i6DqwuNd8SUyObmiC++AO2Q==", + "path": "microsoft.extensions.logging.abstractions/2.0.0", + "hashPath": "microsoft.extensions.logging.abstractions.2.0.0.nupkg.sha512" + }, + "Microsoft.NETCore.Platforms/5.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-VyPlqzH2wavqquTcYpkIIAQ6WdenuKoFN0BdYBbCWsclXacSOHNQn66Gt4z5NBqEYW0FAPm5rlvki9ZiCij5xQ==", + "path": "microsoft.netcore.platforms/5.0.0", + "hashPath": "microsoft.netcore.platforms.5.0.0.nupkg.sha512" + }, + "Microsoft.Win32.Registry/5.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-dDoKi0PnDz31yAyETfRntsLArTlVAVzUzCIvvEDsDsucrl33Dl8pIJG06ePTJTI3tGpeyHS9Cq7Foc/s4EeKcg==", + "path": "microsoft.win32.registry/5.0.0", + "hashPath": "microsoft.win32.registry.5.0.0.nupkg.sha512" + }, + "MongoDB.Bson/3.1.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-3dhaZhz18B5vUoEP13o2j8A6zQfkHdZhwBvLZEjDJum4BTLLv1/Z8bt25UQEtpqvYwLgde4R6ekWZ7XAYUMxuw==", + "path": "mongodb.bson/3.1.0", + "hashPath": "mongodb.bson.3.1.0.nupkg.sha512" + }, + "MongoDB.Driver/3.1.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-+O7lKaIl7VUHptE0hqTd7UY1G5KDp/o8S4upG7YL4uChMNKD/U6tz9i17nMGHaD/L2AiPLgaJcaDe2XACsegGA==", + "path": "mongodb.driver/3.1.0", + "hashPath": "mongodb.driver.3.1.0.nupkg.sha512" + }, + "Newtonsoft.Json/13.0.3": { + "type": "package", + "serviceable": true, + "sha512": "sha512-HrC5BXdl00IP9zeV+0Z848QWPAoCr9P3bDEZguI+gkLcBKAOxix/tLEAAHC+UvDNPv4a2d18lOReHMOagPa+zQ==", + "path": "newtonsoft.json/13.0.3", + "hashPath": "newtonsoft.json.13.0.3.nupkg.sha512" + }, + "protobuf-net/3.2.45": { + "type": "package", + "serviceable": true, + "sha512": "sha512-5UZ/ukUHcGbFSl7vNMrHsfjqdxusdd9w7w0fCEXzf3UUtsrGNVCzV5SmF+sCHAbnRV2qPcD1ixiDP7Aj8lX/HA==", + "path": "protobuf-net/3.2.45", + "hashPath": "protobuf-net.3.2.45.nupkg.sha512" + }, + "protobuf-net.Core/3.2.45": { + "type": "package", + "serviceable": true, + "sha512": "sha512-PMWatW2NrT1uTXD7etJ4VdQ0wWZLFrIfdRGppD2QX7nzZ0+kIzqhq551u6ZiXJHWJgG4hWFEkSnUnt2aB6posg==", + "path": "protobuf-net.core/3.2.45", + "hashPath": "protobuf-net.core.3.2.45.nupkg.sha512" + }, + "SharpCompress/0.30.1": { + "type": "package", + "serviceable": true, + "sha512": "sha512-XqD4TpfyYGa7QTPzaGlMVbcecKnXy4YmYLDWrU+JIj7IuRNl7DH2END+Ll7ekWIY8o3dAMWLFDE1xdhfIWD1nw==", + "path": "sharpcompress/0.30.1", + "hashPath": "sharpcompress.0.30.1.nupkg.sha512" + }, + "Snappier/1.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-rFtK2KEI9hIe8gtx3a0YDXdHOpedIf9wYCEYtBEmtlyiWVX3XlCNV03JrmmAi/Cdfn7dxK+k0sjjcLv4fpHnqA==", + "path": "snappier/1.0.0", + "hashPath": "snappier.1.0.0.nupkg.sha512" + }, + "System.Buffers/4.5.1": { + "type": "package", + "serviceable": true, + "sha512": "sha512-Rw7ijyl1qqRS0YQD/WycNst8hUUMgrMH4FCn1nNm27M4VxchZ1js3fVjQaANHO5f3sN4isvP4a+Met9Y4YomAg==", + "path": "system.buffers/4.5.1", + "hashPath": "system.buffers.4.5.1.nupkg.sha512" + }, + "System.Collections.Immutable/7.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-dQPcs0U1IKnBdRDBkrCTi1FoajSTBzLcVTpjO4MBCMC7f4pDOIPzgBoX8JjG7X6uZRJ8EBxsi8+DR1JuwjnzOQ==", + "path": "system.collections.immutable/7.0.0", + "hashPath": "system.collections.immutable.7.0.0.nupkg.sha512" + }, + "System.IO.Pipelines/9.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-eA3cinogwaNB4jdjQHOP3Z3EuyiDII7MT35jgtnsA4vkn0LUrrSHsU0nzHTzFzmaFYeKV7MYyMxOocFzsBHpTw==", + "path": "system.io.pipelines/9.0.0", + "hashPath": "system.io.pipelines.9.0.0.nupkg.sha512" + }, + "System.Memory/4.5.5": { + "type": "package", + "serviceable": true, + "sha512": "sha512-XIWiDvKPXaTveaB7HVganDlOCRoj03l+jrwNvcge/t8vhGYKvqV+dMv6G4SAX2NoNmN0wZfVPTAlFwZcZvVOUw==", + "path": "system.memory/4.5.5", + "hashPath": "system.memory.4.5.5.nupkg.sha512" + }, + "System.Runtime.CompilerServices.Unsafe/5.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-ZD9TMpsmYJLrxbbmdvhwt9YEgG5WntEnZ/d1eH8JBX9LBp+Ju8BSBhUGbZMNVHHomWo2KVImJhTDl2hIgw/6MA==", + "path": "system.runtime.compilerservices.unsafe/5.0.0", + "hashPath": "system.runtime.compilerservices.unsafe.5.0.0.nupkg.sha512" + }, + "System.Security.AccessControl/5.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-dagJ1mHZO3Ani8GH0PHpPEe/oYO+rVdbQjvjJkBRNQkX4t0r1iaeGn8+/ybkSLEan3/slM0t59SVdHzuHf2jmw==", + "path": "system.security.accesscontrol/5.0.0", + "hashPath": "system.security.accesscontrol.5.0.0.nupkg.sha512" + }, + "System.Security.Principal.Windows/5.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-t0MGLukB5WAVU9bO3MGzvlGnyJPgUlcwerXn1kzBRjwLKixT96XV0Uza41W49gVd8zEMFu9vQEFlv0IOrytICA==", + "path": "system.security.principal.windows/5.0.0", + "hashPath": "system.security.principal.windows.5.0.0.nupkg.sha512" + }, + "ZstdSharp.Port/0.7.3": { + "type": "package", + "serviceable": true, + "sha512": "sha512-U9Ix4l4cl58Kzz1rJzj5hoVTjmbx1qGMwzAcbv1j/d3NzrFaESIurQyg+ow4mivCgkE3S413y+U9k4WdnEIkRA==", + "path": "zstdsharp.port/0.7.3", + "hashPath": "zstdsharp.port.0.7.3.nupkg.sha512" + }, + "Entity/1.0.0": { + "type": "project", + "serviceable": false, + "sha512": "" + }, + "Fantasy-Net/2024.2.24": { + "type": "project", + "serviceable": false, + "sha512": "" + }, + "Fantasy-Net.ConfigTable/2024.2.0": { + "type": "project", + "serviceable": false, + "sha512": "" + }, + "Fantasy-Net.ConfigTable.Reference/1.0.0.0": { + "type": "reference", + "serviceable": false, + "sha512": "" + }, + "Fantasy-Net.Reference/1.0.0.0": { + "type": "reference", + "serviceable": false, + "sha512": "" + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Server/Hotfix/bin/Debug/net8.0/Hotfix.dll b/物品和背包的完整代码/Server/Hotfix/bin/Debug/net8.0/Hotfix.dll new file mode 100644 index 0000000..a491c75 Binary files /dev/null and b/物品和背包的完整代码/Server/Hotfix/bin/Debug/net8.0/Hotfix.dll differ diff --git a/物品和背包的完整代码/Server/Hotfix/bin/Debug/net8.0/Hotfix.pdb b/物品和背包的完整代码/Server/Hotfix/bin/Debug/net8.0/Hotfix.pdb new file mode 100644 index 0000000..a981aa2 Binary files /dev/null and b/物品和背包的完整代码/Server/Hotfix/bin/Debug/net8.0/Hotfix.pdb differ diff --git a/物品和背包的完整代码/Server/Hotfix/obj/Debug/net8.0/.NETCoreApp,Version=v8.0.AssemblyAttributes.cs b/物品和背包的完整代码/Server/Hotfix/obj/Debug/net8.0/.NETCoreApp,Version=v8.0.AssemblyAttributes.cs new file mode 100644 index 0000000..2217181 --- /dev/null +++ b/物品和背包的完整代码/Server/Hotfix/obj/Debug/net8.0/.NETCoreApp,Version=v8.0.AssemblyAttributes.cs @@ -0,0 +1,4 @@ +// +using System; +using System.Reflection; +[assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute(".NETCoreApp,Version=v8.0", FrameworkDisplayName = ".NET 8.0")] diff --git a/物品和背包的完整代码/Server/Hotfix/obj/Debug/net8.0/Hotfix.AssemblyInfo.cs b/物品和背包的完整代码/Server/Hotfix/obj/Debug/net8.0/Hotfix.AssemblyInfo.cs new file mode 100644 index 0000000..10dae85 --- /dev/null +++ b/物品和背包的完整代码/Server/Hotfix/obj/Debug/net8.0/Hotfix.AssemblyInfo.cs @@ -0,0 +1,22 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +using System; +using System.Reflection; + +[assembly: System.Reflection.AssemblyCompanyAttribute("Hotfix")] +[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")] +[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")] +[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0")] +[assembly: System.Reflection.AssemblyProductAttribute("Hotfix")] +[assembly: System.Reflection.AssemblyTitleAttribute("Hotfix")] +[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")] + +// 由 MSBuild WriteCodeFragment 类生成。 + diff --git a/物品和背包的完整代码/Server/Hotfix/obj/Debug/net8.0/Hotfix.AssemblyInfoInputs.cache b/物品和背包的完整代码/Server/Hotfix/obj/Debug/net8.0/Hotfix.AssemblyInfoInputs.cache new file mode 100644 index 0000000..fba9c22 --- /dev/null +++ b/物品和背包的完整代码/Server/Hotfix/obj/Debug/net8.0/Hotfix.AssemblyInfoInputs.cache @@ -0,0 +1 @@ +28c7ffb99846e407a4d90a66ddc760b2a3412294f39e5810dd7ee1d10f0462a6 diff --git a/物品和背包的完整代码/Server/Hotfix/obj/Debug/net8.0/Hotfix.GeneratedMSBuildEditorConfig.editorconfig b/物品和背包的完整代码/Server/Hotfix/obj/Debug/net8.0/Hotfix.GeneratedMSBuildEditorConfig.editorconfig new file mode 100644 index 0000000..04297b3 --- /dev/null +++ b/物品和背包的完整代码/Server/Hotfix/obj/Debug/net8.0/Hotfix.GeneratedMSBuildEditorConfig.editorconfig @@ -0,0 +1,15 @@ +is_global = true +build_property.TargetFramework = net8.0 +build_property.TargetPlatformMinVersion = +build_property.UsingMicrosoftNETSdkWeb = +build_property.ProjectTypeGuids = +build_property.InvariantGlobalization = +build_property.PlatformNeutralAssembly = +build_property.EnforceExtendedAnalyzerRules = +build_property._SupportedPlatformList = Linux,macOS,Windows +build_property.RootNamespace = Hotfix +build_property.ProjectDir = /Users/fantasy/Movies/物品背包开发之旅/B/Server/Hotfix/ +build_property.EnableComHosting = +build_property.EnableGeneratedComInterfaceComImportInterop = +build_property.EffectiveAnalysisLevelStyle = 8.0 +build_property.EnableCodeStyleSeverity = diff --git a/物品和背包的完整代码/Server/Hotfix/obj/Debug/net8.0/Hotfix.GlobalUsings.g.cs b/物品和背包的完整代码/Server/Hotfix/obj/Debug/net8.0/Hotfix.GlobalUsings.g.cs new file mode 100644 index 0000000..8578f3d --- /dev/null +++ b/物品和背包的完整代码/Server/Hotfix/obj/Debug/net8.0/Hotfix.GlobalUsings.g.cs @@ -0,0 +1,8 @@ +// +global using global::System; +global using global::System.Collections.Generic; +global using global::System.IO; +global using global::System.Linq; +global using global::System.Net.Http; +global using global::System.Threading; +global using global::System.Threading.Tasks; diff --git a/物品和背包的完整代码/Server/Hotfix/obj/Debug/net8.0/Hotfix.assets.cache b/物品和背包的完整代码/Server/Hotfix/obj/Debug/net8.0/Hotfix.assets.cache new file mode 100644 index 0000000..b7c59f9 Binary files /dev/null and b/物品和背包的完整代码/Server/Hotfix/obj/Debug/net8.0/Hotfix.assets.cache differ diff --git a/物品和背包的完整代码/Server/Hotfix/obj/Debug/net8.0/Hotfix.csproj.AssemblyReference.cache b/物品和背包的完整代码/Server/Hotfix/obj/Debug/net8.0/Hotfix.csproj.AssemblyReference.cache new file mode 100644 index 0000000..5b2a58c Binary files /dev/null and b/物品和背包的完整代码/Server/Hotfix/obj/Debug/net8.0/Hotfix.csproj.AssemblyReference.cache differ diff --git a/物品和背包的完整代码/Server/Hotfix/obj/Debug/net8.0/Hotfix.csproj.CoreCompileInputs.cache b/物品和背包的完整代码/Server/Hotfix/obj/Debug/net8.0/Hotfix.csproj.CoreCompileInputs.cache new file mode 100644 index 0000000..4bd1d62 --- /dev/null +++ b/物品和背包的完整代码/Server/Hotfix/obj/Debug/net8.0/Hotfix.csproj.CoreCompileInputs.cache @@ -0,0 +1 @@ +8180230488d9aea07d5a530dcacdb95da1678979ab4b00047598415b534951e6 diff --git a/物品和背包的完整代码/Server/Hotfix/obj/Debug/net8.0/Hotfix.csproj.FileListAbsolute.txt b/物品和背包的完整代码/Server/Hotfix/obj/Debug/net8.0/Hotfix.csproj.FileListAbsolute.txt new file mode 100644 index 0000000..481d697 --- /dev/null +++ b/物品和背包的完整代码/Server/Hotfix/obj/Debug/net8.0/Hotfix.csproj.FileListAbsolute.txt @@ -0,0 +1,19 @@ +/Users/fantasy/Movies/物品背包开发之旅/B/Server/Hotfix/bin/Debug/net8.0/Hotfix.deps.json +/Users/fantasy/Movies/物品背包开发之旅/B/Server/Hotfix/bin/Debug/net8.0/Hotfix.dll +/Users/fantasy/Movies/物品背包开发之旅/B/Server/Hotfix/bin/Debug/net8.0/Hotfix.pdb +/Users/fantasy/Movies/物品背包开发之旅/B/Server/Hotfix/bin/Debug/net8.0/Entity.dll +/Users/fantasy/Movies/物品背包开发之旅/B/Server/Hotfix/bin/Debug/net8.0/Entity.pdb +/Users/fantasy/Movies/物品背包开发之旅/B/Server/Hotfix/obj/Debug/net8.0/Hotfix.csproj.AssemblyReference.cache +/Users/fantasy/Movies/物品背包开发之旅/B/Server/Hotfix/obj/Debug/net8.0/Hotfix.GeneratedMSBuildEditorConfig.editorconfig +/Users/fantasy/Movies/物品背包开发之旅/B/Server/Hotfix/obj/Debug/net8.0/Hotfix.AssemblyInfoInputs.cache +/Users/fantasy/Movies/物品背包开发之旅/B/Server/Hotfix/obj/Debug/net8.0/Hotfix.AssemblyInfo.cs +/Users/fantasy/Movies/物品背包开发之旅/B/Server/Hotfix/obj/Debug/net8.0/Hotfix.csproj.CoreCompileInputs.cache +/Users/fantasy/Movies/物品背包开发之旅/B/Server/Hotfix/obj/Debug/net8.0/Hotfix.csproj.Up2Date +/Users/fantasy/Movies/物品背包开发之旅/B/Server/Hotfix/obj/Debug/net8.0/Hotfix.dll +/Users/fantasy/Movies/物品背包开发之旅/B/Server/Hotfix/obj/Debug/net8.0/refint/Hotfix.dll +/Users/fantasy/Movies/物品背包开发之旅/B/Server/Hotfix/obj/Debug/net8.0/Hotfix.pdb +/Users/fantasy/Movies/物品背包开发之旅/B/Server/Hotfix/obj/Debug/net8.0/ref/Hotfix.dll +/Users/fantasy/Movies/物品背包开发之旅/B/Server/Hotfix/bin/Debug/net8.0/Fantasy-Net.dll +/Users/fantasy/Movies/物品背包开发之旅/B/Server/Hotfix/bin/Debug/net8.0/Fantasy-Net.pdb +/Users/fantasy/Movies/物品背包开发之旅/B/Server/Hotfix/bin/Debug/net8.0/Fantasy-Net.ConfigTable.dll +/Users/fantasy/Movies/物品背包开发之旅/B/Server/Hotfix/bin/Debug/net8.0/Fantasy-Net.ConfigTable.pdb diff --git a/物品和背包的完整代码/Server/Hotfix/obj/Debug/net8.0/Hotfix.csproj.Up2Date b/物品和背包的完整代码/Server/Hotfix/obj/Debug/net8.0/Hotfix.csproj.Up2Date new file mode 100644 index 0000000..e69de29 diff --git a/物品和背包的完整代码/Server/Hotfix/obj/Debug/net8.0/Hotfix.dll b/物品和背包的完整代码/Server/Hotfix/obj/Debug/net8.0/Hotfix.dll new file mode 100644 index 0000000..a491c75 Binary files /dev/null and b/物品和背包的完整代码/Server/Hotfix/obj/Debug/net8.0/Hotfix.dll differ diff --git a/物品和背包的完整代码/Server/Hotfix/obj/Debug/net8.0/Hotfix.pdb b/物品和背包的完整代码/Server/Hotfix/obj/Debug/net8.0/Hotfix.pdb new file mode 100644 index 0000000..a981aa2 Binary files /dev/null and b/物品和背包的完整代码/Server/Hotfix/obj/Debug/net8.0/Hotfix.pdb differ diff --git a/物品和背包的完整代码/Server/Hotfix/obj/Debug/net8.0/ref/Hotfix.dll b/物品和背包的完整代码/Server/Hotfix/obj/Debug/net8.0/ref/Hotfix.dll new file mode 100644 index 0000000..1e24d38 Binary files /dev/null and b/物品和背包的完整代码/Server/Hotfix/obj/Debug/net8.0/ref/Hotfix.dll differ diff --git a/物品和背包的完整代码/Server/Hotfix/obj/Debug/net8.0/refint/Hotfix.dll b/物品和背包的完整代码/Server/Hotfix/obj/Debug/net8.0/refint/Hotfix.dll new file mode 100644 index 0000000..1e24d38 Binary files /dev/null and b/物品和背包的完整代码/Server/Hotfix/obj/Debug/net8.0/refint/Hotfix.dll differ diff --git a/物品和背包的完整代码/Server/Hotfix/obj/Hotfix.csproj.nuget.dgspec.json b/物品和背包的完整代码/Server/Hotfix/obj/Hotfix.csproj.nuget.dgspec.json new file mode 100644 index 0000000..5642060 --- /dev/null +++ b/物品和背包的完整代码/Server/Hotfix/obj/Hotfix.csproj.nuget.dgspec.json @@ -0,0 +1,346 @@ +{ + "format": 1, + "restore": { + "/Users/fantasy/Movies/物品背包开发之旅/B/Server/Hotfix/Hotfix.csproj": {} + }, + "projects": { + "/Users/fantasy/Movies/物品背包开发之旅/B/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Fantasy.Net.csproj": { + "version": "2024.2.24", + "restore": { + "projectUniqueName": "/Users/fantasy/Movies/物品背包开发之旅/B/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Fantasy.Net.csproj", + "projectName": "Fantasy-Net", + "projectPath": "/Users/fantasy/Movies/物品背包开发之旅/B/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Fantasy.Net.csproj", + "packagesPath": "/Users/fantasy/.nuget/packages/", + "outputPath": "/Users/fantasy/Movies/物品背包开发之旅/B/Packages/Fantasy/Fantasy.Net/Fantasy.Net/obj/", + "projectStyle": "PackageReference", + "crossTargeting": true, + "configFilePaths": [ + "/Users/fantasy/.nuget/NuGet/NuGet.Config" + ], + "originalTargetFrameworks": [ + "net8.0", + "net9.0" + ], + "sources": { + "/usr/local/share/dotnet/library-packs": {}, + "https://api.nuget.org/v3/index.json": {} + }, + "frameworks": { + "net8.0": { + "targetAlias": "net8.0", + "projectReferences": {} + }, + "net9.0": { + "targetAlias": "net9.0", + "projectReferences": {} + } + }, + "warningProperties": { + "allWarningsAsErrors": true, + "warnAsError": [ + "NU1605" + ] + }, + "restoreAuditProperties": { + "enableAudit": "true", + "auditLevel": "low", + "auditMode": "all" + }, + "SdkAnalysisLevel": "9.0.100" + }, + "frameworks": { + "net8.0": { + "targetAlias": "net8.0", + "dependencies": { + "CommandLineParser": { + "target": "Package", + "version": "[2.9.1, )" + }, + "MongoDB.Bson": { + "target": "Package", + "version": "[3.1.0, )" + }, + "MongoDB.Driver": { + "target": "Package", + "version": "[3.1.0, )" + }, + "Newtonsoft.Json": { + "target": "Package", + "version": "[13.0.3, )" + }, + "System.IO.Pipelines": { + "target": "Package", + "version": "[9.0.0, )" + }, + "protobuf-net": { + "target": "Package", + "version": "[3.2.45, )" + } + }, + "imports": [ + "net461", + "net462", + "net47", + "net471", + "net472", + "net48", + "net481" + ], + "assetTargetFallback": true, + "warn": true, + "frameworkReferences": { + "Microsoft.AspNetCore.App": { + "privateAssets": "none" + }, + "Microsoft.NETCore.App": { + "privateAssets": "all" + } + }, + "runtimeIdentifierGraphPath": "/usr/local/share/dotnet/sdk/9.0.100/PortableRuntimeIdentifierGraph.json" + }, + "net9.0": { + "targetAlias": "net9.0", + "dependencies": { + "CommandLineParser": { + "target": "Package", + "version": "[2.9.1, )" + }, + "MongoDB.Bson": { + "target": "Package", + "version": "[3.1.0, )" + }, + "MongoDB.Driver": { + "target": "Package", + "version": "[3.1.0, )" + }, + "Newtonsoft.Json": { + "target": "Package", + "version": "[13.0.3, )" + }, + "protobuf-net": { + "target": "Package", + "version": "[3.2.45, )" + } + }, + "imports": [ + "net461", + "net462", + "net47", + "net471", + "net472", + "net48", + "net481" + ], + "assetTargetFallback": true, + "warn": true, + "frameworkReferences": { + "Microsoft.AspNetCore.App": { + "privateAssets": "none" + }, + "Microsoft.NETCore.App": { + "privateAssets": "all" + } + }, + "runtimeIdentifierGraphPath": "/usr/local/share/dotnet/sdk/9.0.100/PortableRuntimeIdentifierGraph.json" + } + } + }, + "/Users/fantasy/Movies/物品背包开发之旅/B/Packages/Fantasy/Fantasy.Packages/Fantasy.ConfigTable/Net/Fantasy.ConfigTable.csproj": { + "version": "2024.2.0", + "restore": { + "projectUniqueName": "/Users/fantasy/Movies/物品背包开发之旅/B/Packages/Fantasy/Fantasy.Packages/Fantasy.ConfigTable/Net/Fantasy.ConfigTable.csproj", + "projectName": "Fantasy-Net.ConfigTable", + "projectPath": "/Users/fantasy/Movies/物品背包开发之旅/B/Packages/Fantasy/Fantasy.Packages/Fantasy.ConfigTable/Net/Fantasy.ConfigTable.csproj", + "packagesPath": "/Users/fantasy/.nuget/packages/", + "outputPath": "/Users/fantasy/Movies/物品背包开发之旅/B/Packages/Fantasy/Fantasy.Packages/Fantasy.ConfigTable/Net/obj/", + "projectStyle": "PackageReference", + "configFilePaths": [ + "/Users/fantasy/.nuget/NuGet/NuGet.Config" + ], + "originalTargetFrameworks": [ + "net8.0" + ], + "sources": { + "/usr/local/share/dotnet/library-packs": {}, + "https://api.nuget.org/v3/index.json": {} + }, + "frameworks": { + "net8.0": { + "targetAlias": "net8.0", + "projectReferences": {} + } + }, + "warningProperties": { + "warnAsError": [ + "NU1605" + ] + }, + "restoreAuditProperties": { + "enableAudit": "true", + "auditLevel": "low", + "auditMode": "all" + }, + "SdkAnalysisLevel": "9.0.100" + }, + "frameworks": { + "net8.0": { + "targetAlias": "net8.0", + "dependencies": { + "Fantasy-Net": { + "target": "Package", + "version": "[2024.2.22, )" + } + }, + "imports": [ + "net461", + "net462", + "net47", + "net471", + "net472", + "net48", + "net481" + ], + "assetTargetFallback": true, + "warn": true, + "frameworkReferences": { + "Microsoft.NETCore.App": { + "privateAssets": "all" + } + }, + "runtimeIdentifierGraphPath": "/usr/local/share/dotnet/sdk/9.0.100/PortableRuntimeIdentifierGraph.json" + } + } + }, + "/Users/fantasy/Movies/物品背包开发之旅/B/Server/Entity/Entity.csproj": { + "version": "1.0.0", + "restore": { + "projectUniqueName": "/Users/fantasy/Movies/物品背包开发之旅/B/Server/Entity/Entity.csproj", + "projectName": "Entity", + "projectPath": "/Users/fantasy/Movies/物品背包开发之旅/B/Server/Entity/Entity.csproj", + "packagesPath": "/Users/fantasy/.nuget/packages/", + "outputPath": "/Users/fantasy/Movies/物品背包开发之旅/B/Server/Entity/obj/", + "projectStyle": "PackageReference", + "configFilePaths": [ + "/Users/fantasy/.nuget/NuGet/NuGet.Config" + ], + "originalTargetFrameworks": [ + "net8.0" + ], + "sources": { + "/usr/local/share/dotnet/library-packs": {}, + "https://api.nuget.org/v3/index.json": {} + }, + "frameworks": { + "net8.0": { + "targetAlias": "net8.0", + "projectReferences": { + "/Users/fantasy/Movies/物品背包开发之旅/B/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Fantasy.Net.csproj": { + "projectPath": "/Users/fantasy/Movies/物品背包开发之旅/B/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Fantasy.Net.csproj" + }, + "/Users/fantasy/Movies/物品背包开发之旅/B/Packages/Fantasy/Fantasy.Packages/Fantasy.ConfigTable/Net/Fantasy.ConfigTable.csproj": { + "projectPath": "/Users/fantasy/Movies/物品背包开发之旅/B/Packages/Fantasy/Fantasy.Packages/Fantasy.ConfigTable/Net/Fantasy.ConfigTable.csproj" + } + } + } + }, + "warningProperties": { + "warnAsError": [ + "NU1605" + ] + }, + "restoreAuditProperties": { + "enableAudit": "true", + "auditLevel": "low", + "auditMode": "all" + }, + "SdkAnalysisLevel": "9.0.100" + }, + "frameworks": { + "net8.0": { + "targetAlias": "net8.0", + "imports": [ + "net461", + "net462", + "net47", + "net471", + "net472", + "net48", + "net481" + ], + "assetTargetFallback": true, + "warn": true, + "frameworkReferences": { + "Microsoft.NETCore.App": { + "privateAssets": "all" + } + }, + "runtimeIdentifierGraphPath": "/usr/local/share/dotnet/sdk/9.0.100/PortableRuntimeIdentifierGraph.json" + } + } + }, + "/Users/fantasy/Movies/物品背包开发之旅/B/Server/Hotfix/Hotfix.csproj": { + "version": "1.0.0", + "restore": { + "projectUniqueName": "/Users/fantasy/Movies/物品背包开发之旅/B/Server/Hotfix/Hotfix.csproj", + "projectName": "Hotfix", + "projectPath": "/Users/fantasy/Movies/物品背包开发之旅/B/Server/Hotfix/Hotfix.csproj", + "packagesPath": "/Users/fantasy/.nuget/packages/", + "outputPath": "/Users/fantasy/Movies/物品背包开发之旅/B/Server/Hotfix/obj/", + "projectStyle": "PackageReference", + "configFilePaths": [ + "/Users/fantasy/.nuget/NuGet/NuGet.Config" + ], + "originalTargetFrameworks": [ + "net8.0" + ], + "sources": { + "/usr/local/share/dotnet/library-packs": {}, + "https://api.nuget.org/v3/index.json": {} + }, + "frameworks": { + "net8.0": { + "targetAlias": "net8.0", + "projectReferences": { + "/Users/fantasy/Movies/物品背包开发之旅/B/Server/Entity/Entity.csproj": { + "projectPath": "/Users/fantasy/Movies/物品背包开发之旅/B/Server/Entity/Entity.csproj" + } + } + } + }, + "warningProperties": { + "warnAsError": [ + "NU1605" + ] + }, + "restoreAuditProperties": { + "enableAudit": "true", + "auditLevel": "low", + "auditMode": "all" + }, + "SdkAnalysisLevel": "9.0.100" + }, + "frameworks": { + "net8.0": { + "targetAlias": "net8.0", + "imports": [ + "net461", + "net462", + "net47", + "net471", + "net472", + "net48", + "net481" + ], + "assetTargetFallback": true, + "warn": true, + "frameworkReferences": { + "Microsoft.NETCore.App": { + "privateAssets": "all" + } + }, + "runtimeIdentifierGraphPath": "/usr/local/share/dotnet/sdk/9.0.100/PortableRuntimeIdentifierGraph.json" + } + } + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Server/Hotfix/obj/Hotfix.csproj.nuget.g.props b/物品和背包的完整代码/Server/Hotfix/obj/Hotfix.csproj.nuget.g.props new file mode 100644 index 0000000..f402062 --- /dev/null +++ b/物品和背包的完整代码/Server/Hotfix/obj/Hotfix.csproj.nuget.g.props @@ -0,0 +1,15 @@ + + + + True + NuGet + $(MSBuildThisFileDirectory)project.assets.json + /Users/fantasy/.nuget/packages/ + /Users/fantasy/.nuget/packages/ + PackageReference + 6.12.2 + + + + + \ No newline at end of file diff --git a/物品和背包的完整代码/Server/Hotfix/obj/Hotfix.csproj.nuget.g.targets b/物品和背包的完整代码/Server/Hotfix/obj/Hotfix.csproj.nuget.g.targets new file mode 100644 index 0000000..3dc06ef --- /dev/null +++ b/物品和背包的完整代码/Server/Hotfix/obj/Hotfix.csproj.nuget.g.targets @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/物品和背包的完整代码/Server/Hotfix/obj/project.assets.json b/物品和背包的完整代码/Server/Hotfix/obj/project.assets.json new file mode 100644 index 0000000..b939bfe --- /dev/null +++ b/物品和背包的完整代码/Server/Hotfix/obj/project.assets.json @@ -0,0 +1,971 @@ +{ + "version": 3, + "targets": { + "net8.0": { + "CommandLineParser/2.9.1": { + "type": "package", + "compile": { + "lib/netstandard2.0/CommandLine.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netstandard2.0/CommandLine.dll": { + "related": ".xml" + } + } + }, + "DnsClient/1.6.1": { + "type": "package", + "dependencies": { + "Microsoft.Win32.Registry": "5.0.0" + }, + "compile": { + "lib/net5.0/DnsClient.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net5.0/DnsClient.dll": { + "related": ".xml" + } + } + }, + "Microsoft.Extensions.Logging.Abstractions/2.0.0": { + "type": "package", + "compile": { + "lib/netstandard2.0/Microsoft.Extensions.Logging.Abstractions.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netstandard2.0/Microsoft.Extensions.Logging.Abstractions.dll": { + "related": ".xml" + } + } + }, + "Microsoft.NETCore.Platforms/5.0.0": { + "type": "package", + "compile": { + "lib/netstandard1.0/_._": {} + }, + "runtime": { + "lib/netstandard1.0/_._": {} + } + }, + "Microsoft.Win32.Registry/5.0.0": { + "type": "package", + "dependencies": { + "System.Security.AccessControl": "5.0.0", + "System.Security.Principal.Windows": "5.0.0" + }, + "compile": { + "ref/netstandard2.0/Microsoft.Win32.Registry.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netstandard2.0/Microsoft.Win32.Registry.dll": { + "related": ".xml" + } + }, + "runtimeTargets": { + "runtimes/win/lib/netstandard2.0/Microsoft.Win32.Registry.dll": { + "assetType": "runtime", + "rid": "win" + } + } + }, + "MongoDB.Bson/3.1.0": { + "type": "package", + "dependencies": { + "System.Memory": "4.5.5", + "System.Runtime.CompilerServices.Unsafe": "5.0.0" + }, + "compile": { + "lib/net6.0/MongoDB.Bson.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net6.0/MongoDB.Bson.dll": { + "related": ".xml" + } + } + }, + "MongoDB.Driver/3.1.0": { + "type": "package", + "dependencies": { + "DnsClient": "1.6.1", + "Microsoft.Extensions.Logging.Abstractions": "2.0.0", + "MongoDB.Bson": "3.1.0", + "SharpCompress": "0.30.1", + "Snappier": "1.0.0", + "System.Buffers": "4.5.1", + "ZstdSharp.Port": "0.7.3" + }, + "compile": { + "lib/net6.0/MongoDB.Driver.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net6.0/MongoDB.Driver.dll": { + "related": ".xml" + } + } + }, + "Newtonsoft.Json/13.0.3": { + "type": "package", + "compile": { + "lib/net6.0/Newtonsoft.Json.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net6.0/Newtonsoft.Json.dll": { + "related": ".xml" + } + } + }, + "protobuf-net/3.2.45": { + "type": "package", + "dependencies": { + "protobuf-net.Core": "3.2.45" + }, + "compile": { + "lib/net6.0/protobuf-net.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net6.0/protobuf-net.dll": { + "related": ".xml" + } + } + }, + "protobuf-net.Core/3.2.45": { + "type": "package", + "dependencies": { + "System.Collections.Immutable": "7.0.0" + }, + "compile": { + "lib/net6.0/protobuf-net.Core.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net6.0/protobuf-net.Core.dll": { + "related": ".xml" + } + } + }, + "SharpCompress/0.30.1": { + "type": "package", + "compile": { + "lib/net5.0/SharpCompress.dll": {} + }, + "runtime": { + "lib/net5.0/SharpCompress.dll": {} + } + }, + "Snappier/1.0.0": { + "type": "package", + "compile": { + "lib/net5.0/Snappier.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net5.0/Snappier.dll": { + "related": ".xml" + } + } + }, + "System.Buffers/4.5.1": { + "type": "package", + "compile": { + "ref/netcoreapp2.0/_._": {} + }, + "runtime": { + "lib/netcoreapp2.0/_._": {} + } + }, + "System.Collections.Immutable/7.0.0": { + "type": "package", + "compile": { + "lib/net7.0/System.Collections.Immutable.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net7.0/System.Collections.Immutable.dll": { + "related": ".xml" + } + }, + "build": { + "buildTransitive/net6.0/_._": {} + } + }, + "System.IO.Pipelines/9.0.0": { + "type": "package", + "compile": { + "lib/net8.0/System.IO.Pipelines.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net8.0/System.IO.Pipelines.dll": { + "related": ".xml" + } + }, + "build": { + "buildTransitive/net8.0/_._": {} + } + }, + "System.Memory/4.5.5": { + "type": "package", + "compile": { + "ref/netcoreapp2.1/_._": {} + }, + "runtime": { + "lib/netcoreapp2.1/_._": {} + } + }, + "System.Runtime.CompilerServices.Unsafe/5.0.0": { + "type": "package", + "compile": { + "ref/netstandard2.1/System.Runtime.CompilerServices.Unsafe.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netcoreapp2.0/System.Runtime.CompilerServices.Unsafe.dll": { + "related": ".xml" + } + } + }, + "System.Security.AccessControl/5.0.0": { + "type": "package", + "dependencies": { + "Microsoft.NETCore.Platforms": "5.0.0", + "System.Security.Principal.Windows": "5.0.0" + }, + "compile": { + "ref/netstandard2.0/System.Security.AccessControl.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netstandard2.0/System.Security.AccessControl.dll": { + "related": ".xml" + } + }, + "runtimeTargets": { + "runtimes/win/lib/netcoreapp2.0/System.Security.AccessControl.dll": { + "assetType": "runtime", + "rid": "win" + } + } + }, + "System.Security.Principal.Windows/5.0.0": { + "type": "package", + "compile": { + "ref/netcoreapp3.0/System.Security.Principal.Windows.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netstandard2.0/System.Security.Principal.Windows.dll": { + "related": ".xml" + } + }, + "runtimeTargets": { + "runtimes/unix/lib/netcoreapp2.1/System.Security.Principal.Windows.dll": { + "assetType": "runtime", + "rid": "unix" + }, + "runtimes/win/lib/netcoreapp2.1/System.Security.Principal.Windows.dll": { + "assetType": "runtime", + "rid": "win" + } + } + }, + "ZstdSharp.Port/0.7.3": { + "type": "package", + "compile": { + "lib/net7.0/ZstdSharp.dll": {} + }, + "runtime": { + "lib/net7.0/ZstdSharp.dll": {} + } + }, + "Entity/1.0.0": { + "type": "project", + "framework": ".NETCoreApp,Version=v8.0", + "dependencies": { + "Fantasy-Net": "2024.2.24", + "Fantasy-Net.ConfigTable": "2024.2.0" + }, + "compile": { + "bin/placeholder/Entity.dll": {} + }, + "runtime": { + "bin/placeholder/Entity.dll": {} + } + }, + "Fantasy-Net/2024.2.24": { + "type": "project", + "framework": ".NETCoreApp,Version=v8.0", + "dependencies": { + "CommandLineParser": "2.9.1", + "MongoDB.Bson": "3.1.0", + "MongoDB.Driver": "3.1.0", + "Newtonsoft.Json": "13.0.3", + "System.IO.Pipelines": "9.0.0", + "protobuf-net": "3.2.45" + }, + "compile": { + "bin/placeholder/Fantasy-Net.dll": {} + }, + "runtime": { + "bin/placeholder/Fantasy-Net.dll": {} + }, + "frameworkReferences": [ + "Microsoft.AspNetCore.App" + ] + }, + "Fantasy-Net.ConfigTable/2024.2.0": { + "type": "project", + "framework": ".NETCoreApp,Version=v8.0", + "dependencies": { + "Fantasy-Net": "2024.2.22" + }, + "compile": { + "bin/placeholder/Fantasy-Net.ConfigTable.dll": {} + }, + "runtime": { + "bin/placeholder/Fantasy-Net.ConfigTable.dll": {} + } + } + } + }, + "libraries": { + "CommandLineParser/2.9.1": { + "sha512": "OE0sl1/sQ37bjVsPKKtwQlWDgqaxWgtme3xZz7JssWUzg5JpMIyHgCTY9MVMxOg48fJ1AgGT3tgdH5m/kQ5xhA==", + "type": "package", + "path": "commandlineparser/2.9.1", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "CommandLine20.png", + "License.md", + "README.md", + "commandlineparser.2.9.1.nupkg.sha512", + "commandlineparser.nuspec", + "lib/net40/CommandLine.dll", + "lib/net40/CommandLine.xml", + "lib/net45/CommandLine.dll", + "lib/net45/CommandLine.xml", + "lib/net461/CommandLine.dll", + "lib/net461/CommandLine.xml", + "lib/netstandard2.0/CommandLine.dll", + "lib/netstandard2.0/CommandLine.xml" + ] + }, + "DnsClient/1.6.1": { + "sha512": "4H/f2uYJOZ+YObZjpY9ABrKZI+JNw3uizp6oMzTXwDw6F+2qIPhpRl/1t68O/6e98+vqNiYGu+lswmwdYUy3gg==", + "type": "package", + "path": "dnsclient/1.6.1", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "dnsclient.1.6.1.nupkg.sha512", + "dnsclient.nuspec", + "icon.png", + "lib/net45/DnsClient.dll", + "lib/net45/DnsClient.xml", + "lib/net471/DnsClient.dll", + "lib/net471/DnsClient.xml", + "lib/net5.0/DnsClient.dll", + "lib/net5.0/DnsClient.xml", + "lib/netstandard1.3/DnsClient.dll", + "lib/netstandard1.3/DnsClient.xml", + "lib/netstandard2.0/DnsClient.dll", + "lib/netstandard2.0/DnsClient.xml", + "lib/netstandard2.1/DnsClient.dll", + "lib/netstandard2.1/DnsClient.xml" + ] + }, + "Microsoft.Extensions.Logging.Abstractions/2.0.0": { + "sha512": "6ZCllUYGFukkymSTx3Yr0G/ajRxoNJp7/FqSxSB4fGISST54ifBhgu4Nc0ItGi3i6DqwuNd8SUyObmiC++AO2Q==", + "type": "package", + "path": "microsoft.extensions.logging.abstractions/2.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "lib/netstandard2.0/Microsoft.Extensions.Logging.Abstractions.dll", + "lib/netstandard2.0/Microsoft.Extensions.Logging.Abstractions.xml", + "microsoft.extensions.logging.abstractions.2.0.0.nupkg.sha512", + "microsoft.extensions.logging.abstractions.nuspec" + ] + }, + "Microsoft.NETCore.Platforms/5.0.0": { + "sha512": "VyPlqzH2wavqquTcYpkIIAQ6WdenuKoFN0BdYBbCWsclXacSOHNQn66Gt4z5NBqEYW0FAPm5rlvki9ZiCij5xQ==", + "type": "package", + "path": "microsoft.netcore.platforms/5.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "LICENSE.TXT", + "THIRD-PARTY-NOTICES.TXT", + "lib/netstandard1.0/_._", + "microsoft.netcore.platforms.5.0.0.nupkg.sha512", + "microsoft.netcore.platforms.nuspec", + "runtime.json", + "useSharedDesignerContext.txt", + "version.txt" + ] + }, + "Microsoft.Win32.Registry/5.0.0": { + "sha512": "dDoKi0PnDz31yAyETfRntsLArTlVAVzUzCIvvEDsDsucrl33Dl8pIJG06ePTJTI3tGpeyHS9Cq7Foc/s4EeKcg==", + "type": "package", + "path": "microsoft.win32.registry/5.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "LICENSE.TXT", + "THIRD-PARTY-NOTICES.TXT", + "lib/net46/Microsoft.Win32.Registry.dll", + "lib/net461/Microsoft.Win32.Registry.dll", + "lib/net461/Microsoft.Win32.Registry.xml", + "lib/netstandard1.3/Microsoft.Win32.Registry.dll", + "lib/netstandard2.0/Microsoft.Win32.Registry.dll", + "lib/netstandard2.0/Microsoft.Win32.Registry.xml", + "microsoft.win32.registry.5.0.0.nupkg.sha512", + "microsoft.win32.registry.nuspec", + "ref/net46/Microsoft.Win32.Registry.dll", + "ref/net461/Microsoft.Win32.Registry.dll", + "ref/net461/Microsoft.Win32.Registry.xml", + "ref/netstandard1.3/Microsoft.Win32.Registry.dll", + "ref/netstandard1.3/Microsoft.Win32.Registry.xml", + "ref/netstandard1.3/de/Microsoft.Win32.Registry.xml", + "ref/netstandard1.3/es/Microsoft.Win32.Registry.xml", + "ref/netstandard1.3/fr/Microsoft.Win32.Registry.xml", + "ref/netstandard1.3/it/Microsoft.Win32.Registry.xml", + "ref/netstandard1.3/ja/Microsoft.Win32.Registry.xml", + "ref/netstandard1.3/ko/Microsoft.Win32.Registry.xml", + "ref/netstandard1.3/ru/Microsoft.Win32.Registry.xml", + "ref/netstandard1.3/zh-hans/Microsoft.Win32.Registry.xml", + "ref/netstandard1.3/zh-hant/Microsoft.Win32.Registry.xml", + "ref/netstandard2.0/Microsoft.Win32.Registry.dll", + "ref/netstandard2.0/Microsoft.Win32.Registry.xml", + "runtimes/win/lib/net46/Microsoft.Win32.Registry.dll", + "runtimes/win/lib/net461/Microsoft.Win32.Registry.dll", + "runtimes/win/lib/net461/Microsoft.Win32.Registry.xml", + "runtimes/win/lib/netstandard1.3/Microsoft.Win32.Registry.dll", + "runtimes/win/lib/netstandard2.0/Microsoft.Win32.Registry.dll", + "runtimes/win/lib/netstandard2.0/Microsoft.Win32.Registry.xml", + "useSharedDesignerContext.txt", + "version.txt" + ] + }, + "MongoDB.Bson/3.1.0": { + "sha512": "3dhaZhz18B5vUoEP13o2j8A6zQfkHdZhwBvLZEjDJum4BTLLv1/Z8bt25UQEtpqvYwLgde4R6ekWZ7XAYUMxuw==", + "type": "package", + "path": "mongodb.bson/3.1.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "README.md", + "lib/net472/MongoDB.Bson.dll", + "lib/net472/MongoDB.Bson.xml", + "lib/net6.0/MongoDB.Bson.dll", + "lib/net6.0/MongoDB.Bson.xml", + "lib/netstandard2.1/MongoDB.Bson.dll", + "lib/netstandard2.1/MongoDB.Bson.xml", + "mongodb.bson.3.1.0.nupkg.sha512", + "mongodb.bson.nuspec", + "packageIcon.png" + ] + }, + "MongoDB.Driver/3.1.0": { + "sha512": "+O7lKaIl7VUHptE0hqTd7UY1G5KDp/o8S4upG7YL4uChMNKD/U6tz9i17nMGHaD/L2AiPLgaJcaDe2XACsegGA==", + "type": "package", + "path": "mongodb.driver/3.1.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "README.md", + "lib/net472/MongoDB.Driver.dll", + "lib/net472/MongoDB.Driver.xml", + "lib/net6.0/MongoDB.Driver.dll", + "lib/net6.0/MongoDB.Driver.xml", + "lib/netstandard2.1/MongoDB.Driver.dll", + "lib/netstandard2.1/MongoDB.Driver.xml", + "mongodb.driver.3.1.0.nupkg.sha512", + "mongodb.driver.nuspec", + "packageIcon.png" + ] + }, + "Newtonsoft.Json/13.0.3": { + "sha512": "HrC5BXdl00IP9zeV+0Z848QWPAoCr9P3bDEZguI+gkLcBKAOxix/tLEAAHC+UvDNPv4a2d18lOReHMOagPa+zQ==", + "type": "package", + "path": "newtonsoft.json/13.0.3", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "LICENSE.md", + "README.md", + "lib/net20/Newtonsoft.Json.dll", + "lib/net20/Newtonsoft.Json.xml", + "lib/net35/Newtonsoft.Json.dll", + "lib/net35/Newtonsoft.Json.xml", + "lib/net40/Newtonsoft.Json.dll", + "lib/net40/Newtonsoft.Json.xml", + "lib/net45/Newtonsoft.Json.dll", + "lib/net45/Newtonsoft.Json.xml", + "lib/net6.0/Newtonsoft.Json.dll", + "lib/net6.0/Newtonsoft.Json.xml", + "lib/netstandard1.0/Newtonsoft.Json.dll", + "lib/netstandard1.0/Newtonsoft.Json.xml", + "lib/netstandard1.3/Newtonsoft.Json.dll", + "lib/netstandard1.3/Newtonsoft.Json.xml", + "lib/netstandard2.0/Newtonsoft.Json.dll", + "lib/netstandard2.0/Newtonsoft.Json.xml", + "newtonsoft.json.13.0.3.nupkg.sha512", + "newtonsoft.json.nuspec", + "packageIcon.png" + ] + }, + "protobuf-net/3.2.45": { + "sha512": "5UZ/ukUHcGbFSl7vNMrHsfjqdxusdd9w7w0fCEXzf3UUtsrGNVCzV5SmF+sCHAbnRV2qPcD1ixiDP7Aj8lX/HA==", + "type": "package", + "path": "protobuf-net/3.2.45", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "lib/net462/protobuf-net.dll", + "lib/net462/protobuf-net.xml", + "lib/net6.0/protobuf-net.dll", + "lib/net6.0/protobuf-net.xml", + "lib/netstandard2.0/protobuf-net.dll", + "lib/netstandard2.0/protobuf-net.xml", + "lib/netstandard2.1/protobuf-net.dll", + "lib/netstandard2.1/protobuf-net.xml", + "protobuf-net.3.2.45.nupkg.sha512", + "protobuf-net.nuspec", + "protobuf-net.png", + "readme.md" + ] + }, + "protobuf-net.Core/3.2.45": { + "sha512": "PMWatW2NrT1uTXD7etJ4VdQ0wWZLFrIfdRGppD2QX7nzZ0+kIzqhq551u6ZiXJHWJgG4hWFEkSnUnt2aB6posg==", + "type": "package", + "path": "protobuf-net.core/3.2.45", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "lib/net462/protobuf-net.Core.dll", + "lib/net462/protobuf-net.Core.xml", + "lib/net6.0/protobuf-net.Core.dll", + "lib/net6.0/protobuf-net.Core.xml", + "lib/netstandard2.0/protobuf-net.Core.dll", + "lib/netstandard2.0/protobuf-net.Core.xml", + "lib/netstandard2.1/protobuf-net.Core.dll", + "lib/netstandard2.1/protobuf-net.Core.xml", + "protobuf-net.core.3.2.45.nupkg.sha512", + "protobuf-net.core.nuspec", + "protobuf-net.png", + "readme.md" + ] + }, + "SharpCompress/0.30.1": { + "sha512": "XqD4TpfyYGa7QTPzaGlMVbcecKnXy4YmYLDWrU+JIj7IuRNl7DH2END+Ll7ekWIY8o3dAMWLFDE1xdhfIWD1nw==", + "type": "package", + "path": "sharpcompress/0.30.1", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "lib/net461/SharpCompress.dll", + "lib/net5.0/SharpCompress.dll", + "lib/netcoreapp3.1/SharpCompress.dll", + "lib/netstandard2.0/SharpCompress.dll", + "lib/netstandard2.1/SharpCompress.dll", + "sharpcompress.0.30.1.nupkg.sha512", + "sharpcompress.nuspec" + ] + }, + "Snappier/1.0.0": { + "sha512": "rFtK2KEI9hIe8gtx3a0YDXdHOpedIf9wYCEYtBEmtlyiWVX3XlCNV03JrmmAi/Cdfn7dxK+k0sjjcLv4fpHnqA==", + "type": "package", + "path": "snappier/1.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "COPYING.txt", + "lib/net5.0/Snappier.dll", + "lib/net5.0/Snappier.xml", + "lib/netcoreapp3.0/Snappier.dll", + "lib/netcoreapp3.0/Snappier.xml", + "lib/netstandard2.0/Snappier.dll", + "lib/netstandard2.0/Snappier.xml", + "lib/netstandard2.1/Snappier.dll", + "lib/netstandard2.1/Snappier.xml", + "snappier.1.0.0.nupkg.sha512", + "snappier.nuspec" + ] + }, + "System.Buffers/4.5.1": { + "sha512": "Rw7ijyl1qqRS0YQD/WycNst8hUUMgrMH4FCn1nNm27M4VxchZ1js3fVjQaANHO5f3sN4isvP4a+Met9Y4YomAg==", + "type": "package", + "path": "system.buffers/4.5.1", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "LICENSE.TXT", + "THIRD-PARTY-NOTICES.TXT", + "lib/net461/System.Buffers.dll", + "lib/net461/System.Buffers.xml", + "lib/netcoreapp2.0/_._", + "lib/netstandard1.1/System.Buffers.dll", + "lib/netstandard1.1/System.Buffers.xml", + "lib/netstandard2.0/System.Buffers.dll", + "lib/netstandard2.0/System.Buffers.xml", + "lib/uap10.0.16299/_._", + "ref/net45/System.Buffers.dll", + "ref/net45/System.Buffers.xml", + "ref/netcoreapp2.0/_._", + "ref/netstandard1.1/System.Buffers.dll", + "ref/netstandard1.1/System.Buffers.xml", + "ref/netstandard2.0/System.Buffers.dll", + "ref/netstandard2.0/System.Buffers.xml", + "ref/uap10.0.16299/_._", + "system.buffers.4.5.1.nupkg.sha512", + "system.buffers.nuspec", + "useSharedDesignerContext.txt", + "version.txt" + ] + }, + "System.Collections.Immutable/7.0.0": { + "sha512": "dQPcs0U1IKnBdRDBkrCTi1FoajSTBzLcVTpjO4MBCMC7f4pDOIPzgBoX8JjG7X6uZRJ8EBxsi8+DR1JuwjnzOQ==", + "type": "package", + "path": "system.collections.immutable/7.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "LICENSE.TXT", + "README.md", + "THIRD-PARTY-NOTICES.TXT", + "buildTransitive/net461/System.Collections.Immutable.targets", + "buildTransitive/net462/_._", + "buildTransitive/net6.0/_._", + "buildTransitive/netcoreapp2.0/System.Collections.Immutable.targets", + "lib/net462/System.Collections.Immutable.dll", + "lib/net462/System.Collections.Immutable.xml", + "lib/net6.0/System.Collections.Immutable.dll", + "lib/net6.0/System.Collections.Immutable.xml", + "lib/net7.0/System.Collections.Immutable.dll", + "lib/net7.0/System.Collections.Immutable.xml", + "lib/netstandard2.0/System.Collections.Immutable.dll", + "lib/netstandard2.0/System.Collections.Immutable.xml", + "system.collections.immutable.7.0.0.nupkg.sha512", + "system.collections.immutable.nuspec", + "useSharedDesignerContext.txt" + ] + }, + "System.IO.Pipelines/9.0.0": { + "sha512": "eA3cinogwaNB4jdjQHOP3Z3EuyiDII7MT35jgtnsA4vkn0LUrrSHsU0nzHTzFzmaFYeKV7MYyMxOocFzsBHpTw==", + "type": "package", + "path": "system.io.pipelines/9.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "LICENSE.TXT", + "PACKAGE.md", + "THIRD-PARTY-NOTICES.TXT", + "buildTransitive/net461/System.IO.Pipelines.targets", + "buildTransitive/net462/_._", + "buildTransitive/net8.0/_._", + "buildTransitive/netcoreapp2.0/System.IO.Pipelines.targets", + "lib/net462/System.IO.Pipelines.dll", + "lib/net462/System.IO.Pipelines.xml", + "lib/net8.0/System.IO.Pipelines.dll", + "lib/net8.0/System.IO.Pipelines.xml", + "lib/net9.0/System.IO.Pipelines.dll", + "lib/net9.0/System.IO.Pipelines.xml", + "lib/netstandard2.0/System.IO.Pipelines.dll", + "lib/netstandard2.0/System.IO.Pipelines.xml", + "system.io.pipelines.9.0.0.nupkg.sha512", + "system.io.pipelines.nuspec", + "useSharedDesignerContext.txt" + ] + }, + "System.Memory/4.5.5": { + "sha512": "XIWiDvKPXaTveaB7HVganDlOCRoj03l+jrwNvcge/t8vhGYKvqV+dMv6G4SAX2NoNmN0wZfVPTAlFwZcZvVOUw==", + "type": "package", + "path": "system.memory/4.5.5", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "LICENSE.TXT", + "THIRD-PARTY-NOTICES.TXT", + "lib/net461/System.Memory.dll", + "lib/net461/System.Memory.xml", + "lib/netcoreapp2.1/_._", + "lib/netstandard1.1/System.Memory.dll", + "lib/netstandard1.1/System.Memory.xml", + "lib/netstandard2.0/System.Memory.dll", + "lib/netstandard2.0/System.Memory.xml", + "ref/netcoreapp2.1/_._", + "system.memory.4.5.5.nupkg.sha512", + "system.memory.nuspec", + "useSharedDesignerContext.txt", + "version.txt" + ] + }, + "System.Runtime.CompilerServices.Unsafe/5.0.0": { + "sha512": "ZD9TMpsmYJLrxbbmdvhwt9YEgG5WntEnZ/d1eH8JBX9LBp+Ju8BSBhUGbZMNVHHomWo2KVImJhTDl2hIgw/6MA==", + "type": "package", + "path": "system.runtime.compilerservices.unsafe/5.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "LICENSE.TXT", + "THIRD-PARTY-NOTICES.TXT", + "lib/net45/System.Runtime.CompilerServices.Unsafe.dll", + "lib/net45/System.Runtime.CompilerServices.Unsafe.xml", + "lib/netcoreapp2.0/System.Runtime.CompilerServices.Unsafe.dll", + "lib/netcoreapp2.0/System.Runtime.CompilerServices.Unsafe.xml", + "lib/netstandard1.0/System.Runtime.CompilerServices.Unsafe.dll", + "lib/netstandard1.0/System.Runtime.CompilerServices.Unsafe.xml", + "lib/netstandard2.0/System.Runtime.CompilerServices.Unsafe.dll", + "lib/netstandard2.0/System.Runtime.CompilerServices.Unsafe.xml", + "ref/net461/System.Runtime.CompilerServices.Unsafe.dll", + "ref/net461/System.Runtime.CompilerServices.Unsafe.xml", + "ref/netstandard1.0/System.Runtime.CompilerServices.Unsafe.dll", + "ref/netstandard1.0/System.Runtime.CompilerServices.Unsafe.xml", + "ref/netstandard2.0/System.Runtime.CompilerServices.Unsafe.dll", + "ref/netstandard2.0/System.Runtime.CompilerServices.Unsafe.xml", + "ref/netstandard2.1/System.Runtime.CompilerServices.Unsafe.dll", + "ref/netstandard2.1/System.Runtime.CompilerServices.Unsafe.xml", + "system.runtime.compilerservices.unsafe.5.0.0.nupkg.sha512", + "system.runtime.compilerservices.unsafe.nuspec", + "useSharedDesignerContext.txt", + "version.txt" + ] + }, + "System.Security.AccessControl/5.0.0": { + "sha512": "dagJ1mHZO3Ani8GH0PHpPEe/oYO+rVdbQjvjJkBRNQkX4t0r1iaeGn8+/ybkSLEan3/slM0t59SVdHzuHf2jmw==", + "type": "package", + "path": "system.security.accesscontrol/5.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "LICENSE.TXT", + "THIRD-PARTY-NOTICES.TXT", + "lib/net46/System.Security.AccessControl.dll", + "lib/net461/System.Security.AccessControl.dll", + "lib/net461/System.Security.AccessControl.xml", + "lib/netstandard1.3/System.Security.AccessControl.dll", + "lib/netstandard2.0/System.Security.AccessControl.dll", + "lib/netstandard2.0/System.Security.AccessControl.xml", + "lib/uap10.0.16299/_._", + "ref/net46/System.Security.AccessControl.dll", + "ref/net461/System.Security.AccessControl.dll", + "ref/net461/System.Security.AccessControl.xml", + "ref/netstandard1.3/System.Security.AccessControl.dll", + "ref/netstandard1.3/System.Security.AccessControl.xml", + "ref/netstandard1.3/de/System.Security.AccessControl.xml", + "ref/netstandard1.3/es/System.Security.AccessControl.xml", + "ref/netstandard1.3/fr/System.Security.AccessControl.xml", + "ref/netstandard1.3/it/System.Security.AccessControl.xml", + "ref/netstandard1.3/ja/System.Security.AccessControl.xml", + "ref/netstandard1.3/ko/System.Security.AccessControl.xml", + "ref/netstandard1.3/ru/System.Security.AccessControl.xml", + "ref/netstandard1.3/zh-hans/System.Security.AccessControl.xml", + "ref/netstandard1.3/zh-hant/System.Security.AccessControl.xml", + "ref/netstandard2.0/System.Security.AccessControl.dll", + "ref/netstandard2.0/System.Security.AccessControl.xml", + "ref/uap10.0.16299/_._", + "runtimes/win/lib/net46/System.Security.AccessControl.dll", + "runtimes/win/lib/net461/System.Security.AccessControl.dll", + "runtimes/win/lib/net461/System.Security.AccessControl.xml", + "runtimes/win/lib/netcoreapp2.0/System.Security.AccessControl.dll", + "runtimes/win/lib/netcoreapp2.0/System.Security.AccessControl.xml", + "runtimes/win/lib/netstandard1.3/System.Security.AccessControl.dll", + "runtimes/win/lib/uap10.0.16299/_._", + "system.security.accesscontrol.5.0.0.nupkg.sha512", + "system.security.accesscontrol.nuspec", + "useSharedDesignerContext.txt", + "version.txt" + ] + }, + "System.Security.Principal.Windows/5.0.0": { + "sha512": "t0MGLukB5WAVU9bO3MGzvlGnyJPgUlcwerXn1kzBRjwLKixT96XV0Uza41W49gVd8zEMFu9vQEFlv0IOrytICA==", + "type": "package", + "path": "system.security.principal.windows/5.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "LICENSE.TXT", + "THIRD-PARTY-NOTICES.TXT", + "lib/net46/System.Security.Principal.Windows.dll", + "lib/net461/System.Security.Principal.Windows.dll", + "lib/net461/System.Security.Principal.Windows.xml", + "lib/netstandard1.3/System.Security.Principal.Windows.dll", + "lib/netstandard2.0/System.Security.Principal.Windows.dll", + "lib/netstandard2.0/System.Security.Principal.Windows.xml", + "lib/uap10.0.16299/_._", + "ref/net46/System.Security.Principal.Windows.dll", + "ref/net461/System.Security.Principal.Windows.dll", + "ref/net461/System.Security.Principal.Windows.xml", + "ref/netcoreapp3.0/System.Security.Principal.Windows.dll", + "ref/netcoreapp3.0/System.Security.Principal.Windows.xml", + "ref/netstandard1.3/System.Security.Principal.Windows.dll", + "ref/netstandard1.3/System.Security.Principal.Windows.xml", + "ref/netstandard1.3/de/System.Security.Principal.Windows.xml", + "ref/netstandard1.3/es/System.Security.Principal.Windows.xml", + "ref/netstandard1.3/fr/System.Security.Principal.Windows.xml", + "ref/netstandard1.3/it/System.Security.Principal.Windows.xml", + "ref/netstandard1.3/ja/System.Security.Principal.Windows.xml", + "ref/netstandard1.3/ko/System.Security.Principal.Windows.xml", + "ref/netstandard1.3/ru/System.Security.Principal.Windows.xml", + "ref/netstandard1.3/zh-hans/System.Security.Principal.Windows.xml", + "ref/netstandard1.3/zh-hant/System.Security.Principal.Windows.xml", + "ref/netstandard2.0/System.Security.Principal.Windows.dll", + "ref/netstandard2.0/System.Security.Principal.Windows.xml", + "ref/uap10.0.16299/_._", + "runtimes/unix/lib/netcoreapp2.0/System.Security.Principal.Windows.dll", + "runtimes/unix/lib/netcoreapp2.0/System.Security.Principal.Windows.xml", + "runtimes/unix/lib/netcoreapp2.1/System.Security.Principal.Windows.dll", + "runtimes/unix/lib/netcoreapp2.1/System.Security.Principal.Windows.xml", + "runtimes/win/lib/net46/System.Security.Principal.Windows.dll", + "runtimes/win/lib/net461/System.Security.Principal.Windows.dll", + "runtimes/win/lib/net461/System.Security.Principal.Windows.xml", + "runtimes/win/lib/netcoreapp2.0/System.Security.Principal.Windows.dll", + "runtimes/win/lib/netcoreapp2.0/System.Security.Principal.Windows.xml", + "runtimes/win/lib/netcoreapp2.1/System.Security.Principal.Windows.dll", + "runtimes/win/lib/netcoreapp2.1/System.Security.Principal.Windows.xml", + "runtimes/win/lib/netstandard1.3/System.Security.Principal.Windows.dll", + "runtimes/win/lib/uap10.0.16299/_._", + "system.security.principal.windows.5.0.0.nupkg.sha512", + "system.security.principal.windows.nuspec", + "useSharedDesignerContext.txt", + "version.txt" + ] + }, + "ZstdSharp.Port/0.7.3": { + "sha512": "U9Ix4l4cl58Kzz1rJzj5hoVTjmbx1qGMwzAcbv1j/d3NzrFaESIurQyg+ow4mivCgkE3S413y+U9k4WdnEIkRA==", + "type": "package", + "path": "zstdsharp.port/0.7.3", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "lib/net461/ZstdSharp.dll", + "lib/net5.0/ZstdSharp.dll", + "lib/net6.0/ZstdSharp.dll", + "lib/net7.0/ZstdSharp.dll", + "lib/netcoreapp3.1/ZstdSharp.dll", + "lib/netstandard2.0/ZstdSharp.dll", + "lib/netstandard2.1/ZstdSharp.dll", + "zstdsharp.port.0.7.3.nupkg.sha512", + "zstdsharp.port.nuspec" + ] + }, + "Entity/1.0.0": { + "type": "project", + "path": "../Entity/Entity.csproj", + "msbuildProject": "../Entity/Entity.csproj" + }, + "Fantasy-Net/2024.2.24": { + "type": "project", + "path": "../../Packages/Fantasy/Fantasy.Net/Fantasy.Net/Fantasy.Net.csproj", + "msbuildProject": "../../Packages/Fantasy/Fantasy.Net/Fantasy.Net/Fantasy.Net.csproj" + }, + "Fantasy-Net.ConfigTable/2024.2.0": { + "type": "project", + "path": "../../Packages/Fantasy/Fantasy.Packages/Fantasy.ConfigTable/Net/Fantasy.ConfigTable.csproj", + "msbuildProject": "../../Packages/Fantasy/Fantasy.Packages/Fantasy.ConfigTable/Net/Fantasy.ConfigTable.csproj" + } + }, + "projectFileDependencyGroups": { + "net8.0": [ + "Entity >= 1.0.0" + ] + }, + "packageFolders": { + "/Users/fantasy/.nuget/packages/": {} + }, + "project": { + "version": "1.0.0", + "restore": { + "projectUniqueName": "/Users/fantasy/Movies/物品背包开发之旅/B/Server/Hotfix/Hotfix.csproj", + "projectName": "Hotfix", + "projectPath": "/Users/fantasy/Movies/物品背包开发之旅/B/Server/Hotfix/Hotfix.csproj", + "packagesPath": "/Users/fantasy/.nuget/packages/", + "outputPath": "/Users/fantasy/Movies/物品背包开发之旅/B/Server/Hotfix/obj/", + "projectStyle": "PackageReference", + "configFilePaths": [ + "/Users/fantasy/.nuget/NuGet/NuGet.Config" + ], + "originalTargetFrameworks": [ + "net8.0" + ], + "sources": { + "/usr/local/share/dotnet/library-packs": {}, + "https://api.nuget.org/v3/index.json": {} + }, + "frameworks": { + "net8.0": { + "targetAlias": "net8.0", + "projectReferences": { + "/Users/fantasy/Movies/物品背包开发之旅/B/Server/Entity/Entity.csproj": { + "projectPath": "/Users/fantasy/Movies/物品背包开发之旅/B/Server/Entity/Entity.csproj" + } + } + } + }, + "warningProperties": { + "warnAsError": [ + "NU1605" + ] + }, + "restoreAuditProperties": { + "enableAudit": "true", + "auditLevel": "low", + "auditMode": "all" + }, + "SdkAnalysisLevel": "9.0.100" + }, + "frameworks": { + "net8.0": { + "targetAlias": "net8.0", + "imports": [ + "net461", + "net462", + "net47", + "net471", + "net472", + "net48", + "net481" + ], + "assetTargetFallback": true, + "warn": true, + "frameworkReferences": { + "Microsoft.NETCore.App": { + "privateAssets": "all" + } + }, + "runtimeIdentifierGraphPath": "/usr/local/share/dotnet/sdk/9.0.100/PortableRuntimeIdentifierGraph.json" + } + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Server/Hotfix/obj/project.nuget.cache b/物品和背包的完整代码/Server/Hotfix/obj/project.nuget.cache new file mode 100644 index 0000000..7be87d9 --- /dev/null +++ b/物品和背包的完整代码/Server/Hotfix/obj/project.nuget.cache @@ -0,0 +1,30 @@ +{ + "version": 2, + "dgSpecHash": "C/p08My1wts=", + "success": true, + "projectFilePath": "/Users/fantasy/Movies/物品背包开发之旅/B/Server/Hotfix/Hotfix.csproj", + "expectedPackageFiles": [ + "/Users/fantasy/.nuget/packages/commandlineparser/2.9.1/commandlineparser.2.9.1.nupkg.sha512", + "/Users/fantasy/.nuget/packages/dnsclient/1.6.1/dnsclient.1.6.1.nupkg.sha512", + "/Users/fantasy/.nuget/packages/microsoft.extensions.logging.abstractions/2.0.0/microsoft.extensions.logging.abstractions.2.0.0.nupkg.sha512", + "/Users/fantasy/.nuget/packages/microsoft.netcore.platforms/5.0.0/microsoft.netcore.platforms.5.0.0.nupkg.sha512", + "/Users/fantasy/.nuget/packages/microsoft.win32.registry/5.0.0/microsoft.win32.registry.5.0.0.nupkg.sha512", + "/Users/fantasy/.nuget/packages/mongodb.bson/3.1.0/mongodb.bson.3.1.0.nupkg.sha512", + "/Users/fantasy/.nuget/packages/mongodb.driver/3.1.0/mongodb.driver.3.1.0.nupkg.sha512", + "/Users/fantasy/.nuget/packages/newtonsoft.json/13.0.3/newtonsoft.json.13.0.3.nupkg.sha512", + "/Users/fantasy/.nuget/packages/protobuf-net/3.2.45/protobuf-net.3.2.45.nupkg.sha512", + "/Users/fantasy/.nuget/packages/protobuf-net.core/3.2.45/protobuf-net.core.3.2.45.nupkg.sha512", + "/Users/fantasy/.nuget/packages/sharpcompress/0.30.1/sharpcompress.0.30.1.nupkg.sha512", + "/Users/fantasy/.nuget/packages/snappier/1.0.0/snappier.1.0.0.nupkg.sha512", + "/Users/fantasy/.nuget/packages/system.buffers/4.5.1/system.buffers.4.5.1.nupkg.sha512", + "/Users/fantasy/.nuget/packages/system.collections.immutable/7.0.0/system.collections.immutable.7.0.0.nupkg.sha512", + "/Users/fantasy/.nuget/packages/system.io.pipelines/9.0.0/system.io.pipelines.9.0.0.nupkg.sha512", + "/Users/fantasy/.nuget/packages/system.memory/4.5.5/system.memory.4.5.5.nupkg.sha512", + "/Users/fantasy/.nuget/packages/system.runtime.compilerservices.unsafe/5.0.0/system.runtime.compilerservices.unsafe.5.0.0.nupkg.sha512", + "/Users/fantasy/.nuget/packages/system.security.accesscontrol/5.0.0/system.security.accesscontrol.5.0.0.nupkg.sha512", + "/Users/fantasy/.nuget/packages/system.security.principal.windows/5.0.0/system.security.principal.windows.5.0.0.nupkg.sha512", + "/Users/fantasy/.nuget/packages/zstdsharp.port/0.7.3/zstdsharp.port.0.7.3.nupkg.sha512", + "/Users/fantasy/.nuget/packages/fantasy-net/2024.2.24/fantasy-net.2024.2.24.nupkg.sha512" + ], + "logs": [] +} \ No newline at end of file diff --git a/物品和背包的完整代码/Server/Hotfix/obj/project.packagespec.json b/物品和背包的完整代码/Server/Hotfix/obj/project.packagespec.json new file mode 100644 index 0000000..aa2923f --- /dev/null +++ b/物品和背包的完整代码/Server/Hotfix/obj/project.packagespec.json @@ -0,0 +1 @@ +"restore":{"projectUniqueName":"/Users/fantasy/Movies/物品背包开发之旅/B/Server/Hotfix/Hotfix.csproj","projectName":"Hotfix","projectPath":"/Users/fantasy/Movies/物品背包开发之旅/B/Server/Hotfix/Hotfix.csproj","outputPath":"/Users/fantasy/Movies/物品背包开发之旅/B/Server/Hotfix/obj/","projectStyle":"PackageReference","originalTargetFrameworks":["net8.0"],"sources":{"/usr/local/share/dotnet/library-packs":{},"https://api.nuget.org/v3/index.json":{}},"frameworks":{"net8.0":{"targetAlias":"net8.0","projectReferences":{"/Users/fantasy/Movies/物品背包开发之旅/B/Server/Entity/Entity.csproj":{"projectPath":"/Users/fantasy/Movies/物品背包开发之旅/B/Server/Entity/Entity.csproj"}}}},"warningProperties":{"warnAsError":["NU1605"]},"restoreAuditProperties":{"enableAudit":"true","auditLevel":"low","auditMode":"all"},"SdkAnalysisLevel":"9.0.100"}"frameworks":{"net8.0":{"targetAlias":"net8.0","imports":["net461","net462","net47","net471","net472","net48","net481"],"assetTargetFallback":true,"warn":true,"frameworkReferences":{"Microsoft.NETCore.App":{"privateAssets":"all"}},"runtimeIdentifierGraphPath":"/usr/local/share/dotnet/sdk/9.0.100/PortableRuntimeIdentifierGraph.json"}} \ No newline at end of file diff --git a/物品和背包的完整代码/Server/Hotfix/obj/rider.project.model.nuget.info b/物品和背包的完整代码/Server/Hotfix/obj/rider.project.model.nuget.info new file mode 100644 index 0000000..050006d --- /dev/null +++ b/物品和背包的完整代码/Server/Hotfix/obj/rider.project.model.nuget.info @@ -0,0 +1 @@ +17428701567253416 \ No newline at end of file diff --git a/物品和背包的完整代码/Server/Hotfix/obj/rider.project.restore.info b/物品和背包的完整代码/Server/Hotfix/obj/rider.project.restore.info new file mode 100644 index 0000000..050006d --- /dev/null +++ b/物品和背包的完整代码/Server/Hotfix/obj/rider.project.restore.info @@ -0,0 +1 @@ +17428701567253416 \ No newline at end of file diff --git a/物品和背包的完整代码/Server/Main/.DS_Store b/物品和背包的完整代码/Server/Main/.DS_Store new file mode 100644 index 0000000..32acb3c Binary files /dev/null and b/物品和背包的完整代码/Server/Main/.DS_Store differ diff --git a/物品和背包的完整代码/Server/Main/Main.csproj b/物品和背包的完整代码/Server/Main/Main.csproj new file mode 100644 index 0000000..8917648 --- /dev/null +++ b/物品和背包的完整代码/Server/Main/Main.csproj @@ -0,0 +1,34 @@ + + + + Exe + net8.0 + enable + enable + + + + ../../Bin + + + + ../../Bin + + + + + + + + + + + + Always + + + Always + + + + diff --git a/物品和背包的完整代码/Server/Main/NLog.config b/物品和背包的完整代码/Server/Main/NLog.config new file mode 100644 index 0000000..4df5ea1 --- /dev/null +++ b/物品和背包的完整代码/Server/Main/NLog.config @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/物品和背包的完整代码/Server/Main/NLog.xsd b/物品和背包的完整代码/Server/Main/NLog.xsd new file mode 100644 index 0000000..63c9a0c --- /dev/null +++ b/物品和背包的完整代码/Server/Main/NLog.xsd @@ -0,0 +1,3483 @@ + + + + + + + + + + + + + + + Watch config file for changes and reload automatically. + + + + + Print internal NLog messages to the console. Default value is: false + + + + + Print internal NLog messages to the console error output. Default value is: false + + + + + Write internal NLog messages to the specified file. + + + + + Log level threshold for internal log messages. Default value is: Info. + + + + + Global log level threshold for application log messages. Messages below this level won't be logged. + + + + + Throw an exception when there is an internal error. Default value is: false. Not recommend to set to true in production! + + + + + Throw an exception when there is a configuration error. If not set, determined by throwExceptions. + + + + + Gets or sets a value indicating whether Variables should be kept on configuration reload. Default value is: false. + + + + + Write internal NLog messages to the System.Diagnostics.Trace. Default value is: false. + + + + + Write timestamps for internal NLog messages. Default value is: true. + + + + + Use InvariantCulture as default culture instead of CurrentCulture. Default value is: false. + + + + + Perform message template parsing and formatting of LogEvent messages (true = Always, false = Never, empty = Auto Detect). Default value is: empty. + + + + + + + + + + + + + + Make all targets within this section asynchronous (creates additional threads but the calling thread isn't blocked by any target writes). + + + + + + + + + + + + + + + + + Prefix for targets/layout renderers/filters/conditions loaded from this assembly. + + + + + Load NLog extensions from the specified file (*.dll) + + + + + Load NLog extensions from the specified assembly. Assembly name should be fully qualified. + + + + + + + + + + Filter on the name of the logger. May include wildcard characters ('*' or '?'). + + + + + Comma separated list of levels that this rule matches. + + + + + Minimum level that this rule matches. + + + + + Maximum level that this rule matches. + + + + + Level that this rule matches. + + + + + Comma separated list of target names. + + + + + Ignore further rules if this one matches. + + + + + Enable this rule. Note: disabled rules aren't available from the API. + + + + + Rule identifier to allow rule lookup with Configuration.FindRuleByName and Configuration.RemoveRuleByName. + + + + + Loggers matching will be restricted to specified minimum level for following rules. + + + + + + + + + + + + + + + Default action if none of the filters match. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Name of the file to be included. You could use * wildcard. The name is relative to the name of the current config file. + + + + + Ignore any errors in the include file. + + + + + + + + Variable value. Note, the 'value' attribute has precedence over this one. + + + + + + Variable name. + + + + + Variable value. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Action to be taken when the lazy writer thread request queue count exceeds the set limit. + + + + + Limit on the number of requests in the lazy writer thread request queue. + + + + + Number of log events that should be processed in a batch by the lazy writer thread. + + + + + Whether to use the locking queue, instead of a lock-free concurrent queue + + + + + Number of batches of P:NLog.Targets.Wrappers.AsyncTargetWrapper.BatchSize to write before yielding into P:NLog.Targets.Wrappers.AsyncTargetWrapper.TimeToSleepBetweenBatches + + + + + Time in milliseconds to sleep between batches. (1 or less means trigger on new activity) + + + + + + + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Delay the flush until the LogEvent has been confirmed as written + + + + + Condition expression. Log events who meet this condition will cause a flush on the wrapped target. + + + + + Only flush when LogEvent matches condition. Ignore explicit-flush, config-reload-flush and shutdown-flush + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Number of log events to be buffered. + + + + + Action to take if the buffer overflows. + + + + + Timeout (in milliseconds) after which the contents of buffer will be flushed if there's no write in the specified period of time. Use -1 to disable timed flushes. + + + + + Indicates whether to use sliding timeout. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Separator for T:NLog.ScopeContext operation-states-stack. + + + + + Stack separator for log4j:NDC in output from T:NLog.ScopeContext nested context. + + + + + Renderer for log4j:event logger-xml-attribute (Default ${logger}) + + + + + Whether to include the contents of the T:NLog.ScopeContext properties-dictionary. + + + + + Whether to include log4j:NDC in output from T:NLog.ScopeContext nested context. + + + + + Indicates whether to include source info (file name and line number) in the information sent over the network. + + + + + Whether to include log4j:NDC in output from T:NLog.ScopeContext nested context. + + + + + Option to include all properties from the log events + + + + + Indicates whether to include call site (class and method name) in the information sent over the network. + + + + + AppInfo field. By default it's the friendly name of the current AppDomain. + + + + + Instance of T:NLog.Layouts.Log4JXmlEventLayout that is used to format log messages. + + + + + Indicates whether to include NLog-specific extensions to log4j schema. + + + + + Action that should be taken, when more connections than P:NLog.Targets.NetworkTarget.MaxConnections. + + + + + SSL/TLS protocols. Default no SSL/TLS is used. Currently only implemented for TCP. + + + + + Action that should be taken, when more pending messages than P:NLog.Targets.NetworkTarget.MaxQueueSize. + + + + + Action that should be taken if the message is larger than P:NLog.Targets.NetworkTarget.MaxMessageSize + + + + + Maximum queue size for a single connection. Requires P:NLog.Targets.NetworkTarget.KeepConnection = true + + + + + Network address. + + + + + Indicates whether to keep connection open whenever possible. + + + + + The number of seconds a connection will remain idle before the first keep-alive probe is sent + + + + + Size of the connection cache (number of connections which are kept alive). Requires P:NLog.Targets.NetworkTarget.KeepConnection = true + + + + + Maximum simultaneous connections. Requires P:NLog.Targets.NetworkTarget.KeepConnection = false + + + + + Type of compression for protocol payload. Useful for UDP where datagram max-size is 8192 bytes. + + + + + Skip compression when protocol payload is below limit to reduce overhead in cpu-usage and additional headers + + + + + Maximum message size in bytes. On limit breach then P:NLog.Targets.NetworkTarget.OnOverflow action is activated. + + + + + Encoding to be used. + + + + + End of line value if a newline is appended at the end of log message P:NLog.Targets.NetworkTarget.NewLine. + + + + + Indicates whether to append newline at the end of log message. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Viewer parameter name. + + + + + Layout that should be use to calculate the value for the parameter. + + + + + Whether an attribute with empty value should be included in the output + + + + + + + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Text to be rendered. + + + + + Header. + + + + + Footer. + + + + + Indicates whether to auto-check if the console is available. - Disables console writing if Environment.UserInteractive = False (Windows Service) - Disables console writing if Console Standard Input is not available (Non-Console-App) + + + + + Enables output using ANSI Color Codes + + + + + The encoding for writing messages to the T:System.Console. + + + + + Indicates whether to send the log messages to the standard error instead of the standard output. + + + + + Indicates whether to auto-flush after M:System.Console.WriteLine + + + + + Indicates whether to auto-check if the console has been redirected to file - Disables coloring logic when System.Console.IsOutputRedirected = true + + + + + Indicates whether to use default row highlighting rules. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Background color. + + + + + Condition that must be met in order to set the specified foreground and background color. + + + + + Foreground color. + + + + + + + + + + + + + + + + + Background color. + + + + + Compile the P:NLog.Targets.ConsoleWordHighlightingRule.Regex? This can improve the performance, but at the costs of more memory usage. If false, the Regex Cache is used. + + + + + Condition that must be met before scanning the row for highlight of words + + + + + Foreground color. + + + + + Indicates whether to ignore case when comparing texts. + + + + + Regular expression to be matched. You must specify either text or regex. + + + + + Text to be matched. You must specify either text or regex. + + + + + Indicates whether to match whole words only. + + + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Text to be rendered. + + + + + Header. + + + + + Footer. + + + + + Indicates whether to auto-flush after M:System.Console.WriteLine + + + + + Indicates whether to auto-check if the console is available - Disables console writing if Environment.UserInteractive = False (Windows Service) - Disables console writing if Console Standard Input is not available (Non-Console-App) + + + + + The encoding for writing messages to the T:System.Console. + + + + + Indicates whether to send the log messages to the standard error instead of the standard output. + + + + + Whether to activate internal buffering to allow batch writing, instead of using M:System.Console.WriteLine + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Database user name. If the ConnectionString is not provided this value will be used to construct the "User ID=" part of the connection string. + + + + + Database password. If the ConnectionString is not provided this value will be used to construct the "Password=" part of the connection string. + + + + + Database name. If the ConnectionString is not provided this value will be used to construct the "Database=" part of the connection string. + + + + + Name of the connection string (as specified in <connectionStrings> configuration section. + + + + + Database host name. If the ConnectionString is not provided this value will be used to construct the "Server=" part of the connection string. + + + + + Indicates whether to keep the database connection open between the log events. + + + + + Name of the database provider. + + + + + Connection string. When provided, it overrides the values specified in DBHost, DBUserName, DBPassword, DBDatabase. + + + + + Connection string using for installation and uninstallation. If not provided, regular ConnectionString is being used. + + + + + Configures isolated transaction batch writing. If supported by the database, then it will improve insert performance. + + + + + Text of the SQL command to be run on each log level. + + + + + Type of the SQL command to be run on each log level. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Convert format of the property value + + + + + Culture used for parsing property string-value for type-conversion + + + + + Value to assign on the object-property + + + + + Name for the object-property + + + + + Type of the object-property + + + + + + + + + + + + + + Type of the command. + + + + + Connection string to run the command against. If not provided, connection string from the target is used. + + + + + Indicates whether to ignore failures. + + + + + Command text. + + + + + + + + + + + + + + + + + + + + Database parameter name. + + + + + Layout that should be use to calculate the value for the parameter. + + + + + Database parameter DbType. + + + + + Database parameter size. + + + + + Database parameter precision. + + + + + Database parameter scale. + + + + + Type of the parameter. + + + + + Fallback value when result value is not available + + + + + Convert format of the database parameter value. + + + + + Culture used for parsing parameter string-value for type-conversion + + + + + Whether empty value should translate into DbNull. Requires database column to allow NULL values. + + + + + + + + + + + + + + + Name of the target. + + + + + Text to be rendered. + + + + + Header. + + + + + Footer. + + + + + + + + + + + + + + + + + Name of the target. + + + + + Text to be rendered. + + + + + Header. + + + + + Footer. + + + + + + + + + + + + + + + Name of the target. + + + + + Layout used to format log messages. + + + + + + + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Layout used to format log messages. + + + + + Layout that renders event Category. + + + + + Optional entry type. When not set, or when not convertible to T:System.Diagnostics.EventLogEntryType then determined by T:NLog.LogLevel + + + + + Layout that renders event ID. + + + + + Name of the Event Log to write to. This can be System, Application or any user-defined name. + + + + + Name of the machine on which Event Log service is running. + + + + + Maximum Event log size in kilobytes. + + + + + Message length limit to write to the Event Log. + + + + + Value to be used as the event Source. + + + + + Action to take if the message is larger than the P:NLog.Targets.EventLogTarget.MaxMessageLength option. + + + + + + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Indicates whether to return to the first target after any successful write. + + + + + Whether to enable batching, but fallback will be handled individually + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Name of the file to write to. + + + + + Text to be rendered. + + + + + Header. + + + + + Footer. + + + + + Indicates whether the footer should be written only when the file is archived. + + + + + Maximum number of archive files that should be kept. + + + + + Maximum days of archive files that should be kept. + + + + + Value of the file size threshold to archive old log file on startup. + + + + + Indicates whether to archive old log file on startup. + + + + + Indicates whether to compress archive files into the zip archive format. + + + + + Name of the file to be used for an archive. + + + + + Is the P:NLog.Targets.FileTarget.ArchiveFileName an absolute or relative path? + + + + + Indicates whether to automatically archive log files every time the specified time passes. + + + + + Value specifying the date format to use when archiving files. + + + + + Size in bytes above which log files will be automatically archived. + + + + + Way file archives are numbered. + + + + + Indicates whether to create directories if they do not exist. + + + + + Indicates whether file creation calls should be synchronized by a system global mutex. + + + + + Gets or set a value indicating whether a managed file stream is forced, instead of using the native implementation. + + + + + Is the P:NLog.Targets.FileTarget.FileName an absolute or relative path? + + + + + File attributes (Windows only). + + + + + Cleanup invalid values in a filename, e.g. slashes in a filename. If set to true, this can impact the performance of massive writes. If set to false, nothing gets written when the filename is wrong. + + + + + Indicates whether to write BOM (byte order mark) in created files. Defaults to true for UTF-16 and UTF-32 + + + + + Indicates whether to enable log file(s) to be deleted. + + + + + Indicates whether to delete old log file on startup. + + + + + File encoding. + + + + + Indicates whether to replace file contents on each write instead of appending log message at the end. + + + + + Line ending mode. + + + + + Number of times the write is appended on the file before NLog discards the log message. + + + + + Delay in milliseconds to wait before attempting to write to the file again. + + + + + Maximum number of seconds before open files are flushed. Zero or negative means disabled. + + + + + Maximum number of seconds that files are kept open. Zero or negative means disabled. + + + + + Indicates whether concurrent writes to the log file by multiple processes on different network hosts. + + + + + Log file buffer size in bytes. + + + + + Indicates whether to automatically flush the file buffers after each log message. + + + + + Indicates whether to keep log file open instead of opening and closing it on each logging event. + + + + + Indicates whether concurrent writes to the log file by multiple processes on the same host. + + + + + Whether or not this target should just discard all data that its asked to write. Mostly used for when testing NLog Stack except final write + + + + + Number of files to be kept open. Setting this to a higher value may improve performance in a situation where a single File target is writing to many files (such as splitting by level or by logger). + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Condition expression. Log events who meet this condition will be forwarded to the wrapped target. + + + + + + + + + + + + + + + Name of the target. + + + + + Identifier to perform group-by + + + + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Windows domain name to change context to. + + + + + Required impersonation level. + + + + + Type of the logon provider. + + + + + Logon Type. + + + + + User account password. + + + + + Indicates whether to revert to the credentials of the process instead of impersonating another user. + + + + + Username to change context to. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Interval in which messages will be written up to the P:NLog.Targets.Wrappers.LimitingTargetWrapper.MessageLimit number of messages. + + + + + Maximum allowed number of messages written per P:NLog.Targets.Wrappers.LimitingTargetWrapper.Interval. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Text to be rendered. + + + + + Header. + + + + + Footer. + + + + + Indicates whether NewLine characters in the body should be replaced with tags. + + + + + Priority used for sending mails. + + + + + Encoding to be used for sending e-mail. + + + + + BCC email addresses separated by semicolons (e.g. john@domain.com;jane@domain.com). + + + + + CC email addresses separated by semicolons (e.g. john@domain.com;jane@domain.com). + + + + + Indicates whether to add new lines between log entries. + + + + + Indicates whether to send message as HTML instead of plain text. + + + + + Sender's email address (e.g. joe@domain.com). + + + + + Mail message body (repeated for each log message send in one mail). + + + + + Mail subject. + + + + + Recipients' email addresses separated by semicolons (e.g. john@domain.com;jane@domain.com). + + + + + Specifies how outgoing email messages will be handled. + + + + + SMTP Server to be used for sending. + + + + + SMTP Authentication mode. + + + + + Username used to connect to SMTP server (used when SmtpAuthentication is set to "basic"). + + + + + Password used to authenticate against SMTP server (used when SmtpAuthentication is set to "basic"). + + + + + Indicates whether SSL (secure sockets layer) should be used when communicating with SMTP server. + + + + + Port number that SMTP Server is listening on. + + + + + Indicates whether the default Settings from System.Net.MailSettings should be used. + + + + + Folder where applications save mail messages to be processed by the local SMTP server. + + + + + Indicates the SMTP client timeout. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Text to be rendered. + + + + + Header. + + + + + Footer. + + + + + Max number of items to have in memory + + + + + + + + + + + + + + + + + Name of the target. + + + + + Class name. + + + + + Method name. The method must be public and static. Use the AssemblyQualifiedName , https://msdn.microsoft.com/en-us/library/system.type.assemblyqualifiedname(v=vs.110).aspx e.g. + + + + + + + + + + + + + + + Name of the parameter. + + + + + Layout that should be use to calculate the value for the parameter. + + + + + Fallback value when result value is not available + + + + + Type of the parameter. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Layout used to format log messages. + + + + + SSL/TLS protocols. Default no SSL/TLS is used. Currently only implemented for TCP. + + + + + Action that should be taken, when more pending messages than P:NLog.Targets.NetworkTarget.MaxQueueSize. + + + + + Action that should be taken if the message is larger than P:NLog.Targets.NetworkTarget.MaxMessageSize + + + + + Maximum queue size for a single connection. Requires P:NLog.Targets.NetworkTarget.KeepConnection = true + + + + + Action that should be taken, when more connections than P:NLog.Targets.NetworkTarget.MaxConnections. + + + + + Indicates whether to keep connection open whenever possible. + + + + + The number of seconds a connection will remain idle before the first keep-alive probe is sent + + + + + Size of the connection cache (number of connections which are kept alive). Requires P:NLog.Targets.NetworkTarget.KeepConnection = true + + + + + Network address. + + + + + Maximum simultaneous connections. Requires P:NLog.Targets.NetworkTarget.KeepConnection = false + + + + + Type of compression for protocol payload. Useful for UDP where datagram max-size is 8192 bytes. + + + + + Skip compression when protocol payload is below limit to reduce overhead in cpu-usage and additional headers + + + + + Maximum message size in bytes. On limit breach then P:NLog.Targets.NetworkTarget.OnOverflow action is activated. + + + + + Encoding to be used. + + + + + End of line value if a newline is appended at the end of log message P:NLog.Targets.NetworkTarget.NewLine. + + + + + Indicates whether to append newline at the end of log message. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Separator for T:NLog.ScopeContext operation-states-stack. + + + + + Stack separator for log4j:NDC in output from T:NLog.ScopeContext nested context. + + + + + Renderer for log4j:event logger-xml-attribute (Default ${logger}) + + + + + Whether to include the contents of the T:NLog.ScopeContext properties-dictionary. + + + + + Whether to include log4j:NDC in output from T:NLog.ScopeContext nested context. + + + + + Indicates whether to include source info (file name and line number) in the information sent over the network. + + + + + Whether to include log4j:NDC in output from T:NLog.ScopeContext nested context. + + + + + Option to include all properties from the log events + + + + + Indicates whether to include call site (class and method name) in the information sent over the network. + + + + + AppInfo field. By default it's the friendly name of the current AppDomain. + + + + + Instance of T:NLog.Layouts.Log4JXmlEventLayout that is used to format log messages. + + + + + Indicates whether to include NLog-specific extensions to log4j schema. + + + + + Action that should be taken, when more connections than P:NLog.Targets.NetworkTarget.MaxConnections. + + + + + SSL/TLS protocols. Default no SSL/TLS is used. Currently only implemented for TCP. + + + + + Action that should be taken, when more pending messages than P:NLog.Targets.NetworkTarget.MaxQueueSize. + + + + + Action that should be taken if the message is larger than P:NLog.Targets.NetworkTarget.MaxMessageSize + + + + + Maximum queue size for a single connection. Requires P:NLog.Targets.NetworkTarget.KeepConnection = true + + + + + Network address. + + + + + Indicates whether to keep connection open whenever possible. + + + + + The number of seconds a connection will remain idle before the first keep-alive probe is sent + + + + + Size of the connection cache (number of connections which are kept alive). Requires P:NLog.Targets.NetworkTarget.KeepConnection = true + + + + + Maximum simultaneous connections. Requires P:NLog.Targets.NetworkTarget.KeepConnection = false + + + + + Type of compression for protocol payload. Useful for UDP where datagram max-size is 8192 bytes. + + + + + Skip compression when protocol payload is below limit to reduce overhead in cpu-usage and additional headers + + + + + Maximum message size in bytes. On limit breach then P:NLog.Targets.NetworkTarget.OnOverflow action is activated. + + + + + Encoding to be used. + + + + + End of line value if a newline is appended at the end of log message P:NLog.Targets.NetworkTarget.NewLine. + + + + + Indicates whether to append newline at the end of log message. + + + + + + + + + + + + + + + + Name of the target. + + + + + Layout used to format log messages. + + + + + Indicates whether to perform layout calculation. + + + + + + + + + + + + + + + + Name of the target. + + + + + Default filter to be applied when no specific rule matches. + + + + + + + + + + + + + Condition to be tested. + + + + + Resulting filter to be applied when the condition matches. + + + + + + + + + + + + Name of the target. + + + + + + + + + + + + + + + Name of the target. + + + + + Number of times to repeat each log message. + + + + + + + + + + + + + + + + + Name of the target. + + + + + Whether to enable batching, and only apply single delay when a whole batch fails + + + + + Number of retries that should be attempted on the wrapped target in case of a failure. + + + + + Time to wait between retries in milliseconds. + + + + + + + + + + + + + + Name of the target. + + + + + + + + + + + + + + Name of the target. + + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Text to be rendered. + + + + + Header. + + + + + Footer. + + + + + Forward F:NLog.LogLevel.Fatal to M:System.Diagnostics.Trace.Fail(System.String) (Instead of M:System.Diagnostics.Trace.TraceError(System.String)) + + + + + Force use M:System.Diagnostics.Trace.WriteLine(System.String) independent of T:NLog.LogLevel + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Indicates whether to pre-authenticate the HttpWebRequest (Requires 'Authorization' in P:NLog.Targets.WebServiceTarget.Headers parameters) + + + + + Value whether escaping be done according to Rfc3986 (Supports Internationalized Resource Identifiers - IRIs) + + + + + Value whether escaping be done according to the old NLog style (Very non-standard) + + + + + Value of the User-agent HTTP header. + + + + + Web service URL. + + + + + Proxy configuration when calling web service + + + + + Custom proxy address, include port separated by a colon + + + + + Protocol to be used when calling web service. + + + + + Web service namespace. Only used with Soap. + + + + + Web service method name. Only used with Soap. + + + + + Should we include the BOM (Byte-order-mark) for UTF? Influences the P:NLog.Targets.WebServiceTarget.Encoding property. This will only work for UTF-8. + + + + + Encoding. + + + + + Name of the root XML element, if POST of XML document chosen. If so, this property must not be null. (see P:NLog.Targets.WebServiceTarget.Protocol and F:NLog.Targets.WebServiceProtocol.XmlPost). + + + + + (optional) root namespace of the XML document, if POST of XML document chosen. (see P:NLog.Targets.WebServiceTarget.Protocol and F:NLog.Targets.WebServiceProtocol.XmlPost). + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Custom column delimiter value (valid when ColumnDelimiter is set to 'Custom'). + + + + + Column delimiter. + + + + + Footer layout. + + + + + Header layout. + + + + + Body layout (can be repeated multiple times). + + + + + Quote Character. + + + + + Quoting mode. + + + + + Indicates whether CVS should include header. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Name of the column. + + + + + Layout of the column. + + + + + Override of Quoting mode + + + + + + + + + + + + + + Option to render the empty object value {} + + + + + Option to suppress the extra spaces in the output json + + + + + + + + + + + + + + + + + + + + + + + Option to include all properties from the log event (as JSON) + + + + + Indicates whether to include contents of the T:NLog.GlobalDiagnosticsContext dictionary. + + + + + Whether to include the contents of the T:NLog.ScopeContext dictionary. + + + + + Should forward slashes be escaped? If true, / will be converted to \/ + + + + + Option to exclude null/empty properties from the log event (as JSON) + + + + + List of property names to exclude when P:NLog.Layouts.JsonLayout.IncludeAllProperties is true + + + + + How far should the JSON serializer follow object references before backing off + + + + + Option to render the empty object value {} + + + + + Option to suppress the extra spaces in the output json + + + + + + + + + + + + + + + + + + + Name of the attribute. + + + + + Layout that will be rendered as the attribute's value. + + + + + Fallback value when result value is not available + + + + + Determines whether or not this attribute will be Json encoded. + + + + + Should forward slashes be escaped? If true, / will be converted to \/ + + + + + Indicates whether to escape non-ascii characters + + + + + Whether an attribute with empty value should be included in the output + + + + + Result value type, for conversion of layout rendering output + + + + + + + + + + + + + + Footer layout. + + + + + Header layout. + + + + + Body layout (can be repeated multiple times). + + + + + + + + + + + + + + + + + + + + + + + Option to include all properties from the log events + + + + + Whether to include log4j:NDC in output from T:NLog.ScopeContext nested context. + + + + + Whether to include log4j:NDC in output from T:NLog.ScopeContext nested context. + + + + + Whether to include the contents of the T:NLog.ScopeContext properties-dictionary. + + + + + AppInfo field. By default it's the friendly name of the current AppDomain. + + + + + Indicates whether to include call site (class and method name) in the information sent over the network. + + + + + Indicates whether to include source info (file name and line number) in the information sent over the network. + + + + + Log4j:event logger-xml-attribute (Default ${logger}) + + + + + Whether the log4j:throwable xml-element should be written as CDATA + + + + + + + + + + + + + + Layout text. + + + + + + + + + + + + + + + + + + + + + + + + + + + + Name of the root XML element + + + + + Value inside the root XML element + + + + + Whether to include the contents of the T:NLog.ScopeContext dictionary. + + + + + Determines whether or not this attribute will be Xml encoded. + + + + + List of property names to exclude when P:NLog.Layouts.XmlElementBase.IncludeAllProperties is true + + + + + Whether a ElementValue with empty value should be included in the output + + + + + Auto indent and create new lines + + + + + How far should the XML serializer follow object references before backing off + + + + + XML element name to use for rendering IList-collections items + + + + + XML attribute name to use when rendering property-key When null (or empty) then key-attribute is not included + + + + + XML element name to use when rendering properties + + + + + XML attribute name to use when rendering property-value When null (or empty) then value-attribute is not included and value is formatted as XML-element-value + + + + + Option to include all properties from the log event (as XML) + + + + + + + + + + + + + + + + + Name of the attribute. + + + + + Layout that will be rendered as the attribute's value. + + + + + Fallback value when result value is not available + + + + + Determines whether or not this attribute will be Xml encoded. + + + + + Whether an attribute with empty value should be included in the output + + + + + Result value type, for conversion of layout rendering output + + + + + + + + + + + + + + + + + + + + + + + + Name of the element + + + + + Whether to include the contents of the T:NLog.ScopeContext dictionary. + + + + + Value inside the element + + + + + Determines whether or not this attribute will be Xml encoded. + + + + + List of property names to exclude when P:NLog.Layouts.XmlElementBase.IncludeAllProperties is true + + + + + Whether a ElementValue with empty value should be included in the output + + + + + Auto indent and create new lines + + + + + How far should the XML serializer follow object references before backing off + + + + + XML element name to use for rendering IList-collections items + + + + + XML attribute name to use when rendering property-key When null (or empty) then key-attribute is not included + + + + + XML element name to use when rendering properties + + + + + XML attribute name to use when rendering property-value When null (or empty) then value-attribute is not included and value is formatted as XML-element-value + + + + + Option to include all properties from the log event (as XML) + + + + + + + + + + + + + Action to be taken when filter matches. + + + + + Condition expression. + + + + + + + + + + + + + + + + + + + + + + + + + + Action to be taken when filter matches. + + + + + Indicates whether to ignore case when comparing strings. + + + + + Layout to be used to filter log messages. + + + + + Substring to be matched. + + + + + + + + + + + + + + + + + Action to be taken when filter matches. + + + + + String to compare the layout to. + + + + + Indicates whether to ignore case when comparing strings. + + + + + Layout to be used to filter log messages. + + + + + + + + + + + + + + + + + Action to be taken when filter matches. + + + + + Indicates whether to ignore case when comparing strings. + + + + + Layout to be used to filter log messages. + + + + + Substring to be matched. + + + + + + + + + + + + + + + + + Action to be taken when filter matches. + + + + + String to compare the layout to. + + + + + Indicates whether to ignore case when comparing strings. + + + + + Layout to be used to filter log messages. + + + + + + + + + + + + + + + + + + + + + + + Action to be taken when filter matches. + + + + + Append FilterCount to the P:NLog.LogEventInfo.Message when an event is no longer filtered + + + + + Insert FilterCount value into P:NLog.LogEventInfo.Properties when an event is no longer filtered + + + + + Applies the configured action to the initial logevent that starts the timeout period. Used to configure that it should ignore all events until timeout. + + + + + Layout to be used to filter log messages. + + + + + Max length of filter values, will truncate if above limit + + + + + How long before a filter expires, and logging is accepted again + + + + + Default number of unique filter values to expect, will automatically increase if needed + + + + + Max number of unique filter values to expect simultaneously + + + + + Default buffer size for the internal buffers + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/物品和背包的完整代码/Server/Main/Program.cs b/物品和背包的完整代码/Server/Main/Program.cs new file mode 100644 index 0000000..f927e5b --- /dev/null +++ b/物品和背包的完整代码/Server/Main/Program.cs @@ -0,0 +1,32 @@ +using Fantasy; +using Fantasy.Assembly; +using Fantasy.ConfigTable; +// using Fantasy.ConfigTable; +using Fantasy.DataBase; +using Fantasy.Helper; +using Fantasy.IdFactory; +using Fantasy.Platform.Net; +// 设置配置表的路径 +ConfigTableHelper.Initialize("../../Config/Binary"); +// 设置ID生成规则 +IdFactoryHelper.Initialize(IdFactoryType.World); +// 获取配置文件 +// 比如通过远程获取这个配置文件,这样可以多组服务器共享一套配置了 +var machineConfigText = await FileHelper.GetTextByRelativePath("../../Config/Json/Server/MachineConfigData.Json"); +var processConfigText = await FileHelper.GetTextByRelativePath("../../Config/Json/Server/ProcessConfigData.Json"); +var worldConfigText = await FileHelper.GetTextByRelativePath("../../Config/Json/Server/WorldConfigData.Json"); +var sceneConfigText = await FileHelper.GetTextByRelativePath("../../Config/Json/Server/SceneConfigData.Json"); +// 初始化配置文件 +// 如果重复初始化方法会覆盖掉上一次的数据,非常适合热重载时使用 +MachineConfigData.Initialize(machineConfigText); +ProcessConfigData.Initialize(processConfigText); +WorldConfigData.Initialize(worldConfigText); +SceneConfigData.Initialize(sceneConfigText); +// 注册日志模块到框架 +// 开发者可以自己注册日志系统到框架,只要实现Fantasy.ILog接口就可以。 +// 这里用的是NLog日志系统注册到框架中。 +Fantasy.Log.Register(new Fantasy.NLog("Server")); +// 初始化框架,添加程序集到框架中 +await Fantasy.Platform.Net.Entry.Initialize(Fantasy.AssemblyHelper.Assemblies); +// 启动Fantasy.Net +await Fantasy.Platform.Net.Entry.Start(); \ No newline at end of file diff --git a/物品和背包的完整代码/Server/Main/Properties/launchSettings.json b/物品和背包的完整代码/Server/Main/Properties/launchSettings.json new file mode 100644 index 0000000..cd8b993 --- /dev/null +++ b/物品和背包的完整代码/Server/Main/Properties/launchSettings.json @@ -0,0 +1,10 @@ +{ + "$schema": "http://json.schemastore.org/launchsettings.json", + "profiles": { + "Main": { + "commandName": "Project", + "environmentVariables": {}, + "commandLineArgs": "--m Develop" + } + } +} diff --git a/物品和背包的完整代码/Server/Main/bin/.DS_Store b/物品和背包的完整代码/Server/Main/bin/.DS_Store new file mode 100644 index 0000000..a581838 Binary files /dev/null and b/物品和背包的完整代码/Server/Main/bin/.DS_Store differ diff --git a/物品和背包的完整代码/Server/Main/bin/Debug/.DS_Store b/物品和背包的完整代码/Server/Main/bin/Debug/.DS_Store new file mode 100644 index 0000000..fd897f8 Binary files /dev/null and b/物品和背包的完整代码/Server/Main/bin/Debug/.DS_Store differ diff --git a/物品和背包的完整代码/Server/Main/obj/Debug/net8.0/.NETCoreApp,Version=v8.0.AssemblyAttributes.cs b/物品和背包的完整代码/Server/Main/obj/Debug/net8.0/.NETCoreApp,Version=v8.0.AssemblyAttributes.cs new file mode 100644 index 0000000..2217181 --- /dev/null +++ b/物品和背包的完整代码/Server/Main/obj/Debug/net8.0/.NETCoreApp,Version=v8.0.AssemblyAttributes.cs @@ -0,0 +1,4 @@ +// +using System; +using System.Reflection; +[assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute(".NETCoreApp,Version=v8.0", FrameworkDisplayName = ".NET 8.0")] diff --git a/物品和背包的完整代码/Server/Main/obj/Debug/net8.0/Main.AssemblyInfo.cs b/物品和背包的完整代码/Server/Main/obj/Debug/net8.0/Main.AssemblyInfo.cs new file mode 100644 index 0000000..6d4ddcc --- /dev/null +++ b/物品和背包的完整代码/Server/Main/obj/Debug/net8.0/Main.AssemblyInfo.cs @@ -0,0 +1,22 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +using System; +using System.Reflection; + +[assembly: System.Reflection.AssemblyCompanyAttribute("Main")] +[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")] +[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")] +[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0")] +[assembly: System.Reflection.AssemblyProductAttribute("Main")] +[assembly: System.Reflection.AssemblyTitleAttribute("Main")] +[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")] + +// 由 MSBuild WriteCodeFragment 类生成。 + diff --git a/物品和背包的完整代码/Server/Main/obj/Debug/net8.0/Main.AssemblyInfoInputs.cache b/物品和背包的完整代码/Server/Main/obj/Debug/net8.0/Main.AssemblyInfoInputs.cache new file mode 100644 index 0000000..46a1044 --- /dev/null +++ b/物品和背包的完整代码/Server/Main/obj/Debug/net8.0/Main.AssemblyInfoInputs.cache @@ -0,0 +1 @@ +73a846e799d8ee769f4e4dc02756eb24673accb05fd3a22128b4b3e41a505989 diff --git a/物品和背包的完整代码/Server/Main/obj/Debug/net8.0/Main.GeneratedMSBuildEditorConfig.editorconfig b/物品和背包的完整代码/Server/Main/obj/Debug/net8.0/Main.GeneratedMSBuildEditorConfig.editorconfig new file mode 100644 index 0000000..b46ac72 --- /dev/null +++ b/物品和背包的完整代码/Server/Main/obj/Debug/net8.0/Main.GeneratedMSBuildEditorConfig.editorconfig @@ -0,0 +1,15 @@ +is_global = true +build_property.TargetFramework = net8.0 +build_property.TargetPlatformMinVersion = +build_property.UsingMicrosoftNETSdkWeb = +build_property.ProjectTypeGuids = +build_property.InvariantGlobalization = +build_property.PlatformNeutralAssembly = +build_property.EnforceExtendedAnalyzerRules = +build_property._SupportedPlatformList = Linux,macOS,Windows +build_property.RootNamespace = Main +build_property.ProjectDir = /Users/fantasy/Movies/物品背包开发之旅/B/Server/Main/ +build_property.EnableComHosting = +build_property.EnableGeneratedComInterfaceComImportInterop = +build_property.EffectiveAnalysisLevelStyle = 8.0 +build_property.EnableCodeStyleSeverity = diff --git a/物品和背包的完整代码/Server/Main/obj/Debug/net8.0/Main.GlobalUsings.g.cs b/物品和背包的完整代码/Server/Main/obj/Debug/net8.0/Main.GlobalUsings.g.cs new file mode 100644 index 0000000..8578f3d --- /dev/null +++ b/物品和背包的完整代码/Server/Main/obj/Debug/net8.0/Main.GlobalUsings.g.cs @@ -0,0 +1,8 @@ +// +global using global::System; +global using global::System.Collections.Generic; +global using global::System.IO; +global using global::System.Linq; +global using global::System.Net.Http; +global using global::System.Threading; +global using global::System.Threading.Tasks; diff --git a/物品和背包的完整代码/Server/Main/obj/Debug/net8.0/Main.assets.cache b/物品和背包的完整代码/Server/Main/obj/Debug/net8.0/Main.assets.cache new file mode 100644 index 0000000..2190b03 Binary files /dev/null and b/物品和背包的完整代码/Server/Main/obj/Debug/net8.0/Main.assets.cache differ diff --git a/物品和背包的完整代码/Server/Main/obj/Debug/net8.0/Main.csproj.AssemblyReference.cache b/物品和背包的完整代码/Server/Main/obj/Debug/net8.0/Main.csproj.AssemblyReference.cache new file mode 100644 index 0000000..07a9815 Binary files /dev/null and b/物品和背包的完整代码/Server/Main/obj/Debug/net8.0/Main.csproj.AssemblyReference.cache differ diff --git a/物品和背包的完整代码/Server/Main/obj/Debug/net8.0/Main.csproj.CoreCompileInputs.cache b/物品和背包的完整代码/Server/Main/obj/Debug/net8.0/Main.csproj.CoreCompileInputs.cache new file mode 100644 index 0000000..7e24d60 --- /dev/null +++ b/物品和背包的完整代码/Server/Main/obj/Debug/net8.0/Main.csproj.CoreCompileInputs.cache @@ -0,0 +1 @@ +0b51ee52768bb4c60ec4d12b69c413176424410d05f873ee15309e780511a600 diff --git a/物品和背包的完整代码/Server/Main/obj/Debug/net8.0/Main.csproj.FileListAbsolute.txt b/物品和背包的完整代码/Server/Main/obj/Debug/net8.0/Main.csproj.FileListAbsolute.txt new file mode 100644 index 0000000..de304bb --- /dev/null +++ b/物品和背包的完整代码/Server/Main/obj/Debug/net8.0/Main.csproj.FileListAbsolute.txt @@ -0,0 +1,18 @@ +/Users/fantasy/Movies/物品背包开发之旅/B/Server/Main/obj/Debug/net8.0/Main.csproj.AssemblyReference.cache +/Users/fantasy/Movies/物品背包开发之旅/B/Server/Main/obj/Debug/net8.0/Main.GeneratedMSBuildEditorConfig.editorconfig +/Users/fantasy/Movies/物品背包开发之旅/B/Server/Main/obj/Debug/net8.0/Main.AssemblyInfoInputs.cache +/Users/fantasy/Movies/物品背包开发之旅/B/Server/Main/obj/Debug/net8.0/Main.AssemblyInfo.cs +/Users/fantasy/Movies/物品背包开发之旅/B/Server/Main/obj/Debug/net8.0/Main.csproj.CoreCompileInputs.cache +/Users/fantasy/Movies/物品背包开发之旅/B/Bin/net8.0/Main +/Users/fantasy/Movies/物品背包开发之旅/B/Bin/net8.0/Main.deps.json +/Users/fantasy/Movies/物品背包开发之旅/B/Bin/net8.0/Main.runtimeconfig.json +/Users/fantasy/Movies/物品背包开发之旅/B/Bin/net8.0/Main.dll +/Users/fantasy/Movies/物品背包开发之旅/B/Bin/net8.0/Main.pdb +/Users/fantasy/Movies/物品背包开发之旅/B/Server/Main/obj/Debug/net8.0/Main.csproj.Up2Date +/Users/fantasy/Movies/物品背包开发之旅/B/Server/Main/obj/Debug/net8.0/Main.dll +/Users/fantasy/Movies/物品背包开发之旅/B/Server/Main/obj/Debug/net8.0/refint/Main.dll +/Users/fantasy/Movies/物品背包开发之旅/B/Server/Main/obj/Debug/net8.0/Main.pdb +/Users/fantasy/Movies/物品背包开发之旅/B/Server/Main/obj/Debug/net8.0/Main.genruntimeconfig.cache +/Users/fantasy/Movies/物品背包开发之旅/B/Server/Main/obj/Debug/net8.0/ref/Main.dll +/Users/fantasy/Movies/物品背包开发之旅/B/Bin/net8.0/NLog.config +/Users/fantasy/Movies/物品背包开发之旅/B/Bin/net8.0/NLog.xsd diff --git a/物品和背包的完整代码/Server/Main/obj/Debug/net8.0/Main.csproj.Up2Date b/物品和背包的完整代码/Server/Main/obj/Debug/net8.0/Main.csproj.Up2Date new file mode 100644 index 0000000..e69de29 diff --git a/物品和背包的完整代码/Server/Main/obj/Debug/net8.0/Main.dll b/物品和背包的完整代码/Server/Main/obj/Debug/net8.0/Main.dll new file mode 100644 index 0000000..0d3611a Binary files /dev/null and b/物品和背包的完整代码/Server/Main/obj/Debug/net8.0/Main.dll differ diff --git a/物品和背包的完整代码/Server/Main/obj/Debug/net8.0/Main.genruntimeconfig.cache b/物品和背包的完整代码/Server/Main/obj/Debug/net8.0/Main.genruntimeconfig.cache new file mode 100644 index 0000000..9ebab69 --- /dev/null +++ b/物品和背包的完整代码/Server/Main/obj/Debug/net8.0/Main.genruntimeconfig.cache @@ -0,0 +1 @@ +b92867b672246249b6f9a7307b5f1a5b678661553eb02f4c70677faf71731cfc diff --git a/物品和背包的完整代码/Server/Main/obj/Debug/net8.0/Main.pdb b/物品和背包的完整代码/Server/Main/obj/Debug/net8.0/Main.pdb new file mode 100644 index 0000000..8e51e15 Binary files /dev/null and b/物品和背包的完整代码/Server/Main/obj/Debug/net8.0/Main.pdb differ diff --git a/物品和背包的完整代码/Server/Main/obj/Debug/net8.0/apphost b/物品和背包的完整代码/Server/Main/obj/Debug/net8.0/apphost new file mode 100644 index 0000000..4625826 Binary files /dev/null and b/物品和背包的完整代码/Server/Main/obj/Debug/net8.0/apphost differ diff --git a/物品和背包的完整代码/Server/Main/obj/Debug/net8.0/ref/Main.dll b/物品和背包的完整代码/Server/Main/obj/Debug/net8.0/ref/Main.dll new file mode 100644 index 0000000..b0fde69 Binary files /dev/null and b/物品和背包的完整代码/Server/Main/obj/Debug/net8.0/ref/Main.dll differ diff --git a/物品和背包的完整代码/Server/Main/obj/Debug/net8.0/refint/Main.dll b/物品和背包的完整代码/Server/Main/obj/Debug/net8.0/refint/Main.dll new file mode 100644 index 0000000..b0fde69 Binary files /dev/null and b/物品和背包的完整代码/Server/Main/obj/Debug/net8.0/refint/Main.dll differ diff --git a/物品和背包的完整代码/Server/Main/obj/Main.csproj.nuget.dgspec.json b/物品和背包的完整代码/Server/Main/obj/Main.csproj.nuget.dgspec.json new file mode 100644 index 0000000..1a3e023 --- /dev/null +++ b/物品和背包的完整代码/Server/Main/obj/Main.csproj.nuget.dgspec.json @@ -0,0 +1,489 @@ +{ + "format": 1, + "restore": { + "/Users/fantasy/Movies/物品背包开发之旅/B/Server/Main/Main.csproj": {} + }, + "projects": { + "/Users/fantasy/Movies/物品背包开发之旅/B/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Fantasy.Net.csproj": { + "version": "2024.2.24", + "restore": { + "projectUniqueName": "/Users/fantasy/Movies/物品背包开发之旅/B/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Fantasy.Net.csproj", + "projectName": "Fantasy-Net", + "projectPath": "/Users/fantasy/Movies/物品背包开发之旅/B/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Fantasy.Net.csproj", + "packagesPath": "/Users/fantasy/.nuget/packages/", + "outputPath": "/Users/fantasy/Movies/物品背包开发之旅/B/Packages/Fantasy/Fantasy.Net/Fantasy.Net/obj/", + "projectStyle": "PackageReference", + "crossTargeting": true, + "configFilePaths": [ + "/Users/fantasy/.nuget/NuGet/NuGet.Config" + ], + "originalTargetFrameworks": [ + "net8.0", + "net9.0" + ], + "sources": { + "/usr/local/share/dotnet/library-packs": {}, + "https://api.nuget.org/v3/index.json": {} + }, + "frameworks": { + "net8.0": { + "targetAlias": "net8.0", + "projectReferences": {} + }, + "net9.0": { + "targetAlias": "net9.0", + "projectReferences": {} + } + }, + "warningProperties": { + "allWarningsAsErrors": true, + "warnAsError": [ + "NU1605" + ] + }, + "restoreAuditProperties": { + "enableAudit": "true", + "auditLevel": "low", + "auditMode": "all" + }, + "SdkAnalysisLevel": "9.0.100" + }, + "frameworks": { + "net8.0": { + "targetAlias": "net8.0", + "dependencies": { + "CommandLineParser": { + "target": "Package", + "version": "[2.9.1, )" + }, + "MongoDB.Bson": { + "target": "Package", + "version": "[3.1.0, )" + }, + "MongoDB.Driver": { + "target": "Package", + "version": "[3.1.0, )" + }, + "Newtonsoft.Json": { + "target": "Package", + "version": "[13.0.3, )" + }, + "System.IO.Pipelines": { + "target": "Package", + "version": "[9.0.0, )" + }, + "protobuf-net": { + "target": "Package", + "version": "[3.2.45, )" + } + }, + "imports": [ + "net461", + "net462", + "net47", + "net471", + "net472", + "net48", + "net481" + ], + "assetTargetFallback": true, + "warn": true, + "frameworkReferences": { + "Microsoft.AspNetCore.App": { + "privateAssets": "none" + }, + "Microsoft.NETCore.App": { + "privateAssets": "all" + } + }, + "runtimeIdentifierGraphPath": "/usr/local/share/dotnet/sdk/9.0.100/PortableRuntimeIdentifierGraph.json" + }, + "net9.0": { + "targetAlias": "net9.0", + "dependencies": { + "CommandLineParser": { + "target": "Package", + "version": "[2.9.1, )" + }, + "MongoDB.Bson": { + "target": "Package", + "version": "[3.1.0, )" + }, + "MongoDB.Driver": { + "target": "Package", + "version": "[3.1.0, )" + }, + "Newtonsoft.Json": { + "target": "Package", + "version": "[13.0.3, )" + }, + "protobuf-net": { + "target": "Package", + "version": "[3.2.45, )" + } + }, + "imports": [ + "net461", + "net462", + "net47", + "net471", + "net472", + "net48", + "net481" + ], + "assetTargetFallback": true, + "warn": true, + "frameworkReferences": { + "Microsoft.AspNetCore.App": { + "privateAssets": "none" + }, + "Microsoft.NETCore.App": { + "privateAssets": "all" + } + }, + "runtimeIdentifierGraphPath": "/usr/local/share/dotnet/sdk/9.0.100/PortableRuntimeIdentifierGraph.json" + } + } + }, + "/Users/fantasy/Movies/物品背包开发之旅/B/Packages/Fantasy/Fantasy.Packages/Fantasy.ConfigTable/Net/Fantasy.ConfigTable.csproj": { + "version": "2024.2.0", + "restore": { + "projectUniqueName": "/Users/fantasy/Movies/物品背包开发之旅/B/Packages/Fantasy/Fantasy.Packages/Fantasy.ConfigTable/Net/Fantasy.ConfigTable.csproj", + "projectName": "Fantasy-Net.ConfigTable", + "projectPath": "/Users/fantasy/Movies/物品背包开发之旅/B/Packages/Fantasy/Fantasy.Packages/Fantasy.ConfigTable/Net/Fantasy.ConfigTable.csproj", + "packagesPath": "/Users/fantasy/.nuget/packages/", + "outputPath": "/Users/fantasy/Movies/物品背包开发之旅/B/Packages/Fantasy/Fantasy.Packages/Fantasy.ConfigTable/Net/obj/", + "projectStyle": "PackageReference", + "configFilePaths": [ + "/Users/fantasy/.nuget/NuGet/NuGet.Config" + ], + "originalTargetFrameworks": [ + "net8.0" + ], + "sources": { + "/usr/local/share/dotnet/library-packs": {}, + "https://api.nuget.org/v3/index.json": {} + }, + "frameworks": { + "net8.0": { + "targetAlias": "net8.0", + "projectReferences": {} + } + }, + "warningProperties": { + "warnAsError": [ + "NU1605" + ] + }, + "restoreAuditProperties": { + "enableAudit": "true", + "auditLevel": "low", + "auditMode": "all" + }, + "SdkAnalysisLevel": "9.0.100" + }, + "frameworks": { + "net8.0": { + "targetAlias": "net8.0", + "dependencies": { + "Fantasy-Net": { + "target": "Package", + "version": "[2024.2.22, )" + } + }, + "imports": [ + "net461", + "net462", + "net47", + "net471", + "net472", + "net48", + "net481" + ], + "assetTargetFallback": true, + "warn": true, + "frameworkReferences": { + "Microsoft.NETCore.App": { + "privateAssets": "all" + } + }, + "runtimeIdentifierGraphPath": "/usr/local/share/dotnet/sdk/9.0.100/PortableRuntimeIdentifierGraph.json" + } + } + }, + "/Users/fantasy/Movies/物品背包开发之旅/B/Packages/Fantasy/Fantasy.Packages/Fantasy.NLog/Fantasy.NLog.csproj": { + "version": "2024.1.20", + "restore": { + "projectUniqueName": "/Users/fantasy/Movies/物品背包开发之旅/B/Packages/Fantasy/Fantasy.Packages/Fantasy.NLog/Fantasy.NLog.csproj", + "projectName": "Fantasy-Net.NLog", + "projectPath": "/Users/fantasy/Movies/物品背包开发之旅/B/Packages/Fantasy/Fantasy.Packages/Fantasy.NLog/Fantasy.NLog.csproj", + "packagesPath": "/Users/fantasy/.nuget/packages/", + "outputPath": "/Users/fantasy/Movies/物品背包开发之旅/B/Packages/Fantasy/Fantasy.Packages/Fantasy.NLog/obj/", + "projectStyle": "PackageReference", + "configFilePaths": [ + "/Users/fantasy/.nuget/NuGet/NuGet.Config" + ], + "originalTargetFrameworks": [ + "net8.0" + ], + "sources": { + "/usr/local/share/dotnet/library-packs": {}, + "https://api.nuget.org/v3/index.json": {} + }, + "frameworks": { + "net8.0": { + "targetAlias": "net8.0", + "projectReferences": {} + } + }, + "warningProperties": { + "warnAsError": [ + "NU1605" + ] + }, + "restoreAuditProperties": { + "enableAudit": "true", + "auditLevel": "low", + "auditMode": "all" + }, + "SdkAnalysisLevel": "9.0.100" + }, + "frameworks": { + "net8.0": { + "targetAlias": "net8.0", + "dependencies": { + "Fantasy-Net": { + "target": "Package", + "version": "[2024.2.22, )" + }, + "NLog": { + "target": "Package", + "version": "[5.3.4, )" + } + }, + "imports": [ + "net461", + "net462", + "net47", + "net471", + "net472", + "net48", + "net481" + ], + "assetTargetFallback": true, + "warn": true, + "frameworkReferences": { + "Microsoft.NETCore.App": { + "privateAssets": "all" + } + }, + "runtimeIdentifierGraphPath": "/usr/local/share/dotnet/sdk/9.0.100/PortableRuntimeIdentifierGraph.json" + } + } + }, + "/Users/fantasy/Movies/物品背包开发之旅/B/Server/Entity/Entity.csproj": { + "version": "1.0.0", + "restore": { + "projectUniqueName": "/Users/fantasy/Movies/物品背包开发之旅/B/Server/Entity/Entity.csproj", + "projectName": "Entity", + "projectPath": "/Users/fantasy/Movies/物品背包开发之旅/B/Server/Entity/Entity.csproj", + "packagesPath": "/Users/fantasy/.nuget/packages/", + "outputPath": "/Users/fantasy/Movies/物品背包开发之旅/B/Server/Entity/obj/", + "projectStyle": "PackageReference", + "configFilePaths": [ + "/Users/fantasy/.nuget/NuGet/NuGet.Config" + ], + "originalTargetFrameworks": [ + "net8.0" + ], + "sources": { + "/usr/local/share/dotnet/library-packs": {}, + "https://api.nuget.org/v3/index.json": {} + }, + "frameworks": { + "net8.0": { + "targetAlias": "net8.0", + "projectReferences": { + "/Users/fantasy/Movies/物品背包开发之旅/B/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Fantasy.Net.csproj": { + "projectPath": "/Users/fantasy/Movies/物品背包开发之旅/B/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Fantasy.Net.csproj" + }, + "/Users/fantasy/Movies/物品背包开发之旅/B/Packages/Fantasy/Fantasy.Packages/Fantasy.ConfigTable/Net/Fantasy.ConfigTable.csproj": { + "projectPath": "/Users/fantasy/Movies/物品背包开发之旅/B/Packages/Fantasy/Fantasy.Packages/Fantasy.ConfigTable/Net/Fantasy.ConfigTable.csproj" + } + } + } + }, + "warningProperties": { + "warnAsError": [ + "NU1605" + ] + }, + "restoreAuditProperties": { + "enableAudit": "true", + "auditLevel": "low", + "auditMode": "all" + }, + "SdkAnalysisLevel": "9.0.100" + }, + "frameworks": { + "net8.0": { + "targetAlias": "net8.0", + "imports": [ + "net461", + "net462", + "net47", + "net471", + "net472", + "net48", + "net481" + ], + "assetTargetFallback": true, + "warn": true, + "frameworkReferences": { + "Microsoft.NETCore.App": { + "privateAssets": "all" + } + }, + "runtimeIdentifierGraphPath": "/usr/local/share/dotnet/sdk/9.0.100/PortableRuntimeIdentifierGraph.json" + } + } + }, + "/Users/fantasy/Movies/物品背包开发之旅/B/Server/Hotfix/Hotfix.csproj": { + "version": "1.0.0", + "restore": { + "projectUniqueName": "/Users/fantasy/Movies/物品背包开发之旅/B/Server/Hotfix/Hotfix.csproj", + "projectName": "Hotfix", + "projectPath": "/Users/fantasy/Movies/物品背包开发之旅/B/Server/Hotfix/Hotfix.csproj", + "packagesPath": "/Users/fantasy/.nuget/packages/", + "outputPath": "/Users/fantasy/Movies/物品背包开发之旅/B/Server/Hotfix/obj/", + "projectStyle": "PackageReference", + "configFilePaths": [ + "/Users/fantasy/.nuget/NuGet/NuGet.Config" + ], + "originalTargetFrameworks": [ + "net8.0" + ], + "sources": { + "/usr/local/share/dotnet/library-packs": {}, + "https://api.nuget.org/v3/index.json": {} + }, + "frameworks": { + "net8.0": { + "targetAlias": "net8.0", + "projectReferences": { + "/Users/fantasy/Movies/物品背包开发之旅/B/Server/Entity/Entity.csproj": { + "projectPath": "/Users/fantasy/Movies/物品背包开发之旅/B/Server/Entity/Entity.csproj" + } + } + } + }, + "warningProperties": { + "warnAsError": [ + "NU1605" + ] + }, + "restoreAuditProperties": { + "enableAudit": "true", + "auditLevel": "low", + "auditMode": "all" + }, + "SdkAnalysisLevel": "9.0.100" + }, + "frameworks": { + "net8.0": { + "targetAlias": "net8.0", + "imports": [ + "net461", + "net462", + "net47", + "net471", + "net472", + "net48", + "net481" + ], + "assetTargetFallback": true, + "warn": true, + "frameworkReferences": { + "Microsoft.NETCore.App": { + "privateAssets": "all" + } + }, + "runtimeIdentifierGraphPath": "/usr/local/share/dotnet/sdk/9.0.100/PortableRuntimeIdentifierGraph.json" + } + } + }, + "/Users/fantasy/Movies/物品背包开发之旅/B/Server/Main/Main.csproj": { + "version": "1.0.0", + "restore": { + "projectUniqueName": "/Users/fantasy/Movies/物品背包开发之旅/B/Server/Main/Main.csproj", + "projectName": "Main", + "projectPath": "/Users/fantasy/Movies/物品背包开发之旅/B/Server/Main/Main.csproj", + "packagesPath": "/Users/fantasy/.nuget/packages/", + "outputPath": "/Users/fantasy/Movies/物品背包开发之旅/B/Server/Main/obj/", + "projectStyle": "PackageReference", + "configFilePaths": [ + "/Users/fantasy/.nuget/NuGet/NuGet.Config" + ], + "originalTargetFrameworks": [ + "net8.0" + ], + "sources": { + "/usr/local/share/dotnet/library-packs": {}, + "https://api.nuget.org/v3/index.json": {} + }, + "frameworks": { + "net8.0": { + "targetAlias": "net8.0", + "projectReferences": { + "/Users/fantasy/Movies/物品背包开发之旅/B/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Fantasy.Net.csproj": { + "projectPath": "/Users/fantasy/Movies/物品背包开发之旅/B/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Fantasy.Net.csproj" + }, + "/Users/fantasy/Movies/物品背包开发之旅/B/Packages/Fantasy/Fantasy.Packages/Fantasy.NLog/Fantasy.NLog.csproj": { + "projectPath": "/Users/fantasy/Movies/物品背包开发之旅/B/Packages/Fantasy/Fantasy.Packages/Fantasy.NLog/Fantasy.NLog.csproj" + }, + "/Users/fantasy/Movies/物品背包开发之旅/B/Server/Entity/Entity.csproj": { + "projectPath": "/Users/fantasy/Movies/物品背包开发之旅/B/Server/Entity/Entity.csproj" + }, + "/Users/fantasy/Movies/物品背包开发之旅/B/Server/Hotfix/Hotfix.csproj": { + "projectPath": "/Users/fantasy/Movies/物品背包开发之旅/B/Server/Hotfix/Hotfix.csproj" + } + } + } + }, + "warningProperties": { + "warnAsError": [ + "NU1605" + ] + }, + "restoreAuditProperties": { + "enableAudit": "true", + "auditLevel": "low", + "auditMode": "all" + }, + "SdkAnalysisLevel": "9.0.100" + }, + "frameworks": { + "net8.0": { + "targetAlias": "net8.0", + "imports": [ + "net461", + "net462", + "net47", + "net471", + "net472", + "net48", + "net481" + ], + "assetTargetFallback": true, + "warn": true, + "frameworkReferences": { + "Microsoft.NETCore.App": { + "privateAssets": "all" + } + }, + "runtimeIdentifierGraphPath": "/usr/local/share/dotnet/sdk/9.0.100/PortableRuntimeIdentifierGraph.json" + } + } + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Server/Main/obj/Main.csproj.nuget.g.props b/物品和背包的完整代码/Server/Main/obj/Main.csproj.nuget.g.props new file mode 100644 index 0000000..f402062 --- /dev/null +++ b/物品和背包的完整代码/Server/Main/obj/Main.csproj.nuget.g.props @@ -0,0 +1,15 @@ + + + + True + NuGet + $(MSBuildThisFileDirectory)project.assets.json + /Users/fantasy/.nuget/packages/ + /Users/fantasy/.nuget/packages/ + PackageReference + 6.12.2 + + + + + \ No newline at end of file diff --git a/物品和背包的完整代码/Server/Main/obj/Main.csproj.nuget.g.targets b/物品和背包的完整代码/Server/Main/obj/Main.csproj.nuget.g.targets new file mode 100644 index 0000000..3dc06ef --- /dev/null +++ b/物品和背包的完整代码/Server/Main/obj/Main.csproj.nuget.g.targets @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/物品和背包的完整代码/Server/Main/obj/project.assets.json b/物品和背包的完整代码/Server/Main/obj/project.assets.json new file mode 100644 index 0000000..92aa286 --- /dev/null +++ b/物品和背包的完整代码/Server/Main/obj/project.assets.json @@ -0,0 +1,1057 @@ +{ + "version": 3, + "targets": { + "net8.0": { + "CommandLineParser/2.9.1": { + "type": "package", + "compile": { + "lib/netstandard2.0/CommandLine.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netstandard2.0/CommandLine.dll": { + "related": ".xml" + } + } + }, + "DnsClient/1.6.1": { + "type": "package", + "dependencies": { + "Microsoft.Win32.Registry": "5.0.0" + }, + "compile": { + "lib/net5.0/DnsClient.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net5.0/DnsClient.dll": { + "related": ".xml" + } + } + }, + "Microsoft.Extensions.Logging.Abstractions/2.0.0": { + "type": "package", + "compile": { + "lib/netstandard2.0/Microsoft.Extensions.Logging.Abstractions.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netstandard2.0/Microsoft.Extensions.Logging.Abstractions.dll": { + "related": ".xml" + } + } + }, + "Microsoft.NETCore.Platforms/5.0.0": { + "type": "package", + "compile": { + "lib/netstandard1.0/_._": {} + }, + "runtime": { + "lib/netstandard1.0/_._": {} + } + }, + "Microsoft.Win32.Registry/5.0.0": { + "type": "package", + "dependencies": { + "System.Security.AccessControl": "5.0.0", + "System.Security.Principal.Windows": "5.0.0" + }, + "compile": { + "ref/netstandard2.0/Microsoft.Win32.Registry.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netstandard2.0/Microsoft.Win32.Registry.dll": { + "related": ".xml" + } + }, + "runtimeTargets": { + "runtimes/win/lib/netstandard2.0/Microsoft.Win32.Registry.dll": { + "assetType": "runtime", + "rid": "win" + } + } + }, + "MongoDB.Bson/3.1.0": { + "type": "package", + "dependencies": { + "System.Memory": "4.5.5", + "System.Runtime.CompilerServices.Unsafe": "5.0.0" + }, + "compile": { + "lib/net6.0/MongoDB.Bson.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net6.0/MongoDB.Bson.dll": { + "related": ".xml" + } + } + }, + "MongoDB.Driver/3.1.0": { + "type": "package", + "dependencies": { + "DnsClient": "1.6.1", + "Microsoft.Extensions.Logging.Abstractions": "2.0.0", + "MongoDB.Bson": "3.1.0", + "SharpCompress": "0.30.1", + "Snappier": "1.0.0", + "System.Buffers": "4.5.1", + "ZstdSharp.Port": "0.7.3" + }, + "compile": { + "lib/net6.0/MongoDB.Driver.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net6.0/MongoDB.Driver.dll": { + "related": ".xml" + } + } + }, + "Newtonsoft.Json/13.0.3": { + "type": "package", + "compile": { + "lib/net6.0/Newtonsoft.Json.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net6.0/Newtonsoft.Json.dll": { + "related": ".xml" + } + } + }, + "NLog/5.3.4": { + "type": "package", + "compile": { + "lib/netstandard2.0/NLog.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netstandard2.0/NLog.dll": { + "related": ".xml" + } + } + }, + "protobuf-net/3.2.45": { + "type": "package", + "dependencies": { + "protobuf-net.Core": "3.2.45" + }, + "compile": { + "lib/net6.0/protobuf-net.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net6.0/protobuf-net.dll": { + "related": ".xml" + } + } + }, + "protobuf-net.Core/3.2.45": { + "type": "package", + "dependencies": { + "System.Collections.Immutable": "7.0.0" + }, + "compile": { + "lib/net6.0/protobuf-net.Core.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net6.0/protobuf-net.Core.dll": { + "related": ".xml" + } + } + }, + "SharpCompress/0.30.1": { + "type": "package", + "compile": { + "lib/net5.0/SharpCompress.dll": {} + }, + "runtime": { + "lib/net5.0/SharpCompress.dll": {} + } + }, + "Snappier/1.0.0": { + "type": "package", + "compile": { + "lib/net5.0/Snappier.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net5.0/Snappier.dll": { + "related": ".xml" + } + } + }, + "System.Buffers/4.5.1": { + "type": "package", + "compile": { + "ref/netcoreapp2.0/_._": {} + }, + "runtime": { + "lib/netcoreapp2.0/_._": {} + } + }, + "System.Collections.Immutable/7.0.0": { + "type": "package", + "compile": { + "lib/net7.0/System.Collections.Immutable.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net7.0/System.Collections.Immutable.dll": { + "related": ".xml" + } + }, + "build": { + "buildTransitive/net6.0/_._": {} + } + }, + "System.IO.Pipelines/9.0.0": { + "type": "package", + "compile": { + "lib/net8.0/System.IO.Pipelines.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net8.0/System.IO.Pipelines.dll": { + "related": ".xml" + } + }, + "build": { + "buildTransitive/net8.0/_._": {} + } + }, + "System.Memory/4.5.5": { + "type": "package", + "compile": { + "ref/netcoreapp2.1/_._": {} + }, + "runtime": { + "lib/netcoreapp2.1/_._": {} + } + }, + "System.Runtime.CompilerServices.Unsafe/5.0.0": { + "type": "package", + "compile": { + "ref/netstandard2.1/System.Runtime.CompilerServices.Unsafe.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netcoreapp2.0/System.Runtime.CompilerServices.Unsafe.dll": { + "related": ".xml" + } + } + }, + "System.Security.AccessControl/5.0.0": { + "type": "package", + "dependencies": { + "Microsoft.NETCore.Platforms": "5.0.0", + "System.Security.Principal.Windows": "5.0.0" + }, + "compile": { + "ref/netstandard2.0/System.Security.AccessControl.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netstandard2.0/System.Security.AccessControl.dll": { + "related": ".xml" + } + }, + "runtimeTargets": { + "runtimes/win/lib/netcoreapp2.0/System.Security.AccessControl.dll": { + "assetType": "runtime", + "rid": "win" + } + } + }, + "System.Security.Principal.Windows/5.0.0": { + "type": "package", + "compile": { + "ref/netcoreapp3.0/System.Security.Principal.Windows.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netstandard2.0/System.Security.Principal.Windows.dll": { + "related": ".xml" + } + }, + "runtimeTargets": { + "runtimes/unix/lib/netcoreapp2.1/System.Security.Principal.Windows.dll": { + "assetType": "runtime", + "rid": "unix" + }, + "runtimes/win/lib/netcoreapp2.1/System.Security.Principal.Windows.dll": { + "assetType": "runtime", + "rid": "win" + } + } + }, + "ZstdSharp.Port/0.7.3": { + "type": "package", + "compile": { + "lib/net7.0/ZstdSharp.dll": {} + }, + "runtime": { + "lib/net7.0/ZstdSharp.dll": {} + } + }, + "Entity/1.0.0": { + "type": "project", + "framework": ".NETCoreApp,Version=v8.0", + "dependencies": { + "Fantasy-Net": "2024.2.24", + "Fantasy-Net.ConfigTable": "2024.2.0" + }, + "compile": { + "bin/placeholder/Entity.dll": {} + }, + "runtime": { + "bin/placeholder/Entity.dll": {} + } + }, + "Fantasy-Net/2024.2.24": { + "type": "project", + "framework": ".NETCoreApp,Version=v8.0", + "dependencies": { + "CommandLineParser": "2.9.1", + "MongoDB.Bson": "3.1.0", + "MongoDB.Driver": "3.1.0", + "Newtonsoft.Json": "13.0.3", + "System.IO.Pipelines": "9.0.0", + "protobuf-net": "3.2.45" + }, + "compile": { + "bin/placeholder/Fantasy-Net.dll": {} + }, + "runtime": { + "bin/placeholder/Fantasy-Net.dll": {} + }, + "frameworkReferences": [ + "Microsoft.AspNetCore.App" + ] + }, + "Fantasy-Net.ConfigTable/2024.2.0": { + "type": "project", + "framework": ".NETCoreApp,Version=v8.0", + "dependencies": { + "Fantasy-Net": "2024.2.22" + }, + "compile": { + "bin/placeholder/Fantasy-Net.ConfigTable.dll": {} + }, + "runtime": { + "bin/placeholder/Fantasy-Net.ConfigTable.dll": {} + } + }, + "Fantasy-Net.NLog/2024.1.20": { + "type": "project", + "framework": ".NETCoreApp,Version=v8.0", + "dependencies": { + "Fantasy-Net": "2024.2.22", + "NLog": "5.3.4" + }, + "compile": { + "bin/placeholder/Fantasy-Net.NLog.dll": {} + }, + "runtime": { + "bin/placeholder/Fantasy-Net.NLog.dll": {} + } + }, + "Hotfix/1.0.0": { + "type": "project", + "framework": ".NETCoreApp,Version=v8.0", + "dependencies": { + "Entity": "1.0.0" + }, + "compile": { + "bin/placeholder/Hotfix.dll": {} + }, + "runtime": { + "bin/placeholder/Hotfix.dll": {} + } + } + } + }, + "libraries": { + "CommandLineParser/2.9.1": { + "sha512": "OE0sl1/sQ37bjVsPKKtwQlWDgqaxWgtme3xZz7JssWUzg5JpMIyHgCTY9MVMxOg48fJ1AgGT3tgdH5m/kQ5xhA==", + "type": "package", + "path": "commandlineparser/2.9.1", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "CommandLine20.png", + "License.md", + "README.md", + "commandlineparser.2.9.1.nupkg.sha512", + "commandlineparser.nuspec", + "lib/net40/CommandLine.dll", + "lib/net40/CommandLine.xml", + "lib/net45/CommandLine.dll", + "lib/net45/CommandLine.xml", + "lib/net461/CommandLine.dll", + "lib/net461/CommandLine.xml", + "lib/netstandard2.0/CommandLine.dll", + "lib/netstandard2.0/CommandLine.xml" + ] + }, + "DnsClient/1.6.1": { + "sha512": "4H/f2uYJOZ+YObZjpY9ABrKZI+JNw3uizp6oMzTXwDw6F+2qIPhpRl/1t68O/6e98+vqNiYGu+lswmwdYUy3gg==", + "type": "package", + "path": "dnsclient/1.6.1", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "dnsclient.1.6.1.nupkg.sha512", + "dnsclient.nuspec", + "icon.png", + "lib/net45/DnsClient.dll", + "lib/net45/DnsClient.xml", + "lib/net471/DnsClient.dll", + "lib/net471/DnsClient.xml", + "lib/net5.0/DnsClient.dll", + "lib/net5.0/DnsClient.xml", + "lib/netstandard1.3/DnsClient.dll", + "lib/netstandard1.3/DnsClient.xml", + "lib/netstandard2.0/DnsClient.dll", + "lib/netstandard2.0/DnsClient.xml", + "lib/netstandard2.1/DnsClient.dll", + "lib/netstandard2.1/DnsClient.xml" + ] + }, + "Microsoft.Extensions.Logging.Abstractions/2.0.0": { + "sha512": "6ZCllUYGFukkymSTx3Yr0G/ajRxoNJp7/FqSxSB4fGISST54ifBhgu4Nc0ItGi3i6DqwuNd8SUyObmiC++AO2Q==", + "type": "package", + "path": "microsoft.extensions.logging.abstractions/2.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "lib/netstandard2.0/Microsoft.Extensions.Logging.Abstractions.dll", + "lib/netstandard2.0/Microsoft.Extensions.Logging.Abstractions.xml", + "microsoft.extensions.logging.abstractions.2.0.0.nupkg.sha512", + "microsoft.extensions.logging.abstractions.nuspec" + ] + }, + "Microsoft.NETCore.Platforms/5.0.0": { + "sha512": "VyPlqzH2wavqquTcYpkIIAQ6WdenuKoFN0BdYBbCWsclXacSOHNQn66Gt4z5NBqEYW0FAPm5rlvki9ZiCij5xQ==", + "type": "package", + "path": "microsoft.netcore.platforms/5.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "LICENSE.TXT", + "THIRD-PARTY-NOTICES.TXT", + "lib/netstandard1.0/_._", + "microsoft.netcore.platforms.5.0.0.nupkg.sha512", + "microsoft.netcore.platforms.nuspec", + "runtime.json", + "useSharedDesignerContext.txt", + "version.txt" + ] + }, + "Microsoft.Win32.Registry/5.0.0": { + "sha512": "dDoKi0PnDz31yAyETfRntsLArTlVAVzUzCIvvEDsDsucrl33Dl8pIJG06ePTJTI3tGpeyHS9Cq7Foc/s4EeKcg==", + "type": "package", + "path": "microsoft.win32.registry/5.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "LICENSE.TXT", + "THIRD-PARTY-NOTICES.TXT", + "lib/net46/Microsoft.Win32.Registry.dll", + "lib/net461/Microsoft.Win32.Registry.dll", + "lib/net461/Microsoft.Win32.Registry.xml", + "lib/netstandard1.3/Microsoft.Win32.Registry.dll", + "lib/netstandard2.0/Microsoft.Win32.Registry.dll", + "lib/netstandard2.0/Microsoft.Win32.Registry.xml", + "microsoft.win32.registry.5.0.0.nupkg.sha512", + "microsoft.win32.registry.nuspec", + "ref/net46/Microsoft.Win32.Registry.dll", + "ref/net461/Microsoft.Win32.Registry.dll", + "ref/net461/Microsoft.Win32.Registry.xml", + "ref/netstandard1.3/Microsoft.Win32.Registry.dll", + "ref/netstandard1.3/Microsoft.Win32.Registry.xml", + "ref/netstandard1.3/de/Microsoft.Win32.Registry.xml", + "ref/netstandard1.3/es/Microsoft.Win32.Registry.xml", + "ref/netstandard1.3/fr/Microsoft.Win32.Registry.xml", + "ref/netstandard1.3/it/Microsoft.Win32.Registry.xml", + "ref/netstandard1.3/ja/Microsoft.Win32.Registry.xml", + "ref/netstandard1.3/ko/Microsoft.Win32.Registry.xml", + "ref/netstandard1.3/ru/Microsoft.Win32.Registry.xml", + "ref/netstandard1.3/zh-hans/Microsoft.Win32.Registry.xml", + "ref/netstandard1.3/zh-hant/Microsoft.Win32.Registry.xml", + "ref/netstandard2.0/Microsoft.Win32.Registry.dll", + "ref/netstandard2.0/Microsoft.Win32.Registry.xml", + "runtimes/win/lib/net46/Microsoft.Win32.Registry.dll", + "runtimes/win/lib/net461/Microsoft.Win32.Registry.dll", + "runtimes/win/lib/net461/Microsoft.Win32.Registry.xml", + "runtimes/win/lib/netstandard1.3/Microsoft.Win32.Registry.dll", + "runtimes/win/lib/netstandard2.0/Microsoft.Win32.Registry.dll", + "runtimes/win/lib/netstandard2.0/Microsoft.Win32.Registry.xml", + "useSharedDesignerContext.txt", + "version.txt" + ] + }, + "MongoDB.Bson/3.1.0": { + "sha512": "3dhaZhz18B5vUoEP13o2j8A6zQfkHdZhwBvLZEjDJum4BTLLv1/Z8bt25UQEtpqvYwLgde4R6ekWZ7XAYUMxuw==", + "type": "package", + "path": "mongodb.bson/3.1.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "README.md", + "lib/net472/MongoDB.Bson.dll", + "lib/net472/MongoDB.Bson.xml", + "lib/net6.0/MongoDB.Bson.dll", + "lib/net6.0/MongoDB.Bson.xml", + "lib/netstandard2.1/MongoDB.Bson.dll", + "lib/netstandard2.1/MongoDB.Bson.xml", + "mongodb.bson.3.1.0.nupkg.sha512", + "mongodb.bson.nuspec", + "packageIcon.png" + ] + }, + "MongoDB.Driver/3.1.0": { + "sha512": "+O7lKaIl7VUHptE0hqTd7UY1G5KDp/o8S4upG7YL4uChMNKD/U6tz9i17nMGHaD/L2AiPLgaJcaDe2XACsegGA==", + "type": "package", + "path": "mongodb.driver/3.1.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "README.md", + "lib/net472/MongoDB.Driver.dll", + "lib/net472/MongoDB.Driver.xml", + "lib/net6.0/MongoDB.Driver.dll", + "lib/net6.0/MongoDB.Driver.xml", + "lib/netstandard2.1/MongoDB.Driver.dll", + "lib/netstandard2.1/MongoDB.Driver.xml", + "mongodb.driver.3.1.0.nupkg.sha512", + "mongodb.driver.nuspec", + "packageIcon.png" + ] + }, + "Newtonsoft.Json/13.0.3": { + "sha512": "HrC5BXdl00IP9zeV+0Z848QWPAoCr9P3bDEZguI+gkLcBKAOxix/tLEAAHC+UvDNPv4a2d18lOReHMOagPa+zQ==", + "type": "package", + "path": "newtonsoft.json/13.0.3", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "LICENSE.md", + "README.md", + "lib/net20/Newtonsoft.Json.dll", + "lib/net20/Newtonsoft.Json.xml", + "lib/net35/Newtonsoft.Json.dll", + "lib/net35/Newtonsoft.Json.xml", + "lib/net40/Newtonsoft.Json.dll", + "lib/net40/Newtonsoft.Json.xml", + "lib/net45/Newtonsoft.Json.dll", + "lib/net45/Newtonsoft.Json.xml", + "lib/net6.0/Newtonsoft.Json.dll", + "lib/net6.0/Newtonsoft.Json.xml", + "lib/netstandard1.0/Newtonsoft.Json.dll", + "lib/netstandard1.0/Newtonsoft.Json.xml", + "lib/netstandard1.3/Newtonsoft.Json.dll", + "lib/netstandard1.3/Newtonsoft.Json.xml", + "lib/netstandard2.0/Newtonsoft.Json.dll", + "lib/netstandard2.0/Newtonsoft.Json.xml", + "newtonsoft.json.13.0.3.nupkg.sha512", + "newtonsoft.json.nuspec", + "packageIcon.png" + ] + }, + "NLog/5.3.4": { + "sha512": "gLy7+O1hEYJXIlcTr1/VWjGXrZTQFZzYNO18IWasD64pNwz0BreV+nHLxWKXWZzERRzoKnsk2XYtwLkTVk7J1A==", + "type": "package", + "path": "nlog/5.3.4", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "N.png", + "lib/net35/NLog.dll", + "lib/net35/NLog.xml", + "lib/net45/NLog.dll", + "lib/net45/NLog.xml", + "lib/net46/NLog.dll", + "lib/net46/NLog.xml", + "lib/netstandard1.3/NLog.dll", + "lib/netstandard1.3/NLog.xml", + "lib/netstandard1.5/NLog.dll", + "lib/netstandard1.5/NLog.xml", + "lib/netstandard2.0/NLog.dll", + "lib/netstandard2.0/NLog.xml", + "nlog.5.3.4.nupkg.sha512", + "nlog.nuspec" + ] + }, + "protobuf-net/3.2.45": { + "sha512": "5UZ/ukUHcGbFSl7vNMrHsfjqdxusdd9w7w0fCEXzf3UUtsrGNVCzV5SmF+sCHAbnRV2qPcD1ixiDP7Aj8lX/HA==", + "type": "package", + "path": "protobuf-net/3.2.45", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "lib/net462/protobuf-net.dll", + "lib/net462/protobuf-net.xml", + "lib/net6.0/protobuf-net.dll", + "lib/net6.0/protobuf-net.xml", + "lib/netstandard2.0/protobuf-net.dll", + "lib/netstandard2.0/protobuf-net.xml", + "lib/netstandard2.1/protobuf-net.dll", + "lib/netstandard2.1/protobuf-net.xml", + "protobuf-net.3.2.45.nupkg.sha512", + "protobuf-net.nuspec", + "protobuf-net.png", + "readme.md" + ] + }, + "protobuf-net.Core/3.2.45": { + "sha512": "PMWatW2NrT1uTXD7etJ4VdQ0wWZLFrIfdRGppD2QX7nzZ0+kIzqhq551u6ZiXJHWJgG4hWFEkSnUnt2aB6posg==", + "type": "package", + "path": "protobuf-net.core/3.2.45", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "lib/net462/protobuf-net.Core.dll", + "lib/net462/protobuf-net.Core.xml", + "lib/net6.0/protobuf-net.Core.dll", + "lib/net6.0/protobuf-net.Core.xml", + "lib/netstandard2.0/protobuf-net.Core.dll", + "lib/netstandard2.0/protobuf-net.Core.xml", + "lib/netstandard2.1/protobuf-net.Core.dll", + "lib/netstandard2.1/protobuf-net.Core.xml", + "protobuf-net.core.3.2.45.nupkg.sha512", + "protobuf-net.core.nuspec", + "protobuf-net.png", + "readme.md" + ] + }, + "SharpCompress/0.30.1": { + "sha512": "XqD4TpfyYGa7QTPzaGlMVbcecKnXy4YmYLDWrU+JIj7IuRNl7DH2END+Ll7ekWIY8o3dAMWLFDE1xdhfIWD1nw==", + "type": "package", + "path": "sharpcompress/0.30.1", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "lib/net461/SharpCompress.dll", + "lib/net5.0/SharpCompress.dll", + "lib/netcoreapp3.1/SharpCompress.dll", + "lib/netstandard2.0/SharpCompress.dll", + "lib/netstandard2.1/SharpCompress.dll", + "sharpcompress.0.30.1.nupkg.sha512", + "sharpcompress.nuspec" + ] + }, + "Snappier/1.0.0": { + "sha512": "rFtK2KEI9hIe8gtx3a0YDXdHOpedIf9wYCEYtBEmtlyiWVX3XlCNV03JrmmAi/Cdfn7dxK+k0sjjcLv4fpHnqA==", + "type": "package", + "path": "snappier/1.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "COPYING.txt", + "lib/net5.0/Snappier.dll", + "lib/net5.0/Snappier.xml", + "lib/netcoreapp3.0/Snappier.dll", + "lib/netcoreapp3.0/Snappier.xml", + "lib/netstandard2.0/Snappier.dll", + "lib/netstandard2.0/Snappier.xml", + "lib/netstandard2.1/Snappier.dll", + "lib/netstandard2.1/Snappier.xml", + "snappier.1.0.0.nupkg.sha512", + "snappier.nuspec" + ] + }, + "System.Buffers/4.5.1": { + "sha512": "Rw7ijyl1qqRS0YQD/WycNst8hUUMgrMH4FCn1nNm27M4VxchZ1js3fVjQaANHO5f3sN4isvP4a+Met9Y4YomAg==", + "type": "package", + "path": "system.buffers/4.5.1", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "LICENSE.TXT", + "THIRD-PARTY-NOTICES.TXT", + "lib/net461/System.Buffers.dll", + "lib/net461/System.Buffers.xml", + "lib/netcoreapp2.0/_._", + "lib/netstandard1.1/System.Buffers.dll", + "lib/netstandard1.1/System.Buffers.xml", + "lib/netstandard2.0/System.Buffers.dll", + "lib/netstandard2.0/System.Buffers.xml", + "lib/uap10.0.16299/_._", + "ref/net45/System.Buffers.dll", + "ref/net45/System.Buffers.xml", + "ref/netcoreapp2.0/_._", + "ref/netstandard1.1/System.Buffers.dll", + "ref/netstandard1.1/System.Buffers.xml", + "ref/netstandard2.0/System.Buffers.dll", + "ref/netstandard2.0/System.Buffers.xml", + "ref/uap10.0.16299/_._", + "system.buffers.4.5.1.nupkg.sha512", + "system.buffers.nuspec", + "useSharedDesignerContext.txt", + "version.txt" + ] + }, + "System.Collections.Immutable/7.0.0": { + "sha512": "dQPcs0U1IKnBdRDBkrCTi1FoajSTBzLcVTpjO4MBCMC7f4pDOIPzgBoX8JjG7X6uZRJ8EBxsi8+DR1JuwjnzOQ==", + "type": "package", + "path": "system.collections.immutable/7.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "LICENSE.TXT", + "README.md", + "THIRD-PARTY-NOTICES.TXT", + "buildTransitive/net461/System.Collections.Immutable.targets", + "buildTransitive/net462/_._", + "buildTransitive/net6.0/_._", + "buildTransitive/netcoreapp2.0/System.Collections.Immutable.targets", + "lib/net462/System.Collections.Immutable.dll", + "lib/net462/System.Collections.Immutable.xml", + "lib/net6.0/System.Collections.Immutable.dll", + "lib/net6.0/System.Collections.Immutable.xml", + "lib/net7.0/System.Collections.Immutable.dll", + "lib/net7.0/System.Collections.Immutable.xml", + "lib/netstandard2.0/System.Collections.Immutable.dll", + "lib/netstandard2.0/System.Collections.Immutable.xml", + "system.collections.immutable.7.0.0.nupkg.sha512", + "system.collections.immutable.nuspec", + "useSharedDesignerContext.txt" + ] + }, + "System.IO.Pipelines/9.0.0": { + "sha512": "eA3cinogwaNB4jdjQHOP3Z3EuyiDII7MT35jgtnsA4vkn0LUrrSHsU0nzHTzFzmaFYeKV7MYyMxOocFzsBHpTw==", + "type": "package", + "path": "system.io.pipelines/9.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "LICENSE.TXT", + "PACKAGE.md", + "THIRD-PARTY-NOTICES.TXT", + "buildTransitive/net461/System.IO.Pipelines.targets", + "buildTransitive/net462/_._", + "buildTransitive/net8.0/_._", + "buildTransitive/netcoreapp2.0/System.IO.Pipelines.targets", + "lib/net462/System.IO.Pipelines.dll", + "lib/net462/System.IO.Pipelines.xml", + "lib/net8.0/System.IO.Pipelines.dll", + "lib/net8.0/System.IO.Pipelines.xml", + "lib/net9.0/System.IO.Pipelines.dll", + "lib/net9.0/System.IO.Pipelines.xml", + "lib/netstandard2.0/System.IO.Pipelines.dll", + "lib/netstandard2.0/System.IO.Pipelines.xml", + "system.io.pipelines.9.0.0.nupkg.sha512", + "system.io.pipelines.nuspec", + "useSharedDesignerContext.txt" + ] + }, + "System.Memory/4.5.5": { + "sha512": "XIWiDvKPXaTveaB7HVganDlOCRoj03l+jrwNvcge/t8vhGYKvqV+dMv6G4SAX2NoNmN0wZfVPTAlFwZcZvVOUw==", + "type": "package", + "path": "system.memory/4.5.5", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "LICENSE.TXT", + "THIRD-PARTY-NOTICES.TXT", + "lib/net461/System.Memory.dll", + "lib/net461/System.Memory.xml", + "lib/netcoreapp2.1/_._", + "lib/netstandard1.1/System.Memory.dll", + "lib/netstandard1.1/System.Memory.xml", + "lib/netstandard2.0/System.Memory.dll", + "lib/netstandard2.0/System.Memory.xml", + "ref/netcoreapp2.1/_._", + "system.memory.4.5.5.nupkg.sha512", + "system.memory.nuspec", + "useSharedDesignerContext.txt", + "version.txt" + ] + }, + "System.Runtime.CompilerServices.Unsafe/5.0.0": { + "sha512": "ZD9TMpsmYJLrxbbmdvhwt9YEgG5WntEnZ/d1eH8JBX9LBp+Ju8BSBhUGbZMNVHHomWo2KVImJhTDl2hIgw/6MA==", + "type": "package", + "path": "system.runtime.compilerservices.unsafe/5.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "LICENSE.TXT", + "THIRD-PARTY-NOTICES.TXT", + "lib/net45/System.Runtime.CompilerServices.Unsafe.dll", + "lib/net45/System.Runtime.CompilerServices.Unsafe.xml", + "lib/netcoreapp2.0/System.Runtime.CompilerServices.Unsafe.dll", + "lib/netcoreapp2.0/System.Runtime.CompilerServices.Unsafe.xml", + "lib/netstandard1.0/System.Runtime.CompilerServices.Unsafe.dll", + "lib/netstandard1.0/System.Runtime.CompilerServices.Unsafe.xml", + "lib/netstandard2.0/System.Runtime.CompilerServices.Unsafe.dll", + "lib/netstandard2.0/System.Runtime.CompilerServices.Unsafe.xml", + "ref/net461/System.Runtime.CompilerServices.Unsafe.dll", + "ref/net461/System.Runtime.CompilerServices.Unsafe.xml", + "ref/netstandard1.0/System.Runtime.CompilerServices.Unsafe.dll", + "ref/netstandard1.0/System.Runtime.CompilerServices.Unsafe.xml", + "ref/netstandard2.0/System.Runtime.CompilerServices.Unsafe.dll", + "ref/netstandard2.0/System.Runtime.CompilerServices.Unsafe.xml", + "ref/netstandard2.1/System.Runtime.CompilerServices.Unsafe.dll", + "ref/netstandard2.1/System.Runtime.CompilerServices.Unsafe.xml", + "system.runtime.compilerservices.unsafe.5.0.0.nupkg.sha512", + "system.runtime.compilerservices.unsafe.nuspec", + "useSharedDesignerContext.txt", + "version.txt" + ] + }, + "System.Security.AccessControl/5.0.0": { + "sha512": "dagJ1mHZO3Ani8GH0PHpPEe/oYO+rVdbQjvjJkBRNQkX4t0r1iaeGn8+/ybkSLEan3/slM0t59SVdHzuHf2jmw==", + "type": "package", + "path": "system.security.accesscontrol/5.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "LICENSE.TXT", + "THIRD-PARTY-NOTICES.TXT", + "lib/net46/System.Security.AccessControl.dll", + "lib/net461/System.Security.AccessControl.dll", + "lib/net461/System.Security.AccessControl.xml", + "lib/netstandard1.3/System.Security.AccessControl.dll", + "lib/netstandard2.0/System.Security.AccessControl.dll", + "lib/netstandard2.0/System.Security.AccessControl.xml", + "lib/uap10.0.16299/_._", + "ref/net46/System.Security.AccessControl.dll", + "ref/net461/System.Security.AccessControl.dll", + "ref/net461/System.Security.AccessControl.xml", + "ref/netstandard1.3/System.Security.AccessControl.dll", + "ref/netstandard1.3/System.Security.AccessControl.xml", + "ref/netstandard1.3/de/System.Security.AccessControl.xml", + "ref/netstandard1.3/es/System.Security.AccessControl.xml", + "ref/netstandard1.3/fr/System.Security.AccessControl.xml", + "ref/netstandard1.3/it/System.Security.AccessControl.xml", + "ref/netstandard1.3/ja/System.Security.AccessControl.xml", + "ref/netstandard1.3/ko/System.Security.AccessControl.xml", + "ref/netstandard1.3/ru/System.Security.AccessControl.xml", + "ref/netstandard1.3/zh-hans/System.Security.AccessControl.xml", + "ref/netstandard1.3/zh-hant/System.Security.AccessControl.xml", + "ref/netstandard2.0/System.Security.AccessControl.dll", + "ref/netstandard2.0/System.Security.AccessControl.xml", + "ref/uap10.0.16299/_._", + "runtimes/win/lib/net46/System.Security.AccessControl.dll", + "runtimes/win/lib/net461/System.Security.AccessControl.dll", + "runtimes/win/lib/net461/System.Security.AccessControl.xml", + "runtimes/win/lib/netcoreapp2.0/System.Security.AccessControl.dll", + "runtimes/win/lib/netcoreapp2.0/System.Security.AccessControl.xml", + "runtimes/win/lib/netstandard1.3/System.Security.AccessControl.dll", + "runtimes/win/lib/uap10.0.16299/_._", + "system.security.accesscontrol.5.0.0.nupkg.sha512", + "system.security.accesscontrol.nuspec", + "useSharedDesignerContext.txt", + "version.txt" + ] + }, + "System.Security.Principal.Windows/5.0.0": { + "sha512": "t0MGLukB5WAVU9bO3MGzvlGnyJPgUlcwerXn1kzBRjwLKixT96XV0Uza41W49gVd8zEMFu9vQEFlv0IOrytICA==", + "type": "package", + "path": "system.security.principal.windows/5.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "LICENSE.TXT", + "THIRD-PARTY-NOTICES.TXT", + "lib/net46/System.Security.Principal.Windows.dll", + "lib/net461/System.Security.Principal.Windows.dll", + "lib/net461/System.Security.Principal.Windows.xml", + "lib/netstandard1.3/System.Security.Principal.Windows.dll", + "lib/netstandard2.0/System.Security.Principal.Windows.dll", + "lib/netstandard2.0/System.Security.Principal.Windows.xml", + "lib/uap10.0.16299/_._", + "ref/net46/System.Security.Principal.Windows.dll", + "ref/net461/System.Security.Principal.Windows.dll", + "ref/net461/System.Security.Principal.Windows.xml", + "ref/netcoreapp3.0/System.Security.Principal.Windows.dll", + "ref/netcoreapp3.0/System.Security.Principal.Windows.xml", + "ref/netstandard1.3/System.Security.Principal.Windows.dll", + "ref/netstandard1.3/System.Security.Principal.Windows.xml", + "ref/netstandard1.3/de/System.Security.Principal.Windows.xml", + "ref/netstandard1.3/es/System.Security.Principal.Windows.xml", + "ref/netstandard1.3/fr/System.Security.Principal.Windows.xml", + "ref/netstandard1.3/it/System.Security.Principal.Windows.xml", + "ref/netstandard1.3/ja/System.Security.Principal.Windows.xml", + "ref/netstandard1.3/ko/System.Security.Principal.Windows.xml", + "ref/netstandard1.3/ru/System.Security.Principal.Windows.xml", + "ref/netstandard1.3/zh-hans/System.Security.Principal.Windows.xml", + "ref/netstandard1.3/zh-hant/System.Security.Principal.Windows.xml", + "ref/netstandard2.0/System.Security.Principal.Windows.dll", + "ref/netstandard2.0/System.Security.Principal.Windows.xml", + "ref/uap10.0.16299/_._", + "runtimes/unix/lib/netcoreapp2.0/System.Security.Principal.Windows.dll", + "runtimes/unix/lib/netcoreapp2.0/System.Security.Principal.Windows.xml", + "runtimes/unix/lib/netcoreapp2.1/System.Security.Principal.Windows.dll", + "runtimes/unix/lib/netcoreapp2.1/System.Security.Principal.Windows.xml", + "runtimes/win/lib/net46/System.Security.Principal.Windows.dll", + "runtimes/win/lib/net461/System.Security.Principal.Windows.dll", + "runtimes/win/lib/net461/System.Security.Principal.Windows.xml", + "runtimes/win/lib/netcoreapp2.0/System.Security.Principal.Windows.dll", + "runtimes/win/lib/netcoreapp2.0/System.Security.Principal.Windows.xml", + "runtimes/win/lib/netcoreapp2.1/System.Security.Principal.Windows.dll", + "runtimes/win/lib/netcoreapp2.1/System.Security.Principal.Windows.xml", + "runtimes/win/lib/netstandard1.3/System.Security.Principal.Windows.dll", + "runtimes/win/lib/uap10.0.16299/_._", + "system.security.principal.windows.5.0.0.nupkg.sha512", + "system.security.principal.windows.nuspec", + "useSharedDesignerContext.txt", + "version.txt" + ] + }, + "ZstdSharp.Port/0.7.3": { + "sha512": "U9Ix4l4cl58Kzz1rJzj5hoVTjmbx1qGMwzAcbv1j/d3NzrFaESIurQyg+ow4mivCgkE3S413y+U9k4WdnEIkRA==", + "type": "package", + "path": "zstdsharp.port/0.7.3", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "lib/net461/ZstdSharp.dll", + "lib/net5.0/ZstdSharp.dll", + "lib/net6.0/ZstdSharp.dll", + "lib/net7.0/ZstdSharp.dll", + "lib/netcoreapp3.1/ZstdSharp.dll", + "lib/netstandard2.0/ZstdSharp.dll", + "lib/netstandard2.1/ZstdSharp.dll", + "zstdsharp.port.0.7.3.nupkg.sha512", + "zstdsharp.port.nuspec" + ] + }, + "Entity/1.0.0": { + "type": "project", + "path": "../Entity/Entity.csproj", + "msbuildProject": "../Entity/Entity.csproj" + }, + "Fantasy-Net/2024.2.24": { + "type": "project", + "path": "../../Packages/Fantasy/Fantasy.Net/Fantasy.Net/Fantasy.Net.csproj", + "msbuildProject": "../../Packages/Fantasy/Fantasy.Net/Fantasy.Net/Fantasy.Net.csproj" + }, + "Fantasy-Net.ConfigTable/2024.2.0": { + "type": "project", + "path": "../../Packages/Fantasy/Fantasy.Packages/Fantasy.ConfigTable/Net/Fantasy.ConfigTable.csproj", + "msbuildProject": "../../Packages/Fantasy/Fantasy.Packages/Fantasy.ConfigTable/Net/Fantasy.ConfigTable.csproj" + }, + "Fantasy-Net.NLog/2024.1.20": { + "type": "project", + "path": "../../Packages/Fantasy/Fantasy.Packages/Fantasy.NLog/Fantasy.NLog.csproj", + "msbuildProject": "../../Packages/Fantasy/Fantasy.Packages/Fantasy.NLog/Fantasy.NLog.csproj" + }, + "Hotfix/1.0.0": { + "type": "project", + "path": "../Hotfix/Hotfix.csproj", + "msbuildProject": "../Hotfix/Hotfix.csproj" + } + }, + "projectFileDependencyGroups": { + "net8.0": [ + "Entity >= 1.0.0", + "Fantasy-Net >= 2024.2.24", + "Fantasy-Net.NLog >= 2024.1.20", + "Hotfix >= 1.0.0" + ] + }, + "packageFolders": { + "/Users/fantasy/.nuget/packages/": {} + }, + "project": { + "version": "1.0.0", + "restore": { + "projectUniqueName": "/Users/fantasy/Movies/物品背包开发之旅/B/Server/Main/Main.csproj", + "projectName": "Main", + "projectPath": "/Users/fantasy/Movies/物品背包开发之旅/B/Server/Main/Main.csproj", + "packagesPath": "/Users/fantasy/.nuget/packages/", + "outputPath": "/Users/fantasy/Movies/物品背包开发之旅/B/Server/Main/obj/", + "projectStyle": "PackageReference", + "configFilePaths": [ + "/Users/fantasy/.nuget/NuGet/NuGet.Config" + ], + "originalTargetFrameworks": [ + "net8.0" + ], + "sources": { + "/usr/local/share/dotnet/library-packs": {}, + "https://api.nuget.org/v3/index.json": {} + }, + "frameworks": { + "net8.0": { + "targetAlias": "net8.0", + "projectReferences": { + "/Users/fantasy/Movies/物品背包开发之旅/B/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Fantasy.Net.csproj": { + "projectPath": "/Users/fantasy/Movies/物品背包开发之旅/B/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Fantasy.Net.csproj" + }, + "/Users/fantasy/Movies/物品背包开发之旅/B/Packages/Fantasy/Fantasy.Packages/Fantasy.NLog/Fantasy.NLog.csproj": { + "projectPath": "/Users/fantasy/Movies/物品背包开发之旅/B/Packages/Fantasy/Fantasy.Packages/Fantasy.NLog/Fantasy.NLog.csproj" + }, + "/Users/fantasy/Movies/物品背包开发之旅/B/Server/Entity/Entity.csproj": { + "projectPath": "/Users/fantasy/Movies/物品背包开发之旅/B/Server/Entity/Entity.csproj" + }, + "/Users/fantasy/Movies/物品背包开发之旅/B/Server/Hotfix/Hotfix.csproj": { + "projectPath": "/Users/fantasy/Movies/物品背包开发之旅/B/Server/Hotfix/Hotfix.csproj" + } + } + } + }, + "warningProperties": { + "warnAsError": [ + "NU1605" + ] + }, + "restoreAuditProperties": { + "enableAudit": "true", + "auditLevel": "low", + "auditMode": "all" + }, + "SdkAnalysisLevel": "9.0.100" + }, + "frameworks": { + "net8.0": { + "targetAlias": "net8.0", + "imports": [ + "net461", + "net462", + "net47", + "net471", + "net472", + "net48", + "net481" + ], + "assetTargetFallback": true, + "warn": true, + "frameworkReferences": { + "Microsoft.NETCore.App": { + "privateAssets": "all" + } + }, + "runtimeIdentifierGraphPath": "/usr/local/share/dotnet/sdk/9.0.100/PortableRuntimeIdentifierGraph.json" + } + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Server/Main/obj/project.nuget.cache b/物品和背包的完整代码/Server/Main/obj/project.nuget.cache new file mode 100644 index 0000000..39e3f4a --- /dev/null +++ b/物品和背包的完整代码/Server/Main/obj/project.nuget.cache @@ -0,0 +1,32 @@ +{ + "version": 2, + "dgSpecHash": "hbtLQiBB+7o=", + "success": true, + "projectFilePath": "/Users/fantasy/Movies/物品背包开发之旅/B/Server/Main/Main.csproj", + "expectedPackageFiles": [ + "/Users/fantasy/.nuget/packages/commandlineparser/2.9.1/commandlineparser.2.9.1.nupkg.sha512", + "/Users/fantasy/.nuget/packages/dnsclient/1.6.1/dnsclient.1.6.1.nupkg.sha512", + "/Users/fantasy/.nuget/packages/microsoft.extensions.logging.abstractions/2.0.0/microsoft.extensions.logging.abstractions.2.0.0.nupkg.sha512", + "/Users/fantasy/.nuget/packages/microsoft.netcore.platforms/5.0.0/microsoft.netcore.platforms.5.0.0.nupkg.sha512", + "/Users/fantasy/.nuget/packages/microsoft.win32.registry/5.0.0/microsoft.win32.registry.5.0.0.nupkg.sha512", + "/Users/fantasy/.nuget/packages/mongodb.bson/3.1.0/mongodb.bson.3.1.0.nupkg.sha512", + "/Users/fantasy/.nuget/packages/mongodb.driver/3.1.0/mongodb.driver.3.1.0.nupkg.sha512", + "/Users/fantasy/.nuget/packages/newtonsoft.json/13.0.3/newtonsoft.json.13.0.3.nupkg.sha512", + "/Users/fantasy/.nuget/packages/nlog/5.3.4/nlog.5.3.4.nupkg.sha512", + "/Users/fantasy/.nuget/packages/protobuf-net/3.2.45/protobuf-net.3.2.45.nupkg.sha512", + "/Users/fantasy/.nuget/packages/protobuf-net.core/3.2.45/protobuf-net.core.3.2.45.nupkg.sha512", + "/Users/fantasy/.nuget/packages/sharpcompress/0.30.1/sharpcompress.0.30.1.nupkg.sha512", + "/Users/fantasy/.nuget/packages/snappier/1.0.0/snappier.1.0.0.nupkg.sha512", + "/Users/fantasy/.nuget/packages/system.buffers/4.5.1/system.buffers.4.5.1.nupkg.sha512", + "/Users/fantasy/.nuget/packages/system.collections.immutable/7.0.0/system.collections.immutable.7.0.0.nupkg.sha512", + "/Users/fantasy/.nuget/packages/system.io.pipelines/9.0.0/system.io.pipelines.9.0.0.nupkg.sha512", + "/Users/fantasy/.nuget/packages/system.memory/4.5.5/system.memory.4.5.5.nupkg.sha512", + "/Users/fantasy/.nuget/packages/system.runtime.compilerservices.unsafe/5.0.0/system.runtime.compilerservices.unsafe.5.0.0.nupkg.sha512", + "/Users/fantasy/.nuget/packages/system.security.accesscontrol/5.0.0/system.security.accesscontrol.5.0.0.nupkg.sha512", + "/Users/fantasy/.nuget/packages/system.security.principal.windows/5.0.0/system.security.principal.windows.5.0.0.nupkg.sha512", + "/Users/fantasy/.nuget/packages/zstdsharp.port/0.7.3/zstdsharp.port.0.7.3.nupkg.sha512", + "/Users/fantasy/.nuget/packages/fantasy-net/2024.2.24/fantasy-net.2024.2.24.nupkg.sha512", + "/Users/fantasy/.nuget/packages/fantasy-net.nlog/2024.1.20/fantasy-net.nlog.2024.1.20.nupkg.sha512" + ], + "logs": [] +} \ No newline at end of file diff --git a/物品和背包的完整代码/Server/Main/obj/project.packagespec.json b/物品和背包的完整代码/Server/Main/obj/project.packagespec.json new file mode 100644 index 0000000..2765610 --- /dev/null +++ b/物品和背包的完整代码/Server/Main/obj/project.packagespec.json @@ -0,0 +1 @@ +"restore":{"projectUniqueName":"/Users/fantasy/Movies/物品背包开发之旅/B/Server/Main/Main.csproj","projectName":"Main","projectPath":"/Users/fantasy/Movies/物品背包开发之旅/B/Server/Main/Main.csproj","outputPath":"/Users/fantasy/Movies/物品背包开发之旅/B/Server/Main/obj/","projectStyle":"PackageReference","originalTargetFrameworks":["net8.0"],"sources":{"/usr/local/share/dotnet/library-packs":{},"https://api.nuget.org/v3/index.json":{}},"frameworks":{"net8.0":{"targetAlias":"net8.0","projectReferences":{"/Users/fantasy/Movies/物品背包开发之旅/B/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Fantasy.Net.csproj":{"projectPath":"/Users/fantasy/Movies/物品背包开发之旅/B/Packages/Fantasy/Fantasy.Net/Fantasy.Net/Fantasy.Net.csproj"},"/Users/fantasy/Movies/物品背包开发之旅/B/Packages/Fantasy/Fantasy.Packages/Fantasy.NLog/Fantasy.NLog.csproj":{"projectPath":"/Users/fantasy/Movies/物品背包开发之旅/B/Packages/Fantasy/Fantasy.Packages/Fantasy.NLog/Fantasy.NLog.csproj"},"/Users/fantasy/Movies/物品背包开发之旅/B/Server/Entity/Entity.csproj":{"projectPath":"/Users/fantasy/Movies/物品背包开发之旅/B/Server/Entity/Entity.csproj"},"/Users/fantasy/Movies/物品背包开发之旅/B/Server/Hotfix/Hotfix.csproj":{"projectPath":"/Users/fantasy/Movies/物品背包开发之旅/B/Server/Hotfix/Hotfix.csproj"}}}},"warningProperties":{"warnAsError":["NU1605"]},"restoreAuditProperties":{"enableAudit":"true","auditLevel":"low","auditMode":"all"},"SdkAnalysisLevel":"9.0.100"}"frameworks":{"net8.0":{"targetAlias":"net8.0","imports":["net461","net462","net47","net471","net472","net48","net481"],"assetTargetFallback":true,"warn":true,"frameworkReferences":{"Microsoft.NETCore.App":{"privateAssets":"all"}},"runtimeIdentifierGraphPath":"/usr/local/share/dotnet/sdk/9.0.100/PortableRuntimeIdentifierGraph.json"}} \ No newline at end of file diff --git a/物品和背包的完整代码/Server/Main/obj/rider.project.model.nuget.info b/物品和背包的完整代码/Server/Main/obj/rider.project.model.nuget.info new file mode 100644 index 0000000..dc84076 --- /dev/null +++ b/物品和背包的完整代码/Server/Main/obj/rider.project.model.nuget.info @@ -0,0 +1 @@ +17428701567253970 \ No newline at end of file diff --git a/物品和背包的完整代码/Server/Main/obj/rider.project.restore.info b/物品和背包的完整代码/Server/Main/obj/rider.project.restore.info new file mode 100644 index 0000000..dc84076 --- /dev/null +++ b/物品和背包的完整代码/Server/Main/obj/rider.project.restore.info @@ -0,0 +1 @@ +17428701567253970 \ No newline at end of file diff --git a/物品和背包的完整代码/Tools/.DS_Store b/物品和背包的完整代码/Tools/.DS_Store new file mode 100644 index 0000000..6474d26 Binary files /dev/null and b/物品和背包的完整代码/Tools/.DS_Store differ diff --git a/物品和背包的完整代码/Tools/ConfigTable/CommandLine.dll b/物品和背包的完整代码/Tools/ConfigTable/CommandLine.dll new file mode 100644 index 0000000..3eab2be Binary files /dev/null and b/物品和背包的完整代码/Tools/ConfigTable/CommandLine.dll differ diff --git a/物品和背包的完整代码/Tools/ConfigTable/EPPlus.Interfaces.dll b/物品和背包的完整代码/Tools/ConfigTable/EPPlus.Interfaces.dll new file mode 100644 index 0000000..599a767 Binary files /dev/null and b/物品和背包的完整代码/Tools/ConfigTable/EPPlus.Interfaces.dll differ diff --git a/物品和背包的完整代码/Tools/ConfigTable/EPPlus.System.Drawing.dll b/物品和背包的完整代码/Tools/ConfigTable/EPPlus.System.Drawing.dll new file mode 100644 index 0000000..8df125e Binary files /dev/null and b/物品和背包的完整代码/Tools/ConfigTable/EPPlus.System.Drawing.dll differ diff --git a/物品和背包的完整代码/Tools/ConfigTable/EPPlus.dll b/物品和背包的完整代码/Tools/ConfigTable/EPPlus.dll new file mode 100644 index 0000000..b09ea77 Binary files /dev/null and b/物品和背包的完整代码/Tools/ConfigTable/EPPlus.dll differ diff --git a/物品和背包的完整代码/Tools/ConfigTable/ExporterSettings.json b/物品和背包的完整代码/Tools/ConfigTable/ExporterSettings.json new file mode 100644 index 0000000..27287ac --- /dev/null +++ b/物品和背包的完整代码/Tools/ConfigTable/ExporterSettings.json @@ -0,0 +1,44 @@ +{ + "Export": { + "ExcelProgramPath": { + "Value": "../../Config/Excel/", + "Comment": "Excel文件夹的根目录" + }, + "ExcelVersionFile": { + "Value": "../../Config/Excel/Version.txt", + "Comment": "Excel的Version文件位置、这个文件用于记录每次导出对比是否需要再次导出的文件" + }, + "ExcelServerFileDirectory": { + "Value": "../../Server/Entity/Generate/ConfigTable/Entity/", + "Comment": "Excel生成的代码文件、在服务端文件夹位置" + }, + "ExcelClientFileDirectory": { + "Value": "../../Client/Unity/Assets/Scripts/Hotfix/Generate/ConfigTable/Entity/", + "Comment": "Excel生成的代码文件、在客户端文件夹位置" + }, + "ExcelServerBinaryDirectory": { + "Value": "../../Config/Binary/", + "Comment": "Excel生成服务器二进制数据文件夹位置" + }, + "ExcelClientBinaryDirectory": { + "Value": "../../Client/Unity/Assets/Bundles/Config/", + "Comment": "Excel生成在客户端的二进制数据文件夹位置" + }, + "ExcelServerJsonDirectory": { + "Value": "../../Config/Json/Server/", + "Comment": "Excel生成在服务端的Json数据文件夹位置" + }, + "ExcelClientJsonDirectory": { + "Value": "../../Config/Json/Client/", + "Comment": "Excel生成在客户端的Json数据文件夹位置" + }, + "ServerCustomExportDirectory": { + "Value": "../../Server/Entity/Generate/CustomExport/", + "Comment": "Excel在服务端生成自定义代码的文件夹位置" + }, + "ClientCustomExportDirectory": { + "Value": "../../Client/Unity/Assets/Scripts/Hotfix/Generate/CustomExport", + "Comment": "Excel在客户端端生成自定义代码的文件夹位置" + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Tools/ConfigTable/Fantasy.Tools.ConfigTable b/物品和背包的完整代码/Tools/ConfigTable/Fantasy.Tools.ConfigTable new file mode 100644 index 0000000..351f187 Binary files /dev/null and b/物品和背包的完整代码/Tools/ConfigTable/Fantasy.Tools.ConfigTable differ diff --git a/物品和背包的完整代码/Tools/ConfigTable/Fantasy.Tools.ConfigTable.deps.json b/物品和背包的完整代码/Tools/ConfigTable/Fantasy.Tools.ConfigTable.deps.json new file mode 100644 index 0000000..a7025c3 --- /dev/null +++ b/物品和背包的完整代码/Tools/ConfigTable/Fantasy.Tools.ConfigTable.deps.json @@ -0,0 +1,508 @@ +{ + "runtimeTarget": { + "name": ".NETCoreApp,Version=v8.0", + "signature": "" + }, + "compilationOptions": {}, + "targets": { + ".NETCoreApp,Version=v8.0": { + "Fantasy.Tools.ConfigTable/1.0.0": { + "dependencies": { + "CommandLineParser": "2.9.1", + "EPPlus": "7.3.2", + "Microsoft.CodeAnalysis.CSharp": "4.11.0", + "Microsoft.Extensions.Configuration.Json": "8.0.0", + "Newtonsoft.Json": "13.0.3", + "protobuf-net": "3.2.30" + }, + "runtime": { + "Fantasy.Tools.ConfigTable.dll": {} + } + }, + "CommandLineParser/2.9.1": { + "runtime": { + "lib/netstandard2.0/CommandLine.dll": { + "assemblyVersion": "2.9.1.0", + "fileVersion": "2.9.1.0" + } + } + }, + "EPPlus/7.3.2": { + "dependencies": { + "EPPlus.System.Drawing": "6.1.1", + "Microsoft.Extensions.Configuration.Json": "8.0.0", + "Microsoft.IO.RecyclableMemoryStream": "3.0.1", + "System.ComponentModel.Annotations": "5.0.0", + "System.Formats.Asn1": "8.0.1", + "System.Security.Cryptography.Pkcs": "8.0.0", + "System.Text.Encoding.CodePages": "8.0.0", + "System.Text.Json": "8.0.4" + }, + "runtime": { + "lib/net8.0/EPPlus.dll": { + "assemblyVersion": "7.3.2.0", + "fileVersion": "7.3.2.0" + } + } + }, + "EPPlus.Interfaces/6.1.1": { + "runtime": { + "lib/net7.0/EPPlus.Interfaces.dll": { + "assemblyVersion": "6.1.1.0", + "fileVersion": "6.1.1.0" + } + } + }, + "EPPlus.System.Drawing/6.1.1": { + "dependencies": { + "EPPlus.Interfaces": "6.1.1", + "System.Drawing.Common": "7.0.0" + }, + "runtime": { + "lib/net7.0/EPPlus.System.Drawing.dll": { + "assemblyVersion": "6.1.1.0", + "fileVersion": "6.1.1.0" + } + } + }, + "Microsoft.CodeAnalysis.Analyzers/3.3.4": {}, + "Microsoft.CodeAnalysis.Common/4.11.0": { + "dependencies": { + "Microsoft.CodeAnalysis.Analyzers": "3.3.4", + "System.Collections.Immutable": "8.0.0", + "System.Reflection.Metadata": "8.0.0" + }, + "runtime": { + "lib/net8.0/Microsoft.CodeAnalysis.dll": { + "assemblyVersion": "4.11.0.0", + "fileVersion": "4.1100.24.37604" + } + } + }, + "Microsoft.CodeAnalysis.CSharp/4.11.0": { + "dependencies": { + "Microsoft.CodeAnalysis.Analyzers": "3.3.4", + "Microsoft.CodeAnalysis.Common": "4.11.0", + "System.Collections.Immutable": "8.0.0", + "System.Reflection.Metadata": "8.0.0" + }, + "runtime": { + "lib/net8.0/Microsoft.CodeAnalysis.CSharp.dll": { + "assemblyVersion": "4.11.0.0", + "fileVersion": "4.1100.24.37604" + } + } + }, + "Microsoft.Extensions.Configuration/8.0.0": { + "dependencies": { + "Microsoft.Extensions.Configuration.Abstractions": "8.0.0", + "Microsoft.Extensions.Primitives": "8.0.0" + }, + "runtime": { + "lib/net8.0/Microsoft.Extensions.Configuration.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.23.53103" + } + } + }, + "Microsoft.Extensions.Configuration.Abstractions/8.0.0": { + "dependencies": { + "Microsoft.Extensions.Primitives": "8.0.0" + }, + "runtime": { + "lib/net8.0/Microsoft.Extensions.Configuration.Abstractions.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.23.53103" + } + } + }, + "Microsoft.Extensions.Configuration.FileExtensions/8.0.0": { + "dependencies": { + "Microsoft.Extensions.Configuration": "8.0.0", + "Microsoft.Extensions.Configuration.Abstractions": "8.0.0", + "Microsoft.Extensions.FileProviders.Abstractions": "8.0.0", + "Microsoft.Extensions.FileProviders.Physical": "8.0.0", + "Microsoft.Extensions.Primitives": "8.0.0" + }, + "runtime": { + "lib/net8.0/Microsoft.Extensions.Configuration.FileExtensions.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.23.53103" + } + } + }, + "Microsoft.Extensions.Configuration.Json/8.0.0": { + "dependencies": { + "Microsoft.Extensions.Configuration": "8.0.0", + "Microsoft.Extensions.Configuration.Abstractions": "8.0.0", + "Microsoft.Extensions.Configuration.FileExtensions": "8.0.0", + "Microsoft.Extensions.FileProviders.Abstractions": "8.0.0", + "System.Text.Json": "8.0.4" + }, + "runtime": { + "lib/net8.0/Microsoft.Extensions.Configuration.Json.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.23.53103" + } + } + }, + "Microsoft.Extensions.FileProviders.Abstractions/8.0.0": { + "dependencies": { + "Microsoft.Extensions.Primitives": "8.0.0" + }, + "runtime": { + "lib/net8.0/Microsoft.Extensions.FileProviders.Abstractions.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.23.53103" + } + } + }, + "Microsoft.Extensions.FileProviders.Physical/8.0.0": { + "dependencies": { + "Microsoft.Extensions.FileProviders.Abstractions": "8.0.0", + "Microsoft.Extensions.FileSystemGlobbing": "8.0.0", + "Microsoft.Extensions.Primitives": "8.0.0" + }, + "runtime": { + "lib/net8.0/Microsoft.Extensions.FileProviders.Physical.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.23.53103" + } + } + }, + "Microsoft.Extensions.FileSystemGlobbing/8.0.0": { + "runtime": { + "lib/net8.0/Microsoft.Extensions.FileSystemGlobbing.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.23.53103" + } + } + }, + "Microsoft.Extensions.Primitives/8.0.0": { + "runtime": { + "lib/net8.0/Microsoft.Extensions.Primitives.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.23.53103" + } + } + }, + "Microsoft.IO.RecyclableMemoryStream/3.0.1": { + "runtime": { + "lib/net6.0/Microsoft.IO.RecyclableMemoryStream.dll": { + "assemblyVersion": "3.0.1.0", + "fileVersion": "3.0.1.0" + } + } + }, + "Microsoft.Win32.SystemEvents/7.0.0": { + "runtime": { + "lib/net7.0/Microsoft.Win32.SystemEvents.dll": { + "assemblyVersion": "7.0.0.0", + "fileVersion": "7.0.22.51805" + } + }, + "runtimeTargets": { + "runtimes/win/lib/net7.0/Microsoft.Win32.SystemEvents.dll": { + "rid": "win", + "assetType": "runtime", + "assemblyVersion": "7.0.0.0", + "fileVersion": "7.0.22.51805" + } + } + }, + "Newtonsoft.Json/13.0.3": { + "runtime": { + "lib/net6.0/Newtonsoft.Json.dll": { + "assemblyVersion": "13.0.0.0", + "fileVersion": "13.0.3.27908" + } + } + }, + "protobuf-net/3.2.30": { + "dependencies": { + "protobuf-net.Core": "3.2.30" + }, + "runtime": { + "lib/net6.0/protobuf-net.dll": { + "assemblyVersion": "3.0.0.0", + "fileVersion": "3.2.30.709" + } + } + }, + "protobuf-net.Core/3.2.30": { + "dependencies": { + "System.Collections.Immutable": "8.0.0" + }, + "runtime": { + "lib/net6.0/protobuf-net.Core.dll": { + "assemblyVersion": "3.0.0.0", + "fileVersion": "3.2.30.709" + } + } + }, + "System.Collections.Immutable/8.0.0": {}, + "System.ComponentModel.Annotations/5.0.0": {}, + "System.Drawing.Common/7.0.0": { + "dependencies": { + "Microsoft.Win32.SystemEvents": "7.0.0" + }, + "runtime": { + "lib/net7.0/System.Drawing.Common.dll": { + "assemblyVersion": "7.0.0.0", + "fileVersion": "7.0.22.51805" + } + }, + "runtimeTargets": { + "runtimes/win/lib/net7.0/System.Drawing.Common.dll": { + "rid": "win", + "assetType": "runtime", + "assemblyVersion": "7.0.0.0", + "fileVersion": "7.0.22.51805" + } + } + }, + "System.Formats.Asn1/8.0.1": {}, + "System.Reflection.Metadata/8.0.0": { + "dependencies": { + "System.Collections.Immutable": "8.0.0" + } + }, + "System.Security.Cryptography.Pkcs/8.0.0": { + "dependencies": { + "System.Formats.Asn1": "8.0.1" + }, + "runtime": { + "lib/net8.0/System.Security.Cryptography.Pkcs.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.23.53103" + } + }, + "runtimeTargets": { + "runtimes/win/lib/net8.0/System.Security.Cryptography.Pkcs.dll": { + "rid": "win", + "assetType": "runtime", + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.23.53103" + } + } + }, + "System.Text.Encoding.CodePages/8.0.0": {}, + "System.Text.Encodings.Web/8.0.0": {}, + "System.Text.Json/8.0.4": { + "dependencies": { + "System.Text.Encodings.Web": "8.0.0" + } + } + } + }, + "libraries": { + "Fantasy.Tools.ConfigTable/1.0.0": { + "type": "project", + "serviceable": false, + "sha512": "" + }, + "CommandLineParser/2.9.1": { + "type": "package", + "serviceable": true, + "sha512": "sha512-OE0sl1/sQ37bjVsPKKtwQlWDgqaxWgtme3xZz7JssWUzg5JpMIyHgCTY9MVMxOg48fJ1AgGT3tgdH5m/kQ5xhA==", + "path": "commandlineparser/2.9.1", + "hashPath": "commandlineparser.2.9.1.nupkg.sha512" + }, + "EPPlus/7.3.2": { + "type": "package", + "serviceable": true, + "sha512": "sha512-9DShQD2VuDZ7QLHp+map1r2HdI1G325YGkvRG+qs4N2fgeMF1Uq0TONCEL5gKCWMNDVGO0ZELJTAIzwNyOZQug==", + "path": "epplus/7.3.2", + "hashPath": "epplus.7.3.2.nupkg.sha512" + }, + "EPPlus.Interfaces/6.1.1": { + "type": "package", + "serviceable": true, + "sha512": "sha512-y7dkrOoE1ZR9Vgy1Jf2rEIaTf3SHlUjYt01NklP+F5Qh7S2ruPbzTcpYLRWMeXiG8XL8h2jqX4CyIkFt3NQGZw==", + "path": "epplus.interfaces/6.1.1", + "hashPath": "epplus.interfaces.6.1.1.nupkg.sha512" + }, + "EPPlus.System.Drawing/6.1.1": { + "type": "package", + "serviceable": true, + "sha512": "sha512-lRF5gHYrmkHOOiLMI0t6q8zNYjUrzRgAM5BCXumv5xiqXko8fx3AWI+HCNZfhEqVFGOop+42KfR5GiUcCoyoMw==", + "path": "epplus.system.drawing/6.1.1", + "hashPath": "epplus.system.drawing.6.1.1.nupkg.sha512" + }, + "Microsoft.CodeAnalysis.Analyzers/3.3.4": { + "type": "package", + "serviceable": true, + "sha512": "sha512-AxkxcPR+rheX0SmvpLVIGLhOUXAKG56a64kV9VQZ4y9gR9ZmPXnqZvHJnmwLSwzrEP6junUF11vuc+aqo5r68g==", + "path": "microsoft.codeanalysis.analyzers/3.3.4", + "hashPath": "microsoft.codeanalysis.analyzers.3.3.4.nupkg.sha512" + }, + "Microsoft.CodeAnalysis.Common/4.11.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-djf8ujmqYImFgB04UGtcsEhHrzVqzHowS+EEl/Yunc5LdrYrZhGBWUTXoCF0NzYXJxtfuD+UVQarWpvrNc94Qg==", + "path": "microsoft.codeanalysis.common/4.11.0", + "hashPath": "microsoft.codeanalysis.common.4.11.0.nupkg.sha512" + }, + "Microsoft.CodeAnalysis.CSharp/4.11.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-6XYi2EusI8JT4y2l/F3VVVS+ISoIX9nqHsZRaG6W5aFeJ5BEuBosHfT/ABb73FN0RZ1Z3cj2j7cL28SToJPXOw==", + "path": "microsoft.codeanalysis.csharp/4.11.0", + "hashPath": "microsoft.codeanalysis.csharp.4.11.0.nupkg.sha512" + }, + "Microsoft.Extensions.Configuration/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-0J/9YNXTMWSZP2p2+nvl8p71zpSwokZXZuJW+VjdErkegAnFdO1XlqtA62SJtgVYHdKu3uPxJHcMR/r35HwFBA==", + "path": "microsoft.extensions.configuration/8.0.0", + "hashPath": "microsoft.extensions.configuration.8.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.Configuration.Abstractions/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-3lE/iLSutpgX1CC0NOW70FJoGARRHbyKmG7dc0klnUZ9Dd9hS6N/POPWhKhMLCEuNN5nXEY5agmlFtH562vqhQ==", + "path": "microsoft.extensions.configuration.abstractions/8.0.0", + "hashPath": "microsoft.extensions.configuration.abstractions.8.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.Configuration.FileExtensions/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-McP+Lz/EKwvtCv48z0YImw+L1gi1gy5rHhNaNIY2CrjloV+XY8gydT8DjMR6zWeL13AFK+DioVpppwAuO1Gi1w==", + "path": "microsoft.extensions.configuration.fileextensions/8.0.0", + "hashPath": "microsoft.extensions.configuration.fileextensions.8.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.Configuration.Json/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-C2wqUoh9OmRL1akaCcKSTmRU8z0kckfImG7zLNI8uyi47Lp+zd5LWAD17waPQEqCz3ioWOCrFUo+JJuoeZLOBw==", + "path": "microsoft.extensions.configuration.json/8.0.0", + "hashPath": "microsoft.extensions.configuration.json.8.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.FileProviders.Abstractions/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-ZbaMlhJlpisjuWbvXr4LdAst/1XxH3vZ6A0BsgTphZ2L4PGuxRLz7Jr/S7mkAAnOn78Vu0fKhEgNF5JO3zfjqQ==", + "path": "microsoft.extensions.fileproviders.abstractions/8.0.0", + "hashPath": "microsoft.extensions.fileproviders.abstractions.8.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.FileProviders.Physical/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-UboiXxpPUpwulHvIAVE36Knq0VSHaAmfrFkegLyBZeaADuKezJ/AIXYAW8F5GBlGk/VaibN2k/Zn1ca8YAfVdA==", + "path": "microsoft.extensions.fileproviders.physical/8.0.0", + "hashPath": "microsoft.extensions.fileproviders.physical.8.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.FileSystemGlobbing/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-OK+670i7esqlQrPjdIKRbsyMCe9g5kSLpRRQGSr4Q58AOYEe/hCnfLZprh7viNisSUUQZmMrbbuDaIrP+V1ebQ==", + "path": "microsoft.extensions.filesystemglobbing/8.0.0", + "hashPath": "microsoft.extensions.filesystemglobbing.8.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.Primitives/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-bXJEZrW9ny8vjMF1JV253WeLhpEVzFo1lyaZu1vQ4ZxWUlVvknZ/+ftFgVheLubb4eZPSwwxBeqS1JkCOjxd8g==", + "path": "microsoft.extensions.primitives/8.0.0", + "hashPath": "microsoft.extensions.primitives.8.0.0.nupkg.sha512" + }, + "Microsoft.IO.RecyclableMemoryStream/3.0.1": { + "type": "package", + "serviceable": true, + "sha512": "sha512-s/s20YTVY9r9TPfTrN5g8zPF1YhwxyqO6PxUkrYTGI2B+OGPe9AdajWZrLhFqXIvqIW23fnUE4+ztrUWNU1+9g==", + "path": "microsoft.io.recyclablememorystream/3.0.1", + "hashPath": "microsoft.io.recyclablememorystream.3.0.1.nupkg.sha512" + }, + "Microsoft.Win32.SystemEvents/7.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-2nXPrhdAyAzir0gLl8Yy8S5Mnm/uBSQQA7jEsILOS1MTyS7DbmV1NgViMtvV1sfCD1ebITpNwb1NIinKeJgUVQ==", + "path": "microsoft.win32.systemevents/7.0.0", + "hashPath": "microsoft.win32.systemevents.7.0.0.nupkg.sha512" + }, + "Newtonsoft.Json/13.0.3": { + "type": "package", + "serviceable": true, + "sha512": "sha512-HrC5BXdl00IP9zeV+0Z848QWPAoCr9P3bDEZguI+gkLcBKAOxix/tLEAAHC+UvDNPv4a2d18lOReHMOagPa+zQ==", + "path": "newtonsoft.json/13.0.3", + "hashPath": "newtonsoft.json.13.0.3.nupkg.sha512" + }, + "protobuf-net/3.2.30": { + "type": "package", + "serviceable": true, + "sha512": "sha512-C/UTlmxEJHAHpqm8xQK1UyJKaIynVCSNG4mVrbLgnZ7ccH28nN49O8iMJvKEodTgVbnimvy+3mIiAdW6mATwnw==", + "path": "protobuf-net/3.2.30", + "hashPath": "protobuf-net.3.2.30.nupkg.sha512" + }, + "protobuf-net.Core/3.2.30": { + "type": "package", + "serviceable": true, + "sha512": "sha512-v2ZxxYrz+X212ukSx+uqkLuPu414bvmSAnTyf+PBUKR9ENJxO4P/csorA/27456MCp1JNoMssDj/f91RDiwBfQ==", + "path": "protobuf-net.core/3.2.30", + "hashPath": "protobuf-net.core.3.2.30.nupkg.sha512" + }, + "System.Collections.Immutable/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-AurL6Y5BA1WotzlEvVaIDpqzpIPvYnnldxru8oXJU2yFxFUy3+pNXjXd1ymO+RA0rq0+590Q8gaz2l3Sr7fmqg==", + "path": "system.collections.immutable/8.0.0", + "hashPath": "system.collections.immutable.8.0.0.nupkg.sha512" + }, + "System.ComponentModel.Annotations/5.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-dMkqfy2el8A8/I76n2Hi1oBFEbG1SfxD2l5nhwXV3XjlnOmwxJlQbYpJH4W51odnU9sARCSAgv7S3CyAFMkpYg==", + "path": "system.componentmodel.annotations/5.0.0", + "hashPath": "system.componentmodel.annotations.5.0.0.nupkg.sha512" + }, + "System.Drawing.Common/7.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-KIX+oBU38pxkKPxvLcLfIkOV5Ien8ReN78wro7OF5/erwcmortzeFx+iBswlh2Vz6gVne0khocQudGwaO1Ey6A==", + "path": "system.drawing.common/7.0.0", + "hashPath": "system.drawing.common.7.0.0.nupkg.sha512" + }, + "System.Formats.Asn1/8.0.1": { + "type": "package", + "serviceable": true, + "sha512": "sha512-XqKba7Mm/koKSjKMfW82olQdmfbI5yqeoLV/tidRp7fbh5rmHAQ5raDI/7SU0swTzv+jgqtUGkzmFxuUg0it1A==", + "path": "system.formats.asn1/8.0.1", + "hashPath": "system.formats.asn1.8.0.1.nupkg.sha512" + }, + "System.Reflection.Metadata/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-ptvgrFh7PvWI8bcVqG5rsA/weWM09EnthFHR5SCnS6IN+P4mj6rE1lBDC4U8HL9/57htKAqy4KQ3bBj84cfYyQ==", + "path": "system.reflection.metadata/8.0.0", + "hashPath": "system.reflection.metadata.8.0.0.nupkg.sha512" + }, + "System.Security.Cryptography.Pkcs/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-ULmp3xoOwNYjOYp4JZ2NK/6NdTgiN1GQXzVVN1njQ7LOZ0d0B9vyMnhyqbIi9Qw4JXj1JgCsitkTShboHRx7Eg==", + "path": "system.security.cryptography.pkcs/8.0.0", + "hashPath": "system.security.cryptography.pkcs.8.0.0.nupkg.sha512" + }, + "System.Text.Encoding.CodePages/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-OZIsVplFGaVY90G2SbpgU7EnCoOO5pw1t4ic21dBF3/1omrJFpAGoNAVpPyMVOC90/hvgkGG3VFqR13YgZMQfg==", + "path": "system.text.encoding.codepages/8.0.0", + "hashPath": "system.text.encoding.codepages.8.0.0.nupkg.sha512" + }, + "System.Text.Encodings.Web/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-yev/k9GHAEGx2Rg3/tU6MQh4HGBXJs70y7j1LaM1i/ER9po+6nnQ6RRqTJn1E7Xu0fbIFK80Nh5EoODxrbxwBQ==", + "path": "system.text.encodings.web/8.0.0", + "hashPath": "system.text.encodings.web.8.0.0.nupkg.sha512" + }, + "System.Text.Json/8.0.4": { + "type": "package", + "serviceable": true, + "sha512": "sha512-bAkhgDJ88XTsqczoxEMliSrpijKZHhbJQldhAmObj/RbrN3sU5dcokuXmWJWsdQAhiMJ9bTayWsL1C9fbbCRhw==", + "path": "system.text.json/8.0.4", + "hashPath": "system.text.json.8.0.4.nupkg.sha512" + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Tools/ConfigTable/Fantasy.Tools.ConfigTable.dll b/物品和背包的完整代码/Tools/ConfigTable/Fantasy.Tools.ConfigTable.dll new file mode 100644 index 0000000..816dfbb Binary files /dev/null and b/物品和背包的完整代码/Tools/ConfigTable/Fantasy.Tools.ConfigTable.dll differ diff --git a/物品和背包的完整代码/Tools/ConfigTable/Fantasy.Tools.ConfigTable.pdb b/物品和背包的完整代码/Tools/ConfigTable/Fantasy.Tools.ConfigTable.pdb new file mode 100644 index 0000000..17add89 Binary files /dev/null and b/物品和背包的完整代码/Tools/ConfigTable/Fantasy.Tools.ConfigTable.pdb differ diff --git a/物品和背包的完整代码/Tools/ConfigTable/Fantasy.Tools.ConfigTable.runtimeconfig.json b/物品和背包的完整代码/Tools/ConfigTable/Fantasy.Tools.ConfigTable.runtimeconfig.json new file mode 100644 index 0000000..becfaea --- /dev/null +++ b/物品和背包的完整代码/Tools/ConfigTable/Fantasy.Tools.ConfigTable.runtimeconfig.json @@ -0,0 +1,12 @@ +{ + "runtimeOptions": { + "tfm": "net8.0", + "framework": { + "name": "Microsoft.NETCore.App", + "version": "8.0.0" + }, + "configProperties": { + "System.Runtime.Serialization.EnableUnsafeBinaryFormatterSerialization": false + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Tools/ConfigTable/Microsoft.CodeAnalysis.CSharp.dll b/物品和背包的完整代码/Tools/ConfigTable/Microsoft.CodeAnalysis.CSharp.dll new file mode 100644 index 0000000..c23db48 Binary files /dev/null and b/物品和背包的完整代码/Tools/ConfigTable/Microsoft.CodeAnalysis.CSharp.dll differ diff --git a/物品和背包的完整代码/Tools/ConfigTable/Microsoft.CodeAnalysis.dll b/物品和背包的完整代码/Tools/ConfigTable/Microsoft.CodeAnalysis.dll new file mode 100644 index 0000000..de7eadd Binary files /dev/null and b/物品和背包的完整代码/Tools/ConfigTable/Microsoft.CodeAnalysis.dll differ diff --git a/物品和背包的完整代码/Tools/ConfigTable/Microsoft.Extensions.Configuration.Abstractions.dll b/物品和背包的完整代码/Tools/ConfigTable/Microsoft.Extensions.Configuration.Abstractions.dll new file mode 100644 index 0000000..a5ab313 Binary files /dev/null and b/物品和背包的完整代码/Tools/ConfigTable/Microsoft.Extensions.Configuration.Abstractions.dll differ diff --git a/物品和背包的完整代码/Tools/ConfigTable/Microsoft.Extensions.Configuration.FileExtensions.dll b/物品和背包的完整代码/Tools/ConfigTable/Microsoft.Extensions.Configuration.FileExtensions.dll new file mode 100644 index 0000000..4efc1a5 Binary files /dev/null and b/物品和背包的完整代码/Tools/ConfigTable/Microsoft.Extensions.Configuration.FileExtensions.dll differ diff --git a/物品和背包的完整代码/Tools/ConfigTable/Microsoft.Extensions.Configuration.Json.dll b/物品和背包的完整代码/Tools/ConfigTable/Microsoft.Extensions.Configuration.Json.dll new file mode 100644 index 0000000..296db6a Binary files /dev/null and b/物品和背包的完整代码/Tools/ConfigTable/Microsoft.Extensions.Configuration.Json.dll differ diff --git a/物品和背包的完整代码/Tools/ConfigTable/Microsoft.Extensions.Configuration.dll b/物品和背包的完整代码/Tools/ConfigTable/Microsoft.Extensions.Configuration.dll new file mode 100644 index 0000000..d3e5c22 Binary files /dev/null and b/物品和背包的完整代码/Tools/ConfigTable/Microsoft.Extensions.Configuration.dll differ diff --git a/物品和背包的完整代码/Tools/ConfigTable/Microsoft.Extensions.FileProviders.Abstractions.dll b/物品和背包的完整代码/Tools/ConfigTable/Microsoft.Extensions.FileProviders.Abstractions.dll new file mode 100644 index 0000000..f907206 Binary files /dev/null and b/物品和背包的完整代码/Tools/ConfigTable/Microsoft.Extensions.FileProviders.Abstractions.dll differ diff --git a/物品和背包的完整代码/Tools/ConfigTable/Microsoft.Extensions.FileProviders.Physical.dll b/物品和背包的完整代码/Tools/ConfigTable/Microsoft.Extensions.FileProviders.Physical.dll new file mode 100644 index 0000000..6fb7f47 Binary files /dev/null and b/物品和背包的完整代码/Tools/ConfigTable/Microsoft.Extensions.FileProviders.Physical.dll differ diff --git a/物品和背包的完整代码/Tools/ConfigTable/Microsoft.Extensions.FileSystemGlobbing.dll b/物品和背包的完整代码/Tools/ConfigTable/Microsoft.Extensions.FileSystemGlobbing.dll new file mode 100644 index 0000000..e590735 Binary files /dev/null and b/物品和背包的完整代码/Tools/ConfigTable/Microsoft.Extensions.FileSystemGlobbing.dll differ diff --git a/物品和背包的完整代码/Tools/ConfigTable/Microsoft.Extensions.Primitives.dll b/物品和背包的完整代码/Tools/ConfigTable/Microsoft.Extensions.Primitives.dll new file mode 100644 index 0000000..c24f2a0 Binary files /dev/null and b/物品和背包的完整代码/Tools/ConfigTable/Microsoft.Extensions.Primitives.dll differ diff --git a/物品和背包的完整代码/Tools/ConfigTable/Microsoft.IO.RecyclableMemoryStream.dll b/物品和背包的完整代码/Tools/ConfigTable/Microsoft.IO.RecyclableMemoryStream.dll new file mode 100644 index 0000000..6e0ea40 Binary files /dev/null and b/物品和背包的完整代码/Tools/ConfigTable/Microsoft.IO.RecyclableMemoryStream.dll differ diff --git a/物品和背包的完整代码/Tools/ConfigTable/Microsoft.Win32.SystemEvents.dll b/物品和背包的完整代码/Tools/ConfigTable/Microsoft.Win32.SystemEvents.dll new file mode 100644 index 0000000..4f50adb Binary files /dev/null and b/物品和背包的完整代码/Tools/ConfigTable/Microsoft.Win32.SystemEvents.dll differ diff --git a/物品和背包的完整代码/Tools/ConfigTable/Newtonsoft.Json.dll b/物品和背包的完整代码/Tools/ConfigTable/Newtonsoft.Json.dll new file mode 100644 index 0000000..d035c38 Binary files /dev/null and b/物品和背包的完整代码/Tools/ConfigTable/Newtonsoft.Json.dll differ diff --git a/物品和背包的完整代码/Tools/ConfigTable/Run.bat b/物品和背包的完整代码/Tools/ConfigTable/Run.bat new file mode 100644 index 0000000..082d6b0 --- /dev/null +++ b/物品和背包的完整代码/Tools/ConfigTable/Run.bat @@ -0,0 +1,33 @@ +@echo off + +echo Please select an option: +echo 1. Client Increment +echo 2. Client all +echo 3. Server Increment +echo 4. Server all +echo 5. Client and Server Increment +echo 6. Client and Server all + +set /p choice=Please select an option: + +if "%choice%"=="1" ( + echo Client Increment + dotnet Fantasy.Tools.ConfigTable.dll --p 1 --e 1 +) else if "%choice%"=="2" ( + echo Client all + dotnet Fantasy.Tools.ConfigTable.dll --p 1 --e 2 +) else if "%choice%"=="3" ( + echo Server Increment + dotnet Fantasy.Tools.ConfigTable.dll --p 2 --e 1 +) else if "%choice%"=="4" ( + echo Server all + dotnet Fantasy.Tools.ConfigTable.dll --p 2 --e 2 +) else if "%choice%"=="5" ( + echo Client and Server Increment + dotnet Fantasy.Tools.ConfigTable.dll --p 3 --e 1 +) else if "%choice%"=="6" ( + echo Client and Server all + dotnet Fantasy.Tools.ConfigTable.dll --p 3 --e 2 +) else ( + echo Invalid option +) diff --git a/物品和背包的完整代码/Tools/ConfigTable/Run.sh b/物品和背包的完整代码/Tools/ConfigTable/Run.sh new file mode 100644 index 0000000..7ac9f52 --- /dev/null +++ b/物品和背包的完整代码/Tools/ConfigTable/Run.sh @@ -0,0 +1,34 @@ +#!/bin/bash + +echo "1. Client Increment" +echo "2. Client all" +echo "3. Server Increment" +echo "4. Server all" +echo "5. Client and Server Increment" +echo "6. Client and Server all" + +read -n 1 -p "Please select an option:" choice +echo "" +case $choice in + 1) + dotnet Fantasy.Tools.ConfigTable.dll --p 1 --e 1 + ;; + 2) + dotnet Fantasy.Tools.ConfigTable.dll --p 1 --e 2 + ;; + 3) + dotnet Fantasy.Tools.ConfigTable.dll --p 2 --e 1 + ;; + 4) + dotnet Fantasy.Tools.ConfigTable.dll --p 2 --e 2 + ;; + 5) + dotnet Fantasy.Tools.ConfigTable.dll --p 3 --e 1 + ;; + 6) + dotnet Fantasy.Tools.ConfigTable.dll --p 3 --e 2 + ;; + *) + echo "Invalid option" + ;; +esac diff --git a/物品和背包的完整代码/Tools/ConfigTable/System.Drawing.Common.dll b/物品和背包的完整代码/Tools/ConfigTable/System.Drawing.Common.dll new file mode 100644 index 0000000..310d5e8 Binary files /dev/null and b/物品和背包的完整代码/Tools/ConfigTable/System.Drawing.Common.dll differ diff --git a/物品和背包的完整代码/Tools/ConfigTable/System.Security.Cryptography.Pkcs.dll b/物品和背包的完整代码/Tools/ConfigTable/System.Security.Cryptography.Pkcs.dll new file mode 100644 index 0000000..a76a14a Binary files /dev/null and b/物品和背包的完整代码/Tools/ConfigTable/System.Security.Cryptography.Pkcs.dll differ diff --git a/物品和背包的完整代码/Tools/ConfigTable/protobuf-net.Core.dll b/物品和背包的完整代码/Tools/ConfigTable/protobuf-net.Core.dll new file mode 100644 index 0000000..845a840 Binary files /dev/null and b/物品和背包的完整代码/Tools/ConfigTable/protobuf-net.Core.dll differ diff --git a/物品和背包的完整代码/Tools/ConfigTable/protobuf-net.dll b/物品和背包的完整代码/Tools/ConfigTable/protobuf-net.dll new file mode 100644 index 0000000..e4b6839 Binary files /dev/null and b/物品和背包的完整代码/Tools/ConfigTable/protobuf-net.dll differ diff --git a/物品和背包的完整代码/Tools/ConfigTable/runtimes/win/lib/net7.0/Microsoft.Win32.SystemEvents.dll b/物品和背包的完整代码/Tools/ConfigTable/runtimes/win/lib/net7.0/Microsoft.Win32.SystemEvents.dll new file mode 100644 index 0000000..d40a926 Binary files /dev/null and b/物品和背包的完整代码/Tools/ConfigTable/runtimes/win/lib/net7.0/Microsoft.Win32.SystemEvents.dll differ diff --git a/物品和背包的完整代码/Tools/ConfigTable/runtimes/win/lib/net7.0/System.Drawing.Common.dll b/物品和背包的完整代码/Tools/ConfigTable/runtimes/win/lib/net7.0/System.Drawing.Common.dll new file mode 100644 index 0000000..39493b4 Binary files /dev/null and b/物品和背包的完整代码/Tools/ConfigTable/runtimes/win/lib/net7.0/System.Drawing.Common.dll differ diff --git a/物品和背包的完整代码/Tools/ConfigTable/runtimes/win/lib/net8.0/System.Security.Cryptography.Pkcs.dll b/物品和背包的完整代码/Tools/ConfigTable/runtimes/win/lib/net8.0/System.Security.Cryptography.Pkcs.dll new file mode 100644 index 0000000..cba73d0 Binary files /dev/null and b/物品和背包的完整代码/Tools/ConfigTable/runtimes/win/lib/net8.0/System.Security.Cryptography.Pkcs.dll differ diff --git a/物品和背包的完整代码/Tools/NetworkProtocol/CommandLine.dll b/物品和背包的完整代码/Tools/NetworkProtocol/CommandLine.dll new file mode 100644 index 0000000..3eab2be Binary files /dev/null and b/物品和背包的完整代码/Tools/NetworkProtocol/CommandLine.dll differ diff --git a/物品和背包的完整代码/Tools/NetworkProtocol/ExporterSettings.json b/物品和背包的完整代码/Tools/NetworkProtocol/ExporterSettings.json new file mode 100644 index 0000000..41cb0e4 --- /dev/null +++ b/物品和背包的完整代码/Tools/NetworkProtocol/ExporterSettings.json @@ -0,0 +1,29 @@ +{ + "Export": { + "NetworkProtocolDirectory": { + "Value": "../../Config/NetworkProtocol/", + "Comment": "ProtoBuf文件所在的文件夹位置" + }, + "NetworkProtocolServerDirectory": { + "Value": "../../Server/Entity/Generate/NetworkProtocol/", + "Comment": "ProtoBuf生成到服务端的文件夹位置" + }, + "NetworkProtocolClientDirectory": { + "Value": "../../Client/Unity/Assets/Scripts/Hotfix/Generate/NetworkProtocol/", + "Comment": "ProtoBuf生成到客户端的文件夹位置" + }, + "Serializes": { + "Value": [ +// { +// "KeyIndex": 0, +// "NameSpace" : "MemoryPack", +// "SerializeName": "MemoryPack", +// "Attribute": "\t[MemoryPackable]", +// "Ignore": "\t\t[MemoryPackIgnore]", +// "Member": "MemoryPackOrder" +// } + ], + "Comment": "自定义序列化器" + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Tools/NetworkProtocol/Fantasy.Tools.NetworkProtocol b/物品和背包的完整代码/Tools/NetworkProtocol/Fantasy.Tools.NetworkProtocol new file mode 100644 index 0000000..25ceaf1 Binary files /dev/null and b/物品和背包的完整代码/Tools/NetworkProtocol/Fantasy.Tools.NetworkProtocol differ diff --git a/物品和背包的完整代码/Tools/NetworkProtocol/Fantasy.Tools.NetworkProtocol.deps.json b/物品和背包的完整代码/Tools/NetworkProtocol/Fantasy.Tools.NetworkProtocol.deps.json new file mode 100644 index 0000000..3c053cb --- /dev/null +++ b/物品和背包的完整代码/Tools/NetworkProtocol/Fantasy.Tools.NetworkProtocol.deps.json @@ -0,0 +1,227 @@ +{ + "runtimeTarget": { + "name": ".NETCoreApp,Version=v8.0", + "signature": "" + }, + "compilationOptions": {}, + "targets": { + ".NETCoreApp,Version=v8.0": { + "Fantasy.Tools.NetworkProtocol/1.0.0": { + "dependencies": { + "CommandLineParser": "2.9.1", + "Microsoft.Extensions.Configuration.Json": "8.0.0", + "Newtonsoft.Json": "13.0.3" + }, + "runtime": { + "Fantasy.Tools.NetworkProtocol.dll": {} + } + }, + "CommandLineParser/2.9.1": { + "runtime": { + "lib/netstandard2.0/CommandLine.dll": { + "assemblyVersion": "2.9.1.0", + "fileVersion": "2.9.1.0" + } + } + }, + "Microsoft.Extensions.Configuration/8.0.0": { + "dependencies": { + "Microsoft.Extensions.Configuration.Abstractions": "8.0.0", + "Microsoft.Extensions.Primitives": "8.0.0" + }, + "runtime": { + "lib/net8.0/Microsoft.Extensions.Configuration.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.23.53103" + } + } + }, + "Microsoft.Extensions.Configuration.Abstractions/8.0.0": { + "dependencies": { + "Microsoft.Extensions.Primitives": "8.0.0" + }, + "runtime": { + "lib/net8.0/Microsoft.Extensions.Configuration.Abstractions.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.23.53103" + } + } + }, + "Microsoft.Extensions.Configuration.FileExtensions/8.0.0": { + "dependencies": { + "Microsoft.Extensions.Configuration": "8.0.0", + "Microsoft.Extensions.Configuration.Abstractions": "8.0.0", + "Microsoft.Extensions.FileProviders.Abstractions": "8.0.0", + "Microsoft.Extensions.FileProviders.Physical": "8.0.0", + "Microsoft.Extensions.Primitives": "8.0.0" + }, + "runtime": { + "lib/net8.0/Microsoft.Extensions.Configuration.FileExtensions.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.23.53103" + } + } + }, + "Microsoft.Extensions.Configuration.Json/8.0.0": { + "dependencies": { + "Microsoft.Extensions.Configuration": "8.0.0", + "Microsoft.Extensions.Configuration.Abstractions": "8.0.0", + "Microsoft.Extensions.Configuration.FileExtensions": "8.0.0", + "Microsoft.Extensions.FileProviders.Abstractions": "8.0.0", + "System.Text.Json": "8.0.0" + }, + "runtime": { + "lib/net8.0/Microsoft.Extensions.Configuration.Json.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.23.53103" + } + } + }, + "Microsoft.Extensions.FileProviders.Abstractions/8.0.0": { + "dependencies": { + "Microsoft.Extensions.Primitives": "8.0.0" + }, + "runtime": { + "lib/net8.0/Microsoft.Extensions.FileProviders.Abstractions.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.23.53103" + } + } + }, + "Microsoft.Extensions.FileProviders.Physical/8.0.0": { + "dependencies": { + "Microsoft.Extensions.FileProviders.Abstractions": "8.0.0", + "Microsoft.Extensions.FileSystemGlobbing": "8.0.0", + "Microsoft.Extensions.Primitives": "8.0.0" + }, + "runtime": { + "lib/net8.0/Microsoft.Extensions.FileProviders.Physical.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.23.53103" + } + } + }, + "Microsoft.Extensions.FileSystemGlobbing/8.0.0": { + "runtime": { + "lib/net8.0/Microsoft.Extensions.FileSystemGlobbing.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.23.53103" + } + } + }, + "Microsoft.Extensions.Primitives/8.0.0": { + "runtime": { + "lib/net8.0/Microsoft.Extensions.Primitives.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.23.53103" + } + } + }, + "Newtonsoft.Json/13.0.3": { + "runtime": { + "lib/net6.0/Newtonsoft.Json.dll": { + "assemblyVersion": "13.0.0.0", + "fileVersion": "13.0.3.27908" + } + } + }, + "System.Text.Encodings.Web/8.0.0": {}, + "System.Text.Json/8.0.0": { + "dependencies": { + "System.Text.Encodings.Web": "8.0.0" + } + } + } + }, + "libraries": { + "Fantasy.Tools.NetworkProtocol/1.0.0": { + "type": "project", + "serviceable": false, + "sha512": "" + }, + "CommandLineParser/2.9.1": { + "type": "package", + "serviceable": true, + "sha512": "sha512-OE0sl1/sQ37bjVsPKKtwQlWDgqaxWgtme3xZz7JssWUzg5JpMIyHgCTY9MVMxOg48fJ1AgGT3tgdH5m/kQ5xhA==", + "path": "commandlineparser/2.9.1", + "hashPath": "commandlineparser.2.9.1.nupkg.sha512" + }, + "Microsoft.Extensions.Configuration/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-0J/9YNXTMWSZP2p2+nvl8p71zpSwokZXZuJW+VjdErkegAnFdO1XlqtA62SJtgVYHdKu3uPxJHcMR/r35HwFBA==", + "path": "microsoft.extensions.configuration/8.0.0", + "hashPath": "microsoft.extensions.configuration.8.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.Configuration.Abstractions/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-3lE/iLSutpgX1CC0NOW70FJoGARRHbyKmG7dc0klnUZ9Dd9hS6N/POPWhKhMLCEuNN5nXEY5agmlFtH562vqhQ==", + "path": "microsoft.extensions.configuration.abstractions/8.0.0", + "hashPath": "microsoft.extensions.configuration.abstractions.8.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.Configuration.FileExtensions/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-McP+Lz/EKwvtCv48z0YImw+L1gi1gy5rHhNaNIY2CrjloV+XY8gydT8DjMR6zWeL13AFK+DioVpppwAuO1Gi1w==", + "path": "microsoft.extensions.configuration.fileextensions/8.0.0", + "hashPath": "microsoft.extensions.configuration.fileextensions.8.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.Configuration.Json/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-C2wqUoh9OmRL1akaCcKSTmRU8z0kckfImG7zLNI8uyi47Lp+zd5LWAD17waPQEqCz3ioWOCrFUo+JJuoeZLOBw==", + "path": "microsoft.extensions.configuration.json/8.0.0", + "hashPath": "microsoft.extensions.configuration.json.8.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.FileProviders.Abstractions/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-ZbaMlhJlpisjuWbvXr4LdAst/1XxH3vZ6A0BsgTphZ2L4PGuxRLz7Jr/S7mkAAnOn78Vu0fKhEgNF5JO3zfjqQ==", + "path": "microsoft.extensions.fileproviders.abstractions/8.0.0", + "hashPath": "microsoft.extensions.fileproviders.abstractions.8.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.FileProviders.Physical/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-UboiXxpPUpwulHvIAVE36Knq0VSHaAmfrFkegLyBZeaADuKezJ/AIXYAW8F5GBlGk/VaibN2k/Zn1ca8YAfVdA==", + "path": "microsoft.extensions.fileproviders.physical/8.0.0", + "hashPath": "microsoft.extensions.fileproviders.physical.8.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.FileSystemGlobbing/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-OK+670i7esqlQrPjdIKRbsyMCe9g5kSLpRRQGSr4Q58AOYEe/hCnfLZprh7viNisSUUQZmMrbbuDaIrP+V1ebQ==", + "path": "microsoft.extensions.filesystemglobbing/8.0.0", + "hashPath": "microsoft.extensions.filesystemglobbing.8.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.Primitives/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-bXJEZrW9ny8vjMF1JV253WeLhpEVzFo1lyaZu1vQ4ZxWUlVvknZ/+ftFgVheLubb4eZPSwwxBeqS1JkCOjxd8g==", + "path": "microsoft.extensions.primitives/8.0.0", + "hashPath": "microsoft.extensions.primitives.8.0.0.nupkg.sha512" + }, + "Newtonsoft.Json/13.0.3": { + "type": "package", + "serviceable": true, + "sha512": "sha512-HrC5BXdl00IP9zeV+0Z848QWPAoCr9P3bDEZguI+gkLcBKAOxix/tLEAAHC+UvDNPv4a2d18lOReHMOagPa+zQ==", + "path": "newtonsoft.json/13.0.3", + "hashPath": "newtonsoft.json.13.0.3.nupkg.sha512" + }, + "System.Text.Encodings.Web/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-yev/k9GHAEGx2Rg3/tU6MQh4HGBXJs70y7j1LaM1i/ER9po+6nnQ6RRqTJn1E7Xu0fbIFK80Nh5EoODxrbxwBQ==", + "path": "system.text.encodings.web/8.0.0", + "hashPath": "system.text.encodings.web.8.0.0.nupkg.sha512" + }, + "System.Text.Json/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-OdrZO2WjkiEG6ajEFRABTRCi/wuXQPxeV6g8xvUJqdxMvvuCCEk86zPla8UiIQJz3durtUEbNyY/3lIhS0yZvQ==", + "path": "system.text.json/8.0.0", + "hashPath": "system.text.json.8.0.0.nupkg.sha512" + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Tools/NetworkProtocol/Fantasy.Tools.NetworkProtocol.dll b/物品和背包的完整代码/Tools/NetworkProtocol/Fantasy.Tools.NetworkProtocol.dll new file mode 100644 index 0000000..918803d Binary files /dev/null and b/物品和背包的完整代码/Tools/NetworkProtocol/Fantasy.Tools.NetworkProtocol.dll differ diff --git a/物品和背包的完整代码/Tools/NetworkProtocol/Fantasy.Tools.NetworkProtocol.pdb b/物品和背包的完整代码/Tools/NetworkProtocol/Fantasy.Tools.NetworkProtocol.pdb new file mode 100644 index 0000000..39d574a Binary files /dev/null and b/物品和背包的完整代码/Tools/NetworkProtocol/Fantasy.Tools.NetworkProtocol.pdb differ diff --git a/物品和背包的完整代码/Tools/NetworkProtocol/Fantasy.Tools.NetworkProtocol.runtimeconfig.json b/物品和背包的完整代码/Tools/NetworkProtocol/Fantasy.Tools.NetworkProtocol.runtimeconfig.json new file mode 100644 index 0000000..becfaea --- /dev/null +++ b/物品和背包的完整代码/Tools/NetworkProtocol/Fantasy.Tools.NetworkProtocol.runtimeconfig.json @@ -0,0 +1,12 @@ +{ + "runtimeOptions": { + "tfm": "net8.0", + "framework": { + "name": "Microsoft.NETCore.App", + "version": "8.0.0" + }, + "configProperties": { + "System.Runtime.Serialization.EnableUnsafeBinaryFormatterSerialization": false + } + } +} \ No newline at end of file diff --git a/物品和背包的完整代码/Tools/NetworkProtocol/Microsoft.Extensions.Configuration.Abstractions.dll b/物品和背包的完整代码/Tools/NetworkProtocol/Microsoft.Extensions.Configuration.Abstractions.dll new file mode 100644 index 0000000..a5ab313 Binary files /dev/null and b/物品和背包的完整代码/Tools/NetworkProtocol/Microsoft.Extensions.Configuration.Abstractions.dll differ diff --git a/物品和背包的完整代码/Tools/NetworkProtocol/Microsoft.Extensions.Configuration.FileExtensions.dll b/物品和背包的完整代码/Tools/NetworkProtocol/Microsoft.Extensions.Configuration.FileExtensions.dll new file mode 100644 index 0000000..4efc1a5 Binary files /dev/null and b/物品和背包的完整代码/Tools/NetworkProtocol/Microsoft.Extensions.Configuration.FileExtensions.dll differ diff --git a/物品和背包的完整代码/Tools/NetworkProtocol/Microsoft.Extensions.Configuration.Json.dll b/物品和背包的完整代码/Tools/NetworkProtocol/Microsoft.Extensions.Configuration.Json.dll new file mode 100644 index 0000000..296db6a Binary files /dev/null and b/物品和背包的完整代码/Tools/NetworkProtocol/Microsoft.Extensions.Configuration.Json.dll differ diff --git a/物品和背包的完整代码/Tools/NetworkProtocol/Microsoft.Extensions.Configuration.dll b/物品和背包的完整代码/Tools/NetworkProtocol/Microsoft.Extensions.Configuration.dll new file mode 100644 index 0000000..d3e5c22 Binary files /dev/null and b/物品和背包的完整代码/Tools/NetworkProtocol/Microsoft.Extensions.Configuration.dll differ diff --git a/物品和背包的完整代码/Tools/NetworkProtocol/Microsoft.Extensions.FileProviders.Abstractions.dll b/物品和背包的完整代码/Tools/NetworkProtocol/Microsoft.Extensions.FileProviders.Abstractions.dll new file mode 100644 index 0000000..f907206 Binary files /dev/null and b/物品和背包的完整代码/Tools/NetworkProtocol/Microsoft.Extensions.FileProviders.Abstractions.dll differ diff --git a/物品和背包的完整代码/Tools/NetworkProtocol/Microsoft.Extensions.FileProviders.Physical.dll b/物品和背包的完整代码/Tools/NetworkProtocol/Microsoft.Extensions.FileProviders.Physical.dll new file mode 100644 index 0000000..6fb7f47 Binary files /dev/null and b/物品和背包的完整代码/Tools/NetworkProtocol/Microsoft.Extensions.FileProviders.Physical.dll differ diff --git a/物品和背包的完整代码/Tools/NetworkProtocol/Microsoft.Extensions.FileSystemGlobbing.dll b/物品和背包的完整代码/Tools/NetworkProtocol/Microsoft.Extensions.FileSystemGlobbing.dll new file mode 100644 index 0000000..e590735 Binary files /dev/null and b/物品和背包的完整代码/Tools/NetworkProtocol/Microsoft.Extensions.FileSystemGlobbing.dll differ diff --git a/物品和背包的完整代码/Tools/NetworkProtocol/Microsoft.Extensions.Primitives.dll b/物品和背包的完整代码/Tools/NetworkProtocol/Microsoft.Extensions.Primitives.dll new file mode 100644 index 0000000..c24f2a0 Binary files /dev/null and b/物品和背包的完整代码/Tools/NetworkProtocol/Microsoft.Extensions.Primitives.dll differ diff --git a/物品和背包的完整代码/Tools/NetworkProtocol/Newtonsoft.Json.dll b/物品和背包的完整代码/Tools/NetworkProtocol/Newtonsoft.Json.dll new file mode 100644 index 0000000..d035c38 Binary files /dev/null and b/物品和背包的完整代码/Tools/NetworkProtocol/Newtonsoft.Json.dll differ diff --git a/物品和背包的完整代码/Tools/NetworkProtocol/Run.bat b/物品和背包的完整代码/Tools/NetworkProtocol/Run.bat new file mode 100644 index 0000000..af6e9e9 --- /dev/null +++ b/物品和背包的完整代码/Tools/NetworkProtocol/Run.bat @@ -0,0 +1,21 @@ +@echo off + +echo Please select an option: +echo 1. Client +echo 2. Server +echo 3. All + +set /p choice=Please select an option: + +if "%choice%"=="1" ( + echo Client + dotnet Fantasy.Tools.NetworkProtocol.dll --p 1 +) else if "%choice%"=="2" ( + echo Server + dotnet Fantasy.Tools.NetworkProtocol.dll --p 2 +) else if "%choice%"=="3" ( + echo All + dotnet Fantasy.Tools.NetworkProtocol.dll --p 3 +) else ( + echo Invalid option +) diff --git a/物品和背包的完整代码/Tools/NetworkProtocol/Run.sh b/物品和背包的完整代码/Tools/NetworkProtocol/Run.sh new file mode 100644 index 0000000..015b119 --- /dev/null +++ b/物品和背包的完整代码/Tools/NetworkProtocol/Run.sh @@ -0,0 +1,23 @@ +#!/bin/bash + +echo "1. Client" +echo "2. Server" +echo "3. All" + +read -n 1 -p "Please select an option:" choice +echo "" +echo "" +case $choice in + 1) + dotnet Fantasy.Tools.NetworkProtocol.dll --p 1 + ;; + 2) + dotnet Fantasy.Tools.NetworkProtocol.dll --p 2 + ;; + 3) + dotnet Fantasy.Tools.NetworkProtocol.dll --p 3 + ;; + *) + echo "Invalid option" + ;; +esac diff --git a/聊天系统课程代码/Bin/.DS_Store b/聊天系统课程代码/Bin/.DS_Store new file mode 100644 index 0000000..1de817f Binary files /dev/null and b/聊天系统课程代码/Bin/.DS_Store differ diff --git a/聊天系统课程代码/Bin/Debug/.DS_Store b/聊天系统课程代码/Bin/Debug/.DS_Store new file mode 100644 index 0000000..002c828 Binary files /dev/null and b/聊天系统课程代码/Bin/Debug/.DS_Store differ diff --git a/聊天系统课程代码/Chat.sln b/聊天系统课程代码/Chat.sln new file mode 100644 index 0000000..1964267 --- /dev/null +++ b/聊天系统课程代码/Chat.sln @@ -0,0 +1,67 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Client", "Client", "{DA9F8105-EC81-4BF1-970E-90570644231D}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Server", "Server", "{BC055757-8DDB-4B95-B564-000793687400}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "NuGet", "NuGet", "{F1CAD601-5183-4562-81CB-78FC83869955}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Config", "NuGet\Config\Config.csproj", "{3C4443EC-7DD1-48C7-BCBE-AE8EEE988265}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NetworkProtocolTools", "NuGet\NetworkProtocolTools\NetworkProtocolTools.csproj", "{6E145238-CB22-4B1E-A87A-683F73A3A87F}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ConfigTableTool", "NuGet\ConfigTableTool\ConfigTableTool.csproj", "{113124EE-A1F2-4AE9-9AF7-793D0D62F246}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Main", "Server\Main\Main.csproj", "{A470D256-1045-4D9F-9C89-6BF0BCE85E1F}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Entity", "Server\Entity\Entity.csproj", "{571FED4E-B665-4AE2-90EB-873B45C4F4DE}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Hotfix", "Server\Hotfix\Hotfix.csproj", "{3D760DFE-6963-4ACC-BAA4-302BFE7487FD}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Assembly-CSharp", "Client\Unity\Assembly-CSharp.csproj", "{03938CCD-4B40-8DFB-6B9B-21988D5CAC0A}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {3C4443EC-7DD1-48C7-BCBE-AE8EEE988265} = {F1CAD601-5183-4562-81CB-78FC83869955} + {6E145238-CB22-4B1E-A87A-683F73A3A87F} = {F1CAD601-5183-4562-81CB-78FC83869955} + {113124EE-A1F2-4AE9-9AF7-793D0D62F246} = {F1CAD601-5183-4562-81CB-78FC83869955} + {A470D256-1045-4D9F-9C89-6BF0BCE85E1F} = {BC055757-8DDB-4B95-B564-000793687400} + {571FED4E-B665-4AE2-90EB-873B45C4F4DE} = {BC055757-8DDB-4B95-B564-000793687400} + {3D760DFE-6963-4ACC-BAA4-302BFE7487FD} = {BC055757-8DDB-4B95-B564-000793687400} + {03938CCD-4B40-8DFB-6B9B-21988D5CAC0A} = {DA9F8105-EC81-4BF1-970E-90570644231D} + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {3C4443EC-7DD1-48C7-BCBE-AE8EEE988265}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3C4443EC-7DD1-48C7-BCBE-AE8EEE988265}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3C4443EC-7DD1-48C7-BCBE-AE8EEE988265}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3C4443EC-7DD1-48C7-BCBE-AE8EEE988265}.Release|Any CPU.Build.0 = Release|Any CPU + {6E145238-CB22-4B1E-A87A-683F73A3A87F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6E145238-CB22-4B1E-A87A-683F73A3A87F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6E145238-CB22-4B1E-A87A-683F73A3A87F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6E145238-CB22-4B1E-A87A-683F73A3A87F}.Release|Any CPU.Build.0 = Release|Any CPU + {113124EE-A1F2-4AE9-9AF7-793D0D62F246}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {113124EE-A1F2-4AE9-9AF7-793D0D62F246}.Debug|Any CPU.Build.0 = Debug|Any CPU + {113124EE-A1F2-4AE9-9AF7-793D0D62F246}.Release|Any CPU.ActiveCfg = Release|Any CPU + {113124EE-A1F2-4AE9-9AF7-793D0D62F246}.Release|Any CPU.Build.0 = Release|Any CPU + {A470D256-1045-4D9F-9C89-6BF0BCE85E1F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A470D256-1045-4D9F-9C89-6BF0BCE85E1F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A470D256-1045-4D9F-9C89-6BF0BCE85E1F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A470D256-1045-4D9F-9C89-6BF0BCE85E1F}.Release|Any CPU.Build.0 = Release|Any CPU + {571FED4E-B665-4AE2-90EB-873B45C4F4DE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {571FED4E-B665-4AE2-90EB-873B45C4F4DE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {571FED4E-B665-4AE2-90EB-873B45C4F4DE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {571FED4E-B665-4AE2-90EB-873B45C4F4DE}.Release|Any CPU.Build.0 = Release|Any CPU + {3D760DFE-6963-4ACC-BAA4-302BFE7487FD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3D760DFE-6963-4ACC-BAA4-302BFE7487FD}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3D760DFE-6963-4ACC-BAA4-302BFE7487FD}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3D760DFE-6963-4ACC-BAA4-302BFE7487FD}.Release|Any CPU.Build.0 = Release|Any CPU + {03938CCD-4B40-8DFB-6B9B-21988D5CAC0A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {03938CCD-4B40-8DFB-6B9B-21988D5CAC0A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {03938CCD-4B40-8DFB-6B9B-21988D5CAC0A}.Release|Any CPU.ActiveCfg = Debug|Any CPU + {03938CCD-4B40-8DFB-6B9B-21988D5CAC0A}.Release|Any CPU.Build.0 = Debug|Any CPU + EndGlobalSection +EndGlobal diff --git a/聊天系统课程代码/Chat.sln.DotSettings.user b/聊天系统课程代码/Chat.sln.DotSettings.user new file mode 100644 index 0000000..235b404 --- /dev/null +++ b/聊天系统课程代码/Chat.sln.DotSettings.user @@ -0,0 +1,8 @@ + + ForceIncluded + ForceIncluded + ForceIncluded + ForceIncluded + ForceIncluded + ForceIncluded + ForceIncluded \ No newline at end of file diff --git a/聊天系统课程代码/Client/.DS_Store b/聊天系统课程代码/Client/.DS_Store new file mode 100644 index 0000000..5ee5abb Binary files /dev/null and b/聊天系统课程代码/Client/.DS_Store differ diff --git a/聊天系统课程代码/Client/Unity/.DS_Store b/聊天系统课程代码/Client/Unity/.DS_Store new file mode 100644 index 0000000..cc9b2e5 Binary files /dev/null and b/聊天系统课程代码/Client/Unity/.DS_Store differ diff --git a/聊天系统课程代码/Client/Unity/.idea/.idea.Unity/.idea/.gitignore b/聊天系统课程代码/Client/Unity/.idea/.idea.Unity/.idea/.gitignore new file mode 100644 index 0000000..33d031a --- /dev/null +++ b/聊天系统课程代码/Client/Unity/.idea/.idea.Unity/.idea/.gitignore @@ -0,0 +1,13 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Rider ignored files +/contentModel.xml +/modules.xml +/.idea.Unity.iml +/projectSettingsUpdater.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/聊天系统课程代码/Client/Unity/.idea/.idea.Unity/.idea/encodings.xml b/聊天系统课程代码/Client/Unity/.idea/.idea.Unity/.idea/encodings.xml new file mode 100644 index 0000000..df87cf9 --- /dev/null +++ b/聊天系统课程代码/Client/Unity/.idea/.idea.Unity/.idea/encodings.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/聊天系统课程代码/Client/Unity/.idea/.idea.Unity/.idea/indexLayout.xml b/聊天系统课程代码/Client/Unity/.idea/.idea.Unity/.idea/indexLayout.xml new file mode 100644 index 0000000..7b08163 --- /dev/null +++ b/聊天系统课程代码/Client/Unity/.idea/.idea.Unity/.idea/indexLayout.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/聊天系统课程代码/Client/Unity/Assets/.DS_Store b/聊天系统课程代码/Client/Unity/Assets/.DS_Store new file mode 100644 index 0000000..190c2de Binary files /dev/null and b/聊天系统课程代码/Client/Unity/Assets/.DS_Store differ diff --git a/聊天系统课程代码/Client/Unity/Assets/Scenes.meta b/聊天系统课程代码/Client/Unity/Assets/Scenes.meta new file mode 100644 index 0000000..ff97d69 --- /dev/null +++ b/聊天系统课程代码/Client/Unity/Assets/Scenes.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 73da031d8461248aeab395b3a1f17c41 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/聊天系统课程代码/Client/Unity/Assets/Scenes/SampleScene.unity b/聊天系统课程代码/Client/Unity/Assets/Scenes/SampleScene.unity new file mode 100644 index 0000000..435f4ca --- /dev/null +++ b/聊天系统课程代码/Client/Unity/Assets/Scenes/SampleScene.unity @@ -0,0 +1,3067 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!29 &1 +OcclusionCullingSettings: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_OcclusionBakeSettings: + smallestOccluder: 5 + smallestHole: 0.25 + backfaceThreshold: 100 + m_SceneGUID: 00000000000000000000000000000000 + m_OcclusionCullingData: {fileID: 0} +--- !u!104 &2 +RenderSettings: + m_ObjectHideFlags: 0 + serializedVersion: 9 + m_Fog: 0 + m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} + m_FogMode: 3 + m_FogDensity: 0.01 + m_LinearFogStart: 0 + m_LinearFogEnd: 300 + m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1} + m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1} + m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1} + m_AmbientIntensity: 1 + m_AmbientMode: 0 + m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} + m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0} + m_HaloStrength: 0.5 + m_FlareStrength: 1 + m_FlareFadeSpeed: 3 + m_HaloTexture: {fileID: 0} + m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0} + m_DefaultReflectionMode: 0 + m_DefaultReflectionResolution: 128 + m_ReflectionBounces: 1 + m_ReflectionIntensity: 1 + m_CustomReflection: {fileID: 0} + m_Sun: {fileID: 705507994} + m_UseRadianceAmbientProbe: 0 +--- !u!157 &3 +LightmapSettings: + m_ObjectHideFlags: 0 + serializedVersion: 12 + m_GIWorkflowMode: 1 + m_GISettings: + serializedVersion: 2 + m_BounceScale: 1 + m_IndirectOutputScale: 1 + m_AlbedoBoost: 1 + m_EnvironmentLightingMode: 0 + m_EnableBakedLightmaps: 1 + m_EnableRealtimeLightmaps: 0 + m_LightmapEditorSettings: + serializedVersion: 12 + m_Resolution: 2 + m_BakeResolution: 40 + m_AtlasSize: 1024 + m_AO: 0 + m_AOMaxDistance: 1 + m_CompAOExponent: 1 + m_CompAOExponentDirect: 0 + m_ExtractAmbientOcclusion: 0 + m_Padding: 2 + m_LightmapParameters: {fileID: 0} + m_LightmapsBakeMode: 1 + m_TextureCompression: 1 + m_FinalGather: 0 + m_FinalGatherFiltering: 1 + m_FinalGatherRayCount: 256 + m_ReflectionCompression: 2 + m_MixedBakeMode: 2 + m_BakeBackend: 1 + m_PVRSampling: 1 + m_PVRDirectSampleCount: 32 + m_PVRSampleCount: 500 + m_PVRBounces: 2 + m_PVREnvironmentSampleCount: 500 + m_PVREnvironmentReferencePointCount: 2048 + m_PVRFilteringMode: 2 + m_PVRDenoiserTypeDirect: 0 + m_PVRDenoiserTypeIndirect: 0 + m_PVRDenoiserTypeAO: 0 + m_PVRFilterTypeDirect: 0 + m_PVRFilterTypeIndirect: 0 + m_PVRFilterTypeAO: 0 + m_PVREnvironmentMIS: 0 + m_PVRCulling: 1 + m_PVRFilteringGaussRadiusDirect: 1 + m_PVRFilteringGaussRadiusIndirect: 5 + m_PVRFilteringGaussRadiusAO: 2 + m_PVRFilteringAtrousPositionSigmaDirect: 0.5 + m_PVRFilteringAtrousPositionSigmaIndirect: 2 + m_PVRFilteringAtrousPositionSigmaAO: 1 + m_ExportTrainingData: 0 + m_TrainingDataDestination: TrainingData + m_LightProbeSampleCountMultiplier: 4 + m_LightingDataAsset: {fileID: 0} + m_LightingSettings: {fileID: 0} +--- !u!196 &4 +NavMeshSettings: + serializedVersion: 2 + m_ObjectHideFlags: 0 + m_BuildSettings: + serializedVersion: 3 + agentTypeID: 0 + agentRadius: 0.5 + agentHeight: 2 + agentSlope: 45 + agentClimb: 0.4 + ledgeDropHeight: 0 + maxJumpAcrossDistance: 0 + minRegionArea: 2 + manualCellSize: 0 + cellSize: 0.16666667 + manualTileSize: 0 + tileSize: 256 + buildHeightMesh: 0 + maxJobWorkers: 0 + preserveTilesOutsideBounds: 0 + debug: + m_Flags: 0 + m_NavMeshData: {fileID: 0} +--- !u!1 &15816386 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 15816387} + - component: {fileID: 15816389} + - component: {fileID: 15816388} + m_Layer: 5 + m_Name: Text (Legacy) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &15816387 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 15816386} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 1532065116} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &15816388 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 15816386} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 20 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 2 + m_MaxSize: 40 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: "\u53D1\u9001\u7FA4\u804A\u804A\u5929" +--- !u!222 &15816389 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 15816386} + m_CullTransparentMesh: 1 +--- !u!1 &58764626 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 58764627} + - component: {fileID: 58764629} + - component: {fileID: 58764628} + m_Layer: 5 + m_Name: Text (Legacy) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &58764627 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 58764626} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 1366656110} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &58764628 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 58764626} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 20 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 2 + m_MaxSize: 40 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: "\u53D1\u9001\u79C1\u804A\u804A\u5929" +--- !u!222 &58764629 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 58764626} + m_CullTransparentMesh: 1 +--- !u!1 &63922837 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 63922838} + - component: {fileID: 63922840} + - component: {fileID: 63922839} + m_Layer: 5 + m_Name: Placeholder + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &63922838 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 63922837} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 1411223627} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: -0.5} + m_SizeDelta: {x: -20, y: -13} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &63922839 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 63922837} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 0.5} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 30 + m_FontStyle: 2 + m_BestFit: 0 + m_MinSize: 3 + m_MaxSize: 40 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: "\u7528\u6237\u540D" +--- !u!222 &63922840 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 63922837} + m_CullTransparentMesh: 1 +--- !u!1 &194237014 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 194237015} + - component: {fileID: 194237018} + - component: {fileID: 194237017} + - component: {fileID: 194237016} + m_Layer: 5 + m_Name: SendButton1 + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &194237015 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 194237014} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 1530433480} + m_Father: {fileID: 708275419} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: -305, y: -243} + m_SizeDelta: {x: 179.07288, y: 54.274506} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &194237016 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 194237014} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_WrapAround: 0 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Selected + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 194237017} + m_OnClick: + m_PersistentCalls: + m_Calls: [] +--- !u!114 &194237017 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 194237014} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &194237018 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 194237014} + m_CullTransparentMesh: 1 +--- !u!1 &234816587 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 234816588} + - component: {fileID: 234816590} + - component: {fileID: 234816589} + m_Layer: 5 + m_Name: Text (Legacy) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &234816588 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 234816587} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 1884598134} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &234816589 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 234816587} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 20 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 2 + m_MaxSize: 40 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: "\u767B\u5F55\u6E38\u620F" +--- !u!222 &234816590 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 234816587} + m_CullTransparentMesh: 1 +--- !u!1 &377073743 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 377073744} + - component: {fileID: 377073746} + - component: {fileID: 377073745} + m_Layer: 5 + m_Name: Text + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &377073744 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 377073743} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 708275419} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 0, y: 134} + m_SizeDelta: {x: 1222.7323, y: 420.7108} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &377073745 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 377073743} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.8301887, g: 0.090067655, b: 0.090067655, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 50 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 5 + m_MaxSize: 50 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: "\u804A\u5929\u5185\u5BB9" +--- !u!222 &377073746 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 377073743} + m_CullTransparentMesh: 1 +--- !u!1 &412615209 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 412615210} + - component: {fileID: 412615212} + - component: {fileID: 412615211} + m_Layer: 5 + m_Name: Text (Legacy) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &412615210 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 412615209} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 2123732562} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &412615211 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 412615209} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 20 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 2 + m_MaxSize: 40 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: "\u53D1\u9001\u4E16\u754C\u804A\u5929" +--- !u!222 &412615212 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 412615209} + m_CullTransparentMesh: 1 +--- !u!1 &484878728 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 484878729} + - component: {fileID: 484878731} + - component: {fileID: 484878730} + m_Layer: 5 + m_Name: Placeholder + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &484878729 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 484878728} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 1435210555} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: -0.5} + m_SizeDelta: {x: -20, y: -13} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &484878730 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 484878728} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 0.5} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 24 + m_FontStyle: 2 + m_BestFit: 0 + m_MinSize: 2 + m_MaxSize: 40 + m_Alignment: 3 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: Enter text... +--- !u!222 &484878731 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 484878728} + m_CullTransparentMesh: 1 +--- !u!1 &488014527 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 488014528} + - component: {fileID: 488014530} + - component: {fileID: 488014529} + m_Layer: 5 + m_Name: Placeholder + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &488014528 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 488014527} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 745262432} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: -0.5} + m_SizeDelta: {x: -20, y: -13} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &488014529 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 488014527} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 0.5} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 24 + m_FontStyle: 2 + m_BestFit: 0 + m_MinSize: 2 + m_MaxSize: 40 + m_Alignment: 3 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: "\u79C1\u804A\u76EE\u6807\u7684ID..." +--- !u!222 &488014530 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 488014527} + m_CullTransparentMesh: 1 +--- !u!1 &705507993 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 705507995} + - component: {fileID: 705507994} + m_Layer: 0 + m_Name: Directional Light + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!108 &705507994 +Light: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 705507993} + m_Enabled: 1 + serializedVersion: 10 + m_Type: 1 + m_Shape: 0 + m_Color: {r: 1, g: 0.95686275, b: 0.8392157, a: 1} + m_Intensity: 1 + m_Range: 10 + m_SpotAngle: 30 + m_InnerSpotAngle: 21.802082 + m_CookieSize: 10 + m_Shadows: + m_Type: 2 + m_Resolution: -1 + m_CustomResolution: -1 + m_Strength: 1 + m_Bias: 0.05 + m_NormalBias: 0.4 + m_NearPlane: 0.2 + m_CullingMatrixOverride: + e00: 1 + e01: 0 + e02: 0 + e03: 0 + e10: 0 + e11: 1 + e12: 0 + e13: 0 + e20: 0 + e21: 0 + e22: 1 + e23: 0 + e30: 0 + e31: 0 + e32: 0 + e33: 1 + m_UseCullingMatrixOverride: 0 + m_Cookie: {fileID: 0} + m_DrawHalo: 0 + m_Flare: {fileID: 0} + m_RenderMode: 0 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingLayerMask: 1 + m_Lightmapping: 1 + m_LightShadowCasterMode: 0 + m_AreaSize: {x: 1, y: 1} + m_BounceIntensity: 1 + m_ColorTemperature: 6570 + m_UseColorTemperature: 0 + m_BoundingSphereOverride: {x: 0, y: 0, z: 0, w: 0} + m_UseBoundingSphereOverride: 0 + m_UseViewFrustumForShadowCasterCull: 1 + m_ShadowRadius: 0 + m_ShadowAngle: 0 +--- !u!4 &705507995 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 705507993} + serializedVersion: 2 + m_LocalRotation: {x: 0.40821788, y: -0.23456968, z: 0.10938163, w: 0.8754261} + m_LocalPosition: {x: 0, y: 3, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0} +--- !u!1 &708275416 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 708275419} + - component: {fileID: 708275418} + - component: {fileID: 708275417} + m_Layer: 5 + m_Name: ChatPanel + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &708275417 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 708275416} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 0.392} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10907, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &708275418 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 708275416} + m_CullTransparentMesh: 1 +--- !u!224 &708275419 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 708275416} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 377073744} + - {fileID: 194237015} + - {fileID: 1366656110} + - {fileID: 1478595893} + - {fileID: 1532065116} + - {fileID: 2123732562} + - {fileID: 841340045} + - {fileID: 1435210555} + - {fileID: 745262432} + m_Father: {fileID: 1764947224} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!1 &714528300 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 714528301} + - component: {fileID: 714528303} + - component: {fileID: 714528302} + m_Layer: 5 + m_Name: Text (Legacy) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &714528301 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 714528300} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 1435210555} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: -0.5} + m_SizeDelta: {x: -20, y: -13} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &714528302 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 714528300} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 24 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 2 + m_MaxSize: 40 + m_Alignment: 0 + m_AlignByGeometry: 0 + m_RichText: 0 + m_HorizontalOverflow: 1 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: +--- !u!222 &714528303 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 714528300} + m_CullTransparentMesh: 1 +--- !u!1 &745262431 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 745262432} + - component: {fileID: 745262434} + - component: {fileID: 745262433} + - component: {fileID: 745262435} + m_Layer: 5 + m_Name: PrivateText + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &745262432 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 745262431} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 488014528} + - {fileID: 1047200198} + m_Father: {fileID: 708275419} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: -76, y: -319} + m_SizeDelta: {x: 357.7175, y: 55.863} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &745262433 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 745262431} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10911, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &745262434 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 745262431} + m_CullTransparentMesh: 1 +--- !u!114 &745262435 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 745262431} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d199490a83bb2b844b9695cbf13b01ef, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_WrapAround: 0 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Selected + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 745262433} + m_TextComponent: {fileID: 1047200199} + m_Placeholder: {fileID: 488014529} + m_ContentType: 0 + m_InputType: 0 + m_AsteriskChar: 42 + m_KeyboardType: 0 + m_LineType: 0 + m_HideMobileInput: 0 + m_CharacterValidation: 0 + m_CharacterLimit: 0 + m_OnSubmit: + m_PersistentCalls: + m_Calls: [] + m_OnDidEndEdit: + m_PersistentCalls: + m_Calls: [] + m_OnValueChanged: + m_PersistentCalls: + m_Calls: [] + m_CaretColor: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} + m_CustomCaretColor: 0 + m_SelectionColor: {r: 0.65882355, g: 0.80784315, b: 1, a: 0.7529412} + m_Text: + m_CaretBlinkRate: 0.85 + m_CaretWidth: 1 + m_ReadOnly: 0 + m_ShouldActivateOnSelect: 1 +--- !u!1 &841340041 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 841340045} + - component: {fileID: 841340044} + - component: {fileID: 841340043} + - component: {fileID: 841340042} + m_Layer: 5 + m_Name: ChatNodeEventButton + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &841340042 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 841340041} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_WrapAround: 0 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Selected + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 841340043} + m_OnClick: + m_PersistentCalls: + m_Calls: [] +--- !u!114 &841340043 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 841340041} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &841340044 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 841340041} + m_CullTransparentMesh: 1 +--- !u!224 &841340045 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 841340041} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 1978690994} + m_Father: {fileID: 708275419} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 723, y: -275} + m_SizeDelta: {x: 322.9924, y: 121.8993} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!1 &963194225 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 963194228} + - component: {fileID: 963194227} + - component: {fileID: 963194226} + m_Layer: 0 + m_Name: Main Camera + m_TagString: MainCamera + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!81 &963194226 +AudioListener: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 963194225} + m_Enabled: 1 +--- !u!20 &963194227 +Camera: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 963194225} + m_Enabled: 1 + serializedVersion: 2 + m_ClearFlags: 1 + m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0} + m_projectionMatrixMode: 1 + m_GateFitMode: 2 + m_FOVAxisMode: 0 + m_Iso: 200 + m_ShutterSpeed: 0.005 + m_Aperture: 16 + m_FocusDistance: 10 + m_FocalLength: 50 + m_BladeCount: 5 + m_Curvature: {x: 2, y: 11} + m_BarrelClipping: 0.25 + m_Anamorphism: 0 + m_SensorSize: {x: 36, y: 24} + m_LensShift: {x: 0, y: 0} + m_NormalizedViewPortRect: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 + near clip plane: 0.3 + far clip plane: 1000 + field of view: 60 + orthographic: 0 + orthographic size: 5 + m_Depth: -1 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingPath: -1 + m_TargetTexture: {fileID: 0} + m_TargetDisplay: 0 + m_TargetEye: 3 + m_HDR: 1 + m_AllowMSAA: 1 + m_AllowDynamicResolution: 0 + m_ForceIntoRT: 0 + m_OcclusionCulling: 1 + m_StereoConvergence: 10 + m_StereoSeparation: 0.022 +--- !u!4 &963194228 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 963194225} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 1, z: -10} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1011569671 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1011569674} + - component: {fileID: 1011569673} + - component: {fileID: 1011569672} + m_Layer: 0 + m_Name: EventSystem + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1011569672 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1011569671} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4f231c4fb786f3946a6b90b886c48677, type: 3} + m_Name: + m_EditorClassIdentifier: + m_SendPointerHoverToParent: 1 + m_HorizontalAxis: Horizontal + m_VerticalAxis: Vertical + m_SubmitButton: Submit + m_CancelButton: Cancel + m_InputActionsPerSecond: 10 + m_RepeatDelay: 0.5 + m_ForceModuleActive: 0 +--- !u!114 &1011569673 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1011569671} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 76c392e42b5098c458856cdf6ecaaaa1, type: 3} + m_Name: + m_EditorClassIdentifier: + m_FirstSelected: {fileID: 0} + m_sendNavigationEvents: 1 + m_DragThreshold: 10 +--- !u!4 &1011569674 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1011569671} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1047200197 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1047200198} + - component: {fileID: 1047200200} + - component: {fileID: 1047200199} + m_Layer: 5 + m_Name: Text (Legacy) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1047200198 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1047200197} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 745262432} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: -0.5} + m_SizeDelta: {x: -20, y: -13} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1047200199 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1047200197} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 24 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 2 + m_MaxSize: 40 + m_Alignment: 0 + m_AlignByGeometry: 0 + m_RichText: 0 + m_HorizontalOverflow: 1 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: +--- !u!222 &1047200200 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1047200197} + m_CullTransparentMesh: 1 +--- !u!1 &1321765049 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1321765050} + - component: {fileID: 1321765052} + - component: {fileID: 1321765051} + m_Layer: 5 + m_Name: Text (Legacy) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1321765050 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1321765049} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 1478595893} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1321765051 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1321765049} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 20 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 2 + m_MaxSize: 40 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: "\u9000\u51FA\u6E38\u620F" +--- !u!222 &1321765052 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1321765049} + m_CullTransparentMesh: 1 +--- !u!1 &1366656109 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1366656110} + - component: {fileID: 1366656113} + - component: {fileID: 1366656112} + - component: {fileID: 1366656111} + m_Layer: 5 + m_Name: PrivateButton + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1366656110 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1366656109} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 58764627} + m_Father: {fileID: 708275419} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: -99.99999, y: -243} + m_SizeDelta: {x: 179.07288, y: 54.274506} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1366656111 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1366656109} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_WrapAround: 0 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Selected + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 1366656112} + m_OnClick: + m_PersistentCalls: + m_Calls: [] +--- !u!114 &1366656112 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1366656109} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &1366656113 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1366656109} + m_CullTransparentMesh: 1 +--- !u!1 &1411223626 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1411223627} + - component: {fileID: 1411223630} + - component: {fileID: 1411223629} + - component: {fileID: 1411223628} + m_Layer: 5 + m_Name: UserName + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1411223627 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1411223626} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 63922838} + - {fileID: 1858956216} + m_Father: {fileID: 1871532048} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 323.2301, y: 66.448} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1411223628 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1411223626} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d199490a83bb2b844b9695cbf13b01ef, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_WrapAround: 0 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Selected + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 1411223629} + m_TextComponent: {fileID: 1858956217} + m_Placeholder: {fileID: 63922839} + m_ContentType: 0 + m_InputType: 0 + m_AsteriskChar: 42 + m_KeyboardType: 0 + m_LineType: 0 + m_HideMobileInput: 0 + m_CharacterValidation: 0 + m_CharacterLimit: 0 + m_OnSubmit: + m_PersistentCalls: + m_Calls: [] + m_OnDidEndEdit: + m_PersistentCalls: + m_Calls: [] + m_OnValueChanged: + m_PersistentCalls: + m_Calls: [] + m_CaretColor: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} + m_CustomCaretColor: 0 + m_SelectionColor: {r: 0.65882355, g: 0.80784315, b: 1, a: 0.7529412} + m_Text: + m_CaretBlinkRate: 0.85 + m_CaretWidth: 1 + m_ReadOnly: 0 + m_ShouldActivateOnSelect: 1 +--- !u!114 &1411223629 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1411223626} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10911, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &1411223630 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1411223626} + m_CullTransparentMesh: 1 +--- !u!1 &1435210554 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1435210555} + - component: {fileID: 1435210558} + - component: {fileID: 1435210557} + - component: {fileID: 1435210556} + m_Layer: 5 + m_Name: SendMessageText + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1435210555 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1435210554} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 484878729} + - {fileID: 714528301} + m_Father: {fileID: 708275419} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: -4.3353, y: -154.93} + m_SizeDelta: {x: 1028.7632, y: 55.863} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1435210556 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1435210554} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d199490a83bb2b844b9695cbf13b01ef, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_WrapAround: 0 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Selected + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 1435210557} + m_TextComponent: {fileID: 714528302} + m_Placeholder: {fileID: 484878730} + m_ContentType: 0 + m_InputType: 0 + m_AsteriskChar: 42 + m_KeyboardType: 0 + m_LineType: 0 + m_HideMobileInput: 0 + m_CharacterValidation: 0 + m_CharacterLimit: 0 + m_OnSubmit: + m_PersistentCalls: + m_Calls: [] + m_OnDidEndEdit: + m_PersistentCalls: + m_Calls: [] + m_OnValueChanged: + m_PersistentCalls: + m_Calls: [] + m_CaretColor: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} + m_CustomCaretColor: 0 + m_SelectionColor: {r: 0.65882355, g: 0.80784315, b: 1, a: 0.7529412} + m_Text: + m_CaretBlinkRate: 0.85 + m_CaretWidth: 1 + m_ReadOnly: 0 + m_ShouldActivateOnSelect: 1 +--- !u!114 &1435210557 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1435210554} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10911, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &1435210558 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1435210554} + m_CullTransparentMesh: 1 +--- !u!1 &1478595892 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1478595893} + - component: {fileID: 1478595895} + - component: {fileID: 1478595894} + - component: {fileID: 1478595896} + m_Layer: 5 + m_Name: ExitButton + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1478595893 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1478595892} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 1321765050} + m_Father: {fileID: 708275419} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: -521, y: -243} + m_SizeDelta: {x: 179.07288, y: 54.274506} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1478595894 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1478595892} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &1478595895 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1478595892} + m_CullTransparentMesh: 1 +--- !u!114 &1478595896 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1478595892} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_WrapAround: 0 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Selected + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 1478595894} + m_OnClick: + m_PersistentCalls: + m_Calls: [] +--- !u!1 &1530433479 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1530433480} + - component: {fileID: 1530433482} + - component: {fileID: 1530433481} + m_Layer: 5 + m_Name: Text (Legacy) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1530433480 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1530433479} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 194237015} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1530433481 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1530433479} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 20 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 2 + m_MaxSize: 40 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: "\u53D1\u9001\u666E\u901A\u804A\u5929" +--- !u!222 &1530433482 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1530433479} + m_CullTransparentMesh: 1 +--- !u!1 &1532065115 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1532065116} + - component: {fileID: 1532065119} + - component: {fileID: 1532065118} + - component: {fileID: 1532065117} + m_Layer: 5 + m_Name: ChannelButton + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1532065116 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1532065115} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 15816387} + m_Father: {fileID: 708275419} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 103.00001, y: -243} + m_SizeDelta: {x: 179.07288, y: 54.274506} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1532065117 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1532065115} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_WrapAround: 0 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Selected + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 1532065118} + m_OnClick: + m_PersistentCalls: + m_Calls: [] +--- !u!114 &1532065118 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1532065115} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &1532065119 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1532065115} + m_CullTransparentMesh: 1 +--- !u!1 &1764947220 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1764947224} + - component: {fileID: 1764947223} + - component: {fileID: 1764947222} + - component: {fileID: 1764947221} + - component: {fileID: 1764947225} + m_Layer: 5 + m_Name: Canvas + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1764947221 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1764947220} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: dc42784cf147c0c48a680349fa168899, type: 3} + m_Name: + m_EditorClassIdentifier: + m_IgnoreReversedGraphics: 1 + m_BlockingObjects: 0 + m_BlockingMask: + serializedVersion: 2 + m_Bits: 4294967295 +--- !u!114 &1764947222 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1764947220} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 0cd44c1031e13a943bb63640046fad76, type: 3} + m_Name: + m_EditorClassIdentifier: + m_UiScaleMode: 1 + m_ReferencePixelsPerUnit: 100 + m_ScaleFactor: 1 + m_ReferenceResolution: {x: 1920, y: 1080} + m_ScreenMatchMode: 0 + m_MatchWidthOrHeight: 0.5 + m_PhysicalUnit: 3 + m_FallbackScreenDPI: 96 + m_DefaultSpriteDPI: 96 + m_DynamicPixelsPerUnit: 1 + m_PresetInfoIsWorld: 0 +--- !u!223 &1764947223 +Canvas: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1764947220} + m_Enabled: 1 + serializedVersion: 3 + m_RenderMode: 0 + m_Camera: {fileID: 0} + m_PlaneDistance: 100 + m_PixelPerfect: 0 + m_ReceivesEvents: 1 + m_OverrideSorting: 0 + m_OverridePixelPerfect: 0 + m_SortingBucketNormalizedSize: 0 + m_VertexColorAlwaysGammaSpace: 0 + m_AdditionalShaderChannelsFlag: 0 + m_UpdateRectTransformForStandalone: 0 + m_SortingLayerID: 0 + m_SortingOrder: 0 + m_TargetDisplay: 0 +--- !u!224 &1764947224 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1764947220} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 0, y: 0, z: 0} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 1871532048} + - {fileID: 708275419} + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 0} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0, y: 0} +--- !u!114 &1764947225 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1764947220} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: ff1382f197f7f4cf39f6ae0745b57ee6, type: 3} + m_Name: + m_EditorClassIdentifier: + LoginPanel: {fileID: 1871532047} + ChatPanel: {fileID: 708275416} + MessageText: {fileID: 377073745} + PrivateText: {fileID: 745262435} + UserName: {fileID: 1411223628} + SendMessageText: {fileID: 1435210556} + LoginButton: {fileID: 1884598135} + ExitButton: {fileID: 1478595896} + BroadcastButton: {fileID: 2123732563} + ChannelButton: {fileID: 1532065117} + PrivateButton: {fileID: 1366656111} + SendButton1: {fileID: 194237016} + ChatNodeEventButton: {fileID: 841340042} +--- !u!1 &1858956215 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1858956216} + - component: {fileID: 1858956218} + - component: {fileID: 1858956217} + m_Layer: 5 + m_Name: Text (Legacy) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1858956216 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1858956215} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 1411223627} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: -0.5} + m_SizeDelta: {x: -20, y: -13} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1858956217 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1858956215} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 30 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 3 + m_MaxSize: 40 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 0 + m_HorizontalOverflow: 1 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: +--- !u!222 &1858956218 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1858956215} + m_CullTransparentMesh: 1 +--- !u!1 &1871532047 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1871532048} + - component: {fileID: 1871532050} + - component: {fileID: 1871532049} + m_Layer: 5 + m_Name: LoginPanel + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 0 +--- !u!224 &1871532048 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1871532047} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 1884598134} + - {fileID: 1411223627} + m_Father: {fileID: 1764947224} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1871532049 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1871532047} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 0.392} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10907, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &1871532050 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1871532047} + m_CullTransparentMesh: 1 +--- !u!1 &1884598133 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1884598134} + - component: {fileID: 1884598137} + - component: {fileID: 1884598136} + - component: {fileID: 1884598135} + m_Layer: 5 + m_Name: LoginButton + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1884598134 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1884598133} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 234816588} + m_Father: {fileID: 1871532048} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 0, y: -104} + m_SizeDelta: {x: 179.07288, y: 54.274506} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1884598135 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1884598133} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_WrapAround: 0 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Selected + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 1884598136} + m_OnClick: + m_PersistentCalls: + m_Calls: [] +--- !u!114 &1884598136 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1884598133} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &1884598137 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1884598133} + m_CullTransparentMesh: 1 +--- !u!1 &1978690993 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1978690994} + - component: {fileID: 1978690996} + - component: {fileID: 1978690995} + m_Layer: 5 + m_Name: Text (Legacy) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1978690994 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1978690993} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 841340045} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1978690995 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1978690993} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 20 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 2 + m_MaxSize: 40 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: "\u8FD0\u884C\u804A\u5929\u5185\u5BB9\u7B2C\u4E00\u4E2A\u8282\u70B9\u7684\u4E8B\u4EF6" +--- !u!222 &1978690996 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1978690993} + m_CullTransparentMesh: 1 +--- !u!1 &2123732561 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2123732562} + - component: {fileID: 2123732565} + - component: {fileID: 2123732564} + - component: {fileID: 2123732563} + m_Layer: 5 + m_Name: BroadcastButton + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &2123732562 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2123732561} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 412615210} + m_Father: {fileID: 708275419} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 310, y: -243} + m_SizeDelta: {x: 179.07288, y: 54.274506} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &2123732563 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2123732561} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_WrapAround: 0 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Selected + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 2123732564} + m_OnClick: + m_PersistentCalls: + m_Calls: [] +--- !u!114 &2123732564 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2123732561} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &2123732565 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2123732561} + m_CullTransparentMesh: 1 +--- !u!1660057539 &9223372036854775807 +SceneRoots: + m_ObjectHideFlags: 0 + m_Roots: + - {fileID: 963194228} + - {fileID: 705507995} + - {fileID: 1764947224} + - {fileID: 1011569674} diff --git a/聊天系统课程代码/Client/Unity/Assets/Scenes/SampleScene.unity.meta b/聊天系统课程代码/Client/Unity/Assets/Scenes/SampleScene.unity.meta new file mode 100644 index 0000000..952bd1e --- /dev/null +++ b/聊天系统课程代码/Client/Unity/Assets/Scenes/SampleScene.unity.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 9fc0d4010bbf28b4594072e72b8655ab +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/聊天系统课程代码/Client/Unity/Assets/Scripts.meta b/聊天系统课程代码/Client/Unity/Assets/Scripts.meta new file mode 100644 index 0000000..fb96fc2 --- /dev/null +++ b/聊天系统课程代码/Client/Unity/Assets/Scripts.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: dcecc97fbd8214f2fb856c62b80b50f1 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/聊天系统课程代码/Client/Unity/Assets/Scripts/.DS_Store b/聊天系统课程代码/Client/Unity/Assets/Scripts/.DS_Store new file mode 100644 index 0000000..ff01778 Binary files /dev/null and b/聊天系统课程代码/Client/Unity/Assets/Scripts/.DS_Store differ diff --git a/聊天系统课程代码/Client/Unity/Assets/Scripts/Entry.cs b/聊天系统课程代码/Client/Unity/Assets/Scripts/Entry.cs new file mode 100644 index 0000000..5ce874a --- /dev/null +++ b/聊天系统课程代码/Client/Unity/Assets/Scripts/Entry.cs @@ -0,0 +1,182 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Fantasy; +using Fantasy.Async; +using Fantasy.Entitas; +using Fantasy.Network; +using UnityEngine; +using UnityEngine.UI; + +public sealed class EntryComponent : Entity +{ + public Entry Entry; +} + +public class Entry : MonoBehaviour +{ + private Scene _scene; + private Session _session; + + public GameObject LoginPanel; + public GameObject ChatPanel; + + public Text MessageText; + public InputField PrivateText; + public InputField UserName; + public InputField SendMessageText; + public Button LoginButton; + public Button ExitButton; + public Button BroadcastButton; + public Button ChannelButton; + public Button PrivateButton; + + public Button SendButton1; + public Button ChatNodeEventButton; + void Start() + { + LoginPanel.SetActive(true); + ChatPanel.SetActive(false); + StartAsync().Coroutine(); + LoginButton.onClick.RemoveAllListeners(); + LoginButton.onClick.AddListener(() => { OnLoginButtonClick().Coroutine();}); + ExitButton.onClick.RemoveAllListeners(); + ExitButton.onClick.AddListener(() => { OnExitButtonClick().Coroutine();}); + SendButton1.onClick.RemoveAllListeners(); + SendButton1.onClick.AddListener(() => { OnSendButton1Click().Coroutine();}); + BroadcastButton.onClick.RemoveAllListeners(); + BroadcastButton.onClick.AddListener(() => { OnBroadcastButtonClick().Coroutine();}); + ChannelButton.onClick.RemoveAllListeners(); + ChannelButton.onClick.AddListener(() => { OnChannelButtonClick().Coroutine();}); + PrivateButton.onClick.RemoveAllListeners(); + PrivateButton.onClick.AddListener(() => { OnPrivateButtonClick().Coroutine();}); + } + + private async FTask StartAsync() + { + Fantasy.Platform.Unity.Entry.Initialize(GetType().Assembly); + _scene = await Scene.Create(SceneRuntimeType.MainThread); + _scene.AddComponent().Entry = this; + _scene.AddComponent().Initialize(); + } + + private async FTask OnLoginButtonClick() + { + // 创建一个连接,这里是连接到目标的Gate服务器 + _session = _scene.Connect( + "127.0.0.1:20000", + NetworkProtocolType.KCP, + () => + { + Log.Debug("连接成功!"); + _session.AddComponent().Start(2000); + }, + () => + { + Log.Debug("连接失败!"); + }, + () => + { + Log.Debug("断开连接!"); + }, + false, 5000); + // 发送登录请求 + var response = (G2C_LoginResponse)await _session.Call(new C2G_LoginRequest() + { + UserName = UserName.text + }); + // 查看错误码 + if (response.ErrorCode != 0) + { + Log.Error($"登录错误 ErrorCode:{response.ErrorCode}"); + return; + } + LoginPanel.SetActive(false); + ChatPanel.SetActive(true); + Log.Debug("登录成功!"); + } + + private async FTask OnExitButtonClick() + { + var response = (G2C_ExitResponse)await _session.Call(new C2G_ExitRequest()); + if (response.ErrorCode != 0) + { + Log.Error($"退出游戏错误 ErrorCode:{response.ErrorCode}"); + return; + } + LoginPanel.SetActive(true); + ChatPanel.SetActive(false); + Log.Debug("退出游戏成功!"); + } + + private async FTask OnSendButton1Click() + { + await FTask.CompletedTask; + // SendButton1.interactable = false; + // var response = (Chat2C_SendMessageResponse) await _session.Call(new C2Chat_SendMessageRequest()); + // if (response.ErrorCode != 0) + // { + // Log.Error($"发送聊天消息失败 ErrorCode:{response.ErrorCode}"); + // return; + // } + // Log.Debug("发送聊天消息成功!"); + // SendButton1.interactable = true; + } + + private async FTask OnBroadcastButtonClick() + { + BroadcastButton.interactable = false; + var tree = ChatTreeFactory.Broadcast(_scene); + tree = tree.AddendPositionNode(SendMessageText.text, "勇者大陆", 121, 131, 111); + + var response = (Chat2C_SendMessageResponse)await _session.Call(new C2Chat_SendMessageRequest() + { + ChatInfoTree = tree + }); + if (response.ErrorCode != 0) + { + Log.Error($"发送聊天消息失败 ErrorCode:{response.ErrorCode}"); + } + + BroadcastButton.interactable = true; + } + + private async FTask OnChannelButtonClick() + { + ChannelButton.interactable = false; + var tree = ChatTreeFactory.Team(_scene); + tree.ChatChannelId = 1; + // tree = tree.AddendTextNode("你好,欢迎来到Fantasy Chat!").AddendLinkNode("点击这里http://www.fantasy.com.cn"); + var response = (Chat2C_SendMessageResponse)await _session.Call(new C2Chat_SendMessageRequest() + { + ChatInfoTree = tree + }); + if (response.ErrorCode != 0) + { + Log.Error($"发送频道聊天消息失败 ErrorCode:{response.ErrorCode}"); + } + + ChannelButton.interactable = true; + } + + private async FTask OnPrivateButtonClick() + { + PrivateButton.interactable = false; + var tree = ChatTreeFactory.Private(_scene); + tree.Target.Add(Convert.ToInt64(PrivateText.text)); + // tree = tree.AddendTextNode("你好,欢迎来到Fantasy Chat!").AddendLinkNode("点击这里http://www.fantasy.com.cn"); + + var response = (Chat2C_SendMessageResponse)await _session.Call(new C2Chat_SendMessageRequest() + { + ChatInfoTree = tree + }); + if (response.ErrorCode != 0) + { + Log.Error($"发送私聊消息失败 ErrorCode:{response.ErrorCode}"); + } + + PrivateButton.interactable = true; + } + + +} diff --git a/聊天系统课程代码/Client/Unity/Assets/Scripts/Entry.cs.meta b/聊天系统课程代码/Client/Unity/Assets/Scripts/Entry.cs.meta new file mode 100644 index 0000000..3faebd6 --- /dev/null +++ b/聊天系统课程代码/Client/Unity/Assets/Scripts/Entry.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ff1382f197f7f4cf39f6ae0745b57ee6 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/聊天系统课程代码/Client/Unity/Assets/Scripts/Hotfix.meta b/聊天系统课程代码/Client/Unity/Assets/Scripts/Hotfix.meta new file mode 100644 index 0000000..6180536 --- /dev/null +++ b/聊天系统课程代码/Client/Unity/Assets/Scripts/Hotfix.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 019a0eb317f11413fa9c6be7fd61e28e +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/聊天系统课程代码/Client/Unity/Assets/Scripts/Hotfix/.DS_Store b/聊天系统课程代码/Client/Unity/Assets/Scripts/Hotfix/.DS_Store new file mode 100644 index 0000000..f0c828e Binary files /dev/null and b/聊天系统课程代码/Client/Unity/Assets/Scripts/Hotfix/.DS_Store differ diff --git a/聊天系统课程代码/Client/Unity/Assets/Scripts/Hotfix/Chat.meta b/聊天系统课程代码/Client/Unity/Assets/Scripts/Hotfix/Chat.meta new file mode 100644 index 0000000..4db27ca --- /dev/null +++ b/聊天系统课程代码/Client/Unity/Assets/Scripts/Hotfix/Chat.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 84d0e5cdfe24a42e4b1a6a5d3fa0796b +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/聊天系统课程代码/Client/Unity/Assets/Scripts/Hotfix/Chat/ChatChannelType.cs b/聊天系统课程代码/Client/Unity/Assets/Scripts/Hotfix/Chat/ChatChannelType.cs new file mode 100644 index 0000000..cc8aadb --- /dev/null +++ b/聊天系统课程代码/Client/Unity/Assets/Scripts/Hotfix/Chat/ChatChannelType.cs @@ -0,0 +1,52 @@ +using System; + +namespace Fantasy +{ + /// + /// 聊天频道类型 + /// + [Flags] + public enum ChatChannelType + { + None = 0, + World = 1 << 1, // 世界频道 + Private = 1 << 2, // 私聊频道 + System = 1 << 3, // 系统频道 + Broadcast = 1 << 4, // 广播频道 + Notice = 1 << 5, // 公告频道 + Team = 1 << 6, // 队伍频道 + Near = 1 << 7, // 附近频道 + CurrentMap = 1 << 8, // 当前地图频道 + + // 所有频道 + All = World | Private | System | Broadcast | Notice | Team | Near, + // 其他聊天栏显示的频道 + Display = World | Private | System | Broadcast | Notice | Team | Near | CurrentMap + } + + /// + /// 聊天节点类型 + /// + public enum ChatNodeType + { + None = 0, + Position = 1, // 位置节点 + OpenUI = 2, // 打开UI节点 + Link = 3, // 链接节点 + Item = 4, // 物品节点 + Text = 5, // 文本节点 + Image = 6, // 图片节点 + } + + /// + /// 聊天节点事件类型 + /// + public enum ChatNodeEvent + { + None = 0, + OpenUI = 1, // 打开UI节点 + ClickLink = 2, // 点击链接节点 + UseItem = 3, // 使用物品节点 + Position = 4, // 位置节点 + } +} \ No newline at end of file diff --git a/聊天系统课程代码/Client/Unity/Assets/Scripts/Hotfix/Chat/ChatChannelType.cs.meta b/聊天系统课程代码/Client/Unity/Assets/Scripts/Hotfix/Chat/ChatChannelType.cs.meta new file mode 100644 index 0000000..eec325e --- /dev/null +++ b/聊天系统课程代码/Client/Unity/Assets/Scripts/Hotfix/Chat/ChatChannelType.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1cf2785958c454fb98765b594d346806 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/聊天系统课程代码/Client/Unity/Assets/Scripts/Hotfix/Chat/ChatInfoTree.cs b/聊天系统课程代码/Client/Unity/Assets/Scripts/Hotfix/Chat/ChatInfoTree.cs new file mode 100644 index 0000000..a3f6ea0 --- /dev/null +++ b/聊天系统课程代码/Client/Unity/Assets/Scripts/Hotfix/Chat/ChatInfoTree.cs @@ -0,0 +1,16 @@ +using System.Runtime.Serialization; +using MongoDB.Bson.Serialization.Attributes; +using Newtonsoft.Json; +using ProtoBuf; + +namespace Fantasy +{ + public partial class ChatInfoTree + { + [BsonIgnore] + [JsonIgnore] + [ProtoIgnore] + [IgnoreDataMember] + public Scene Scene { get; set; } + } +} \ No newline at end of file diff --git a/聊天系统课程代码/Client/Unity/Assets/Scripts/Hotfix/Chat/ChatInfoTree.cs.meta b/聊天系统课程代码/Client/Unity/Assets/Scripts/Hotfix/Chat/ChatInfoTree.cs.meta new file mode 100644 index 0000000..7835146 --- /dev/null +++ b/聊天系统课程代码/Client/Unity/Assets/Scripts/Hotfix/Chat/ChatInfoTree.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0079ff8530a474be1a7962b88311db20 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/聊天系统课程代码/Client/Unity/Assets/Scripts/Hotfix/Chat/ChatNodeEventHelper.cs b/聊天系统课程代码/Client/Unity/Assets/Scripts/Hotfix/Chat/ChatNodeEventHelper.cs new file mode 100644 index 0000000..c4652e3 --- /dev/null +++ b/聊天系统课程代码/Client/Unity/Assets/Scripts/Hotfix/Chat/ChatNodeEventHelper.cs @@ -0,0 +1,78 @@ +using System.Collections.Generic; + +namespace Fantasy +{ + public static class ChatNodeEventHelper + { + public static void Handler(Scene scene, ChatInfoNode node) + { + switch ((ChatNodeEvent)node.ChatNodeEvent) + { + case ChatNodeEvent.ClickLink: + { + ClickLinkHandler(scene, node); + return; + } + case ChatNodeEvent.OpenUI: + { + OpenUIHandler(scene, node); + return; + } + case ChatNodeEvent.Position: + { + PositionHandler(scene, node); + return; + } + case ChatNodeEvent.UseItem: + { + UseItemHandler(scene, node); + return; + } + } + } + + private static void ClickLinkHandler(Scene scene, ChatInfoNode node) + { + if (node.Data == null || node.Data.Length == 0) + { + return; + } + + var chatLinkNode = scene.GetComponent().Deserialize(node.Data); + // 拿到这个之后,就可以为所欲为了。 + // 根据自己的逻辑和UI设计,做出相应的处理。 + Log.Debug($"ClickLinkHandler Link:{chatLinkNode.Link}"); + } + + private static void OpenUIHandler(Scene scene, ChatInfoNode node) + { + if (node.Data == null || node.Data.Length == 0) + { + return; + } + + var chatOpenUINode =scene.GetComponent().Deserialize(node.Data); + // 拿到这个之后,就可以为所欲为了。 + // 根据自己的逻辑和UI设计,做出相应的处理。 + Log.Debug($"OpenUIHandler UIName:{chatOpenUINode.UIName}"); + } + + private static void PositionHandler(Scene scene, ChatInfoNode node) + { + if (node.Data == null || node.Data.Length == 0) + { + return; + } + + var chatPositionNode =scene.GetComponent().Deserialize(node.Data); + // 拿到这个之后,就可以为所欲为了。 + // 根据自己的逻辑和UI设计,做出相应的处理。 + Log.Debug($"PositionHandler MapName:{chatPositionNode.MapName} X:{chatPositionNode.PosX} Y:{chatPositionNode.PosY} Z:{chatPositionNode.PosZ}"); + } + + private static void UseItemHandler(Scene scene, ChatInfoNode node) + { + // TODO: Implement UseItemHandler + } + } +} \ No newline at end of file diff --git a/聊天系统课程代码/Client/Unity/Assets/Scripts/Hotfix/Chat/ChatNodeEventHelper.cs.meta b/聊天系统课程代码/Client/Unity/Assets/Scripts/Hotfix/Chat/ChatNodeEventHelper.cs.meta new file mode 100644 index 0000000..8d0c403 --- /dev/null +++ b/聊天系统课程代码/Client/Unity/Assets/Scripts/Hotfix/Chat/ChatNodeEventHelper.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 17bb297b8f01b4b90a7f306acd81b672 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/聊天系统课程代码/Client/Unity/Assets/Scripts/Hotfix/Chat/ChatNodeFactory.cs b/聊天系统课程代码/Client/Unity/Assets/Scripts/Hotfix/Chat/ChatNodeFactory.cs new file mode 100644 index 0000000..a6197a1 --- /dev/null +++ b/聊天系统课程代码/Client/Unity/Assets/Scripts/Hotfix/Chat/ChatNodeFactory.cs @@ -0,0 +1,126 @@ +namespace Fantasy +{ + /// + /// 聊天信息节点 + /// + public static class ChatNodeFactory + { + /// + /// 添加文本节点 + /// + /// + /// + /// + public static ChatInfoTree AddendTextNode(this ChatInfoTree chatInfoTree, string content) + { + var chatInfoNode = new ChatInfoNode() + { + ChatNodeType = (int)ChatNodeType.Text, + Content = content + }; + chatInfoTree.Node.Add(chatInfoNode); + return chatInfoTree; + } + + /// + /// 添加链接节点 + /// + /// + /// + /// + /// + public static ChatInfoTree AddendLinkNode(this ChatInfoTree chatInfoTree, string content,string link) + { + var chatLinkNode = new ChatLinkNode() + { + Link = link + }; + var serializerComponent = chatInfoTree.Scene.GetComponent(); + var chatInfoNode = new ChatInfoNode() + { + ChatNodeType = (int)ChatNodeType.Link, + ChatNodeEvent = (int)ChatNodeEvent.ClickLink, + Content = content, + Data = serializerComponent.Serialize(chatLinkNode) + }; + chatInfoTree.Node.Add(chatInfoNode); + return chatInfoTree; + } + + /// + /// 添加图片节点 + /// + /// + /// + /// + public static ChatInfoTree AddendImageNode(this ChatInfoTree chatInfoTree, string content) + { + var chatInfoNode = new ChatInfoNode() + { + ChatNodeType = (int)ChatNodeType.Image, + Content = content + }; + chatInfoTree.Node.Add(chatInfoNode); + return chatInfoTree; + } + + /// + /// 添加打开UI节点 + /// + /// + /// + /// + /// + public static ChatInfoTree AddendOpenUINode(this ChatInfoTree chatInfoTree, string content,string uiName) + { + var chatOpenUINode = new ChatOpenUINode() + { + UIName = uiName + }; + var serializerComponent = chatInfoTree.Scene.GetComponent(); + var chatInfoNode = new ChatInfoNode() + { + ChatNodeType = (int)ChatNodeType.OpenUI, + ChatNodeEvent = (int)ChatNodeEvent.OpenUI, + Content = content, + Data = serializerComponent.Serialize(chatOpenUINode) + }; + chatInfoTree.Node.Add(chatInfoNode); + return chatInfoTree; + } + + /// + /// 添加位置节点 + /// + /// + /// + /// + /// + /// + /// + /// + public static ChatInfoTree AddendPositionNode(this ChatInfoTree chatInfoTree, string content, string mapName, + float mapX, float mapY, float mapZ) + { + var chatPositionNode = new ChatPositionNode() + { + MapName = mapName, + PosX = mapX, + PosY = mapY, + PosZ = mapZ, + }; + + var serializerComponent = chatInfoTree.Scene.GetComponent(); + var chatInfoNode = new ChatInfoNode() + { + ChatNodeType = (int)ChatNodeType.Position, + ChatNodeEvent = (int)ChatNodeEvent.Position, + Content = content, + Data = serializerComponent.Serialize(chatPositionNode) + }; + + chatInfoTree.Node.Add(chatInfoNode); + return chatInfoTree; + } + } +} \ No newline at end of file diff --git a/聊天系统课程代码/Client/Unity/Assets/Scripts/Hotfix/Chat/ChatNodeFactory.cs.meta b/聊天系统课程代码/Client/Unity/Assets/Scripts/Hotfix/Chat/ChatNodeFactory.cs.meta new file mode 100644 index 0000000..71e121a --- /dev/null +++ b/聊天系统课程代码/Client/Unity/Assets/Scripts/Hotfix/Chat/ChatNodeFactory.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 608005f1b93de4f9c965dd56e560e9c4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/聊天系统课程代码/Client/Unity/Assets/Scripts/Hotfix/Chat/ChatTreeFactory.cs b/聊天系统课程代码/Client/Unity/Assets/Scripts/Hotfix/Chat/ChatTreeFactory.cs new file mode 100644 index 0000000..8b06bfe --- /dev/null +++ b/聊天系统课程代码/Client/Unity/Assets/Scripts/Hotfix/Chat/ChatTreeFactory.cs @@ -0,0 +1,120 @@ +namespace Fantasy +{ + /// + /// 创建聊天树的总入口 + /// + public static class ChatTreeFactory + { + /// + /// 创建世界聊天树 + /// + /// + /// + public static ChatInfoTree World(Scene scene) + { + return new ChatInfoTree() + { + Scene = scene, + ChatChannelType = (int)ChatChannelType.World, + }; + } + + /// + /// 创建私聊聊天树 + /// + /// + /// + public static ChatInfoTree Private(Scene scene) + { + return new ChatInfoTree() + { + Scene = scene, + ChatChannelType = (int)ChatChannelType.Private, + }; + } + + /// + /// 创建系统聊天树 + /// + /// + /// + public static ChatInfoTree System(Scene scene) + { + return new ChatInfoTree() + { + Scene = scene, + ChatChannelType = (int)ChatChannelType.System, + }; + } + + /// + /// 创建公广播聊天树 + /// + /// + /// + public static ChatInfoTree Broadcast(Scene scene) + { + return new ChatInfoTree() + { + Scene = scene, + ChatChannelType = (int)ChatChannelType.Broadcast, + }; + } + + /// + /// 创建公告聊天树 + /// + /// + /// + public static ChatInfoTree Notice(Scene scene) + { + return new ChatInfoTree() + { + Scene = scene, + ChatChannelType = (int)ChatChannelType.Notice, + }; + } + + /// + /// 创建队伍聊天树 + /// + /// + /// + public static ChatInfoTree Team(Scene scene) + { + return new ChatInfoTree() + { + Scene = scene, + ChatChannelType = (int)ChatChannelType.Team, + }; + } + + /// + /// 创建附近人聊天树 + /// + /// + /// + public static ChatInfoTree Near(Scene scene) + { + return new ChatInfoTree() + { + Scene = scene, + ChatChannelType = (int)ChatChannelType.Near, + }; + } + + /// + /// 创建当前地图聊天树 + /// + /// + /// + public static ChatInfoTree CurrentMap(Scene scene) + { + return new ChatInfoTree() + { + Scene = scene, + ChatChannelType = (int)ChatChannelType.CurrentMap, + }; + } + } +} \ No newline at end of file diff --git a/聊天系统课程代码/Client/Unity/Assets/Scripts/Hotfix/Chat/ChatTreeFactory.cs.meta b/聊天系统课程代码/Client/Unity/Assets/Scripts/Hotfix/Chat/ChatTreeFactory.cs.meta new file mode 100644 index 0000000..c0aea31 --- /dev/null +++ b/聊天系统课程代码/Client/Unity/Assets/Scripts/Hotfix/Chat/ChatTreeFactory.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 13c4041549f6e405a985eea47dbf08b7 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/聊天系统课程代码/Client/Unity/Assets/Scripts/Hotfix/Generate.meta b/聊天系统课程代码/Client/Unity/Assets/Scripts/Hotfix/Generate.meta new file mode 100644 index 0000000..f467847 --- /dev/null +++ b/聊天系统课程代码/Client/Unity/Assets/Scripts/Hotfix/Generate.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 6edca5b81b75f4d49b42c024e919cb3b +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/聊天系统课程代码/Client/Unity/Assets/Scripts/Hotfix/Generate/NetworkProtocol.meta b/聊天系统课程代码/Client/Unity/Assets/Scripts/Hotfix/Generate/NetworkProtocol.meta new file mode 100644 index 0000000..2b8909a --- /dev/null +++ b/聊天系统课程代码/Client/Unity/Assets/Scripts/Hotfix/Generate/NetworkProtocol.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: c3689f1e79f954f2fbe17fbf98116bc7 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/聊天系统课程代码/Client/Unity/Assets/Scripts/Hotfix/Generate/NetworkProtocol/OuterMessage.cs b/聊天系统课程代码/Client/Unity/Assets/Scripts/Hotfix/Generate/NetworkProtocol/OuterMessage.cs new file mode 100644 index 0000000..8461131 --- /dev/null +++ b/聊天系统课程代码/Client/Unity/Assets/Scripts/Hotfix/Generate/NetworkProtocol/OuterMessage.cs @@ -0,0 +1,318 @@ +using ProtoBuf; + +using System.Collections.Generic; +using Fantasy; +using Fantasy.Network.Interface; +using Fantasy.Serialize; +#pragma warning disable CS8618 + +namespace Fantasy +{ + /// + /// 登录游戏 + /// + [ProtoContract] + public partial class C2G_LoginRequest : AMessage, IRequest, IProto + { + public static C2G_LoginRequest Create(Scene scene) + { + return scene.MessagePoolComponent.Rent(); + } + public override void Dispose() + { + UserName = default; +#if FANTASY_NET || FANTASY_UNITY + GetScene().MessagePoolComponent.Return(this); +#endif + } + [ProtoIgnore] + public G2C_LoginResponse ResponseType { get; set; } + public uint OpCode() { return OuterOpcode.C2G_LoginRequest; } + [ProtoMember(1)] + public string UserName { get; set; } + } + [ProtoContract] + public partial class G2C_LoginResponse : AMessage, IResponse, IProto + { + public static G2C_LoginResponse Create(Scene scene) + { + return scene.MessagePoolComponent.Rent(); + } + public override void Dispose() + { + ErrorCode = default; +#if FANTASY_NET || FANTASY_UNITY + GetScene().MessagePoolComponent.Return(this); +#endif + } + public uint OpCode() { return OuterOpcode.G2C_LoginResponse; } + [ProtoMember(1)] + public uint ErrorCode { get; set; } + } + /// + /// 退出游戏 + /// + [ProtoContract] + public partial class C2G_ExitRequest : AMessage, IRequest, IProto + { + public static C2G_ExitRequest Create(Scene scene) + { + return scene.MessagePoolComponent.Rent(); + } + public override void Dispose() + { +#if FANTASY_NET || FANTASY_UNITY + GetScene().MessagePoolComponent.Return(this); +#endif + } + [ProtoIgnore] + public G2C_ExitResponse ResponseType { get; set; } + public uint OpCode() { return OuterOpcode.C2G_ExitRequest; } + } + [ProtoContract] + public partial class G2C_ExitResponse : AMessage, IResponse, IProto + { + public static G2C_ExitResponse Create(Scene scene) + { + return scene.MessagePoolComponent.Rent(); + } + public override void Dispose() + { + ErrorCode = default; +#if FANTASY_NET || FANTASY_UNITY + GetScene().MessagePoolComponent.Return(this); +#endif + } + public uint OpCode() { return OuterOpcode.G2C_ExitResponse; } + [ProtoMember(1)] + public uint ErrorCode { get; set; } + } + /// + /// 发送一个聊天消息给Chat服务器,中间是经过Gate中转的 + /// + [ProtoContract] + public partial class C2Chat_SendMessageRequest : AMessage, ICustomRouteRequest, IProto + { + public static C2Chat_SendMessageRequest Create(Scene scene) + { + return scene.MessagePoolComponent.Rent(); + } + public override void Dispose() + { + ChatInfoTree = default; +#if FANTASY_NET || FANTASY_UNITY + GetScene().MessagePoolComponent.Return(this); +#endif + } + [ProtoIgnore] + public Chat2C_SendMessageResponse ResponseType { get; set; } + public uint OpCode() { return OuterOpcode.C2Chat_SendMessageRequest; } + [ProtoIgnore] + public int RouteType => Fantasy.RouteType.ChatRoute; + [ProtoMember(1)] + public ChatInfoTree ChatInfoTree { get; set; } + } + [ProtoContract] + public partial class Chat2C_SendMessageResponse : AMessage, ICustomRouteResponse, IProto + { + public static Chat2C_SendMessageResponse Create(Scene scene) + { + return scene.MessagePoolComponent.Rent(); + } + public override void Dispose() + { + ErrorCode = default; +#if FANTASY_NET || FANTASY_UNITY + GetScene().MessagePoolComponent.Return(this); +#endif + } + public uint OpCode() { return OuterOpcode.Chat2C_SendMessageResponse; } + [ProtoMember(1)] + public uint ErrorCode { get; set; } + } + [ProtoContract] + public partial class Chat2C_Message : AMessage, ICustomRouteMessage, IProto + { + public static Chat2C_Message Create(Scene scene) + { + return scene.MessagePoolComponent.Rent(); + } + public override void Dispose() + { + ChatInfoTree = default; +#if FANTASY_NET || FANTASY_UNITY + GetScene().MessagePoolComponent.Return(this); +#endif + } + public uint OpCode() { return OuterOpcode.Chat2C_Message; } + [ProtoIgnore] + public int RouteType => Fantasy.RouteType.ChatRoute; + [ProtoMember(1)] + public ChatInfoTree ChatInfoTree { get; set; } + } + /// + /// 聊天消息树 + /// + [ProtoContract] + public partial class ChatInfoTree : AMessage, IProto + { + public static ChatInfoTree Create(Scene scene) + { + return scene.MessagePoolComponent.Rent(); + } + public override void Dispose() + { + ChatChannelType = default; + ChatChannelId = default; + UnitId = default; + UserName = default; + Target.Clear(); + Node.Clear(); +#if FANTASY_NET || FANTASY_UNITY + GetScene().MessagePoolComponent.Return(this); +#endif + } + [ProtoMember(1)] + public int ChatChannelType { get; set; } + [ProtoMember(2)] + public long ChatChannelId { get; set; } + [ProtoMember(3)] + public long UnitId { get; set; } + [ProtoMember(4)] + public string UserName { get; set; } + [ProtoMember(5)] + public List Target = new List(); + [ProtoMember(6)] + public List Node = new List(); + } + /// + /// 聊天信息节点 + /// + [ProtoContract] + public partial class ChatInfoNode : AMessage, IProto + { + public static ChatInfoNode Create(Scene scene) + { + return scene.MessagePoolComponent.Rent(); + } + public override void Dispose() + { + ChatNodeType = default; + ChatNodeEvent = default; + Content = default; + Color = default; + Data = default; +#if FANTASY_NET || FANTASY_UNITY + GetScene().MessagePoolComponent.Return(this); +#endif + } + [ProtoMember(1)] + public int ChatNodeType { get; set; } + [ProtoMember(2)] + public int ChatNodeEvent { get; set; } + [ProtoMember(3)] + public string Content { get; set; } + [ProtoMember(4)] + public string Color { get; set; } + [ProtoMember(5)] + public byte[] Data { get; set; } + } + /// + /// 聊天位置信息节点 + /// + [ProtoContract] + public partial class ChatPositionNode : AMessage, IProto + { + public static ChatPositionNode Create(Scene scene) + { + return scene.MessagePoolComponent.Rent(); + } + public override void Dispose() + { + MapName = default; + PosX = default; + PosY = default; + PosZ = default; +#if FANTASY_NET || FANTASY_UNITY + GetScene().MessagePoolComponent.Return(this); +#endif + } + [ProtoMember(1)] + public string MapName { get; set; } + [ProtoMember(2)] + public float PosX { get; set; } + [ProtoMember(3)] + public float PosY { get; set; } + [ProtoMember(4)] + public float PosZ { get; set; } + } + /// + /// 聊天位置信息节点 + /// + [ProtoContract] + public partial class ChatOpenUINode : AMessage, IProto + { + public static ChatOpenUINode Create(Scene scene) + { + return scene.MessagePoolComponent.Rent(); + } + public override void Dispose() + { + UIName = default; +#if FANTASY_NET || FANTASY_UNITY + GetScene().MessagePoolComponent.Return(this); +#endif + } + [ProtoMember(1)] + public string UIName { get; set; } + } + /// + /// 聊天连接信息节点 + /// + [ProtoContract] + public partial class ChatLinkNode : AMessage, IProto + { + public static ChatLinkNode Create(Scene scene) + { + return scene.MessagePoolComponent.Rent(); + } + public override void Dispose() + { + Link = default; +#if FANTASY_NET || FANTASY_UNITY + GetScene().MessagePoolComponent.Return(this); +#endif + } + [ProtoMember(1)] + public string Link { get; set; } + } + /// + /// 装备信息实体 + /// + [ProtoContract] + public partial class Item : AMessage, IProto + { + public static Item Create(Scene scene) + { + return scene.MessagePoolComponent.Rent(); + } + public override void Dispose() + { + Level = default; + Name = default; + HP = default; + MP = default; +#if FANTASY_NET || FANTASY_UNITY + GetScene().MessagePoolComponent.Return(this); +#endif + } + [ProtoMember(1)] + public string Level { get; set; } + [ProtoMember(2)] + public string Name { get; set; } + [ProtoMember(3)] + public string HP { get; set; } + [ProtoMember(4)] + public string MP { get; set; } + } +} diff --git a/聊天系统课程代码/Client/Unity/Assets/Scripts/Hotfix/Generate/NetworkProtocol/OuterMessage.cs.meta b/聊天系统课程代码/Client/Unity/Assets/Scripts/Hotfix/Generate/NetworkProtocol/OuterMessage.cs.meta new file mode 100644 index 0000000..cfcace1 --- /dev/null +++ b/聊天系统课程代码/Client/Unity/Assets/Scripts/Hotfix/Generate/NetworkProtocol/OuterMessage.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d8b7e9d1d45c14f28ba2e43726bae843 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/聊天系统课程代码/Client/Unity/Assets/Scripts/Hotfix/Generate/NetworkProtocol/OuterOpcode.cs b/聊天系统课程代码/Client/Unity/Assets/Scripts/Hotfix/Generate/NetworkProtocol/OuterOpcode.cs new file mode 100644 index 0000000..5ea474b --- /dev/null +++ b/聊天系统课程代码/Client/Unity/Assets/Scripts/Hotfix/Generate/NetworkProtocol/OuterOpcode.cs @@ -0,0 +1,13 @@ +namespace Fantasy +{ + public static partial class OuterOpcode + { + public const uint C2G_LoginRequest = 268445457; + public const uint G2C_LoginResponse = 402663185; + public const uint C2G_ExitRequest = 268445458; + public const uint G2C_ExitResponse = 402663186; + public const uint C2Chat_SendMessageRequest = 2281711377; + public const uint Chat2C_SendMessageResponse = 2415929105; + public const uint Chat2C_Message = 2147493649; + } +} diff --git a/聊天系统课程代码/Client/Unity/Assets/Scripts/Hotfix/Generate/NetworkProtocol/OuterOpcode.cs.meta b/聊天系统课程代码/Client/Unity/Assets/Scripts/Hotfix/Generate/NetworkProtocol/OuterOpcode.cs.meta new file mode 100644 index 0000000..61c13e3 --- /dev/null +++ b/聊天系统课程代码/Client/Unity/Assets/Scripts/Hotfix/Generate/NetworkProtocol/OuterOpcode.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 99247fb17248243e591419cbf976f158 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/聊天系统课程代码/Client/Unity/Assets/Scripts/Hotfix/Generate/NetworkProtocol/RouteType.cs b/聊天系统课程代码/Client/Unity/Assets/Scripts/Hotfix/Generate/NetworkProtocol/RouteType.cs new file mode 100644 index 0000000..cdd0df0 --- /dev/null +++ b/聊天系统课程代码/Client/Unity/Assets/Scripts/Hotfix/Generate/NetworkProtocol/RouteType.cs @@ -0,0 +1,9 @@ +namespace Fantasy +{ + // Route协议定义(需要定义1000以上、因为1000以内的框架预留) + public static class RouteType + { + public const int GateRoute = 1001; // Gate + public const int ChatRoute = 1002; // Chat + } +} diff --git a/聊天系统课程代码/Client/Unity/Assets/Scripts/Hotfix/Generate/NetworkProtocol/RouteType.cs.meta b/聊天系统课程代码/Client/Unity/Assets/Scripts/Hotfix/Generate/NetworkProtocol/RouteType.cs.meta new file mode 100644 index 0000000..51c7db5 --- /dev/null +++ b/聊天系统课程代码/Client/Unity/Assets/Scripts/Hotfix/Generate/NetworkProtocol/RouteType.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c84127d566a0345b19311b3a293ab9cc +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/聊天系统课程代码/Client/Unity/Assets/Scripts/Hotfix/Handler.meta b/聊天系统课程代码/Client/Unity/Assets/Scripts/Hotfix/Handler.meta new file mode 100644 index 0000000..755ae6f --- /dev/null +++ b/聊天系统课程代码/Client/Unity/Assets/Scripts/Hotfix/Handler.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 330f024527274b83903606afd0c61e91 +timeCreated: 1730859225 \ No newline at end of file diff --git a/聊天系统课程代码/Client/Unity/Assets/Scripts/Hotfix/Handler/Chat2C_MessageHandler.cs b/聊天系统课程代码/Client/Unity/Assets/Scripts/Hotfix/Handler/Chat2C_MessageHandler.cs new file mode 100644 index 0000000..8231691 --- /dev/null +++ b/聊天系统课程代码/Client/Unity/Assets/Scripts/Hotfix/Handler/Chat2C_MessageHandler.cs @@ -0,0 +1,38 @@ +using System.Text; +using Fantasy.Async; +using Fantasy.Network; +using Fantasy.Network.Interface; + +namespace Fantasy +{ + public sealed class Chat2C_MessageHandler : Message + { + protected override async FTask Run(Session session, Chat2C_Message message) + { + ChatTreeParser.Parse(session.Scene,message.ChatInfoTree); + Log.Info("收到聊天信息:"); + await FTask.CompletedTask; + } + } + + public static class ChatTreeParser + { + public static void Parse(Scene scene, ChatInfoTree tree) + { + var entryComponent = scene.GetComponent(); + var sb = new StringBuilder(); + foreach (var chatInfoNode in tree.Node) + { + // 这里只是演示一下处理事件的效果,实际使用时,需要根据实际情况处理事件 + // 明显我现在这样做的方式不是对的,应该是自己拼接一个聊天信息,然后调用这个接口来处理事件 + entryComponent.Entry.ChatNodeEventButton.onClick.RemoveAllListeners(); + entryComponent.Entry.ChatNodeEventButton.onClick.AddListener(() => + { + ChatNodeEventHelper.Handler(scene, chatInfoNode); + }); + sb.Append(chatInfoNode.Content); + } + entryComponent.Entry.MessageText.text = sb.ToString(); + } + } +} \ No newline at end of file diff --git a/聊天系统课程代码/Client/Unity/Assets/Scripts/Hotfix/Handler/Chat2C_MessageHandler.cs.meta b/聊天系统课程代码/Client/Unity/Assets/Scripts/Hotfix/Handler/Chat2C_MessageHandler.cs.meta new file mode 100644 index 0000000..7ef0fe2 --- /dev/null +++ b/聊天系统课程代码/Client/Unity/Assets/Scripts/Hotfix/Handler/Chat2C_MessageHandler.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: afa90e99edd2f4388a789f81ed9a7b33 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/聊天系统课程代码/Client/Unity/Assets/Scripts/Hotfix/Share.meta b/聊天系统课程代码/Client/Unity/Assets/Scripts/Hotfix/Share.meta new file mode 100644 index 0000000..80839d9 --- /dev/null +++ b/聊天系统课程代码/Client/Unity/Assets/Scripts/Hotfix/Share.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: bec9e556fd6314d1c91b0c661e9ad9e0 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/聊天系统课程代码/Client/Unity/Assets/Scripts/Hotfix/Share/ChatNodeEventComponent.meta b/聊天系统课程代码/Client/Unity/Assets/Scripts/Hotfix/Share/ChatNodeEventComponent.meta new file mode 100644 index 0000000..c1827f6 --- /dev/null +++ b/聊天系统课程代码/Client/Unity/Assets/Scripts/Hotfix/Share/ChatNodeEventComponent.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 08d331f22f1e247d59c27aacbd722f8d +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/聊天系统课程代码/Client/Unity/Assets/Scripts/Hotfix/Share/Entity.meta b/聊天系统课程代码/Client/Unity/Assets/Scripts/Hotfix/Share/Entity.meta new file mode 100644 index 0000000..76cd1d6 --- /dev/null +++ b/聊天系统课程代码/Client/Unity/Assets/Scripts/Hotfix/Share/Entity.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 78bb35e99848447fa8ac1ffee50625db +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/聊天系统课程代码/Client/Unity/Assets/Scripts/Hotfix/Share/Entity/SerializerComponent.cs b/聊天系统课程代码/Client/Unity/Assets/Scripts/Hotfix/Share/Entity/SerializerComponent.cs new file mode 100644 index 0000000..0f3ebf3 --- /dev/null +++ b/聊天系统课程代码/Client/Unity/Assets/Scripts/Hotfix/Share/Entity/SerializerComponent.cs @@ -0,0 +1,12 @@ +using Fantasy.Entitas; +using Fantasy.Network; +using Fantasy.Serialize; + +namespace Fantasy +{ + public class SerializerComponent : Entity + { + public ISerialize Serialize; + public readonly MemoryStreamBufferPool BufferPool = new MemoryStreamBufferPool(); + } +} \ No newline at end of file diff --git a/聊天系统课程代码/Client/Unity/Assets/Scripts/Hotfix/Share/Entity/SerializerComponent.cs.meta b/聊天系统课程代码/Client/Unity/Assets/Scripts/Hotfix/Share/Entity/SerializerComponent.cs.meta new file mode 100644 index 0000000..398b200 --- /dev/null +++ b/聊天系统课程代码/Client/Unity/Assets/Scripts/Hotfix/Share/Entity/SerializerComponent.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a4d1516b4175743438426bd6554bf1e1 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/聊天系统课程代码/Client/Unity/Assets/Scripts/Hotfix/Share/System.meta b/聊天系统课程代码/Client/Unity/Assets/Scripts/Hotfix/Share/System.meta new file mode 100644 index 0000000..f4dd8b7 --- /dev/null +++ b/聊天系统课程代码/Client/Unity/Assets/Scripts/Hotfix/Share/System.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b82fed53e9e2c4773a399408912da4c6 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/聊天系统课程代码/Client/Unity/Assets/Scripts/Hotfix/Share/System/SerializerComponentSystem.cs b/聊天系统课程代码/Client/Unity/Assets/Scripts/Hotfix/Share/System/SerializerComponentSystem.cs new file mode 100644 index 0000000..da63a06 --- /dev/null +++ b/聊天系统课程代码/Client/Unity/Assets/Scripts/Hotfix/Share/System/SerializerComponentSystem.cs @@ -0,0 +1,24 @@ +using Fantasy.Serialize; + +namespace Fantasy +{ + public static class SerializerComponentSystem + { + public static void Initialize(this SerializerComponent self) + { + self.Serialize = SerializerManager.GetSerializer(FantasySerializerType.ProtoBuf); + } + + public static byte[] Serialize(this SerializerComponent self, T @object) + { + using var memoryStreamBuffer = self.BufferPool.RentMemoryStream(MemoryStreamBufferSource.None); + self.Serialize.Serialize(typeof(T), @object, memoryStreamBuffer); + return memoryStreamBuffer.ToArray(); + } + + public static T Deserialize(this SerializerComponent self, byte[] bytes) + { + return self.Serialize.Deserialize(bytes); + } + } +} \ No newline at end of file diff --git a/聊天系统课程代码/Client/Unity/Assets/Scripts/Hotfix/Share/System/SerializerComponentSystem.cs.meta b/聊天系统课程代码/Client/Unity/Assets/Scripts/Hotfix/Share/System/SerializerComponentSystem.cs.meta new file mode 100644 index 0000000..e40c5a8 --- /dev/null +++ b/聊天系统课程代码/Client/Unity/Assets/Scripts/Hotfix/Share/System/SerializerComponentSystem.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8608556722ae54798affab26b57a36d1 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/聊天系统课程代码/Client/Unity/Packages/manifest.json b/聊天系统课程代码/Client/Unity/Packages/manifest.json new file mode 100644 index 0000000..8c3e753 --- /dev/null +++ b/聊天系统课程代码/Client/Unity/Packages/manifest.json @@ -0,0 +1,42 @@ +{ + "dependencies": { + "com.fantasy.unity": "https://gitee.com/Sining/Fantasy.Unity.git", + "com.unity.collab-proxy": "2.5.2", + "com.unity.feature.development": "1.0.1", + "com.unity.textmeshpro": "3.0.7", + "com.unity.timeline": "1.7.6", + "com.unity.ugui": "1.0.0", + "com.unity.visualscripting": "1.9.4", + "com.unity.modules.ai": "1.0.0", + "com.unity.modules.androidjni": "1.0.0", + "com.unity.modules.animation": "1.0.0", + "com.unity.modules.assetbundle": "1.0.0", + "com.unity.modules.audio": "1.0.0", + "com.unity.modules.cloth": "1.0.0", + "com.unity.modules.director": "1.0.0", + "com.unity.modules.imageconversion": "1.0.0", + "com.unity.modules.imgui": "1.0.0", + "com.unity.modules.jsonserialize": "1.0.0", + "com.unity.modules.particlesystem": "1.0.0", + "com.unity.modules.physics": "1.0.0", + "com.unity.modules.physics2d": "1.0.0", + "com.unity.modules.screencapture": "1.0.0", + "com.unity.modules.terrain": "1.0.0", + "com.unity.modules.terrainphysics": "1.0.0", + "com.unity.modules.tilemap": "1.0.0", + "com.unity.modules.ui": "1.0.0", + "com.unity.modules.uielements": "1.0.0", + "com.unity.modules.umbra": "1.0.0", + "com.unity.modules.unityanalytics": "1.0.0", + "com.unity.modules.unitywebrequest": "1.0.0", + "com.unity.modules.unitywebrequestassetbundle": "1.0.0", + "com.unity.modules.unitywebrequestaudio": "1.0.0", + "com.unity.modules.unitywebrequesttexture": "1.0.0", + "com.unity.modules.unitywebrequestwww": "1.0.0", + "com.unity.modules.vehicles": "1.0.0", + "com.unity.modules.video": "1.0.0", + "com.unity.modules.vr": "1.0.0", + "com.unity.modules.wind": "1.0.0", + "com.unity.modules.xr": "1.0.0" + } +} diff --git a/聊天系统课程代码/Client/Unity/Packages/packages-lock.json b/聊天系统课程代码/Client/Unity/Packages/packages-lock.json new file mode 100644 index 0000000..000b14f --- /dev/null +++ b/聊天系统课程代码/Client/Unity/Packages/packages-lock.json @@ -0,0 +1,398 @@ +{ + "dependencies": { + "com.fantasy.unity": { + "version": "https://gitee.com/Sining/Fantasy.Unity.git", + "depth": 0, + "source": "git", + "dependencies": { + "com.unity.nuget.newtonsoft-json": "3.2.1" + }, + "hash": "2316347ec602e2743978dc19bdc83e887c299d90" + }, + "com.unity.collab-proxy": { + "version": "2.5.2", + "depth": 0, + "source": "registry", + "dependencies": {}, + "url": "https://packages.unity.com" + }, + "com.unity.editorcoroutines": { + "version": "1.0.0", + "depth": 1, + "source": "registry", + "dependencies": {}, + "url": "https://packages.unity.com" + }, + "com.unity.ext.nunit": { + "version": "1.0.6", + "depth": 2, + "source": "registry", + "dependencies": {}, + "url": "https://packages.unity.com" + }, + "com.unity.feature.development": { + "version": "1.0.1", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.ide.visualstudio": "2.0.22", + "com.unity.ide.rider": "3.0.31", + "com.unity.ide.vscode": "1.2.5", + "com.unity.editorcoroutines": "1.0.0", + "com.unity.performance.profile-analyzer": "1.2.2", + "com.unity.test-framework": "1.1.33", + "com.unity.testtools.codecoverage": "1.2.6" + } + }, + "com.unity.ide.rider": { + "version": "3.0.31", + "depth": 1, + "source": "registry", + "dependencies": { + "com.unity.ext.nunit": "1.0.6" + }, + "url": "https://packages.unity.com" + }, + "com.unity.ide.visualstudio": { + "version": "2.0.22", + "depth": 1, + "source": "registry", + "dependencies": { + "com.unity.test-framework": "1.1.9" + }, + "url": "https://packages.unity.com" + }, + "com.unity.ide.vscode": { + "version": "1.2.5", + "depth": 1, + "source": "registry", + "dependencies": {}, + "url": "https://packages.unity.com" + }, + "com.unity.nuget.newtonsoft-json": { + "version": "3.2.1", + "depth": 1, + "source": "registry", + "dependencies": {}, + "url": "https://packages.unity.com" + }, + "com.unity.performance.profile-analyzer": { + "version": "1.2.2", + "depth": 1, + "source": "registry", + "dependencies": {}, + "url": "https://packages.unity.com" + }, + "com.unity.settings-manager": { + "version": "2.0.1", + "depth": 2, + "source": "registry", + "dependencies": {}, + "url": "https://packages.unity.com" + }, + "com.unity.test-framework": { + "version": "1.1.33", + "depth": 1, + "source": "registry", + "dependencies": { + "com.unity.ext.nunit": "1.0.6", + "com.unity.modules.imgui": "1.0.0", + "com.unity.modules.jsonserialize": "1.0.0" + }, + "url": "https://packages.unity.com" + }, + "com.unity.testtools.codecoverage": { + "version": "1.2.6", + "depth": 1, + "source": "registry", + "dependencies": { + "com.unity.test-framework": "1.0.16", + "com.unity.settings-manager": "1.0.1" + }, + "url": "https://packages.unity.com" + }, + "com.unity.textmeshpro": { + "version": "3.0.7", + "depth": 0, + "source": "registry", + "dependencies": { + "com.unity.ugui": "1.0.0" + }, + "url": "https://packages.unity.com" + }, + "com.unity.timeline": { + "version": "1.7.6", + "depth": 0, + "source": "registry", + "dependencies": { + "com.unity.modules.audio": "1.0.0", + "com.unity.modules.director": "1.0.0", + "com.unity.modules.animation": "1.0.0", + "com.unity.modules.particlesystem": "1.0.0" + }, + "url": "https://packages.unity.com" + }, + "com.unity.ugui": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.ui": "1.0.0", + "com.unity.modules.imgui": "1.0.0" + } + }, + "com.unity.visualscripting": { + "version": "1.9.4", + "depth": 0, + "source": "registry", + "dependencies": { + "com.unity.ugui": "1.0.0", + "com.unity.modules.jsonserialize": "1.0.0" + }, + "url": "https://packages.unity.com" + }, + "com.unity.modules.ai": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.androidjni": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.animation": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.assetbundle": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.audio": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.cloth": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.physics": "1.0.0" + } + }, + "com.unity.modules.director": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.audio": "1.0.0", + "com.unity.modules.animation": "1.0.0" + } + }, + "com.unity.modules.imageconversion": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.imgui": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.jsonserialize": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.particlesystem": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.physics": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.physics2d": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.screencapture": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.imageconversion": "1.0.0" + } + }, + "com.unity.modules.subsystems": { + "version": "1.0.0", + "depth": 1, + "source": "builtin", + "dependencies": { + "com.unity.modules.jsonserialize": "1.0.0" + } + }, + "com.unity.modules.terrain": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.terrainphysics": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.physics": "1.0.0", + "com.unity.modules.terrain": "1.0.0" + } + }, + "com.unity.modules.tilemap": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.physics2d": "1.0.0" + } + }, + "com.unity.modules.ui": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.uielements": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.ui": "1.0.0", + "com.unity.modules.imgui": "1.0.0", + "com.unity.modules.jsonserialize": "1.0.0" + } + }, + "com.unity.modules.umbra": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.unityanalytics": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.unitywebrequest": "1.0.0", + "com.unity.modules.jsonserialize": "1.0.0" + } + }, + "com.unity.modules.unitywebrequest": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.unitywebrequestassetbundle": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.assetbundle": "1.0.0", + "com.unity.modules.unitywebrequest": "1.0.0" + } + }, + "com.unity.modules.unitywebrequestaudio": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.unitywebrequest": "1.0.0", + "com.unity.modules.audio": "1.0.0" + } + }, + "com.unity.modules.unitywebrequesttexture": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.unitywebrequest": "1.0.0", + "com.unity.modules.imageconversion": "1.0.0" + } + }, + "com.unity.modules.unitywebrequestwww": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.unitywebrequest": "1.0.0", + "com.unity.modules.unitywebrequestassetbundle": "1.0.0", + "com.unity.modules.unitywebrequestaudio": "1.0.0", + "com.unity.modules.audio": "1.0.0", + "com.unity.modules.assetbundle": "1.0.0", + "com.unity.modules.imageconversion": "1.0.0" + } + }, + "com.unity.modules.vehicles": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.physics": "1.0.0" + } + }, + "com.unity.modules.video": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.audio": "1.0.0", + "com.unity.modules.ui": "1.0.0", + "com.unity.modules.unitywebrequest": "1.0.0" + } + }, + "com.unity.modules.vr": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.jsonserialize": "1.0.0", + "com.unity.modules.physics": "1.0.0", + "com.unity.modules.xr": "1.0.0" + } + }, + "com.unity.modules.wind": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.xr": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.physics": "1.0.0", + "com.unity.modules.jsonserialize": "1.0.0", + "com.unity.modules.subsystems": "1.0.0" + } + } + } +} diff --git a/聊天系统课程代码/Client/Unity/ProjectSettings/AudioManager.asset b/聊天系统课程代码/Client/Unity/ProjectSettings/AudioManager.asset new file mode 100644 index 0000000..07ebfb0 --- /dev/null +++ b/聊天系统课程代码/Client/Unity/ProjectSettings/AudioManager.asset @@ -0,0 +1,19 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!11 &1 +AudioManager: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Volume: 1 + Rolloff Scale: 1 + Doppler Factor: 1 + Default Speaker Mode: 2 + m_SampleRate: 0 + m_DSPBufferSize: 1024 + m_VirtualVoiceCount: 512 + m_RealVoiceCount: 32 + m_SpatializerPlugin: + m_AmbisonicDecoderPlugin: + m_DisableAudio: 0 + m_VirtualizeEffects: 1 + m_RequestedDSPBufferSize: 1024 diff --git a/聊天系统课程代码/Client/Unity/ProjectSettings/ClusterInputManager.asset b/聊天系统课程代码/Client/Unity/ProjectSettings/ClusterInputManager.asset new file mode 100644 index 0000000..e7886b2 --- /dev/null +++ b/聊天系统课程代码/Client/Unity/ProjectSettings/ClusterInputManager.asset @@ -0,0 +1,6 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!236 &1 +ClusterInputManager: + m_ObjectHideFlags: 0 + m_Inputs: [] diff --git a/聊天系统课程代码/Client/Unity/ProjectSettings/DynamicsManager.asset b/聊天系统课程代码/Client/Unity/ProjectSettings/DynamicsManager.asset new file mode 100644 index 0000000..cdc1f3e --- /dev/null +++ b/聊天系统课程代码/Client/Unity/ProjectSettings/DynamicsManager.asset @@ -0,0 +1,34 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!55 &1 +PhysicsManager: + m_ObjectHideFlags: 0 + serializedVersion: 11 + m_Gravity: {x: 0, y: -9.81, z: 0} + m_DefaultMaterial: {fileID: 0} + m_BounceThreshold: 2 + m_SleepThreshold: 0.005 + m_DefaultContactOffset: 0.01 + m_DefaultSolverIterations: 6 + m_DefaultSolverVelocityIterations: 1 + m_QueriesHitBackfaces: 0 + m_QueriesHitTriggers: 1 + m_EnableAdaptiveForce: 0 + m_ClothInterCollisionDistance: 0 + m_ClothInterCollisionStiffness: 0 + m_ContactsGeneration: 1 + m_LayerCollisionMatrix: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff + m_AutoSimulation: 1 + m_AutoSyncTransforms: 0 + m_ReuseCollisionCallbacks: 1 + m_ClothInterCollisionSettingsToggle: 0 + m_ContactPairsMode: 0 + m_BroadphaseType: 0 + m_WorldBounds: + m_Center: {x: 0, y: 0, z: 0} + m_Extent: {x: 250, y: 250, z: 250} + m_WorldSubdivisions: 8 + m_FrictionType: 0 + m_EnableEnhancedDeterminism: 0 + m_EnableUnifiedHeightmaps: 1 + m_DefaultMaxAngluarSpeed: 7 diff --git a/聊天系统课程代码/Client/Unity/ProjectSettings/EditorBuildSettings.asset b/聊天系统课程代码/Client/Unity/ProjectSettings/EditorBuildSettings.asset new file mode 100644 index 0000000..40917b0 --- /dev/null +++ b/聊天系统课程代码/Client/Unity/ProjectSettings/EditorBuildSettings.asset @@ -0,0 +1,11 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1045 &1 +EditorBuildSettings: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Scenes: + - enabled: 1 + path: Assets/Scenes/SampleScene.unity + guid: 9fc0d4010bbf28b4594072e72b8655ab + m_configObjects: {} diff --git a/聊天系统课程代码/Client/Unity/ProjectSettings/EditorSettings.asset b/聊天系统课程代码/Client/Unity/ProjectSettings/EditorSettings.asset new file mode 100644 index 0000000..1e44a0a --- /dev/null +++ b/聊天系统课程代码/Client/Unity/ProjectSettings/EditorSettings.asset @@ -0,0 +1,30 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!159 &1 +EditorSettings: + m_ObjectHideFlags: 0 + serializedVersion: 11 + m_ExternalVersionControlSupport: Visible Meta Files + m_SerializationMode: 2 + m_LineEndingsForNewScripts: 0 + m_DefaultBehaviorMode: 0 + m_PrefabRegularEnvironment: {fileID: 0} + m_PrefabUIEnvironment: {fileID: 0} + m_SpritePackerMode: 0 + m_SpritePackerPaddingPower: 1 + m_EtcTextureCompressorBehavior: 1 + m_EtcTextureFastCompressor: 1 + m_EtcTextureNormalCompressor: 2 + m_EtcTextureBestCompressor: 4 + m_ProjectGenerationIncludedExtensions: txt;xml;fnt;cd;asmdef;rsp;asmref + m_ProjectGenerationRootNamespace: + m_CollabEditorSettings: + inProgressEnabled: 1 + m_EnableTextureStreamingInEditMode: 1 + m_EnableTextureStreamingInPlayMode: 1 + m_AsyncShaderCompilation: 1 + m_EnterPlayModeOptionsEnabled: 0 + m_EnterPlayModeOptions: 3 + m_ShowLightmapResolutionOverlay: 1 + m_UseLegacyProbeSampleCount: 0 + m_SerializeInlineMappingsOnOneLine: 1 diff --git a/聊天系统课程代码/Client/Unity/ProjectSettings/FantasySettings.asset b/聊天系统课程代码/Client/Unity/ProjectSettings/FantasySettings.asset new file mode 100644 index 0000000..1942c66 --- /dev/null +++ b/聊天系统课程代码/Client/Unity/ProjectSettings/FantasySettings.asset @@ -0,0 +1,18 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &1 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 27a37e930ca3454fb57bc895f50d2106, type: 3} + m_Name: + m_EditorClassIdentifier: + autoCopyAssembly: 0 + hotUpdatePath: + hotUpdateAssemblyDefinitions: [] + linkAssemblyDefinitions: [] diff --git a/聊天系统课程代码/Client/Unity/ProjectSettings/GraphicsSettings.asset b/聊天系统课程代码/Client/Unity/ProjectSettings/GraphicsSettings.asset new file mode 100644 index 0000000..43369e3 --- /dev/null +++ b/聊天系统课程代码/Client/Unity/ProjectSettings/GraphicsSettings.asset @@ -0,0 +1,63 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!30 &1 +GraphicsSettings: + m_ObjectHideFlags: 0 + serializedVersion: 13 + m_Deferred: + m_Mode: 1 + m_Shader: {fileID: 69, guid: 0000000000000000f000000000000000, type: 0} + m_DeferredReflections: + m_Mode: 1 + m_Shader: {fileID: 74, guid: 0000000000000000f000000000000000, type: 0} + m_ScreenSpaceShadows: + m_Mode: 1 + m_Shader: {fileID: 64, guid: 0000000000000000f000000000000000, type: 0} + m_LegacyDeferred: + m_Mode: 1 + m_Shader: {fileID: 63, guid: 0000000000000000f000000000000000, type: 0} + m_DepthNormals: + m_Mode: 1 + m_Shader: {fileID: 62, guid: 0000000000000000f000000000000000, type: 0} + m_MotionVectors: + m_Mode: 1 + m_Shader: {fileID: 75, guid: 0000000000000000f000000000000000, type: 0} + m_LightHalo: + m_Mode: 1 + m_Shader: {fileID: 105, guid: 0000000000000000f000000000000000, type: 0} + m_LensFlare: + m_Mode: 1 + m_Shader: {fileID: 102, guid: 0000000000000000f000000000000000, type: 0} + m_AlwaysIncludedShaders: + - {fileID: 7, guid: 0000000000000000f000000000000000, type: 0} + - {fileID: 15104, guid: 0000000000000000f000000000000000, type: 0} + - {fileID: 15105, guid: 0000000000000000f000000000000000, type: 0} + - {fileID: 15106, guid: 0000000000000000f000000000000000, type: 0} + - {fileID: 10753, guid: 0000000000000000f000000000000000, type: 0} + - {fileID: 10770, guid: 0000000000000000f000000000000000, type: 0} + m_PreloadedShaders: [] + m_SpritesDefaultMaterial: {fileID: 10754, guid: 0000000000000000f000000000000000, + type: 0} + m_CustomRenderPipeline: {fileID: 0} + m_TransparencySortMode: 0 + m_TransparencySortAxis: {x: 0, y: 0, z: 1} + m_DefaultRenderingPath: 1 + m_DefaultMobileRenderingPath: 1 + m_TierSettings: [] + m_LightmapStripping: 0 + m_FogStripping: 0 + m_InstancingStripping: 0 + m_LightmapKeepPlain: 1 + m_LightmapKeepDirCombined: 1 + m_LightmapKeepDynamicPlain: 1 + m_LightmapKeepDynamicDirCombined: 1 + m_LightmapKeepShadowMask: 1 + m_LightmapKeepSubtractive: 1 + m_FogKeepLinear: 1 + m_FogKeepExp: 1 + m_FogKeepExp2: 1 + m_AlbedoSwatchInfos: [] + m_LightsUseLinearIntensity: 0 + m_LightsUseColorTemperature: 0 + m_LogWhenShaderIsCompiled: 0 + m_AllowEnlightenSupportForUpgradedProject: 0 diff --git a/聊天系统课程代码/Client/Unity/ProjectSettings/InputManager.asset b/聊天系统课程代码/Client/Unity/ProjectSettings/InputManager.asset new file mode 100644 index 0000000..17c8f53 --- /dev/null +++ b/聊天系统课程代码/Client/Unity/ProjectSettings/InputManager.asset @@ -0,0 +1,295 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!13 &1 +InputManager: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Axes: + - serializedVersion: 3 + m_Name: Horizontal + descriptiveName: + descriptiveNegativeName: + negativeButton: left + positiveButton: right + altNegativeButton: a + altPositiveButton: d + gravity: 3 + dead: 0.001 + sensitivity: 3 + snap: 1 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Vertical + descriptiveName: + descriptiveNegativeName: + negativeButton: down + positiveButton: up + altNegativeButton: s + altPositiveButton: w + gravity: 3 + dead: 0.001 + sensitivity: 3 + snap: 1 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Fire1 + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: left ctrl + altNegativeButton: + altPositiveButton: mouse 0 + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Fire2 + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: left alt + altNegativeButton: + altPositiveButton: mouse 1 + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Fire3 + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: left shift + altNegativeButton: + altPositiveButton: mouse 2 + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Jump + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: space + altNegativeButton: + altPositiveButton: + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Mouse X + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: + altNegativeButton: + altPositiveButton: + gravity: 0 + dead: 0 + sensitivity: 0.1 + snap: 0 + invert: 0 + type: 1 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Mouse Y + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: + altNegativeButton: + altPositiveButton: + gravity: 0 + dead: 0 + sensitivity: 0.1 + snap: 0 + invert: 0 + type: 1 + axis: 1 + joyNum: 0 + - serializedVersion: 3 + m_Name: Mouse ScrollWheel + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: + altNegativeButton: + altPositiveButton: + gravity: 0 + dead: 0 + sensitivity: 0.1 + snap: 0 + invert: 0 + type: 1 + axis: 2 + joyNum: 0 + - serializedVersion: 3 + m_Name: Horizontal + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: + altNegativeButton: + altPositiveButton: + gravity: 0 + dead: 0.19 + sensitivity: 1 + snap: 0 + invert: 0 + type: 2 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Vertical + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: + altNegativeButton: + altPositiveButton: + gravity: 0 + dead: 0.19 + sensitivity: 1 + snap: 0 + invert: 1 + type: 2 + axis: 1 + joyNum: 0 + - serializedVersion: 3 + m_Name: Fire1 + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: joystick button 0 + altNegativeButton: + altPositiveButton: + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Fire2 + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: joystick button 1 + altNegativeButton: + altPositiveButton: + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Fire3 + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: joystick button 2 + altNegativeButton: + altPositiveButton: + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Jump + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: joystick button 3 + altNegativeButton: + altPositiveButton: + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Submit + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: return + altNegativeButton: + altPositiveButton: joystick button 0 + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Submit + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: enter + altNegativeButton: + altPositiveButton: space + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Cancel + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: escape + altNegativeButton: + altPositiveButton: joystick button 1 + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 diff --git a/聊天系统课程代码/Client/Unity/ProjectSettings/MemorySettings.asset b/聊天系统课程代码/Client/Unity/ProjectSettings/MemorySettings.asset new file mode 100644 index 0000000..5b5face --- /dev/null +++ b/聊天系统课程代码/Client/Unity/ProjectSettings/MemorySettings.asset @@ -0,0 +1,35 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!387306366 &1 +MemorySettings: + m_ObjectHideFlags: 0 + m_EditorMemorySettings: + m_MainAllocatorBlockSize: -1 + m_ThreadAllocatorBlockSize: -1 + m_MainGfxBlockSize: -1 + m_ThreadGfxBlockSize: -1 + m_CacheBlockSize: -1 + m_TypetreeBlockSize: -1 + m_ProfilerBlockSize: -1 + m_ProfilerEditorBlockSize: -1 + m_BucketAllocatorGranularity: -1 + m_BucketAllocatorBucketsCount: -1 + m_BucketAllocatorBlockSize: -1 + m_BucketAllocatorBlockCount: -1 + m_ProfilerBucketAllocatorGranularity: -1 + m_ProfilerBucketAllocatorBucketsCount: -1 + m_ProfilerBucketAllocatorBlockSize: -1 + m_ProfilerBucketAllocatorBlockCount: -1 + m_TempAllocatorSizeMain: -1 + m_JobTempAllocatorBlockSize: -1 + m_BackgroundJobTempAllocatorBlockSize: -1 + m_JobTempAllocatorReducedBlockSize: -1 + m_TempAllocatorSizeGIBakingWorker: -1 + m_TempAllocatorSizeNavMeshWorker: -1 + m_TempAllocatorSizeAudioWorker: -1 + m_TempAllocatorSizeCloudWorker: -1 + m_TempAllocatorSizeGfx: -1 + m_TempAllocatorSizeJobWorker: -1 + m_TempAllocatorSizeBackgroundWorker: -1 + m_TempAllocatorSizePreloadManager: -1 + m_PlatformMemorySettings: {} diff --git a/聊天系统课程代码/Client/Unity/ProjectSettings/NavMeshAreas.asset b/聊天系统课程代码/Client/Unity/ProjectSettings/NavMeshAreas.asset new file mode 100644 index 0000000..3b0b7c3 --- /dev/null +++ b/聊天系统课程代码/Client/Unity/ProjectSettings/NavMeshAreas.asset @@ -0,0 +1,91 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!126 &1 +NavMeshProjectSettings: + m_ObjectHideFlags: 0 + serializedVersion: 2 + areas: + - name: Walkable + cost: 1 + - name: Not Walkable + cost: 1 + - name: Jump + cost: 2 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + m_LastAgentTypeID: -887442657 + m_Settings: + - serializedVersion: 2 + agentTypeID: 0 + agentRadius: 0.5 + agentHeight: 2 + agentSlope: 45 + agentClimb: 0.75 + ledgeDropHeight: 0 + maxJumpAcrossDistance: 0 + minRegionArea: 2 + manualCellSize: 0 + cellSize: 0.16666667 + manualTileSize: 0 + tileSize: 256 + accuratePlacement: 0 + debug: + m_Flags: 0 + m_SettingNames: + - Humanoid diff --git a/聊天系统课程代码/Client/Unity/ProjectSettings/PackageManagerSettings.asset b/聊天系统课程代码/Client/Unity/ProjectSettings/PackageManagerSettings.asset new file mode 100644 index 0000000..112a053 --- /dev/null +++ b/聊天系统课程代码/Client/Unity/ProjectSettings/PackageManagerSettings.asset @@ -0,0 +1,35 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &1 +MonoBehaviour: + m_ObjectHideFlags: 61 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 13964, guid: 0000000000000000e000000000000000, type: 0} + m_Name: + m_EditorClassIdentifier: + m_EnablePreReleasePackages: 0 + m_EnablePackageDependencies: 0 + m_AdvancedSettingsExpanded: 1 + m_ScopedRegistriesSettingsExpanded: 1 + m_SeeAllPackageVersions: 0 + oneTimeWarningShown: 0 + m_Registries: + - m_Id: main + m_Name: + m_Url: https://packages.unity.com + m_Scopes: [] + m_IsDefault: 1 + m_Capabilities: 7 + m_UserSelectedRegistryName: + m_UserAddingNewScopedRegistry: 0 + m_RegistryInfoDraft: + m_Modified: 0 + m_ErrorMessage: + m_UserModificationsInstanceId: -830 + m_OriginalInstanceId: -832 + m_LoadAssets: 0 diff --git a/聊天系统课程代码/Client/Unity/ProjectSettings/Packages/com.unity.testtools.codecoverage/Settings.json b/聊天系统课程代码/Client/Unity/ProjectSettings/Packages/com.unity.testtools.codecoverage/Settings.json new file mode 100644 index 0000000..3c7b4c1 --- /dev/null +++ b/聊天系统课程代码/Client/Unity/ProjectSettings/Packages/com.unity.testtools.codecoverage/Settings.json @@ -0,0 +1,5 @@ +{ + "m_Dictionary": { + "m_DictionaryValues": [] + } +} \ No newline at end of file diff --git a/聊天系统课程代码/Client/Unity/ProjectSettings/Physics2DSettings.asset b/聊天系统课程代码/Client/Unity/ProjectSettings/Physics2DSettings.asset new file mode 100644 index 0000000..47880b1 --- /dev/null +++ b/聊天系统课程代码/Client/Unity/ProjectSettings/Physics2DSettings.asset @@ -0,0 +1,56 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!19 &1 +Physics2DSettings: + m_ObjectHideFlags: 0 + serializedVersion: 4 + m_Gravity: {x: 0, y: -9.81} + m_DefaultMaterial: {fileID: 0} + m_VelocityIterations: 8 + m_PositionIterations: 3 + m_VelocityThreshold: 1 + m_MaxLinearCorrection: 0.2 + m_MaxAngularCorrection: 8 + m_MaxTranslationSpeed: 100 + m_MaxRotationSpeed: 360 + m_BaumgarteScale: 0.2 + m_BaumgarteTimeOfImpactScale: 0.75 + m_TimeToSleep: 0.5 + m_LinearSleepTolerance: 0.01 + m_AngularSleepTolerance: 2 + m_DefaultContactOffset: 0.01 + m_JobOptions: + serializedVersion: 2 + useMultithreading: 0 + useConsistencySorting: 0 + m_InterpolationPosesPerJob: 100 + m_NewContactsPerJob: 30 + m_CollideContactsPerJob: 100 + m_ClearFlagsPerJob: 200 + m_ClearBodyForcesPerJob: 200 + m_SyncDiscreteFixturesPerJob: 50 + m_SyncContinuousFixturesPerJob: 50 + m_FindNearestContactsPerJob: 100 + m_UpdateTriggerContactsPerJob: 100 + m_IslandSolverCostThreshold: 100 + m_IslandSolverBodyCostScale: 1 + m_IslandSolverContactCostScale: 10 + m_IslandSolverJointCostScale: 10 + m_IslandSolverBodiesPerJob: 50 + m_IslandSolverContactsPerJob: 50 + m_AutoSimulation: 1 + m_QueriesHitTriggers: 1 + m_QueriesStartInColliders: 1 + m_CallbacksOnDisable: 1 + m_ReuseCollisionCallbacks: 1 + m_AutoSyncTransforms: 0 + m_AlwaysShowColliders: 0 + m_ShowColliderSleep: 1 + m_ShowColliderContacts: 0 + m_ShowColliderAABB: 0 + m_ContactArrowScale: 0.2 + m_ColliderAwakeColor: {r: 0.5686275, g: 0.95686275, b: 0.54509807, a: 0.7529412} + m_ColliderAsleepColor: {r: 0.5686275, g: 0.95686275, b: 0.54509807, a: 0.36078432} + m_ColliderContactColor: {r: 1, g: 0, b: 1, a: 0.6862745} + m_ColliderAABBColor: {r: 1, g: 1, b: 0, a: 0.2509804} + m_LayerCollisionMatrix: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff diff --git a/聊天系统课程代码/Client/Unity/ProjectSettings/PresetManager.asset b/聊天系统课程代码/Client/Unity/ProjectSettings/PresetManager.asset new file mode 100644 index 0000000..67a94da --- /dev/null +++ b/聊天系统课程代码/Client/Unity/ProjectSettings/PresetManager.asset @@ -0,0 +1,7 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1386491679 &1 +PresetManager: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_DefaultPresets: {} diff --git a/聊天系统课程代码/Client/Unity/ProjectSettings/ProjectSettings.asset b/聊天系统课程代码/Client/Unity/ProjectSettings/ProjectSettings.asset new file mode 100644 index 0000000..80d50bb --- /dev/null +++ b/聊天系统课程代码/Client/Unity/ProjectSettings/ProjectSettings.asset @@ -0,0 +1,956 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!129 &1 +PlayerSettings: + m_ObjectHideFlags: 0 + serializedVersion: 26 + productGUID: a31af1ff152264ba79dcc081adbf4d43 + AndroidProfiler: 0 + AndroidFilterTouchesWhenObscured: 0 + AndroidEnableSustainedPerformanceMode: 0 + defaultScreenOrientation: 4 + targetDevice: 2 + useOnDemandResources: 0 + accelerometerFrequency: 60 + companyName: DefaultCompany + productName: Unity + defaultCursor: {fileID: 0} + cursorHotspot: {x: 0, y: 0} + m_SplashScreenBackgroundColor: {r: 0.13725491, g: 0.12156863, b: 0.1254902, a: 1} + m_ShowUnitySplashScreen: 1 + m_ShowUnitySplashLogo: 1 + m_SplashScreenOverlayOpacity: 1 + m_SplashScreenAnimation: 1 + m_SplashScreenLogoStyle: 1 + m_SplashScreenDrawMode: 0 + m_SplashScreenBackgroundAnimationZoom: 1 + m_SplashScreenLogoAnimationZoom: 1 + m_SplashScreenBackgroundLandscapeAspect: 1 + m_SplashScreenBackgroundPortraitAspect: 1 + m_SplashScreenBackgroundLandscapeUvs: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 + m_SplashScreenBackgroundPortraitUvs: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 + m_SplashScreenLogos: [] + m_VirtualRealitySplashScreen: {fileID: 0} + m_HolographicTrackingLossScreen: {fileID: 0} + defaultScreenWidth: 1920 + defaultScreenHeight: 1080 + defaultScreenWidthWeb: 960 + defaultScreenHeightWeb: 600 + m_StereoRenderingPath: 0 + m_ActiveColorSpace: 1 + unsupportedMSAAFallback: 0 + m_SpriteBatchVertexThreshold: 300 + m_MTRendering: 1 + mipStripping: 0 + numberOfMipsStripped: 0 + numberOfMipsStrippedPerMipmapLimitGroup: {} + m_StackTraceTypes: 010000000100000001000000010000000100000001000000 + iosShowActivityIndicatorOnLoading: -1 + androidShowActivityIndicatorOnLoading: -1 + iosUseCustomAppBackgroundBehavior: 0 + allowedAutorotateToPortrait: 1 + allowedAutorotateToPortraitUpsideDown: 1 + allowedAutorotateToLandscapeRight: 1 + allowedAutorotateToLandscapeLeft: 1 + useOSAutorotation: 1 + use32BitDisplayBuffer: 1 + preserveFramebufferAlpha: 0 + disableDepthAndStencilBuffers: 0 + androidStartInFullscreen: 1 + androidRenderOutsideSafeArea: 1 + androidUseSwappy: 1 + androidBlitType: 0 + androidResizableWindow: 0 + androidDefaultWindowWidth: 1920 + androidDefaultWindowHeight: 1080 + androidMinimumWindowWidth: 400 + androidMinimumWindowHeight: 300 + androidFullscreenMode: 1 + androidAutoRotationBehavior: 1 + defaultIsNativeResolution: 1 + macRetinaSupport: 1 + runInBackground: 1 + captureSingleScreen: 0 + muteOtherAudioSources: 0 + Prepare IOS For Recording: 0 + Force IOS Speakers When Recording: 0 + deferSystemGesturesMode: 0 + hideHomeButton: 0 + submitAnalytics: 1 + usePlayerLog: 1 + dedicatedServerOptimizations: 0 + bakeCollisionMeshes: 0 + forceSingleInstance: 0 + useFlipModelSwapchain: 1 + resizableWindow: 0 + useMacAppStoreValidation: 0 + macAppStoreCategory: public.app-category.games + gpuSkinning: 1 + xboxPIXTextureCapture: 0 + xboxEnableAvatar: 0 + xboxEnableKinect: 0 + xboxEnableKinectAutoTracking: 0 + xboxEnableFitness: 0 + visibleInBackground: 1 + allowFullscreenSwitch: 1 + fullscreenMode: 1 + xboxSpeechDB: 0 + xboxEnableHeadOrientation: 0 + xboxEnableGuest: 0 + xboxEnablePIXSampling: 0 + metalFramebufferOnly: 0 + xboxOneResolution: 0 + xboxOneSResolution: 0 + xboxOneXResolution: 3 + xboxOneMonoLoggingLevel: 0 + xboxOneLoggingLevel: 1 + xboxOneDisableEsram: 0 + xboxOneEnableTypeOptimization: 0 + xboxOnePresentImmediateThreshold: 0 + switchQueueCommandMemory: 0 + switchQueueControlMemory: 16384 + switchQueueComputeMemory: 262144 + switchNVNShaderPoolsGranularity: 33554432 + switchNVNDefaultPoolsGranularity: 16777216 + switchNVNOtherPoolsGranularity: 16777216 + switchGpuScratchPoolGranularity: 2097152 + switchAllowGpuScratchShrinking: 0 + switchNVNMaxPublicTextureIDCount: 0 + switchNVNMaxPublicSamplerIDCount: 0 + switchNVNGraphicsFirmwareMemory: 32 + switchMaxWorkerMultiple: 8 + stadiaPresentMode: 0 + stadiaTargetFramerate: 0 + vulkanNumSwapchainBuffers: 3 + vulkanEnableSetSRGBWrite: 0 + vulkanEnablePreTransform: 1 + vulkanEnableLateAcquireNextImage: 0 + vulkanEnableCommandBufferRecycling: 1 + loadStoreDebugModeEnabled: 0 + visionOSBundleVersion: 1.0 + tvOSBundleVersion: 1.0 + bundleVersion: 0.1 + preloadedAssets: [] + metroInputSource: 0 + wsaTransparentSwapchain: 0 + m_HolographicPauseOnTrackingLoss: 1 + xboxOneDisableKinectGpuReservation: 1 + xboxOneEnable7thCore: 1 + vrSettings: + enable360StereoCapture: 0 + isWsaHolographicRemotingEnabled: 0 + enableFrameTimingStats: 0 + enableOpenGLProfilerGPURecorders: 1 + allowHDRDisplaySupport: 0 + useHDRDisplay: 0 + hdrBitDepth: 0 + m_ColorGamuts: 00000000 + targetPixelDensity: 30 + resolutionScalingMode: 0 + resetResolutionOnWindowResize: 0 + androidSupportedAspectRatio: 1 + androidMaxAspectRatio: 2.1 + applicationIdentifier: {} + buildNumber: + Standalone: 0 + VisionOS: 0 + iPhone: 0 + tvOS: 0 + overrideDefaultApplicationIdentifier: 0 + AndroidBundleVersionCode: 1 + AndroidMinSdkVersion: 22 + AndroidTargetSdkVersion: 0 + AndroidPreferredInstallLocation: 1 + aotOptions: + stripEngineCode: 1 + iPhoneStrippingLevel: 0 + iPhoneScriptCallOptimization: 0 + ForceInternetPermission: 0 + ForceSDCardPermission: 0 + CreateWallpaper: 0 + APKExpansionFiles: 0 + keepLoadedShadersAlive: 0 + StripUnusedMeshComponents: 1 + strictShaderVariantMatching: 0 + VertexChannelCompressionMask: 4054 + iPhoneSdkVersion: 988 + iOSTargetOSVersionString: 12.0 + tvOSSdkVersion: 0 + tvOSRequireExtendedGameController: 0 + tvOSTargetOSVersionString: 12.0 + VisionOSSdkVersion: 0 + VisionOSTargetOSVersionString: 1.0 + uIPrerenderedIcon: 0 + uIRequiresPersistentWiFi: 0 + uIRequiresFullScreen: 1 + uIStatusBarHidden: 1 + uIExitOnSuspend: 0 + uIStatusBarStyle: 0 + appleTVSplashScreen: {fileID: 0} + appleTVSplashScreen2x: {fileID: 0} + tvOSSmallIconLayers: [] + tvOSSmallIconLayers2x: [] + tvOSLargeIconLayers: [] + tvOSLargeIconLayers2x: [] + tvOSTopShelfImageLayers: [] + tvOSTopShelfImageLayers2x: [] + tvOSTopShelfImageWideLayers: [] + tvOSTopShelfImageWideLayers2x: [] + iOSLaunchScreenType: 0 + iOSLaunchScreenPortrait: {fileID: 0} + iOSLaunchScreenLandscape: {fileID: 0} + iOSLaunchScreenBackgroundColor: + serializedVersion: 2 + rgba: 0 + iOSLaunchScreenFillPct: 100 + iOSLaunchScreenSize: 100 + iOSLaunchScreenCustomXibPath: + iOSLaunchScreeniPadType: 0 + iOSLaunchScreeniPadImage: {fileID: 0} + iOSLaunchScreeniPadBackgroundColor: + serializedVersion: 2 + rgba: 0 + iOSLaunchScreeniPadFillPct: 100 + iOSLaunchScreeniPadSize: 100 + iOSLaunchScreeniPadCustomXibPath: + iOSLaunchScreenCustomStoryboardPath: + iOSLaunchScreeniPadCustomStoryboardPath: + iOSDeviceRequirements: [] + iOSURLSchemes: [] + macOSURLSchemes: [] + iOSBackgroundModes: 0 + iOSMetalForceHardShadows: 0 + metalEditorSupport: 1 + metalAPIValidation: 1 + metalCompileShaderBinary: 0 + iOSRenderExtraFrameOnPause: 0 + iosCopyPluginsCodeInsteadOfSymlink: 0 + appleDeveloperTeamID: + iOSManualSigningProvisioningProfileID: + tvOSManualSigningProvisioningProfileID: + VisionOSManualSigningProvisioningProfileID: + iOSManualSigningProvisioningProfileType: 0 + tvOSManualSigningProvisioningProfileType: 0 + VisionOSManualSigningProvisioningProfileType: 0 + appleEnableAutomaticSigning: 0 + iOSRequireARKit: 0 + iOSAutomaticallyDetectAndAddCapabilities: 1 + appleEnableProMotion: 0 + shaderPrecisionModel: 0 + clonedFromGUID: c0afd0d1d80e3634a9dac47e8a0426ea + templatePackageId: com.unity.template.3d@8.1.3 + templateDefaultScene: Assets/Scenes/SampleScene.unity + useCustomMainManifest: 0 + useCustomLauncherManifest: 0 + useCustomMainGradleTemplate: 0 + useCustomLauncherGradleManifest: 0 + useCustomBaseGradleTemplate: 0 + useCustomGradlePropertiesTemplate: 0 + useCustomGradleSettingsTemplate: 0 + useCustomProguardFile: 0 + AndroidTargetArchitectures: 1 + AndroidTargetDevices: 0 + AndroidSplashScreenScale: 0 + androidSplashScreen: {fileID: 0} + AndroidKeystoreName: + AndroidKeyaliasName: + AndroidEnableArmv9SecurityFeatures: 0 + AndroidBuildApkPerCpuArchitecture: 0 + AndroidTVCompatibility: 0 + AndroidIsGame: 1 + AndroidEnableTango: 0 + androidEnableBanner: 1 + androidUseLowAccuracyLocation: 0 + androidUseCustomKeystore: 0 + m_AndroidBanners: + - width: 320 + height: 180 + banner: {fileID: 0} + androidGamepadSupportLevel: 0 + chromeosInputEmulation: 1 + AndroidMinifyRelease: 0 + AndroidMinifyDebug: 0 + AndroidValidateAppBundleSize: 1 + AndroidAppBundleSizeToValidate: 150 + m_BuildTargetIcons: [] + m_BuildTargetPlatformIcons: + - m_BuildTarget: iPhone + m_Icons: + - m_Textures: [] + m_Width: 180 + m_Height: 180 + m_Kind: 0 + m_SubKind: iPhone + - m_Textures: [] + m_Width: 120 + m_Height: 120 + m_Kind: 0 + m_SubKind: iPhone + - m_Textures: [] + m_Width: 167 + m_Height: 167 + m_Kind: 0 + m_SubKind: iPad + - m_Textures: [] + m_Width: 152 + m_Height: 152 + m_Kind: 0 + m_SubKind: iPad + - m_Textures: [] + m_Width: 76 + m_Height: 76 + m_Kind: 0 + m_SubKind: iPad + - m_Textures: [] + m_Width: 120 + m_Height: 120 + m_Kind: 3 + m_SubKind: iPhone + - m_Textures: [] + m_Width: 80 + m_Height: 80 + m_Kind: 3 + m_SubKind: iPhone + - m_Textures: [] + m_Width: 80 + m_Height: 80 + m_Kind: 3 + m_SubKind: iPad + - m_Textures: [] + m_Width: 40 + m_Height: 40 + m_Kind: 3 + m_SubKind: iPad + - m_Textures: [] + m_Width: 87 + m_Height: 87 + m_Kind: 1 + m_SubKind: iPhone + - m_Textures: [] + m_Width: 58 + m_Height: 58 + m_Kind: 1 + m_SubKind: iPhone + - m_Textures: [] + m_Width: 29 + m_Height: 29 + m_Kind: 1 + m_SubKind: iPhone + - m_Textures: [] + m_Width: 58 + m_Height: 58 + m_Kind: 1 + m_SubKind: iPad + - m_Textures: [] + m_Width: 29 + m_Height: 29 + m_Kind: 1 + m_SubKind: iPad + - m_Textures: [] + m_Width: 60 + m_Height: 60 + m_Kind: 2 + m_SubKind: iPhone + - m_Textures: [] + m_Width: 40 + m_Height: 40 + m_Kind: 2 + m_SubKind: iPhone + - m_Textures: [] + m_Width: 40 + m_Height: 40 + m_Kind: 2 + m_SubKind: iPad + - m_Textures: [] + m_Width: 20 + m_Height: 20 + m_Kind: 2 + m_SubKind: iPad + - m_Textures: [] + m_Width: 1024 + m_Height: 1024 + m_Kind: 4 + m_SubKind: App Store + - m_BuildTarget: Android + m_Icons: + - m_Textures: [] + m_Width: 432 + m_Height: 432 + m_Kind: 2 + m_SubKind: + - m_Textures: [] + m_Width: 324 + m_Height: 324 + m_Kind: 2 + m_SubKind: + - m_Textures: [] + m_Width: 216 + m_Height: 216 + m_Kind: 2 + m_SubKind: + - m_Textures: [] + m_Width: 162 + m_Height: 162 + m_Kind: 2 + m_SubKind: + - m_Textures: [] + m_Width: 108 + m_Height: 108 + m_Kind: 2 + m_SubKind: + - m_Textures: [] + m_Width: 81 + m_Height: 81 + m_Kind: 2 + m_SubKind: + - m_Textures: [] + m_Width: 192 + m_Height: 192 + m_Kind: 1 + m_SubKind: + - m_Textures: [] + m_Width: 144 + m_Height: 144 + m_Kind: 1 + m_SubKind: + - m_Textures: [] + m_Width: 96 + m_Height: 96 + m_Kind: 1 + m_SubKind: + - m_Textures: [] + m_Width: 72 + m_Height: 72 + m_Kind: 1 + m_SubKind: + - m_Textures: [] + m_Width: 48 + m_Height: 48 + m_Kind: 1 + m_SubKind: + - m_Textures: [] + m_Width: 36 + m_Height: 36 + m_Kind: 1 + m_SubKind: + - m_Textures: [] + m_Width: 192 + m_Height: 192 + m_Kind: 0 + m_SubKind: + - m_Textures: [] + m_Width: 144 + m_Height: 144 + m_Kind: 0 + m_SubKind: + - m_Textures: [] + m_Width: 96 + m_Height: 96 + m_Kind: 0 + m_SubKind: + - m_Textures: [] + m_Width: 72 + m_Height: 72 + m_Kind: 0 + m_SubKind: + - m_Textures: [] + m_Width: 48 + m_Height: 48 + m_Kind: 0 + m_SubKind: + - m_Textures: [] + m_Width: 36 + m_Height: 36 + m_Kind: 0 + m_SubKind: + m_BuildTargetBatching: + - m_BuildTarget: Standalone + m_StaticBatching: 1 + m_DynamicBatching: 0 + - m_BuildTarget: tvOS + m_StaticBatching: 1 + m_DynamicBatching: 0 + - m_BuildTarget: Android + m_StaticBatching: 1 + m_DynamicBatching: 0 + - m_BuildTarget: iPhone + m_StaticBatching: 1 + m_DynamicBatching: 0 + - m_BuildTarget: WebGL + m_StaticBatching: 0 + m_DynamicBatching: 0 + m_BuildTargetShaderSettings: [] + m_BuildTargetGraphicsJobs: + - m_BuildTarget: MacStandaloneSupport + m_GraphicsJobs: 0 + - m_BuildTarget: Switch + m_GraphicsJobs: 1 + - m_BuildTarget: MetroSupport + m_GraphicsJobs: 1 + - m_BuildTarget: AppleTVSupport + m_GraphicsJobs: 0 + - m_BuildTarget: BJMSupport + m_GraphicsJobs: 1 + - m_BuildTarget: LinuxStandaloneSupport + m_GraphicsJobs: 1 + - m_BuildTarget: PS4Player + m_GraphicsJobs: 1 + - m_BuildTarget: iOSSupport + m_GraphicsJobs: 0 + - m_BuildTarget: WindowsStandaloneSupport + m_GraphicsJobs: 1 + - m_BuildTarget: XboxOnePlayer + m_GraphicsJobs: 1 + - m_BuildTarget: LuminSupport + m_GraphicsJobs: 0 + - m_BuildTarget: AndroidPlayer + m_GraphicsJobs: 0 + - m_BuildTarget: WebGLSupport + m_GraphicsJobs: 0 + m_BuildTargetGraphicsJobMode: + - m_BuildTarget: PS4Player + m_GraphicsJobMode: 0 + - m_BuildTarget: XboxOnePlayer + m_GraphicsJobMode: 0 + m_BuildTargetGraphicsAPIs: + - m_BuildTarget: AndroidPlayer + m_APIs: 150000000b000000 + m_Automatic: 1 + - m_BuildTarget: iOSSupport + m_APIs: 10000000 + m_Automatic: 1 + - m_BuildTarget: AppleTVSupport + m_APIs: 10000000 + m_Automatic: 1 + - m_BuildTarget: WebGLSupport + m_APIs: 0b000000 + m_Automatic: 1 + m_BuildTargetVRSettings: + - m_BuildTarget: Standalone + m_Enabled: 0 + m_Devices: + - Oculus + - OpenVR + m_DefaultShaderChunkSizeInMB: 16 + m_DefaultShaderChunkCount: 0 + openGLRequireES31: 0 + openGLRequireES31AEP: 0 + openGLRequireES32: 0 + m_TemplateCustomTags: {} + mobileMTRendering: + Android: 1 + iPhone: 1 + tvOS: 1 + m_BuildTargetGroupLightmapEncodingQuality: + - m_BuildTarget: Android + m_EncodingQuality: 1 + - m_BuildTarget: iPhone + m_EncodingQuality: 1 + - m_BuildTarget: tvOS + m_EncodingQuality: 1 + m_BuildTargetGroupHDRCubemapEncodingQuality: + - m_BuildTarget: Android + m_EncodingQuality: 1 + - m_BuildTarget: iPhone + m_EncodingQuality: 1 + - m_BuildTarget: tvOS + m_EncodingQuality: 1 + m_BuildTargetGroupLightmapSettings: [] + m_BuildTargetGroupLoadStoreDebugModeSettings: [] + m_BuildTargetNormalMapEncoding: + - m_BuildTarget: Android + m_Encoding: 1 + - m_BuildTarget: iPhone + m_Encoding: 1 + - m_BuildTarget: tvOS + m_Encoding: 1 + m_BuildTargetDefaultTextureCompressionFormat: + - m_BuildTarget: Android + m_Format: 3 + playModeTestRunnerEnabled: 0 + runPlayModeTestAsEditModeTest: 0 + actionOnDotNetUnhandledException: 1 + enableInternalProfiler: 0 + logObjCUncaughtExceptions: 1 + enableCrashReportAPI: 0 + cameraUsageDescription: + locationUsageDescription: + microphoneUsageDescription: + bluetoothUsageDescription: + macOSTargetOSVersion: 10.13.0 + switchNMETAOverride: + switchNetLibKey: + switchSocketMemoryPoolSize: 6144 + switchSocketAllocatorPoolSize: 128 + switchSocketConcurrencyLimit: 14 + switchScreenResolutionBehavior: 2 + switchUseCPUProfiler: 0 + switchEnableFileSystemTrace: 0 + switchLTOSetting: 0 + switchApplicationID: 0x01004b9000490000 + switchNSODependencies: + switchCompilerFlags: + switchTitleNames_0: + switchTitleNames_1: + switchTitleNames_2: + switchTitleNames_3: + switchTitleNames_4: + switchTitleNames_5: + switchTitleNames_6: + switchTitleNames_7: + switchTitleNames_8: + switchTitleNames_9: + switchTitleNames_10: + switchTitleNames_11: + switchTitleNames_12: + switchTitleNames_13: + switchTitleNames_14: + switchTitleNames_15: + switchPublisherNames_0: + switchPublisherNames_1: + switchPublisherNames_2: + switchPublisherNames_3: + switchPublisherNames_4: + switchPublisherNames_5: + switchPublisherNames_6: + switchPublisherNames_7: + switchPublisherNames_8: + switchPublisherNames_9: + switchPublisherNames_10: + switchPublisherNames_11: + switchPublisherNames_12: + switchPublisherNames_13: + switchPublisherNames_14: + switchPublisherNames_15: + switchIcons_0: {fileID: 0} + switchIcons_1: {fileID: 0} + switchIcons_2: {fileID: 0} + switchIcons_3: {fileID: 0} + switchIcons_4: {fileID: 0} + switchIcons_5: {fileID: 0} + switchIcons_6: {fileID: 0} + switchIcons_7: {fileID: 0} + switchIcons_8: {fileID: 0} + switchIcons_9: {fileID: 0} + switchIcons_10: {fileID: 0} + switchIcons_11: {fileID: 0} + switchIcons_12: {fileID: 0} + switchIcons_13: {fileID: 0} + switchIcons_14: {fileID: 0} + switchIcons_15: {fileID: 0} + switchSmallIcons_0: {fileID: 0} + switchSmallIcons_1: {fileID: 0} + switchSmallIcons_2: {fileID: 0} + switchSmallIcons_3: {fileID: 0} + switchSmallIcons_4: {fileID: 0} + switchSmallIcons_5: {fileID: 0} + switchSmallIcons_6: {fileID: 0} + switchSmallIcons_7: {fileID: 0} + switchSmallIcons_8: {fileID: 0} + switchSmallIcons_9: {fileID: 0} + switchSmallIcons_10: {fileID: 0} + switchSmallIcons_11: {fileID: 0} + switchSmallIcons_12: {fileID: 0} + switchSmallIcons_13: {fileID: 0} + switchSmallIcons_14: {fileID: 0} + switchSmallIcons_15: {fileID: 0} + switchManualHTML: + switchAccessibleURLs: + switchLegalInformation: + switchMainThreadStackSize: 1048576 + switchPresenceGroupId: + switchLogoHandling: 0 + switchReleaseVersion: 0 + switchDisplayVersion: 1.0.0 + switchStartupUserAccount: 0 + switchSupportedLanguagesMask: 0 + switchLogoType: 0 + switchApplicationErrorCodeCategory: + switchUserAccountSaveDataSize: 0 + switchUserAccountSaveDataJournalSize: 0 + switchApplicationAttribute: 0 + switchCardSpecSize: -1 + switchCardSpecClock: -1 + switchRatingsMask: 0 + switchRatingsInt_0: 0 + switchRatingsInt_1: 0 + switchRatingsInt_2: 0 + switchRatingsInt_3: 0 + switchRatingsInt_4: 0 + switchRatingsInt_5: 0 + switchRatingsInt_6: 0 + switchRatingsInt_7: 0 + switchRatingsInt_8: 0 + switchRatingsInt_9: 0 + switchRatingsInt_10: 0 + switchRatingsInt_11: 0 + switchRatingsInt_12: 0 + switchLocalCommunicationIds_0: + switchLocalCommunicationIds_1: + switchLocalCommunicationIds_2: + switchLocalCommunicationIds_3: + switchLocalCommunicationIds_4: + switchLocalCommunicationIds_5: + switchLocalCommunicationIds_6: + switchLocalCommunicationIds_7: + switchParentalControl: 0 + switchAllowsScreenshot: 1 + switchAllowsVideoCapturing: 1 + switchAllowsRuntimeAddOnContentInstall: 0 + switchDataLossConfirmation: 0 + switchUserAccountLockEnabled: 0 + switchSystemResourceMemory: 16777216 + switchSupportedNpadStyles: 22 + switchNativeFsCacheSize: 32 + switchIsHoldTypeHorizontal: 0 + switchSupportedNpadCount: 8 + switchEnableTouchScreen: 1 + switchSocketConfigEnabled: 0 + switchTcpInitialSendBufferSize: 32 + switchTcpInitialReceiveBufferSize: 64 + switchTcpAutoSendBufferSizeMax: 256 + switchTcpAutoReceiveBufferSizeMax: 256 + switchUdpSendBufferSize: 9 + switchUdpReceiveBufferSize: 42 + switchSocketBufferEfficiency: 4 + switchSocketInitializeEnabled: 1 + switchNetworkInterfaceManagerInitializeEnabled: 1 + switchUseNewStyleFilepaths: 1 + switchUseLegacyFmodPriorities: 0 + switchUseMicroSleepForYield: 1 + switchEnableRamDiskSupport: 0 + switchMicroSleepForYieldTime: 25 + switchRamDiskSpaceSize: 12 + ps4NPAgeRating: 12 + ps4NPTitleSecret: + ps4NPTrophyPackPath: + ps4ParentalLevel: 11 + ps4ContentID: ED1633-NPXX51362_00-0000000000000000 + ps4Category: 0 + ps4MasterVersion: 01.00 + ps4AppVersion: 01.00 + ps4AppType: 0 + ps4ParamSfxPath: + ps4VideoOutPixelFormat: 0 + ps4VideoOutInitialWidth: 1920 + ps4VideoOutBaseModeInitialWidth: 1920 + ps4VideoOutReprojectionRate: 60 + ps4PronunciationXMLPath: + ps4PronunciationSIGPath: + ps4BackgroundImagePath: + ps4StartupImagePath: + ps4StartupImagesFolder: + ps4IconImagesFolder: + ps4SaveDataImagePath: + ps4SdkOverride: + ps4BGMPath: + ps4ShareFilePath: + ps4ShareOverlayImagePath: + ps4PrivacyGuardImagePath: + ps4ExtraSceSysFile: + ps4NPtitleDatPath: + ps4RemotePlayKeyAssignment: -1 + ps4RemotePlayKeyMappingDir: + ps4PlayTogetherPlayerCount: 0 + ps4EnterButtonAssignment: 1 + ps4ApplicationParam1: 0 + ps4ApplicationParam2: 0 + ps4ApplicationParam3: 0 + ps4ApplicationParam4: 0 + ps4DownloadDataSize: 0 + ps4GarlicHeapSize: 2048 + ps4ProGarlicHeapSize: 2560 + playerPrefsMaxSize: 32768 + ps4Passcode: frAQBc8Wsa1xVPfvJcrgRYwTiizs2trQ + ps4pnSessions: 1 + ps4pnPresence: 1 + ps4pnFriends: 1 + ps4pnGameCustomData: 1 + playerPrefsSupport: 0 + enableApplicationExit: 0 + resetTempFolder: 1 + restrictedAudioUsageRights: 0 + ps4UseResolutionFallback: 0 + ps4ReprojectionSupport: 0 + ps4UseAudio3dBackend: 0 + ps4UseLowGarlicFragmentationMode: 1 + ps4SocialScreenEnabled: 0 + ps4ScriptOptimizationLevel: 0 + ps4Audio3dVirtualSpeakerCount: 14 + ps4attribCpuUsage: 0 + ps4PatchPkgPath: + ps4PatchLatestPkgPath: + ps4PatchChangeinfoPath: + ps4PatchDayOne: 0 + ps4attribUserManagement: 0 + ps4attribMoveSupport: 0 + ps4attrib3DSupport: 0 + ps4attribShareSupport: 0 + ps4attribExclusiveVR: 0 + ps4disableAutoHideSplash: 0 + ps4videoRecordingFeaturesUsed: 0 + ps4contentSearchFeaturesUsed: 0 + ps4CompatibilityPS5: 0 + ps4AllowPS5Detection: 0 + ps4GPU800MHz: 1 + ps4attribEyeToEyeDistanceSettingVR: 0 + ps4IncludedModules: [] + ps4attribVROutputEnabled: 0 + monoEnv: + splashScreenBackgroundSourceLandscape: {fileID: 0} + splashScreenBackgroundSourcePortrait: {fileID: 0} + blurSplashScreenBackground: 1 + spritePackerPolicy: + webGLMemorySize: 16 + webGLExceptionSupport: 1 + webGLNameFilesAsHashes: 0 + webGLShowDiagnostics: 0 + webGLDataCaching: 1 + webGLDebugSymbols: 0 + webGLEmscriptenArgs: + webGLModulesDirectory: + webGLTemplate: APPLICATION:Default + webGLAnalyzeBuildSize: 0 + webGLUseEmbeddedResources: 0 + webGLCompressionFormat: 1 + webGLWasmArithmeticExceptions: 0 + webGLLinkerTarget: 1 + webGLThreadsSupport: 0 + webGLDecompressionFallback: 0 + webGLInitialMemorySize: 32 + webGLMaximumMemorySize: 2048 + webGLMemoryGrowthMode: 2 + webGLMemoryLinearGrowthStep: 16 + webGLMemoryGeometricGrowthStep: 0.2 + webGLMemoryGeometricGrowthCap: 96 + webGLPowerPreference: 2 + scriptingDefineSymbols: {} + additionalCompilerArguments: {} + platformArchitecture: {} + scriptingBackend: {} + il2cppCompilerConfiguration: {} + il2cppCodeGeneration: {} + managedStrippingLevel: + EmbeddedLinux: 1 + GameCoreScarlett: 1 + GameCoreXboxOne: 1 + Nintendo Switch: 1 + PS4: 1 + PS5: 1 + QNX: 1 + Stadia: 1 + VisionOS: 1 + WebGL: 1 + Windows Store Apps: 1 + XboxOne: 1 + iPhone: 1 + tvOS: 1 + incrementalIl2cppBuild: {} + suppressCommonWarnings: 1 + allowUnsafeCode: 0 + useDeterministicCompilation: 1 + additionalIl2CppArgs: + scriptingRuntimeVersion: 1 + gcIncremental: 1 + gcWBarrierValidation: 0 + apiCompatibilityLevelPerPlatform: {} + m_RenderingPath: 1 + m_MobileRenderingPath: 1 + metroPackageName: Unity + metroPackageVersion: + metroCertificatePath: + metroCertificatePassword: + metroCertificateSubject: + metroCertificateIssuer: + metroCertificateNotAfter: 0000000000000000 + metroApplicationDescription: Unity + wsaImages: {} + metroTileShortName: + metroTileShowName: 0 + metroMediumTileShowName: 0 + metroLargeTileShowName: 0 + metroWideTileShowName: 0 + metroSupportStreamingInstall: 0 + metroLastRequiredScene: 0 + metroDefaultTileSize: 1 + metroTileForegroundText: 2 + metroTileBackgroundColor: {r: 0.13333334, g: 0.17254902, b: 0.21568628, a: 0} + metroSplashScreenBackgroundColor: {r: 0.12941177, g: 0.17254902, b: 0.21568628, a: 1} + metroSplashScreenUseBackgroundColor: 0 + syncCapabilities: 0 + platformCapabilities: {} + metroTargetDeviceFamilies: {} + metroFTAName: + metroFTAFileTypes: [] + metroProtocolName: + vcxProjDefaultLanguage: + XboxOneProductId: + XboxOneUpdateKey: + XboxOneSandboxId: + XboxOneContentId: + XboxOneTitleId: + XboxOneSCId: + XboxOneGameOsOverridePath: + XboxOnePackagingOverridePath: + XboxOneAppManifestOverridePath: + XboxOneVersion: 1.0.0.0 + XboxOnePackageEncryption: 0 + XboxOnePackageUpdateGranularity: 2 + XboxOneDescription: + XboxOneLanguage: + - enus + XboxOneCapability: [] + XboxOneGameRating: {} + XboxOneIsContentPackage: 0 + XboxOneEnhancedXboxCompatibilityMode: 0 + XboxOneEnableGPUVariability: 1 + XboxOneSockets: {} + XboxOneSplashScreen: {fileID: 0} + XboxOneAllowedProductIds: [] + XboxOnePersistentLocalStorageSize: 0 + XboxOneXTitleMemory: 8 + XboxOneOverrideIdentityName: + XboxOneOverrideIdentityPublisher: + vrEditorSettings: {} + cloudServicesEnabled: + UNet: 1 + luminIcon: + m_Name: + m_ModelFolderPath: + m_PortalFolderPath: + luminCert: + m_CertPath: + m_SignPackage: 1 + luminIsChannelApp: 0 + luminVersion: + m_VersionCode: 1 + m_VersionName: + hmiPlayerDataPath: + hmiForceSRGBBlit: 1 + embeddedLinuxEnableGamepadInput: 1 + hmiLogStartupTiming: 0 + hmiCpuConfiguration: + apiCompatibilityLevel: 6 + activeInputHandler: 0 + windowsGamepadBackendHint: 0 + cloudProjectId: dc55f1ee-c70b-4459-888b-1c2eb6c59297 + framebufferDepthMemorylessMode: 0 + qualitySettingsNames: [] + projectName: Unity 2024-11-05_08-34-15 + organizationId: mrsining + cloudEnabled: 0 + legacyClampBlendShapeWeights: 0 + hmiLoadingImage: {fileID: 0} + platformRequiresReadableAssets: 0 + virtualTexturingSupportEnabled: 0 + insecureHttpOption: 0 diff --git a/聊天系统课程代码/Client/Unity/ProjectSettings/ProjectVersion.txt b/聊天系统课程代码/Client/Unity/ProjectSettings/ProjectVersion.txt new file mode 100644 index 0000000..4cef776 --- /dev/null +++ b/聊天系统课程代码/Client/Unity/ProjectSettings/ProjectVersion.txt @@ -0,0 +1,2 @@ +m_EditorVersion: 2022.3.48f1 +m_EditorVersionWithRevision: 2022.3.48f1 (8bf49c377ebf) diff --git a/聊天系统课程代码/Client/Unity/ProjectSettings/QualitySettings.asset b/聊天系统课程代码/Client/Unity/ProjectSettings/QualitySettings.asset new file mode 100644 index 0000000..36c0dad --- /dev/null +++ b/聊天系统课程代码/Client/Unity/ProjectSettings/QualitySettings.asset @@ -0,0 +1,234 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!47 &1 +QualitySettings: + m_ObjectHideFlags: 0 + serializedVersion: 5 + m_CurrentQuality: 5 + m_QualitySettings: + - serializedVersion: 2 + name: Very Low + pixelLightCount: 0 + shadows: 0 + shadowResolution: 0 + shadowProjection: 1 + shadowCascades: 1 + shadowDistance: 15 + shadowNearPlaneOffset: 3 + shadowCascade2Split: 0.33333334 + shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} + shadowmaskMode: 0 + blendWeights: 1 + textureQuality: 1 + anisotropicTextures: 0 + antiAliasing: 0 + softParticles: 0 + softVegetation: 0 + realtimeReflectionProbes: 0 + billboardsFaceCameraPosition: 0 + vSyncCount: 0 + lodBias: 0.3 + maximumLODLevel: 0 + streamingMipmapsActive: 0 + streamingMipmapsAddAllCameras: 1 + streamingMipmapsMemoryBudget: 512 + streamingMipmapsRenderersPerFrame: 512 + streamingMipmapsMaxLevelReduction: 2 + streamingMipmapsMaxFileIORequests: 1024 + particleRaycastBudget: 4 + asyncUploadTimeSlice: 2 + asyncUploadBufferSize: 16 + asyncUploadPersistentBuffer: 1 + resolutionScalingFixedDPIFactor: 1 + excludedTargetPlatforms: [] + - serializedVersion: 2 + name: Low + pixelLightCount: 0 + shadows: 0 + shadowResolution: 0 + shadowProjection: 1 + shadowCascades: 1 + shadowDistance: 20 + shadowNearPlaneOffset: 3 + shadowCascade2Split: 0.33333334 + shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} + shadowmaskMode: 0 + blendWeights: 2 + textureQuality: 0 + anisotropicTextures: 0 + antiAliasing: 0 + softParticles: 0 + softVegetation: 0 + realtimeReflectionProbes: 0 + billboardsFaceCameraPosition: 0 + vSyncCount: 0 + lodBias: 0.4 + maximumLODLevel: 0 + streamingMipmapsActive: 0 + streamingMipmapsAddAllCameras: 1 + streamingMipmapsMemoryBudget: 512 + streamingMipmapsRenderersPerFrame: 512 + streamingMipmapsMaxLevelReduction: 2 + streamingMipmapsMaxFileIORequests: 1024 + particleRaycastBudget: 16 + asyncUploadTimeSlice: 2 + asyncUploadBufferSize: 16 + asyncUploadPersistentBuffer: 1 + resolutionScalingFixedDPIFactor: 1 + excludedTargetPlatforms: [] + - serializedVersion: 2 + name: Medium + pixelLightCount: 1 + shadows: 1 + shadowResolution: 0 + shadowProjection: 1 + shadowCascades: 1 + shadowDistance: 20 + shadowNearPlaneOffset: 3 + shadowCascade2Split: 0.33333334 + shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} + shadowmaskMode: 0 + blendWeights: 2 + textureQuality: 0 + anisotropicTextures: 1 + antiAliasing: 0 + softParticles: 0 + softVegetation: 0 + realtimeReflectionProbes: 0 + billboardsFaceCameraPosition: 0 + vSyncCount: 1 + lodBias: 0.7 + maximumLODLevel: 0 + streamingMipmapsActive: 0 + streamingMipmapsAddAllCameras: 1 + streamingMipmapsMemoryBudget: 512 + streamingMipmapsRenderersPerFrame: 512 + streamingMipmapsMaxLevelReduction: 2 + streamingMipmapsMaxFileIORequests: 1024 + particleRaycastBudget: 64 + asyncUploadTimeSlice: 2 + asyncUploadBufferSize: 16 + asyncUploadPersistentBuffer: 1 + resolutionScalingFixedDPIFactor: 1 + excludedTargetPlatforms: [] + - serializedVersion: 2 + name: High + pixelLightCount: 2 + shadows: 2 + shadowResolution: 1 + shadowProjection: 1 + shadowCascades: 2 + shadowDistance: 40 + shadowNearPlaneOffset: 3 + shadowCascade2Split: 0.33333334 + shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} + shadowmaskMode: 1 + blendWeights: 2 + textureQuality: 0 + anisotropicTextures: 1 + antiAliasing: 0 + softParticles: 0 + softVegetation: 1 + realtimeReflectionProbes: 1 + billboardsFaceCameraPosition: 1 + vSyncCount: 1 + lodBias: 1 + maximumLODLevel: 0 + streamingMipmapsActive: 0 + streamingMipmapsAddAllCameras: 1 + streamingMipmapsMemoryBudget: 512 + streamingMipmapsRenderersPerFrame: 512 + streamingMipmapsMaxLevelReduction: 2 + streamingMipmapsMaxFileIORequests: 1024 + particleRaycastBudget: 256 + asyncUploadTimeSlice: 2 + asyncUploadBufferSize: 16 + asyncUploadPersistentBuffer: 1 + resolutionScalingFixedDPIFactor: 1 + excludedTargetPlatforms: [] + - serializedVersion: 2 + name: Very High + pixelLightCount: 3 + shadows: 2 + shadowResolution: 2 + shadowProjection: 1 + shadowCascades: 2 + shadowDistance: 70 + shadowNearPlaneOffset: 3 + shadowCascade2Split: 0.33333334 + shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} + shadowmaskMode: 1 + blendWeights: 4 + textureQuality: 0 + anisotropicTextures: 2 + antiAliasing: 2 + softParticles: 1 + softVegetation: 1 + realtimeReflectionProbes: 1 + billboardsFaceCameraPosition: 1 + vSyncCount: 1 + lodBias: 1.5 + maximumLODLevel: 0 + streamingMipmapsActive: 0 + streamingMipmapsAddAllCameras: 1 + streamingMipmapsMemoryBudget: 512 + streamingMipmapsRenderersPerFrame: 512 + streamingMipmapsMaxLevelReduction: 2 + streamingMipmapsMaxFileIORequests: 1024 + particleRaycastBudget: 1024 + asyncUploadTimeSlice: 2 + asyncUploadBufferSize: 16 + asyncUploadPersistentBuffer: 1 + resolutionScalingFixedDPIFactor: 1 + excludedTargetPlatforms: [] + - serializedVersion: 2 + name: Ultra + pixelLightCount: 4 + shadows: 2 + shadowResolution: 2 + shadowProjection: 1 + shadowCascades: 4 + shadowDistance: 150 + shadowNearPlaneOffset: 3 + shadowCascade2Split: 0.33333334 + shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} + shadowmaskMode: 1 + blendWeights: 4 + textureQuality: 0 + anisotropicTextures: 2 + antiAliasing: 2 + softParticles: 1 + softVegetation: 1 + realtimeReflectionProbes: 1 + billboardsFaceCameraPosition: 1 + vSyncCount: 1 + lodBias: 2 + maximumLODLevel: 0 + streamingMipmapsActive: 0 + streamingMipmapsAddAllCameras: 1 + streamingMipmapsMemoryBudget: 512 + streamingMipmapsRenderersPerFrame: 512 + streamingMipmapsMaxLevelReduction: 2 + streamingMipmapsMaxFileIORequests: 1024 + particleRaycastBudget: 4096 + asyncUploadTimeSlice: 2 + asyncUploadBufferSize: 16 + asyncUploadPersistentBuffer: 1 + resolutionScalingFixedDPIFactor: 1 + excludedTargetPlatforms: [] + m_PerPlatformDefaultQuality: + Android: 2 + Lumin: 5 + GameCoreScarlett: 5 + GameCoreXboxOne: 5 + Nintendo 3DS: 5 + Nintendo Switch: 5 + PS4: 5 + PS5: 5 + Stadia: 5 + Standalone: 5 + WebGL: 3 + Windows Store Apps: 5 + XboxOne: 5 + iPhone: 2 + tvOS: 2 diff --git a/聊天系统课程代码/Client/Unity/ProjectSettings/SceneTemplateSettings.json b/聊天系统课程代码/Client/Unity/ProjectSettings/SceneTemplateSettings.json new file mode 100644 index 0000000..5e97f83 --- /dev/null +++ b/聊天系统课程代码/Client/Unity/ProjectSettings/SceneTemplateSettings.json @@ -0,0 +1,121 @@ +{ + "templatePinStates": [], + "dependencyTypeInfos": [ + { + "userAdded": false, + "type": "UnityEngine.AnimationClip", + "defaultInstantiationMode": 0 + }, + { + "userAdded": false, + "type": "UnityEditor.Animations.AnimatorController", + "defaultInstantiationMode": 0 + }, + { + "userAdded": false, + "type": "UnityEngine.AnimatorOverrideController", + "defaultInstantiationMode": 0 + }, + { + "userAdded": false, + "type": "UnityEditor.Audio.AudioMixerController", + "defaultInstantiationMode": 0 + }, + { + "userAdded": false, + "type": "UnityEngine.ComputeShader", + "defaultInstantiationMode": 1 + }, + { + "userAdded": false, + "type": "UnityEngine.Cubemap", + "defaultInstantiationMode": 0 + }, + { + "userAdded": false, + "type": "UnityEngine.GameObject", + "defaultInstantiationMode": 0 + }, + { + "userAdded": false, + "type": "UnityEditor.LightingDataAsset", + "defaultInstantiationMode": 0 + }, + { + "userAdded": false, + "type": "UnityEngine.LightingSettings", + "defaultInstantiationMode": 0 + }, + { + "userAdded": false, + "type": "UnityEngine.Material", + "defaultInstantiationMode": 0 + }, + { + "userAdded": false, + "type": "UnityEditor.MonoScript", + "defaultInstantiationMode": 1 + }, + { + "userAdded": false, + "type": "UnityEngine.PhysicMaterial", + "defaultInstantiationMode": 0 + }, + { + "userAdded": false, + "type": "UnityEngine.PhysicsMaterial2D", + "defaultInstantiationMode": 0 + }, + { + "userAdded": false, + "type": "UnityEngine.Rendering.PostProcessing.PostProcessProfile", + "defaultInstantiationMode": 0 + }, + { + "userAdded": false, + "type": "UnityEngine.Rendering.PostProcessing.PostProcessResources", + "defaultInstantiationMode": 0 + }, + { + "userAdded": false, + "type": "UnityEngine.Rendering.VolumeProfile", + "defaultInstantiationMode": 0 + }, + { + "userAdded": false, + "type": "UnityEditor.SceneAsset", + "defaultInstantiationMode": 1 + }, + { + "userAdded": false, + "type": "UnityEngine.Shader", + "defaultInstantiationMode": 1 + }, + { + "userAdded": false, + "type": "UnityEngine.ShaderVariantCollection", + "defaultInstantiationMode": 1 + }, + { + "userAdded": false, + "type": "UnityEngine.Texture", + "defaultInstantiationMode": 0 + }, + { + "userAdded": false, + "type": "UnityEngine.Texture2D", + "defaultInstantiationMode": 0 + }, + { + "userAdded": false, + "type": "UnityEngine.Timeline.TimelineAsset", + "defaultInstantiationMode": 0 + } + ], + "defaultDependencyTypeInfo": { + "userAdded": false, + "type": "", + "defaultInstantiationMode": 1 + }, + "newSceneOverride": 0 +} \ No newline at end of file diff --git a/聊天系统课程代码/Client/Unity/ProjectSettings/TagManager.asset b/聊天系统课程代码/Client/Unity/ProjectSettings/TagManager.asset new file mode 100644 index 0000000..1c92a78 --- /dev/null +++ b/聊天系统课程代码/Client/Unity/ProjectSettings/TagManager.asset @@ -0,0 +1,43 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!78 &1 +TagManager: + serializedVersion: 2 + tags: [] + layers: + - Default + - TransparentFX + - Ignore Raycast + - + - Water + - UI + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + m_SortingLayers: + - name: Default + uniqueID: 0 + locked: 0 diff --git a/聊天系统课程代码/Client/Unity/ProjectSettings/TimeManager.asset b/聊天系统课程代码/Client/Unity/ProjectSettings/TimeManager.asset new file mode 100644 index 0000000..558a017 --- /dev/null +++ b/聊天系统课程代码/Client/Unity/ProjectSettings/TimeManager.asset @@ -0,0 +1,9 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!5 &1 +TimeManager: + m_ObjectHideFlags: 0 + Fixed Timestep: 0.02 + Maximum Allowed Timestep: 0.33333334 + m_TimeScale: 1 + Maximum Particle Timestep: 0.03 diff --git a/聊天系统课程代码/Client/Unity/ProjectSettings/UnityConnectSettings.asset b/聊天系统课程代码/Client/Unity/ProjectSettings/UnityConnectSettings.asset new file mode 100644 index 0000000..a88bee0 --- /dev/null +++ b/聊天系统课程代码/Client/Unity/ProjectSettings/UnityConnectSettings.asset @@ -0,0 +1,36 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!310 &1 +UnityConnectSettings: + m_ObjectHideFlags: 0 + serializedVersion: 1 + m_Enabled: 0 + m_TestMode: 0 + m_EventOldUrl: https://api.uca.cloud.unity3d.com/v1/events + m_EventUrl: https://cdp.cloud.unity3d.com/v1/events + m_ConfigUrl: https://config.uca.cloud.unity3d.com + m_DashboardUrl: https://dashboard.unity3d.com + m_TestInitMode: 0 + CrashReportingSettings: + m_EventUrl: https://perf-events.cloud.unity3d.com + m_Enabled: 0 + m_LogBufferSize: 10 + m_CaptureEditorExceptions: 1 + UnityPurchasingSettings: + m_Enabled: 0 + m_TestMode: 0 + UnityAnalyticsSettings: + m_Enabled: 0 + m_TestMode: 0 + m_InitializeOnStartup: 1 + m_PackageRequiringCoreStatsPresent: 0 + UnityAdsSettings: + m_Enabled: 0 + m_InitializeOnStartup: 1 + m_TestMode: 0 + m_IosGameId: + m_AndroidGameId: + m_GameIds: {} + m_GameId: + PerformanceReportingSettings: + m_Enabled: 0 diff --git a/聊天系统课程代码/Client/Unity/ProjectSettings/VFXManager.asset b/聊天系统课程代码/Client/Unity/ProjectSettings/VFXManager.asset new file mode 100644 index 0000000..3a95c98 --- /dev/null +++ b/聊天系统课程代码/Client/Unity/ProjectSettings/VFXManager.asset @@ -0,0 +1,12 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!937362698 &1 +VFXManager: + m_ObjectHideFlags: 0 + m_IndirectShader: {fileID: 0} + m_CopyBufferShader: {fileID: 0} + m_SortShader: {fileID: 0} + m_StripUpdateShader: {fileID: 0} + m_RenderPipeSettingsPath: + m_FixedTimeStep: 0.016666668 + m_MaxDeltaTime: 0.05 diff --git a/聊天系统课程代码/Client/Unity/ProjectSettings/VersionControlSettings.asset b/聊天系统课程代码/Client/Unity/ProjectSettings/VersionControlSettings.asset new file mode 100644 index 0000000..dca2881 --- /dev/null +++ b/聊天系统课程代码/Client/Unity/ProjectSettings/VersionControlSettings.asset @@ -0,0 +1,8 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!890905787 &1 +VersionControlSettings: + m_ObjectHideFlags: 0 + m_Mode: Visible Meta Files + m_CollabEditorSettings: + inProgressEnabled: 1 diff --git a/聊天系统课程代码/Client/Unity/ProjectSettings/XRSettings.asset b/聊天系统课程代码/Client/Unity/ProjectSettings/XRSettings.asset new file mode 100644 index 0000000..482590c --- /dev/null +++ b/聊天系统课程代码/Client/Unity/ProjectSettings/XRSettings.asset @@ -0,0 +1,10 @@ +{ + "m_SettingKeys": [ + "VR Device Disabled", + "VR Device User Alert" + ], + "m_SettingValues": [ + "False", + "False" + ] +} \ No newline at end of file diff --git a/聊天系统课程代码/Client/Unity/UserSettings/EditorUserSettings.asset b/聊天系统课程代码/Client/Unity/UserSettings/EditorUserSettings.asset new file mode 100644 index 0000000..b9a0f7d --- /dev/null +++ b/聊天系统课程代码/Client/Unity/UserSettings/EditorUserSettings.asset @@ -0,0 +1,29 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!162 &1 +EditorUserSettings: + m_ObjectHideFlags: 0 + serializedVersion: 4 + m_ConfigSettings: + RecentlyUsedSceneGuid-0: + value: 5a5757560101590a5d0c0e24427b5d44434e4c7a7b7a23677f2b4565b7b5353a + flags: 0 + vcSharedLogLevel: + value: 0d5e400f0650 + flags: 0 + m_VCAutomaticAdd: 1 + m_VCDebugCom: 0 + m_VCDebugCmd: 0 + m_VCDebugOut: 0 + m_SemanticMergeMode: 2 + m_DesiredImportWorkerCount: 2 + m_StandbyImportWorkerCount: 2 + m_IdleImportWorkerShutdownDelay: 60000 + m_VCShowFailedCheckout: 1 + m_VCOverwriteFailedCheckoutAssets: 1 + m_VCProjectOverlayIcons: 1 + m_VCHierarchyOverlayIcons: 1 + m_VCOtherOverlayIcons: 1 + m_VCAllowAsyncUpdate: 1 + m_VCScanLocalPackagesOnConnect: 1 + m_ArtifactGarbageCollection: 1 diff --git a/聊天系统课程代码/Client/Unity/UserSettings/Search.index b/聊天系统课程代码/Client/Unity/UserSettings/Search.index new file mode 100644 index 0000000..4b70da6 --- /dev/null +++ b/聊天系统课程代码/Client/Unity/UserSettings/Search.index @@ -0,0 +1,13 @@ +{ + "name": "Assets", + "roots": ["Assets"], + "includes": [], + "excludes": ["Assets/Temp/", "Assets/External/"], + "options": { + "types": true, + "properties": true, + "extended": false, + "dependencies": false + }, + "baseScore": 999 +} \ No newline at end of file diff --git a/聊天系统课程代码/Client/Unity/UserSettings/Search.settings b/聊天系统课程代码/Client/Unity/UserSettings/Search.settings new file mode 100644 index 0000000..b0d87b2 --- /dev/null +++ b/聊天系统课程代码/Client/Unity/UserSettings/Search.settings @@ -0,0 +1,76 @@ +trackSelection = true +refreshSearchWindowsInPlayMode = false +pickerAdvancedUI = false +fetchPreview = true +defaultFlags = 0 +keepOpen = true +queryFolder = "Assets" +onBoardingDoNotAskAgain = true +showPackageIndexes = false +showStatusBar = false +scopes = { +} +providers = { + asset = { + active = true + priority = 25 + defaultAction = null + } + scene = { + active = true + priority = 50 + defaultAction = null + } + adb = { + active = false + priority = 2500 + defaultAction = null + } + find = { + active = true + priority = 25 + defaultAction = null + } + packages = { + active = false + priority = 90 + defaultAction = null + } + store = { + active = false + priority = 100 + defaultAction = null + } + performance = { + active = false + priority = 100 + defaultAction = null + } + profilermarkers = { + active = false + priority = 100 + defaultAction = null + } + log = { + active = false + priority = 210 + defaultAction = null + } +} +objectSelectors = { +} +recentSearches = [ +] +searchItemFavorites = [ +] +savedSearchesSortOrder = 0 +showSavedSearchPanel = false +hideTabs = false +expandedQueries = [ +] +queryBuilder = true +ignoredProperties = "id;name;classname;imagecontentshash" +helperWidgetCurrentArea = "all" +disabledIndexers = "" +minIndexVariations = 2 +findProviderIndexHelper = true \ No newline at end of file diff --git a/聊天系统课程代码/Config/.DS_Store b/聊天系统课程代码/Config/.DS_Store new file mode 100644 index 0000000..044b265 Binary files /dev/null and b/聊天系统课程代码/Config/.DS_Store differ diff --git a/聊天系统课程代码/Config/Binary/MachineConfigData.bytes b/聊天系统课程代码/Config/Binary/MachineConfigData.bytes new file mode 100644 index 0000000..d4ebe57 --- /dev/null +++ b/聊天系统课程代码/Config/Binary/MachineConfigData.bytes @@ -0,0 +1,2 @@ + +# 127.0.0.1 127.0.0.1" 127.0.0.1 \ No newline at end of file diff --git a/聊天系统课程代码/Config/Binary/ProcessConfigData.bytes b/聊天系统课程代码/Config/Binary/ProcessConfigData.bytes new file mode 100644 index 0000000..b9c2dfd --- /dev/null +++ b/聊天系统课程代码/Config/Binary/ProcessConfigData.bytes @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/聊天系统课程代码/Config/Binary/SceneConfigData.bytes b/聊天系统课程代码/Config/Binary/SceneConfigData.bytes new file mode 100644 index 0000000..e9d2255 --- /dev/null +++ b/聊天系统课程代码/Config/Binary/SceneConfigData.bytes @@ -0,0 +1,4 @@ + +(" MultiThread*Gate2KCP8@UH +" MultiThread*Chat@UH +" MultiThread*Map@UH \ No newline at end of file diff --git a/聊天系统课程代码/Config/Binary/WorldConfigData.bytes b/聊天系统课程代码/Config/Binary/WorldConfigData.bytes new file mode 100644 index 0000000..beded13 --- /dev/null +++ b/聊天系统课程代码/Config/Binary/WorldConfigData.bytes @@ -0,0 +1,2 @@ + +$ 测试服" fantasy_main*MongoDB \ No newline at end of file diff --git a/聊天系统课程代码/Config/Excel/.DS_Store b/聊天系统课程代码/Config/Excel/.DS_Store new file mode 100644 index 0000000..f8ddafa Binary files /dev/null and b/聊天系统课程代码/Config/Excel/.DS_Store differ diff --git a/聊天系统课程代码/Config/Excel/Custom.txt b/聊天系统课程代码/Config/Excel/Custom.txt new file mode 100644 index 0000000..fd90a9b --- /dev/null +++ b/聊天系统课程代码/Config/Excel/Custom.txt @@ -0,0 +1 @@ +// 自定义导出配置文件,用于配置自定义导出自定义程序的路径 diff --git a/聊天系统课程代码/Config/Excel/Server/MachineConfig.xlsx b/聊天系统课程代码/Config/Excel/Server/MachineConfig.xlsx new file mode 100644 index 0000000..999e939 Binary files /dev/null and b/聊天系统课程代码/Config/Excel/Server/MachineConfig.xlsx differ diff --git a/聊天系统课程代码/Config/Excel/Server/ProcessConfig.xlsx b/聊天系统课程代码/Config/Excel/Server/ProcessConfig.xlsx new file mode 100644 index 0000000..001235a Binary files /dev/null and b/聊天系统课程代码/Config/Excel/Server/ProcessConfig.xlsx differ diff --git a/聊天系统课程代码/Config/Excel/Server/SceneConfig.xlsx b/聊天系统课程代码/Config/Excel/Server/SceneConfig.xlsx new file mode 100644 index 0000000..f493c06 Binary files /dev/null and b/聊天系统课程代码/Config/Excel/Server/SceneConfig.xlsx differ diff --git a/聊天系统课程代码/Config/Excel/Server/WorldConfig.xlsx b/聊天系统课程代码/Config/Excel/Server/WorldConfig.xlsx new file mode 100644 index 0000000..8194c9a Binary files /dev/null and b/聊天系统课程代码/Config/Excel/Server/WorldConfig.xlsx differ diff --git a/聊天系统课程代码/Config/Excel/Version.txt b/聊天系统课程代码/Config/Excel/Version.txt new file mode 100644 index 0000000..9260318 --- /dev/null +++ b/聊天系统课程代码/Config/Excel/Version.txt @@ -0,0 +1 @@ +{"WorksheetNames":["ProcessConfig","MachineConfig","WorldConfig","SceneConfig","SceneTypeConfig"],"Tables":{"MachineConfig":1727164776000,"SceneConfig":1731926283644,"WorldConfig":1727164776000,"ProcessConfig":1727164776000}} \ No newline at end of file diff --git a/聊天系统课程代码/Config/Json/.DS_Store b/聊天系统课程代码/Config/Json/.DS_Store new file mode 100644 index 0000000..79f2146 Binary files /dev/null and b/聊天系统课程代码/Config/Json/.DS_Store differ diff --git a/聊天系统课程代码/Config/Json/Server/MachineConfigData.Json b/聊天系统课程代码/Config/Json/Server/MachineConfigData.Json new file mode 100644 index 0000000..f56f98e --- /dev/null +++ b/聊天系统课程代码/Config/Json/Server/MachineConfigData.Json @@ -0,0 +1,3 @@ +{"List":[ +{"Id":1,"OuterIP":"127.0.0.1","OuterBindIP":"127.0.0.1","InnerBindIP":"127.0.0.1"} +]} diff --git a/聊天系统课程代码/Config/Json/Server/ProcessConfigData.Json b/聊天系统课程代码/Config/Json/Server/ProcessConfigData.Json new file mode 100644 index 0000000..a05a13c --- /dev/null +++ b/聊天系统课程代码/Config/Json/Server/ProcessConfigData.Json @@ -0,0 +1,3 @@ +{"List":[ +{"Id":1,"MachineId":1,"StartupGroup":0} +]} diff --git a/聊天系统课程代码/Config/Json/Server/SceneConfigData.Json b/聊天系统课程代码/Config/Json/Server/SceneConfigData.Json new file mode 100644 index 0000000..f8bb89b --- /dev/null +++ b/聊天系统课程代码/Config/Json/Server/SceneConfigData.Json @@ -0,0 +1,5 @@ +{"List":[ +{"Id":1001,"ProcessConfigId":1,"WorldConfigId":1,"SceneRuntimeType":"MultiThread","SceneTypeString":"Gate","NetworkProtocol":"KCP","OuterPort":20000,"InnerPort":11000,"SceneType":3}, +{"Id":1002,"ProcessConfigId":1,"WorldConfigId":1,"SceneRuntimeType":"MultiThread","SceneTypeString":"Chat","NetworkProtocol":null,"OuterPort":0,"InnerPort":11001,"SceneType":8}, +{"Id":1003,"ProcessConfigId":1,"WorldConfigId":1,"SceneRuntimeType":"MultiThread","SceneTypeString":"Map","NetworkProtocol":null,"OuterPort":0,"InnerPort":11002,"SceneType":4} +]} diff --git a/聊天系统课程代码/Config/Json/Server/WorldConfigData.Json b/聊天系统课程代码/Config/Json/Server/WorldConfigData.Json new file mode 100644 index 0000000..60dd090 --- /dev/null +++ b/聊天系统课程代码/Config/Json/Server/WorldConfigData.Json @@ -0,0 +1,3 @@ +{"List":[ +{"Id":1,"WorldName":"测试服","DbConnection":null,"DbName":"fantasy_main","DbType":"MongoDB"} +]} diff --git a/聊天系统课程代码/Config/NetworkProtocol/.DS_Store b/聊天系统课程代码/Config/NetworkProtocol/.DS_Store new file mode 100644 index 0000000..4a1744c Binary files /dev/null and b/聊天系统课程代码/Config/NetworkProtocol/.DS_Store differ diff --git a/聊天系统课程代码/Config/NetworkProtocol/Inner/InnerMessage.proto b/聊天系统课程代码/Config/NetworkProtocol/Inner/InnerMessage.proto new file mode 100644 index 0000000..ebd89b7 --- /dev/null +++ b/聊天系统课程代码/Config/NetworkProtocol/Inner/InnerMessage.proto @@ -0,0 +1,42 @@ +syntax = "proto3"; +package Sining.Message; +/// Gate登录到Chat服务器 +message G2Chat_LoginRequest // IRouteRequest,Chat2G_LoginResponse +{ + string UserName = 1; + long UnitId = 2; + long GateRouteId = 3; +} +message Chat2G_LoginResponse // IRouteResponse +{ + int64 ChatRouteId = 1; +} +/// Gate通知Chat服务器下线 +message G2Chat_OfflineRequest // IRouteRequest,Chat2G_OfflineResponse +{ + +} +message Chat2G_OfflineResponse // IRouteResponse +{ + +} +/// Chat通知Gate发送一个全服广播的聊天信息 +message Chat2G_ChatMessage // IRouteMessage +{ + ChatInfoTree ChatInfoTree = 1; +} +/// 其他服务器发送聊天消息到Chat +message Other2Chat_ChatMessage // IRouteMessage +{ + ChatInfoTree ChatInfoTree = 1; +} +/// Gate登录到Map服务器 +message G2M_LoginRequest // IRouteRequest,M2G_LoginResponse +{ + long ChatUnitRouteId = 1; +} +message M2G_LoginResponse // IRouteResponse +{ + int64 MapRouteId = 1; +} + diff --git a/聊天系统课程代码/Config/NetworkProtocol/OpCode.Cache b/聊天系统课程代码/Config/NetworkProtocol/OpCode.Cache new file mode 100644 index 0000000..9e26dfe --- /dev/null +++ b/聊天系统课程代码/Config/NetworkProtocol/OpCode.Cache @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/聊天系统课程代码/Config/NetworkProtocol/Outer/OuterMessage.proto b/聊天系统课程代码/Config/NetworkProtocol/Outer/OuterMessage.proto new file mode 100644 index 0000000..08e0e08 --- /dev/null +++ b/聊天系统课程代码/Config/NetworkProtocol/Outer/OuterMessage.proto @@ -0,0 +1,102 @@ +syntax = "proto3"; +package Fantasy.Network.Message; +// 协议分为: +// ProtoBuf:可以在Outer和Inner文件里使用。 +// MemoryPack:可以在Outer和Inner文件里使用。 +// Bson:仅支持在Inner文件里使用。 +// 使用方式: +// 在message协议上方添加// Protocol+空格+协议名字 +// 例如:// Protocol ProtoBuf 或 // Protocol MemoryPack +/// 登录游戏 +message C2G_LoginRequest // IRequest,G2C_LoginResponse +{ + string UserName = 1; +} +message G2C_LoginResponse // IResponse +{ + +} +/// 退出游戏 +message C2G_ExitRequest // IRequest,G2C_ExitResponse +{ + +} +message G2C_ExitResponse // IResponse +{ + +} +/// 发送一个聊天消息给Chat服务器,中间是经过Gate中转的 +message C2Chat_SendMessageRequest // ICustomRouteRequest,Chat2C_SendMessageResponse,ChatRoute +{ + ChatInfoTree ChatInfoTree = 1; +} +message Chat2C_SendMessageResponse // ICustomRouteResponse +{ + +} +// 该消息是Chat发送给Gate服务器,让Gate服务器自动转发到客户端 +message Chat2C_Message // ICustomRouteMessage,ChatRoute +{ + ChatInfoTree ChatInfoTree = 1; +} +/// 聊天消息树 +message ChatInfoTree +{ + int32 ChatChannelType = 1; // 频道的类型 + int64 ChatChannelId = 2; // 频道的ID + int64 UnitId = 3; // 发送人的UnitId + string UserName = 4; // 发送人的名字 + repeated int64 Target = 5; // 接收聊天信息的目标数组 + repeated ChatInfoNode Node = 6; // 聊天节点 +} +/// 聊天信息节点 +message ChatInfoNode +{ + int32 ChatNodeType = 1; // 节点类型(例如:超链接、普通的内容、表情...) + int32 ChatNodeEvent = 2; // 节点分发事件的类型(例如:点击某个字打开某个UI或者执行某些操作) + string Content = 3; // 信息内容 + string Color = 4; // 表示这个内容的颜色 + byte[] Data = 5; // 表示附加的一些数据 +} +/// 聊天位置信息节点 +message ChatPositionNode +{ + string MapName = 1; + float PosX = 2; + float PosY = 3; + float PosZ = 4; +} +/// 聊天位置信息节点 +message ChatOpenUINode +{ + string UIName = 1; +} +/// 聊天连接信息节点 +message ChatLinkNode +{ + string Link = 1; +} +/// 装备信息实体 +message Item +{ + string Level = 1; + string Name = 2; + string HP = 3; + string MP = 4; +} + + + + + + + + + + + + + + + + diff --git a/聊天系统课程代码/Config/NetworkProtocol/RouteType.Config b/聊天系统课程代码/Config/NetworkProtocol/RouteType.Config new file mode 100644 index 0000000..66082cf --- /dev/null +++ b/聊天系统课程代码/Config/NetworkProtocol/RouteType.Config @@ -0,0 +1,3 @@ +// Route协议定义(需要定义1000以上、因为1000以内的框架预留) +GateRoute = 1001 // Gate +ChatRoute = 1002 // Chat \ No newline at end of file diff --git a/聊天系统课程代码/NuGet/.DS_Store b/聊天系统课程代码/NuGet/.DS_Store new file mode 100644 index 0000000..c0febfa Binary files /dev/null and b/聊天系统课程代码/NuGet/.DS_Store differ diff --git a/聊天系统课程代码/NuGet/Config/.DS_Store b/聊天系统课程代码/NuGet/Config/.DS_Store new file mode 100644 index 0000000..96a7641 Binary files /dev/null and b/聊天系统课程代码/NuGet/Config/.DS_Store differ diff --git a/聊天系统课程代码/NuGet/Config/Config.csproj b/聊天系统课程代码/NuGet/Config/Config.csproj new file mode 100644 index 0000000..42e8eb9 --- /dev/null +++ b/聊天系统课程代码/NuGet/Config/Config.csproj @@ -0,0 +1,13 @@ + + + + net8.0 + enable + enable + + + + + + + diff --git a/聊天系统课程代码/NuGet/Config/Tools/.DS_Store b/聊天系统课程代码/NuGet/Config/Tools/.DS_Store new file mode 100644 index 0000000..a3512b8 Binary files /dev/null and b/聊天系统课程代码/NuGet/Config/Tools/.DS_Store differ diff --git a/聊天系统课程代码/NuGet/Config/Tools/Exporter/.DS_Store b/聊天系统课程代码/NuGet/Config/Tools/Exporter/.DS_Store new file mode 100644 index 0000000..070ea80 Binary files /dev/null and b/聊天系统课程代码/NuGet/Config/Tools/Exporter/.DS_Store differ diff --git a/聊天系统课程代码/NuGet/Config/Tools/Exporter/ConfigTable/Excel/Custom.txt b/聊天系统课程代码/NuGet/Config/Tools/Exporter/ConfigTable/Excel/Custom.txt new file mode 100644 index 0000000..fd90a9b --- /dev/null +++ b/聊天系统课程代码/NuGet/Config/Tools/Exporter/ConfigTable/Excel/Custom.txt @@ -0,0 +1 @@ +// 自定义导出配置文件,用于配置自定义导出自定义程序的路径 diff --git a/聊天系统课程代码/NuGet/Config/Tools/Exporter/ConfigTable/Excel/Server/MachineConfig.xlsx b/聊天系统课程代码/NuGet/Config/Tools/Exporter/ConfigTable/Excel/Server/MachineConfig.xlsx new file mode 100644 index 0000000..999e939 Binary files /dev/null and b/聊天系统课程代码/NuGet/Config/Tools/Exporter/ConfigTable/Excel/Server/MachineConfig.xlsx differ diff --git a/聊天系统课程代码/NuGet/Config/Tools/Exporter/ConfigTable/Excel/Server/ProcessConfig.xlsx b/聊天系统课程代码/NuGet/Config/Tools/Exporter/ConfigTable/Excel/Server/ProcessConfig.xlsx new file mode 100644 index 0000000..001235a Binary files /dev/null and b/聊天系统课程代码/NuGet/Config/Tools/Exporter/ConfigTable/Excel/Server/ProcessConfig.xlsx differ diff --git a/聊天系统课程代码/NuGet/Config/Tools/Exporter/ConfigTable/Excel/Server/SceneConfig.xlsx b/聊天系统课程代码/NuGet/Config/Tools/Exporter/ConfigTable/Excel/Server/SceneConfig.xlsx new file mode 100644 index 0000000..a4ca05e Binary files /dev/null and b/聊天系统课程代码/NuGet/Config/Tools/Exporter/ConfigTable/Excel/Server/SceneConfig.xlsx differ diff --git a/聊天系统课程代码/NuGet/Config/Tools/Exporter/ConfigTable/Excel/Server/WorldConfig.xlsx b/聊天系统课程代码/NuGet/Config/Tools/Exporter/ConfigTable/Excel/Server/WorldConfig.xlsx new file mode 100644 index 0000000..8194c9a Binary files /dev/null and b/聊天系统课程代码/NuGet/Config/Tools/Exporter/ConfigTable/Excel/Server/WorldConfig.xlsx differ diff --git a/聊天系统课程代码/NuGet/Config/Tools/Exporter/ConfigTable/Excel/Version.txt b/聊天系统课程代码/NuGet/Config/Tools/Exporter/ConfigTable/Excel/Version.txt new file mode 100644 index 0000000..1877ad8 --- /dev/null +++ b/聊天系统课程代码/NuGet/Config/Tools/Exporter/ConfigTable/Excel/Version.txt @@ -0,0 +1 @@ +{"WorksheetNames":["MachineConfig","ProcessConfig","WorldConfig","SceneConfig","SceneTypeConfig"],"Tables":{"MachineConfig":1725984682557,"SceneConfig":1726083372000,"WorldConfig":1724007858627,"ProcessConfig":1725195494442}} \ No newline at end of file diff --git a/聊天系统课程代码/NuGet/Config/Tools/Exporter/ConfigTable/Json/Server/MachineConfigData.Json b/聊天系统课程代码/NuGet/Config/Tools/Exporter/ConfigTable/Json/Server/MachineConfigData.Json new file mode 100644 index 0000000..f56f98e --- /dev/null +++ b/聊天系统课程代码/NuGet/Config/Tools/Exporter/ConfigTable/Json/Server/MachineConfigData.Json @@ -0,0 +1,3 @@ +{"List":[ +{"Id":1,"OuterIP":"127.0.0.1","OuterBindIP":"127.0.0.1","InnerBindIP":"127.0.0.1"} +]} diff --git a/聊天系统课程代码/NuGet/Config/Tools/Exporter/ConfigTable/Json/Server/ProcessConfigData.Json b/聊天系统课程代码/NuGet/Config/Tools/Exporter/ConfigTable/Json/Server/ProcessConfigData.Json new file mode 100644 index 0000000..a05a13c --- /dev/null +++ b/聊天系统课程代码/NuGet/Config/Tools/Exporter/ConfigTable/Json/Server/ProcessConfigData.Json @@ -0,0 +1,3 @@ +{"List":[ +{"Id":1,"MachineId":1,"StartupGroup":0} +]} diff --git a/聊天系统课程代码/NuGet/Config/Tools/Exporter/ConfigTable/Json/Server/SceneConfigData.Json b/聊天系统课程代码/NuGet/Config/Tools/Exporter/ConfigTable/Json/Server/SceneConfigData.Json new file mode 100644 index 0000000..44996e7 --- /dev/null +++ b/聊天系统课程代码/NuGet/Config/Tools/Exporter/ConfigTable/Json/Server/SceneConfigData.Json @@ -0,0 +1,6 @@ +{"List":[ +{"Id":1001,"ProcessConfigId":1,"WorldConfigId":1,"SceneRuntimeType":"MultiThread","SceneTypeString":"Addressable","NetworkProtocol":null,"OuterPort":0,"InnerPort":11001,"SceneType":2}, +{"Id":1002,"ProcessConfigId":1,"WorldConfigId":1,"SceneRuntimeType":"MultiThread","SceneTypeString":"Gate","NetworkProtocol":"KCP","OuterPort":20000,"InnerPort":11002,"SceneType":3}, +{"Id":1003,"ProcessConfigId":1,"WorldConfigId":1,"SceneRuntimeType":"MultiThread","SceneTypeString":"Map","NetworkProtocol":null,"OuterPort":0,"InnerPort":11003,"SceneType":4}, +{"Id":1004,"ProcessConfigId":1,"WorldConfigId":1,"SceneRuntimeType":"MultiThread","SceneTypeString":"Chat","NetworkProtocol":null,"OuterPort":0,"InnerPort":11004,"SceneType":8} +]} diff --git a/聊天系统课程代码/NuGet/Config/Tools/Exporter/ConfigTable/Json/Server/WorldConfigData.Json b/聊天系统课程代码/NuGet/Config/Tools/Exporter/ConfigTable/Json/Server/WorldConfigData.Json new file mode 100644 index 0000000..60dd090 --- /dev/null +++ b/聊天系统课程代码/NuGet/Config/Tools/Exporter/ConfigTable/Json/Server/WorldConfigData.Json @@ -0,0 +1,3 @@ +{"List":[ +{"Id":1,"WorldName":"测试服","DbConnection":null,"DbName":"fantasy_main","DbType":"MongoDB"} +]} diff --git a/聊天系统课程代码/NuGet/Config/Tools/Exporter/ConfigTable/NetworkProtocol/Inner/InnerMessage.proto b/聊天系统课程代码/NuGet/Config/Tools/Exporter/ConfigTable/NetworkProtocol/Inner/InnerMessage.proto new file mode 100644 index 0000000..a8b51b8 --- /dev/null +++ b/聊天系统课程代码/NuGet/Config/Tools/Exporter/ConfigTable/NetworkProtocol/Inner/InnerMessage.proto @@ -0,0 +1,27 @@ +syntax = "proto3"; +package Sining.Message; +message G2A_TestRequest // IRouteRequest,G2A_TestResponse +{ + +} +message G2A_TestResponse // IRouteResponse +{ + +} +message G2M_RequestAddressableId // IRouteRequest,M2G_ResponseAddressableId +{ + +} +message M2G_ResponseAddressableId // IRouteResponse +{ + int64 AddressableId = 1; // Map服务器返回的AddressableId +} +/// 通知Chat服务器创建一个RouteId +message G2Chat_CreateRouteRequest // IRouteRequest,Chat2G_CreateRouteResponse +{ + int64 GateRouteId = 1; +} +message Chat2G_CreateRouteResponse // IRouteResponse +{ + int64 ChatRouteId = 1; +} \ No newline at end of file diff --git a/聊天系统课程代码/NuGet/Config/Tools/Exporter/ConfigTable/NetworkProtocol/OpCode.Cache b/聊天系统课程代码/NuGet/Config/Tools/Exporter/ConfigTable/NetworkProtocol/OpCode.Cache new file mode 100644 index 0000000..9e26dfe --- /dev/null +++ b/聊天系统课程代码/NuGet/Config/Tools/Exporter/ConfigTable/NetworkProtocol/OpCode.Cache @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/聊天系统课程代码/NuGet/Config/Tools/Exporter/ConfigTable/NetworkProtocol/Outer/OuterMessage.proto b/聊天系统课程代码/NuGet/Config/Tools/Exporter/ConfigTable/NetworkProtocol/Outer/OuterMessage.proto new file mode 100644 index 0000000..b036a74 --- /dev/null +++ b/聊天系统课程代码/NuGet/Config/Tools/Exporter/ConfigTable/NetworkProtocol/Outer/OuterMessage.proto @@ -0,0 +1,64 @@ +syntax = "proto3"; +package Fantasy.Network.Message; +// 协议分为: +// ProtoBuf:可以在Outer和Inner文件里使用。 +// MemoryPack:可以在Outer和Inner文件里使用。 +// Bson:仅支持在Inner文件里使用。 +// 使用方式: +// 在message协议上方添加// Protocol+空格+协议名字 +// 例如:// Protocol ProtoBuf 或 // Protocol MemoryPack +message C2G_TestMessage // IMessage +{ + string Tag = 1; +} +message C2G_TestRequest // IRequest,G2C_TestResponse +{ + string Tag = 1; +} +message G2C_TestResponse // IResponse +{ + string Tag = 1; +} +message C2G_CreateAddressableRequest // IRequest,G2C_CreateAddressableResponse +{ + +} +message G2C_CreateAddressableResponse // IResponse +{ + +} +message C2M_TestMessage // IAddressableRouteMessage +{ + string Tag = 1; +} +message C2M_TestRequest // IAddressableRouteRequest,M2C_TestResponse +{ + string Tag = 1; +} +message M2C_TestResponse // IAddressableRouteResponse +{ + string Tag = 1; +} +/// 通知Gate服务器创建一个Chat的Route连接 +message C2G_CreateChatRouteRequest // IRequest,G2C_CreateChatRouteResponse +{ + +} +message G2C_CreateChatRouteResponse // IResponse +{ + +} +/// 发送一个Route消息给Chat +message C2Chat_TestMessage // ICustomRouteMessage,ChatRoute +{ + string Tag = 1; +} +/// 发送一个RPCRoute消息给Chat +message C2Chat_TestMessageRequest // ICustomRouteRequest,Chat2C_TestMessageResponse,ChatRoute +{ + string Tag = 1; +} +message Chat2C_TestMessageResponse // ICustomRouteResponse +{ + string Tag = 1; +} \ No newline at end of file diff --git a/聊天系统课程代码/NuGet/Config/Tools/Exporter/ConfigTable/NetworkProtocol/RouteType.Config b/聊天系统课程代码/NuGet/Config/Tools/Exporter/ConfigTable/NetworkProtocol/RouteType.Config new file mode 100644 index 0000000..66082cf --- /dev/null +++ b/聊天系统课程代码/NuGet/Config/Tools/Exporter/ConfigTable/NetworkProtocol/RouteType.Config @@ -0,0 +1,3 @@ +// Route协议定义(需要定义1000以上、因为1000以内的框架预留) +GateRoute = 1001 // Gate +ChatRoute = 1002 // Chat \ No newline at end of file diff --git a/聊天系统课程代码/NuGet/Config/Tools/Exporter/ConfigTable/README.md b/聊天系统课程代码/NuGet/Config/Tools/Exporter/ConfigTable/README.md new file mode 100644 index 0000000..697ec05 --- /dev/null +++ b/聊天系统课程代码/NuGet/Config/Tools/Exporter/ConfigTable/README.md @@ -0,0 +1,16 @@ +# Fantasy-Net.Config +在Config文件夹中,存放着Fantasy所需的各种配置文件。这些文件涵盖了多个方面。每个配置文件都有其特定的格式和功能,通过精心设计的这些配置文件,开发团队能够快速调整框架参数,以实现更好的游戏体验,从而提升Fantasy的整体质量。 +## Excel文件夹 +里面存放了Fantasy.Net所需的四个Excel配置文件。用户可以利用Fantasy-Net.Exporter工具,依据这四个Excel文件生成相应的JSON文件,以供框架使用。这一过程不仅简化了数据处理,还确保了不同组件之间的无缝对接,使得工作流程更加高效。请确保在导出之前,Excel文件的格式和内容符合要求,以避免产生错误。 +## Json文件夹 +在该目录中存放了Fantasy.Net所需的四个JSON配置文件。用户可以根据这四个文件的模板进行添加或修改配置,以满足具体需求。每个项目的功能说明在相应的Excel文件中有详细描述,方便用户理解和使用这些配置文件。我们建议用户仔细阅读Excel文件中的说明,以确保配置的正确性和有效性。 +## NetworkProtocol文件夹 +存放框架所需定义网络协议的模版和文件夹 +### Inner文件夹 +定义服务器之间的网络协议 +### Outer文件夹 +定义客户端和服务器之间的网络协议 +### RouteType.Config +定义自定义Route协议的配置文件 +## 交流与讨论: +__讨论QQ群 : Fantasy服务器开发交流群 569888673 __ \ No newline at end of file diff --git a/聊天系统课程代码/NuGet/Config/obj/Config.csproj.nuget.dgspec.json b/聊天系统课程代码/NuGet/Config/obj/Config.csproj.nuget.dgspec.json new file mode 100644 index 0000000..fc1553f --- /dev/null +++ b/聊天系统课程代码/NuGet/Config/obj/Config.csproj.nuget.dgspec.json @@ -0,0 +1,73 @@ +{ + "format": 1, + "restore": { + "/Users/fantasy/Code/ServerLessions/Chat/NuGet/Config/Config.csproj": {} + }, + "projects": { + "/Users/fantasy/Code/ServerLessions/Chat/NuGet/Config/Config.csproj": { + "version": "1.0.0", + "restore": { + "projectUniqueName": "/Users/fantasy/Code/ServerLessions/Chat/NuGet/Config/Config.csproj", + "projectName": "Config", + "projectPath": "/Users/fantasy/Code/ServerLessions/Chat/NuGet/Config/Config.csproj", + "packagesPath": "/Users/fantasy/.nuget/packages/", + "outputPath": "/Users/fantasy/Code/ServerLessions/Chat/NuGet/Config/obj/", + "projectStyle": "PackageReference", + "UsingMicrosoftNETSdk": false, + "configFilePaths": [ + "/Users/fantasy/.nuget/NuGet/NuGet.Config" + ], + "originalTargetFrameworks": [ + "net8.0" + ], + "sources": { + "https://api.nuget.org/v3/index.json": {} + }, + "frameworks": { + "net8.0": { + "targetAlias": "net8.0", + "projectReferences": {} + } + }, + "warningProperties": { + "warnAsError": [ + "NU1605" + ] + }, + "restoreAuditProperties": { + "enableAudit": "true", + "auditLevel": "low", + "auditMode": "all" + } + }, + "frameworks": { + "net8.0": { + "targetAlias": "net8.0", + "dependencies": { + "Fantasy-Net.Config": { + "target": "Package", + "version": "[2024.1.4, )" + } + }, + "imports": [ + "net461", + "net462", + "net47", + "net471", + "net472", + "net48", + "net481" + ], + "assetTargetFallback": true, + "warn": true, + "frameworkReferences": { + "Microsoft.NETCore.App": { + "privateAssets": "all" + } + }, + "runtimeIdentifierGraphPath": "/usr/local/share/dotnet/sdk/9.0.100/PortableRuntimeIdentifierGraph.json" + } + } + } + } +} \ No newline at end of file diff --git a/聊天系统课程代码/NuGet/Config/obj/Config.csproj.nuget.g.props b/聊天系统课程代码/NuGet/Config/obj/Config.csproj.nuget.g.props new file mode 100644 index 0000000..e2edc37 --- /dev/null +++ b/聊天系统课程代码/NuGet/Config/obj/Config.csproj.nuget.g.props @@ -0,0 +1,18 @@ + + + + True + NuGet + $(MSBuildThisFileDirectory)project.assets.json + /Users/fantasy/.nuget/packages/ + /Users/fantasy/.nuget/packages/ + PackageReference + 6.12.0 + + + + + + /Users/fantasy/.nuget/packages/fantasy-net.config/2024.1.4 + + \ No newline at end of file diff --git a/聊天系统课程代码/NuGet/Config/obj/Config.csproj.nuget.g.targets b/聊天系统课程代码/NuGet/Config/obj/Config.csproj.nuget.g.targets new file mode 100644 index 0000000..a660f7f --- /dev/null +++ b/聊天系统课程代码/NuGet/Config/obj/Config.csproj.nuget.g.targets @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/聊天系统课程代码/NuGet/Config/obj/Debug/net8.0/.NETCoreApp,Version=v8.0.AssemblyAttributes.cs b/聊天系统课程代码/NuGet/Config/obj/Debug/net8.0/.NETCoreApp,Version=v8.0.AssemblyAttributes.cs new file mode 100644 index 0000000..2217181 --- /dev/null +++ b/聊天系统课程代码/NuGet/Config/obj/Debug/net8.0/.NETCoreApp,Version=v8.0.AssemblyAttributes.cs @@ -0,0 +1,4 @@ +// +using System; +using System.Reflection; +[assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute(".NETCoreApp,Version=v8.0", FrameworkDisplayName = ".NET 8.0")] diff --git a/聊天系统课程代码/NuGet/Config/obj/Debug/net8.0/Config.AssemblyInfo.cs b/聊天系统课程代码/NuGet/Config/obj/Debug/net8.0/Config.AssemblyInfo.cs new file mode 100644 index 0000000..a3c2705 --- /dev/null +++ b/聊天系统课程代码/NuGet/Config/obj/Debug/net8.0/Config.AssemblyInfo.cs @@ -0,0 +1,22 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +using System; +using System.Reflection; + +[assembly: System.Reflection.AssemblyCompanyAttribute("Config")] +[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")] +[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")] +[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0")] +[assembly: System.Reflection.AssemblyProductAttribute("Config")] +[assembly: System.Reflection.AssemblyTitleAttribute("Config")] +[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")] + +// 由 MSBuild WriteCodeFragment 类生成。 + diff --git a/聊天系统课程代码/NuGet/Config/obj/Debug/net8.0/Config.AssemblyInfoInputs.cache b/聊天系统课程代码/NuGet/Config/obj/Debug/net8.0/Config.AssemblyInfoInputs.cache new file mode 100644 index 0000000..0727707 --- /dev/null +++ b/聊天系统课程代码/NuGet/Config/obj/Debug/net8.0/Config.AssemblyInfoInputs.cache @@ -0,0 +1 @@ +31cc5c8b5122dd214e0621748a2b62641e9f69993c09f22886943de8b2575cdb diff --git a/聊天系统课程代码/NuGet/Config/obj/Debug/net8.0/Config.GeneratedMSBuildEditorConfig.editorconfig b/聊天系统课程代码/NuGet/Config/obj/Debug/net8.0/Config.GeneratedMSBuildEditorConfig.editorconfig new file mode 100644 index 0000000..8da0b4d --- /dev/null +++ b/聊天系统课程代码/NuGet/Config/obj/Debug/net8.0/Config.GeneratedMSBuildEditorConfig.editorconfig @@ -0,0 +1,15 @@ +is_global = true +build_property.TargetFramework = net8.0 +build_property.TargetPlatformMinVersion = +build_property.UsingMicrosoftNETSdkWeb = +build_property.ProjectTypeGuids = +build_property.InvariantGlobalization = +build_property.PlatformNeutralAssembly = +build_property.EnforceExtendedAnalyzerRules = +build_property._SupportedPlatformList = Linux,macOS,Windows +build_property.RootNamespace = Config +build_property.ProjectDir = /Users/fantasy/Code/ServerLessions/Chat/NuGet/Config/ +build_property.EnableComHosting = +build_property.EnableGeneratedComInterfaceComImportInterop = +build_property.EffectiveAnalysisLevelStyle = 8.0 +build_property.EnableCodeStyleSeverity = diff --git a/聊天系统课程代码/NuGet/Config/obj/Debug/net8.0/Config.GlobalUsings.g.cs b/聊天系统课程代码/NuGet/Config/obj/Debug/net8.0/Config.GlobalUsings.g.cs new file mode 100644 index 0000000..8578f3d --- /dev/null +++ b/聊天系统课程代码/NuGet/Config/obj/Debug/net8.0/Config.GlobalUsings.g.cs @@ -0,0 +1,8 @@ +// +global using global::System; +global using global::System.Collections.Generic; +global using global::System.IO; +global using global::System.Linq; +global using global::System.Net.Http; +global using global::System.Threading; +global using global::System.Threading.Tasks; diff --git a/聊天系统课程代码/NuGet/Config/obj/Debug/net8.0/Config.assets.cache b/聊天系统课程代码/NuGet/Config/obj/Debug/net8.0/Config.assets.cache new file mode 100644 index 0000000..bac80d3 Binary files /dev/null and b/聊天系统课程代码/NuGet/Config/obj/Debug/net8.0/Config.assets.cache differ diff --git a/聊天系统课程代码/NuGet/Config/obj/Debug/net8.0/Config.csproj.AssemblyReference.cache b/聊天系统课程代码/NuGet/Config/obj/Debug/net8.0/Config.csproj.AssemblyReference.cache new file mode 100644 index 0000000..b6b9bb9 Binary files /dev/null and b/聊天系统课程代码/NuGet/Config/obj/Debug/net8.0/Config.csproj.AssemblyReference.cache differ diff --git a/聊天系统课程代码/NuGet/Config/obj/project.assets.json b/聊天系统课程代码/NuGet/Config/obj/project.assets.json new file mode 100644 index 0000000..093814b --- /dev/null +++ b/聊天系统课程代码/NuGet/Config/obj/project.assets.json @@ -0,0 +1,125 @@ +{ + "version": 3, + "targets": { + "net8.0": { + "Fantasy-Net.Config/2024.1.4": { + "type": "package", + "compile": { + "lib/net8.0/Fantasy-Net.Config.dll": {} + }, + "runtime": { + "lib/net8.0/Fantasy-Net.Config.dll": {} + }, + "build": { + "buildTransitive/Fantasy-Net.Config.targets": {} + } + } + } + }, + "libraries": { + "Fantasy-Net.Config/2024.1.4": { + "sha512": "zStTIJq91mx3VjCcU7eAtrExAcv1Zg+dAd8UdDvpHu7kTY8ldDQMp8sCmez2s+vUTmNyH1hlOgEE3rJILAijfQ==", + "type": "package", + "path": "fantasy-net.config/2024.1.4", + "hasTools": true, + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "README.md", + "buildTransitive/Fantasy-Net.Config.targets", + "fantasy-net.config.2024.1.4.nupkg.sha512", + "fantasy-net.config.nuspec", + "icon.png", + "lib/net8.0/Fantasy-Net.Config.dll", + "tools/output/Excel/Custom.txt", + "tools/output/Excel/Server/MachineConfig.xlsx", + "tools/output/Excel/Server/ProcessConfig.xlsx", + "tools/output/Excel/Server/SceneConfig.xlsx", + "tools/output/Excel/Server/WorldConfig.xlsx", + "tools/output/Excel/Version.txt", + "tools/output/Json/Server/MachineConfigData.Json", + "tools/output/Json/Server/ProcessConfigData.Json", + "tools/output/Json/Server/SceneConfigData.Json", + "tools/output/Json/Server/WorldConfigData.Json", + "tools/output/NetworkProtocol/Inner/InnerMessage.proto", + "tools/output/NetworkProtocol/OpCode.Cache", + "tools/output/NetworkProtocol/Outer/OuterMessage.proto", + "tools/output/NetworkProtocol/RouteType.Config", + "tools/output/README.md" + ] + } + }, + "projectFileDependencyGroups": { + "net8.0": [ + "Fantasy-Net.Config >= 2024.1.4" + ] + }, + "packageFolders": { + "/Users/fantasy/.nuget/packages/": {} + }, + "project": { + "version": "1.0.0", + "restore": { + "projectUniqueName": "/Users/fantasy/Code/ServerLessions/Chat/NuGet/Config/Config.csproj", + "projectName": "Config", + "projectPath": "/Users/fantasy/Code/ServerLessions/Chat/NuGet/Config/Config.csproj", + "packagesPath": "/Users/fantasy/.nuget/packages/", + "outputPath": "/Users/fantasy/Code/ServerLessions/Chat/NuGet/Config/obj/", + "projectStyle": "PackageReference", + "UsingMicrosoftNETSdk": false, + "configFilePaths": [ + "/Users/fantasy/.nuget/NuGet/NuGet.Config" + ], + "originalTargetFrameworks": [ + "net8.0" + ], + "sources": { + "https://api.nuget.org/v3/index.json": {} + }, + "frameworks": { + "net8.0": { + "targetAlias": "net8.0", + "projectReferences": {} + } + }, + "warningProperties": { + "warnAsError": [ + "NU1605" + ] + }, + "restoreAuditProperties": { + "enableAudit": "true", + "auditLevel": "low", + "auditMode": "all" + } + }, + "frameworks": { + "net8.0": { + "targetAlias": "net8.0", + "dependencies": { + "Fantasy-Net.Config": { + "target": "Package", + "version": "[2024.1.4, )" + } + }, + "imports": [ + "net461", + "net462", + "net47", + "net471", + "net472", + "net48", + "net481" + ], + "assetTargetFallback": true, + "warn": true, + "frameworkReferences": { + "Microsoft.NETCore.App": { + "privateAssets": "all" + } + }, + "runtimeIdentifierGraphPath": "/usr/local/share/dotnet/sdk/9.0.100/PortableRuntimeIdentifierGraph.json" + } + } + } +} \ No newline at end of file diff --git a/聊天系统课程代码/NuGet/Config/obj/project.nuget.cache b/聊天系统课程代码/NuGet/Config/obj/project.nuget.cache new file mode 100644 index 0000000..687b022 --- /dev/null +++ b/聊天系统课程代码/NuGet/Config/obj/project.nuget.cache @@ -0,0 +1,10 @@ +{ + "version": 2, + "dgSpecHash": "gPBuheBUH+E=", + "success": true, + "projectFilePath": "/Users/fantasy/Code/ServerLessions/Chat/NuGet/Config/Config.csproj", + "expectedPackageFiles": [ + "/Users/fantasy/.nuget/packages/fantasy-net.config/2024.1.4/fantasy-net.config.2024.1.4.nupkg.sha512" + ], + "logs": [] +} \ No newline at end of file diff --git a/聊天系统课程代码/NuGet/Config/obj/project.packagespec.json b/聊天系统课程代码/NuGet/Config/obj/project.packagespec.json new file mode 100644 index 0000000..940f144 --- /dev/null +++ b/聊天系统课程代码/NuGet/Config/obj/project.packagespec.json @@ -0,0 +1 @@ +"restore":{"projectUniqueName":"/Users/fantasy/Code/ServerLessions/Chat/NuGet/Config/Config.csproj","projectName":"Config","projectPath":"/Users/fantasy/Code/ServerLessions/Chat/NuGet/Config/Config.csproj","outputPath":"/Users/fantasy/Code/ServerLessions/Chat/NuGet/Config/obj/","projectStyle":"PackageReference","UsingMicrosoftNETSdk":false,"originalTargetFrameworks":["net8.0"],"sources":{"https://api.nuget.org/v3/index.json":{}},"frameworks":{"net8.0":{"targetAlias":"net8.0","projectReferences":{}}},"warningProperties":{"warnAsError":["NU1605"]},"restoreAuditProperties":{"enableAudit":"true","auditLevel":"low","auditMode":"all"}}"frameworks":{"net8.0":{"targetAlias":"net8.0","dependencies":{"Fantasy-Net.Config":{"target":"Package","version":"[2024.1.4, )"}},"imports":["net461","net462","net47","net471","net472","net48","net481"],"assetTargetFallback":true,"warn":true,"frameworkReferences":{"Microsoft.NETCore.App":{"privateAssets":"all"}},"runtimeIdentifierGraphPath":"/usr/local/share/dotnet/sdk/9.0.100/PortableRuntimeIdentifierGraph.json"}} \ No newline at end of file diff --git a/聊天系统课程代码/NuGet/Config/obj/rider.project.model.nuget.info b/聊天系统课程代码/NuGet/Config/obj/rider.project.model.nuget.info new file mode 100644 index 0000000..95ccddb --- /dev/null +++ b/聊天系统课程代码/NuGet/Config/obj/rider.project.model.nuget.info @@ -0,0 +1 @@ +17324493181399999 \ No newline at end of file diff --git a/聊天系统课程代码/NuGet/Config/obj/rider.project.restore.info b/聊天系统课程代码/NuGet/Config/obj/rider.project.restore.info new file mode 100644 index 0000000..1819a5e --- /dev/null +++ b/聊天系统课程代码/NuGet/Config/obj/rider.project.restore.info @@ -0,0 +1 @@ +17331012454241100 \ No newline at end of file diff --git a/聊天系统课程代码/NuGet/ConfigTableTool/.DS_Store b/聊天系统课程代码/NuGet/ConfigTableTool/.DS_Store new file mode 100644 index 0000000..f92f27a Binary files /dev/null and b/聊天系统课程代码/NuGet/ConfigTableTool/.DS_Store differ diff --git a/聊天系统课程代码/NuGet/ConfigTableTool/ConfigTableTool.csproj b/聊天系统课程代码/NuGet/ConfigTableTool/ConfigTableTool.csproj new file mode 100644 index 0000000..49882cd --- /dev/null +++ b/聊天系统课程代码/NuGet/ConfigTableTool/ConfigTableTool.csproj @@ -0,0 +1,13 @@ + + + + net8.0 + enable + enable + + + + + + + diff --git a/聊天系统课程代码/NuGet/ConfigTableTool/Tools/.DS_Store b/聊天系统课程代码/NuGet/ConfigTableTool/Tools/.DS_Store new file mode 100644 index 0000000..a3512b8 Binary files /dev/null and b/聊天系统课程代码/NuGet/ConfigTableTool/Tools/.DS_Store differ diff --git a/聊天系统课程代码/NuGet/ConfigTableTool/Tools/Exporter/ConfigTable/CommandLine.dll b/聊天系统课程代码/NuGet/ConfigTableTool/Tools/Exporter/ConfigTable/CommandLine.dll new file mode 100644 index 0000000..3eab2be Binary files /dev/null and b/聊天系统课程代码/NuGet/ConfigTableTool/Tools/Exporter/ConfigTable/CommandLine.dll differ diff --git a/聊天系统课程代码/NuGet/ConfigTableTool/Tools/Exporter/ConfigTable/EPPlus.Interfaces.dll b/聊天系统课程代码/NuGet/ConfigTableTool/Tools/Exporter/ConfigTable/EPPlus.Interfaces.dll new file mode 100644 index 0000000..599a767 Binary files /dev/null and b/聊天系统课程代码/NuGet/ConfigTableTool/Tools/Exporter/ConfigTable/EPPlus.Interfaces.dll differ diff --git a/聊天系统课程代码/NuGet/ConfigTableTool/Tools/Exporter/ConfigTable/EPPlus.System.Drawing.dll b/聊天系统课程代码/NuGet/ConfigTableTool/Tools/Exporter/ConfigTable/EPPlus.System.Drawing.dll new file mode 100644 index 0000000..8df125e Binary files /dev/null and b/聊天系统课程代码/NuGet/ConfigTableTool/Tools/Exporter/ConfigTable/EPPlus.System.Drawing.dll differ diff --git a/聊天系统课程代码/NuGet/ConfigTableTool/Tools/Exporter/ConfigTable/EPPlus.dll b/聊天系统课程代码/NuGet/ConfigTableTool/Tools/Exporter/ConfigTable/EPPlus.dll new file mode 100644 index 0000000..b09ea77 Binary files /dev/null and b/聊天系统课程代码/NuGet/ConfigTableTool/Tools/Exporter/ConfigTable/EPPlus.dll differ diff --git a/聊天系统课程代码/NuGet/ConfigTableTool/Tools/Exporter/ConfigTable/ExporterSettings.json b/聊天系统课程代码/NuGet/ConfigTableTool/Tools/Exporter/ConfigTable/ExporterSettings.json new file mode 100644 index 0000000..7499bd6 --- /dev/null +++ b/聊天系统课程代码/NuGet/ConfigTableTool/Tools/Exporter/ConfigTable/ExporterSettings.json @@ -0,0 +1,44 @@ +{ + "Export": { + "ExcelProgramPath": { + "Value": "../../../Examples/Config/Excel/", + "Comment": "Excel文件夹的根目录" + }, + "ExcelVersionFile": { + "Value": "../../../Examples/Config/Excel/Version.txt", + "Comment": "Excel的Version文件位置、这个文件用于记录每次导出对比是否需要再次导出的文件" + }, + "ExcelServerFileDirectory": { + "Value": "../../../Examples/Server/Entity/Generate/ConfigTable/Entity/", + "Comment": "Excel生成的代码文件、在服务端文件夹位置" + }, + "ExcelClientFileDirectory": { + "Value": "../../../Examples/Client/Unity/Assets/Scripts/Hotfix/Generate/ConfigTable/Entity/", + "Comment": "Excel生成的代码文件、在客户端文件夹位置" + }, + "ExcelServerBinaryDirectory": { + "Value": "../../../Examples/Config/Binary/", + "Comment": "Excel生成服务器二进制数据文件夹位置" + }, + "ExcelClientBinaryDirectory": { + "Value": "../../../Examples/Client/Unity/Assets/Bundles/Config/", + "Comment": "Excel生成在客户端的二进制数据文件夹位置" + }, + "ExcelServerJsonDirectory": { + "Value": "../../../Examples/Config/Json/Server/", + "Comment": "Excel生成在服务端的Json数据文件夹位置" + }, + "ExcelClientJsonDirectory": { + "Value": "../../../Examples/Config/Json/Client/", + "Comment": "Excel生成在客户端的Json数据文件夹位置" + }, + "ServerCustomExportDirectory": { + "Value": "../../../Examples/Server/Entity/Generate/CustomExport/", + "Comment": "Excel在服务端生成自定义代码的文件夹位置" + }, + "ClientCustomExportDirectory": { + "Value": "../../../Examples/Client/Unity/Assets/Scripts/Hotfix/Generate/CustomExport", + "Comment": "Excel在客户端端生成自定义代码的文件夹位置" + } + } +} \ No newline at end of file diff --git a/聊天系统课程代码/NuGet/ConfigTableTool/Tools/Exporter/ConfigTable/Fantasy.Tools.ConfigTable b/聊天系统课程代码/NuGet/ConfigTableTool/Tools/Exporter/ConfigTable/Fantasy.Tools.ConfigTable new file mode 100644 index 0000000..434496e Binary files /dev/null and b/聊天系统课程代码/NuGet/ConfigTableTool/Tools/Exporter/ConfigTable/Fantasy.Tools.ConfigTable differ diff --git a/聊天系统课程代码/NuGet/ConfigTableTool/Tools/Exporter/ConfigTable/Fantasy.Tools.ConfigTable.deps.json b/聊天系统课程代码/NuGet/ConfigTableTool/Tools/Exporter/ConfigTable/Fantasy.Tools.ConfigTable.deps.json new file mode 100644 index 0000000..b248849 --- /dev/null +++ b/聊天系统课程代码/NuGet/ConfigTableTool/Tools/Exporter/ConfigTable/Fantasy.Tools.ConfigTable.deps.json @@ -0,0 +1,521 @@ +{ + "runtimeTarget": { + "name": ".NETCoreApp,Version=v8.0", + "signature": "" + }, + "compilationOptions": {}, + "targets": { + ".NETCoreApp,Version=v8.0": { + "Fantasy.Tools.ConfigTable/1.0.0": { + "dependencies": { + "CommandLineParser": "2.9.1", + "EPPlus": "7.3.2", + "Microsoft.CodeAnalysis.CSharp": "4.11.0", + "Microsoft.Extensions.Configuration.Json": "8.0.0", + "Newtonsoft.Json": "13.0.3", + "protobuf-net": "3.2.30" + }, + "runtime": { + "Fantasy.Tools.ConfigTable.dll": {} + } + }, + "CommandLineParser/2.9.1": { + "runtime": { + "lib/netstandard2.0/CommandLine.dll": { + "assemblyVersion": "2.9.1.0", + "fileVersion": "2.9.1.0" + } + } + }, + "EPPlus/7.3.2": { + "dependencies": { + "EPPlus.System.Drawing": "6.1.1", + "Microsoft.Extensions.Configuration.Json": "8.0.0", + "Microsoft.IO.RecyclableMemoryStream": "3.0.1", + "System.ComponentModel.Annotations": "5.0.0", + "System.Formats.Asn1": "8.0.1", + "System.Security.Cryptography.Pkcs": "8.0.0", + "System.Text.Encoding.CodePages": "8.0.0", + "System.Text.Json": "8.0.4" + }, + "runtime": { + "lib/net8.0/EPPlus.dll": { + "assemblyVersion": "7.3.2.0", + "fileVersion": "7.3.2.0" + } + } + }, + "EPPlus.Interfaces/6.1.1": { + "runtime": { + "lib/net7.0/EPPlus.Interfaces.dll": { + "assemblyVersion": "6.1.1.0", + "fileVersion": "6.1.1.0" + } + } + }, + "EPPlus.System.Drawing/6.1.1": { + "dependencies": { + "EPPlus.Interfaces": "6.1.1", + "System.Drawing.Common": "7.0.0" + }, + "runtime": { + "lib/net7.0/EPPlus.System.Drawing.dll": { + "assemblyVersion": "6.1.1.0", + "fileVersion": "6.1.1.0" + } + } + }, + "Microsoft.CodeAnalysis.Analyzers/3.3.4": {}, + "Microsoft.CodeAnalysis.Common/4.11.0": { + "dependencies": { + "Microsoft.CodeAnalysis.Analyzers": "3.3.4", + "System.Collections.Immutable": "8.0.0", + "System.Reflection.Metadata": "8.0.0" + }, + "runtime": { + "lib/net8.0/Microsoft.CodeAnalysis.dll": { + "assemblyVersion": "4.11.0.0", + "fileVersion": "4.1100.24.37604" + } + } + }, + "Microsoft.CodeAnalysis.CSharp/4.11.0": { + "dependencies": { + "Microsoft.CodeAnalysis.Analyzers": "3.3.4", + "Microsoft.CodeAnalysis.Common": "4.11.0", + "System.Collections.Immutable": "8.0.0", + "System.Reflection.Metadata": "8.0.0" + }, + "runtime": { + "lib/net8.0/Microsoft.CodeAnalysis.CSharp.dll": { + "assemblyVersion": "4.11.0.0", + "fileVersion": "4.1100.24.37604" + } + } + }, + "Microsoft.Extensions.Configuration/8.0.0": { + "dependencies": { + "Microsoft.Extensions.Configuration.Abstractions": "8.0.0", + "Microsoft.Extensions.Primitives": "8.0.0" + }, + "runtime": { + "lib/net8.0/Microsoft.Extensions.Configuration.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.23.53103" + } + } + }, + "Microsoft.Extensions.Configuration.Abstractions/8.0.0": { + "dependencies": { + "Microsoft.Extensions.Primitives": "8.0.0" + }, + "runtime": { + "lib/net8.0/Microsoft.Extensions.Configuration.Abstractions.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.23.53103" + } + } + }, + "Microsoft.Extensions.Configuration.FileExtensions/8.0.0": { + "dependencies": { + "Microsoft.Extensions.Configuration": "8.0.0", + "Microsoft.Extensions.Configuration.Abstractions": "8.0.0", + "Microsoft.Extensions.FileProviders.Abstractions": "8.0.0", + "Microsoft.Extensions.FileProviders.Physical": "8.0.0", + "Microsoft.Extensions.Primitives": "8.0.0" + }, + "runtime": { + "lib/net8.0/Microsoft.Extensions.Configuration.FileExtensions.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.23.53103" + } + } + }, + "Microsoft.Extensions.Configuration.Json/8.0.0": { + "dependencies": { + "Microsoft.Extensions.Configuration": "8.0.0", + "Microsoft.Extensions.Configuration.Abstractions": "8.0.0", + "Microsoft.Extensions.Configuration.FileExtensions": "8.0.0", + "Microsoft.Extensions.FileProviders.Abstractions": "8.0.0", + "System.Text.Json": "8.0.4" + }, + "runtime": { + "lib/net8.0/Microsoft.Extensions.Configuration.Json.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.23.53103" + } + } + }, + "Microsoft.Extensions.FileProviders.Abstractions/8.0.0": { + "dependencies": { + "Microsoft.Extensions.Primitives": "8.0.0" + }, + "runtime": { + "lib/net8.0/Microsoft.Extensions.FileProviders.Abstractions.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.23.53103" + } + } + }, + "Microsoft.Extensions.FileProviders.Physical/8.0.0": { + "dependencies": { + "Microsoft.Extensions.FileProviders.Abstractions": "8.0.0", + "Microsoft.Extensions.FileSystemGlobbing": "8.0.0", + "Microsoft.Extensions.Primitives": "8.0.0" + }, + "runtime": { + "lib/net8.0/Microsoft.Extensions.FileProviders.Physical.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.23.53103" + } + } + }, + "Microsoft.Extensions.FileSystemGlobbing/8.0.0": { + "runtime": { + "lib/net8.0/Microsoft.Extensions.FileSystemGlobbing.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.23.53103" + } + } + }, + "Microsoft.Extensions.Primitives/8.0.0": { + "runtime": { + "lib/net8.0/Microsoft.Extensions.Primitives.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.23.53103" + } + } + }, + "Microsoft.IO.RecyclableMemoryStream/3.0.1": { + "runtime": { + "lib/net6.0/Microsoft.IO.RecyclableMemoryStream.dll": { + "assemblyVersion": "3.0.1.0", + "fileVersion": "3.0.1.0" + } + } + }, + "Microsoft.Win32.SystemEvents/7.0.0": { + "runtime": { + "lib/net7.0/Microsoft.Win32.SystemEvents.dll": { + "assemblyVersion": "7.0.0.0", + "fileVersion": "7.0.22.51805" + } + }, + "runtimeTargets": { + "runtimes/win/lib/net7.0/Microsoft.Win32.SystemEvents.dll": { + "rid": "win", + "assetType": "runtime", + "assemblyVersion": "7.0.0.0", + "fileVersion": "7.0.22.51805" + } + } + }, + "Newtonsoft.Json/13.0.3": { + "runtime": { + "lib/net6.0/Newtonsoft.Json.dll": { + "assemblyVersion": "13.0.0.0", + "fileVersion": "13.0.3.27908" + } + } + }, + "protobuf-net/3.2.30": { + "dependencies": { + "protobuf-net.Core": "3.2.30" + }, + "runtime": { + "lib/net6.0/protobuf-net.dll": { + "assemblyVersion": "3.0.0.0", + "fileVersion": "3.2.30.709" + } + } + }, + "protobuf-net.Core/3.2.30": { + "dependencies": { + "System.Collections.Immutable": "8.0.0" + }, + "runtime": { + "lib/net6.0/protobuf-net.Core.dll": { + "assemblyVersion": "3.0.0.0", + "fileVersion": "3.2.30.709" + } + } + }, + "System.Collections.Immutable/8.0.0": {}, + "System.ComponentModel.Annotations/5.0.0": {}, + "System.Drawing.Common/7.0.0": { + "dependencies": { + "Microsoft.Win32.SystemEvents": "7.0.0" + }, + "runtime": { + "lib/net7.0/System.Drawing.Common.dll": { + "assemblyVersion": "7.0.0.0", + "fileVersion": "7.0.22.51805" + } + }, + "runtimeTargets": { + "runtimes/win/lib/net7.0/System.Drawing.Common.dll": { + "rid": "win", + "assetType": "runtime", + "assemblyVersion": "7.0.0.0", + "fileVersion": "7.0.22.51805" + } + } + }, + "System.Formats.Asn1/8.0.1": { + "runtime": { + "lib/net8.0/System.Formats.Asn1.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.724.31311" + } + } + }, + "System.Reflection.Metadata/8.0.0": { + "dependencies": { + "System.Collections.Immutable": "8.0.0" + } + }, + "System.Security.Cryptography.Pkcs/8.0.0": { + "dependencies": { + "System.Formats.Asn1": "8.0.1" + }, + "runtime": { + "lib/net8.0/System.Security.Cryptography.Pkcs.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.23.53103" + } + }, + "runtimeTargets": { + "runtimes/win/lib/net8.0/System.Security.Cryptography.Pkcs.dll": { + "rid": "win", + "assetType": "runtime", + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.23.53103" + } + } + }, + "System.Text.Encoding.CodePages/8.0.0": {}, + "System.Text.Encodings.Web/8.0.0": {}, + "System.Text.Json/8.0.4": { + "dependencies": { + "System.Text.Encodings.Web": "8.0.0" + }, + "runtime": { + "lib/net8.0/System.Text.Json.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.724.31311" + } + } + } + } + }, + "libraries": { + "Fantasy.Tools.ConfigTable/1.0.0": { + "type": "project", + "serviceable": false, + "sha512": "" + }, + "CommandLineParser/2.9.1": { + "type": "package", + "serviceable": true, + "sha512": "sha512-OE0sl1/sQ37bjVsPKKtwQlWDgqaxWgtme3xZz7JssWUzg5JpMIyHgCTY9MVMxOg48fJ1AgGT3tgdH5m/kQ5xhA==", + "path": "commandlineparser/2.9.1", + "hashPath": "commandlineparser.2.9.1.nupkg.sha512" + }, + "EPPlus/7.3.2": { + "type": "package", + "serviceable": true, + "sha512": "sha512-9DShQD2VuDZ7QLHp+map1r2HdI1G325YGkvRG+qs4N2fgeMF1Uq0TONCEL5gKCWMNDVGO0ZELJTAIzwNyOZQug==", + "path": "epplus/7.3.2", + "hashPath": "epplus.7.3.2.nupkg.sha512" + }, + "EPPlus.Interfaces/6.1.1": { + "type": "package", + "serviceable": true, + "sha512": "sha512-y7dkrOoE1ZR9Vgy1Jf2rEIaTf3SHlUjYt01NklP+F5Qh7S2ruPbzTcpYLRWMeXiG8XL8h2jqX4CyIkFt3NQGZw==", + "path": "epplus.interfaces/6.1.1", + "hashPath": "epplus.interfaces.6.1.1.nupkg.sha512" + }, + "EPPlus.System.Drawing/6.1.1": { + "type": "package", + "serviceable": true, + "sha512": "sha512-lRF5gHYrmkHOOiLMI0t6q8zNYjUrzRgAM5BCXumv5xiqXko8fx3AWI+HCNZfhEqVFGOop+42KfR5GiUcCoyoMw==", + "path": "epplus.system.drawing/6.1.1", + "hashPath": "epplus.system.drawing.6.1.1.nupkg.sha512" + }, + "Microsoft.CodeAnalysis.Analyzers/3.3.4": { + "type": "package", + "serviceable": true, + "sha512": "sha512-AxkxcPR+rheX0SmvpLVIGLhOUXAKG56a64kV9VQZ4y9gR9ZmPXnqZvHJnmwLSwzrEP6junUF11vuc+aqo5r68g==", + "path": "microsoft.codeanalysis.analyzers/3.3.4", + "hashPath": "microsoft.codeanalysis.analyzers.3.3.4.nupkg.sha512" + }, + "Microsoft.CodeAnalysis.Common/4.11.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-djf8ujmqYImFgB04UGtcsEhHrzVqzHowS+EEl/Yunc5LdrYrZhGBWUTXoCF0NzYXJxtfuD+UVQarWpvrNc94Qg==", + "path": "microsoft.codeanalysis.common/4.11.0", + "hashPath": "microsoft.codeanalysis.common.4.11.0.nupkg.sha512" + }, + "Microsoft.CodeAnalysis.CSharp/4.11.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-6XYi2EusI8JT4y2l/F3VVVS+ISoIX9nqHsZRaG6W5aFeJ5BEuBosHfT/ABb73FN0RZ1Z3cj2j7cL28SToJPXOw==", + "path": "microsoft.codeanalysis.csharp/4.11.0", + "hashPath": "microsoft.codeanalysis.csharp.4.11.0.nupkg.sha512" + }, + "Microsoft.Extensions.Configuration/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-0J/9YNXTMWSZP2p2+nvl8p71zpSwokZXZuJW+VjdErkegAnFdO1XlqtA62SJtgVYHdKu3uPxJHcMR/r35HwFBA==", + "path": "microsoft.extensions.configuration/8.0.0", + "hashPath": "microsoft.extensions.configuration.8.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.Configuration.Abstractions/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-3lE/iLSutpgX1CC0NOW70FJoGARRHbyKmG7dc0klnUZ9Dd9hS6N/POPWhKhMLCEuNN5nXEY5agmlFtH562vqhQ==", + "path": "microsoft.extensions.configuration.abstractions/8.0.0", + "hashPath": "microsoft.extensions.configuration.abstractions.8.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.Configuration.FileExtensions/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-McP+Lz/EKwvtCv48z0YImw+L1gi1gy5rHhNaNIY2CrjloV+XY8gydT8DjMR6zWeL13AFK+DioVpppwAuO1Gi1w==", + "path": "microsoft.extensions.configuration.fileextensions/8.0.0", + "hashPath": "microsoft.extensions.configuration.fileextensions.8.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.Configuration.Json/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-C2wqUoh9OmRL1akaCcKSTmRU8z0kckfImG7zLNI8uyi47Lp+zd5LWAD17waPQEqCz3ioWOCrFUo+JJuoeZLOBw==", + "path": "microsoft.extensions.configuration.json/8.0.0", + "hashPath": "microsoft.extensions.configuration.json.8.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.FileProviders.Abstractions/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-ZbaMlhJlpisjuWbvXr4LdAst/1XxH3vZ6A0BsgTphZ2L4PGuxRLz7Jr/S7mkAAnOn78Vu0fKhEgNF5JO3zfjqQ==", + "path": "microsoft.extensions.fileproviders.abstractions/8.0.0", + "hashPath": "microsoft.extensions.fileproviders.abstractions.8.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.FileProviders.Physical/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-UboiXxpPUpwulHvIAVE36Knq0VSHaAmfrFkegLyBZeaADuKezJ/AIXYAW8F5GBlGk/VaibN2k/Zn1ca8YAfVdA==", + "path": "microsoft.extensions.fileproviders.physical/8.0.0", + "hashPath": "microsoft.extensions.fileproviders.physical.8.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.FileSystemGlobbing/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-OK+670i7esqlQrPjdIKRbsyMCe9g5kSLpRRQGSr4Q58AOYEe/hCnfLZprh7viNisSUUQZmMrbbuDaIrP+V1ebQ==", + "path": "microsoft.extensions.filesystemglobbing/8.0.0", + "hashPath": "microsoft.extensions.filesystemglobbing.8.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.Primitives/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-bXJEZrW9ny8vjMF1JV253WeLhpEVzFo1lyaZu1vQ4ZxWUlVvknZ/+ftFgVheLubb4eZPSwwxBeqS1JkCOjxd8g==", + "path": "microsoft.extensions.primitives/8.0.0", + "hashPath": "microsoft.extensions.primitives.8.0.0.nupkg.sha512" + }, + "Microsoft.IO.RecyclableMemoryStream/3.0.1": { + "type": "package", + "serviceable": true, + "sha512": "sha512-s/s20YTVY9r9TPfTrN5g8zPF1YhwxyqO6PxUkrYTGI2B+OGPe9AdajWZrLhFqXIvqIW23fnUE4+ztrUWNU1+9g==", + "path": "microsoft.io.recyclablememorystream/3.0.1", + "hashPath": "microsoft.io.recyclablememorystream.3.0.1.nupkg.sha512" + }, + "Microsoft.Win32.SystemEvents/7.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-2nXPrhdAyAzir0gLl8Yy8S5Mnm/uBSQQA7jEsILOS1MTyS7DbmV1NgViMtvV1sfCD1ebITpNwb1NIinKeJgUVQ==", + "path": "microsoft.win32.systemevents/7.0.0", + "hashPath": "microsoft.win32.systemevents.7.0.0.nupkg.sha512" + }, + "Newtonsoft.Json/13.0.3": { + "type": "package", + "serviceable": true, + "sha512": "sha512-HrC5BXdl00IP9zeV+0Z848QWPAoCr9P3bDEZguI+gkLcBKAOxix/tLEAAHC+UvDNPv4a2d18lOReHMOagPa+zQ==", + "path": "newtonsoft.json/13.0.3", + "hashPath": "newtonsoft.json.13.0.3.nupkg.sha512" + }, + "protobuf-net/3.2.30": { + "type": "package", + "serviceable": true, + "sha512": "sha512-C/UTlmxEJHAHpqm8xQK1UyJKaIynVCSNG4mVrbLgnZ7ccH28nN49O8iMJvKEodTgVbnimvy+3mIiAdW6mATwnw==", + "path": "protobuf-net/3.2.30", + "hashPath": "protobuf-net.3.2.30.nupkg.sha512" + }, + "protobuf-net.Core/3.2.30": { + "type": "package", + "serviceable": true, + "sha512": "sha512-v2ZxxYrz+X212ukSx+uqkLuPu414bvmSAnTyf+PBUKR9ENJxO4P/csorA/27456MCp1JNoMssDj/f91RDiwBfQ==", + "path": "protobuf-net.core/3.2.30", + "hashPath": "protobuf-net.core.3.2.30.nupkg.sha512" + }, + "System.Collections.Immutable/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-AurL6Y5BA1WotzlEvVaIDpqzpIPvYnnldxru8oXJU2yFxFUy3+pNXjXd1ymO+RA0rq0+590Q8gaz2l3Sr7fmqg==", + "path": "system.collections.immutable/8.0.0", + "hashPath": "system.collections.immutable.8.0.0.nupkg.sha512" + }, + "System.ComponentModel.Annotations/5.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-dMkqfy2el8A8/I76n2Hi1oBFEbG1SfxD2l5nhwXV3XjlnOmwxJlQbYpJH4W51odnU9sARCSAgv7S3CyAFMkpYg==", + "path": "system.componentmodel.annotations/5.0.0", + "hashPath": "system.componentmodel.annotations.5.0.0.nupkg.sha512" + }, + "System.Drawing.Common/7.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-KIX+oBU38pxkKPxvLcLfIkOV5Ien8ReN78wro7OF5/erwcmortzeFx+iBswlh2Vz6gVne0khocQudGwaO1Ey6A==", + "path": "system.drawing.common/7.0.0", + "hashPath": "system.drawing.common.7.0.0.nupkg.sha512" + }, + "System.Formats.Asn1/8.0.1": { + "type": "package", + "serviceable": true, + "sha512": "sha512-XqKba7Mm/koKSjKMfW82olQdmfbI5yqeoLV/tidRp7fbh5rmHAQ5raDI/7SU0swTzv+jgqtUGkzmFxuUg0it1A==", + "path": "system.formats.asn1/8.0.1", + "hashPath": "system.formats.asn1.8.0.1.nupkg.sha512" + }, + "System.Reflection.Metadata/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-ptvgrFh7PvWI8bcVqG5rsA/weWM09EnthFHR5SCnS6IN+P4mj6rE1lBDC4U8HL9/57htKAqy4KQ3bBj84cfYyQ==", + "path": "system.reflection.metadata/8.0.0", + "hashPath": "system.reflection.metadata.8.0.0.nupkg.sha512" + }, + "System.Security.Cryptography.Pkcs/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-ULmp3xoOwNYjOYp4JZ2NK/6NdTgiN1GQXzVVN1njQ7LOZ0d0B9vyMnhyqbIi9Qw4JXj1JgCsitkTShboHRx7Eg==", + "path": "system.security.cryptography.pkcs/8.0.0", + "hashPath": "system.security.cryptography.pkcs.8.0.0.nupkg.sha512" + }, + "System.Text.Encoding.CodePages/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-OZIsVplFGaVY90G2SbpgU7EnCoOO5pw1t4ic21dBF3/1omrJFpAGoNAVpPyMVOC90/hvgkGG3VFqR13YgZMQfg==", + "path": "system.text.encoding.codepages/8.0.0", + "hashPath": "system.text.encoding.codepages.8.0.0.nupkg.sha512" + }, + "System.Text.Encodings.Web/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-yev/k9GHAEGx2Rg3/tU6MQh4HGBXJs70y7j1LaM1i/ER9po+6nnQ6RRqTJn1E7Xu0fbIFK80Nh5EoODxrbxwBQ==", + "path": "system.text.encodings.web/8.0.0", + "hashPath": "system.text.encodings.web.8.0.0.nupkg.sha512" + }, + "System.Text.Json/8.0.4": { + "type": "package", + "serviceable": true, + "sha512": "sha512-bAkhgDJ88XTsqczoxEMliSrpijKZHhbJQldhAmObj/RbrN3sU5dcokuXmWJWsdQAhiMJ9bTayWsL1C9fbbCRhw==", + "path": "system.text.json/8.0.4", + "hashPath": "system.text.json.8.0.4.nupkg.sha512" + } + } +} \ No newline at end of file diff --git a/聊天系统课程代码/NuGet/ConfigTableTool/Tools/Exporter/ConfigTable/Fantasy.Tools.ConfigTable.dll b/聊天系统课程代码/NuGet/ConfigTableTool/Tools/Exporter/ConfigTable/Fantasy.Tools.ConfigTable.dll new file mode 100644 index 0000000..691c3ec Binary files /dev/null and b/聊天系统课程代码/NuGet/ConfigTableTool/Tools/Exporter/ConfigTable/Fantasy.Tools.ConfigTable.dll differ diff --git a/聊天系统课程代码/NuGet/ConfigTableTool/Tools/Exporter/ConfigTable/Fantasy.Tools.ConfigTable.pdb b/聊天系统课程代码/NuGet/ConfigTableTool/Tools/Exporter/ConfigTable/Fantasy.Tools.ConfigTable.pdb new file mode 100644 index 0000000..e28ebf3 Binary files /dev/null and b/聊天系统课程代码/NuGet/ConfigTableTool/Tools/Exporter/ConfigTable/Fantasy.Tools.ConfigTable.pdb differ diff --git a/聊天系统课程代码/NuGet/ConfigTableTool/Tools/Exporter/ConfigTable/Fantasy.Tools.ConfigTable.runtimeconfig.json b/聊天系统课程代码/NuGet/ConfigTableTool/Tools/Exporter/ConfigTable/Fantasy.Tools.ConfigTable.runtimeconfig.json new file mode 100644 index 0000000..becfaea --- /dev/null +++ b/聊天系统课程代码/NuGet/ConfigTableTool/Tools/Exporter/ConfigTable/Fantasy.Tools.ConfigTable.runtimeconfig.json @@ -0,0 +1,12 @@ +{ + "runtimeOptions": { + "tfm": "net8.0", + "framework": { + "name": "Microsoft.NETCore.App", + "version": "8.0.0" + }, + "configProperties": { + "System.Runtime.Serialization.EnableUnsafeBinaryFormatterSerialization": false + } + } +} \ No newline at end of file diff --git a/聊天系统课程代码/NuGet/ConfigTableTool/Tools/Exporter/ConfigTable/Microsoft.CodeAnalysis.CSharp.dll b/聊天系统课程代码/NuGet/ConfigTableTool/Tools/Exporter/ConfigTable/Microsoft.CodeAnalysis.CSharp.dll new file mode 100644 index 0000000..c23db48 Binary files /dev/null and b/聊天系统课程代码/NuGet/ConfigTableTool/Tools/Exporter/ConfigTable/Microsoft.CodeAnalysis.CSharp.dll differ diff --git a/聊天系统课程代码/NuGet/ConfigTableTool/Tools/Exporter/ConfigTable/Microsoft.CodeAnalysis.dll b/聊天系统课程代码/NuGet/ConfigTableTool/Tools/Exporter/ConfigTable/Microsoft.CodeAnalysis.dll new file mode 100644 index 0000000..de7eadd Binary files /dev/null and b/聊天系统课程代码/NuGet/ConfigTableTool/Tools/Exporter/ConfigTable/Microsoft.CodeAnalysis.dll differ diff --git a/聊天系统课程代码/NuGet/ConfigTableTool/Tools/Exporter/ConfigTable/Microsoft.Extensions.Configuration.Abstractions.dll b/聊天系统课程代码/NuGet/ConfigTableTool/Tools/Exporter/ConfigTable/Microsoft.Extensions.Configuration.Abstractions.dll new file mode 100644 index 0000000..a5ab313 Binary files /dev/null and b/聊天系统课程代码/NuGet/ConfigTableTool/Tools/Exporter/ConfigTable/Microsoft.Extensions.Configuration.Abstractions.dll differ diff --git a/聊天系统课程代码/NuGet/ConfigTableTool/Tools/Exporter/ConfigTable/Microsoft.Extensions.Configuration.FileExtensions.dll b/聊天系统课程代码/NuGet/ConfigTableTool/Tools/Exporter/ConfigTable/Microsoft.Extensions.Configuration.FileExtensions.dll new file mode 100644 index 0000000..4efc1a5 Binary files /dev/null and b/聊天系统课程代码/NuGet/ConfigTableTool/Tools/Exporter/ConfigTable/Microsoft.Extensions.Configuration.FileExtensions.dll differ diff --git a/聊天系统课程代码/NuGet/ConfigTableTool/Tools/Exporter/ConfigTable/Microsoft.Extensions.Configuration.Json.dll b/聊天系统课程代码/NuGet/ConfigTableTool/Tools/Exporter/ConfigTable/Microsoft.Extensions.Configuration.Json.dll new file mode 100644 index 0000000..296db6a Binary files /dev/null and b/聊天系统课程代码/NuGet/ConfigTableTool/Tools/Exporter/ConfigTable/Microsoft.Extensions.Configuration.Json.dll differ diff --git a/聊天系统课程代码/NuGet/ConfigTableTool/Tools/Exporter/ConfigTable/Microsoft.Extensions.Configuration.dll b/聊天系统课程代码/NuGet/ConfigTableTool/Tools/Exporter/ConfigTable/Microsoft.Extensions.Configuration.dll new file mode 100644 index 0000000..d3e5c22 Binary files /dev/null and b/聊天系统课程代码/NuGet/ConfigTableTool/Tools/Exporter/ConfigTable/Microsoft.Extensions.Configuration.dll differ diff --git a/聊天系统课程代码/NuGet/ConfigTableTool/Tools/Exporter/ConfigTable/Microsoft.Extensions.FileProviders.Abstractions.dll b/聊天系统课程代码/NuGet/ConfigTableTool/Tools/Exporter/ConfigTable/Microsoft.Extensions.FileProviders.Abstractions.dll new file mode 100644 index 0000000..f907206 Binary files /dev/null and b/聊天系统课程代码/NuGet/ConfigTableTool/Tools/Exporter/ConfigTable/Microsoft.Extensions.FileProviders.Abstractions.dll differ diff --git a/聊天系统课程代码/NuGet/ConfigTableTool/Tools/Exporter/ConfigTable/Microsoft.Extensions.FileProviders.Physical.dll b/聊天系统课程代码/NuGet/ConfigTableTool/Tools/Exporter/ConfigTable/Microsoft.Extensions.FileProviders.Physical.dll new file mode 100644 index 0000000..6fb7f47 Binary files /dev/null and b/聊天系统课程代码/NuGet/ConfigTableTool/Tools/Exporter/ConfigTable/Microsoft.Extensions.FileProviders.Physical.dll differ diff --git a/聊天系统课程代码/NuGet/ConfigTableTool/Tools/Exporter/ConfigTable/Microsoft.Extensions.FileSystemGlobbing.dll b/聊天系统课程代码/NuGet/ConfigTableTool/Tools/Exporter/ConfigTable/Microsoft.Extensions.FileSystemGlobbing.dll new file mode 100644 index 0000000..e590735 Binary files /dev/null and b/聊天系统课程代码/NuGet/ConfigTableTool/Tools/Exporter/ConfigTable/Microsoft.Extensions.FileSystemGlobbing.dll differ diff --git a/聊天系统课程代码/NuGet/ConfigTableTool/Tools/Exporter/ConfigTable/Microsoft.Extensions.Primitives.dll b/聊天系统课程代码/NuGet/ConfigTableTool/Tools/Exporter/ConfigTable/Microsoft.Extensions.Primitives.dll new file mode 100644 index 0000000..c24f2a0 Binary files /dev/null and b/聊天系统课程代码/NuGet/ConfigTableTool/Tools/Exporter/ConfigTable/Microsoft.Extensions.Primitives.dll differ diff --git a/聊天系统课程代码/NuGet/ConfigTableTool/Tools/Exporter/ConfigTable/Microsoft.IO.RecyclableMemoryStream.dll b/聊天系统课程代码/NuGet/ConfigTableTool/Tools/Exporter/ConfigTable/Microsoft.IO.RecyclableMemoryStream.dll new file mode 100644 index 0000000..6e0ea40 Binary files /dev/null and b/聊天系统课程代码/NuGet/ConfigTableTool/Tools/Exporter/ConfigTable/Microsoft.IO.RecyclableMemoryStream.dll differ diff --git a/聊天系统课程代码/NuGet/ConfigTableTool/Tools/Exporter/ConfigTable/Microsoft.Win32.SystemEvents.dll b/聊天系统课程代码/NuGet/ConfigTableTool/Tools/Exporter/ConfigTable/Microsoft.Win32.SystemEvents.dll new file mode 100644 index 0000000..d40a926 Binary files /dev/null and b/聊天系统课程代码/NuGet/ConfigTableTool/Tools/Exporter/ConfigTable/Microsoft.Win32.SystemEvents.dll differ diff --git a/聊天系统课程代码/NuGet/ConfigTableTool/Tools/Exporter/ConfigTable/Newtonsoft.Json.dll b/聊天系统课程代码/NuGet/ConfigTableTool/Tools/Exporter/ConfigTable/Newtonsoft.Json.dll new file mode 100644 index 0000000..d035c38 Binary files /dev/null and b/聊天系统课程代码/NuGet/ConfigTableTool/Tools/Exporter/ConfigTable/Newtonsoft.Json.dll differ diff --git a/聊天系统课程代码/NuGet/ConfigTableTool/Tools/Exporter/ConfigTable/Run.bat b/聊天系统课程代码/NuGet/ConfigTableTool/Tools/Exporter/ConfigTable/Run.bat new file mode 100644 index 0000000..e166f0e --- /dev/null +++ b/聊天系统课程代码/NuGet/ConfigTableTool/Tools/Exporter/ConfigTable/Run.bat @@ -0,0 +1,21 @@ +@echo off + +echo Please select an option: +echo 1. Client +echo 2. Server +echo 3. All + +set /p choice=Please select an option: + +if "%choice%"=="1" ( + echo Client + dotnet Fantasy.Tools.ConfigTable.dll --ExportPlatform 1 +) else if "%choice%"=="2" ( + echo Server + dotnet Fantasy.Tools.ConfigTable.dll --ExportPlatform 2 +) else if "%choice%"=="3" ( + echo All + dotnet Fantasy.Tools.ConfigTable.dll --ExportPlatform 3 +) else ( + echo Invalid option +) diff --git a/聊天系统课程代码/NuGet/ConfigTableTool/Tools/Exporter/ConfigTable/Run.sh b/聊天系统课程代码/NuGet/ConfigTableTool/Tools/Exporter/ConfigTable/Run.sh new file mode 100644 index 0000000..491d8d9 --- /dev/null +++ b/聊天系统课程代码/NuGet/ConfigTableTool/Tools/Exporter/ConfigTable/Run.sh @@ -0,0 +1,23 @@ +#!/bin/bash + +echo "1. Client" +echo "2. Server" +echo "3. All" + +read -n 1 -p "Please select an option:" choice +echo "" +echo "" +case $choice in + 1) + dotnet Fantasy.Tools.ConfigTable.dll --ExportPlatform 1 + ;; + 2) + dotnet Fantasy.Tools.ConfigTable.dll --ExportPlatform 2 + ;; + 3) + dotnet Fantasy.Tools.ConfigTable.dll --ExportPlatform 3 + ;; + *) + echo "Invalid option" + ;; +esac diff --git a/聊天系统课程代码/NuGet/ConfigTableTool/Tools/Exporter/ConfigTable/System.Drawing.Common.dll b/聊天系统课程代码/NuGet/ConfigTableTool/Tools/Exporter/ConfigTable/System.Drawing.Common.dll new file mode 100644 index 0000000..310d5e8 Binary files /dev/null and b/聊天系统课程代码/NuGet/ConfigTableTool/Tools/Exporter/ConfigTable/System.Drawing.Common.dll differ diff --git a/聊天系统课程代码/NuGet/ConfigTableTool/Tools/Exporter/ConfigTable/System.Formats.Asn1.dll b/聊天系统课程代码/NuGet/ConfigTableTool/Tools/Exporter/ConfigTable/System.Formats.Asn1.dll new file mode 100644 index 0000000..16cc849 Binary files /dev/null and b/聊天系统课程代码/NuGet/ConfigTableTool/Tools/Exporter/ConfigTable/System.Formats.Asn1.dll differ diff --git a/聊天系统课程代码/NuGet/ConfigTableTool/Tools/Exporter/ConfigTable/System.Security.Cryptography.Pkcs.dll b/聊天系统课程代码/NuGet/ConfigTableTool/Tools/Exporter/ConfigTable/System.Security.Cryptography.Pkcs.dll new file mode 100644 index 0000000..a76a14a Binary files /dev/null and b/聊天系统课程代码/NuGet/ConfigTableTool/Tools/Exporter/ConfigTable/System.Security.Cryptography.Pkcs.dll differ diff --git a/聊天系统课程代码/NuGet/ConfigTableTool/Tools/Exporter/ConfigTable/System.Text.Json.dll b/聊天系统课程代码/NuGet/ConfigTableTool/Tools/Exporter/ConfigTable/System.Text.Json.dll new file mode 100644 index 0000000..0c6d406 Binary files /dev/null and b/聊天系统课程代码/NuGet/ConfigTableTool/Tools/Exporter/ConfigTable/System.Text.Json.dll differ diff --git a/聊天系统课程代码/NuGet/ConfigTableTool/Tools/Exporter/ConfigTable/protobuf-net.Core.dll b/聊天系统课程代码/NuGet/ConfigTableTool/Tools/Exporter/ConfigTable/protobuf-net.Core.dll new file mode 100644 index 0000000..845a840 Binary files /dev/null and b/聊天系统课程代码/NuGet/ConfigTableTool/Tools/Exporter/ConfigTable/protobuf-net.Core.dll differ diff --git a/聊天系统课程代码/NuGet/ConfigTableTool/Tools/Exporter/ConfigTable/protobuf-net.dll b/聊天系统课程代码/NuGet/ConfigTableTool/Tools/Exporter/ConfigTable/protobuf-net.dll new file mode 100644 index 0000000..e4b6839 Binary files /dev/null and b/聊天系统课程代码/NuGet/ConfigTableTool/Tools/Exporter/ConfigTable/protobuf-net.dll differ diff --git a/聊天系统课程代码/NuGet/ConfigTableTool/obj/ConfigTableTool.csproj.nuget.dgspec.json b/聊天系统课程代码/NuGet/ConfigTableTool/obj/ConfigTableTool.csproj.nuget.dgspec.json new file mode 100644 index 0000000..0673838 --- /dev/null +++ b/聊天系统课程代码/NuGet/ConfigTableTool/obj/ConfigTableTool.csproj.nuget.dgspec.json @@ -0,0 +1,73 @@ +{ + "format": 1, + "restore": { + "/Users/fantasy/Code/ServerLessions/Chat/NuGet/ConfigTableTool/ConfigTableTool.csproj": {} + }, + "projects": { + "/Users/fantasy/Code/ServerLessions/Chat/NuGet/ConfigTableTool/ConfigTableTool.csproj": { + "version": "1.0.0", + "restore": { + "projectUniqueName": "/Users/fantasy/Code/ServerLessions/Chat/NuGet/ConfigTableTool/ConfigTableTool.csproj", + "projectName": "ConfigTableTool", + "projectPath": "/Users/fantasy/Code/ServerLessions/Chat/NuGet/ConfigTableTool/ConfigTableTool.csproj", + "packagesPath": "/Users/fantasy/.nuget/packages/", + "outputPath": "/Users/fantasy/Code/ServerLessions/Chat/NuGet/ConfigTableTool/obj/", + "projectStyle": "PackageReference", + "UsingMicrosoftNETSdk": false, + "configFilePaths": [ + "/Users/fantasy/.nuget/NuGet/NuGet.Config" + ], + "originalTargetFrameworks": [ + "net8.0" + ], + "sources": { + "https://api.nuget.org/v3/index.json": {} + }, + "frameworks": { + "net8.0": { + "targetAlias": "net8.0", + "projectReferences": {} + } + }, + "warningProperties": { + "warnAsError": [ + "NU1605" + ] + }, + "restoreAuditProperties": { + "enableAudit": "true", + "auditLevel": "low", + "auditMode": "all" + } + }, + "frameworks": { + "net8.0": { + "targetAlias": "net8.0", + "dependencies": { + "Fantasy-Net.Tools.ExporterConfigTable": { + "target": "Package", + "version": "[2024.1.8, )" + } + }, + "imports": [ + "net461", + "net462", + "net47", + "net471", + "net472", + "net48", + "net481" + ], + "assetTargetFallback": true, + "warn": true, + "frameworkReferences": { + "Microsoft.NETCore.App": { + "privateAssets": "all" + } + }, + "runtimeIdentifierGraphPath": "/usr/local/share/dotnet/sdk/9.0.100/PortableRuntimeIdentifierGraph.json" + } + } + } + } +} \ No newline at end of file diff --git a/聊天系统课程代码/NuGet/ConfigTableTool/obj/ConfigTableTool.csproj.nuget.g.props b/聊天系统课程代码/NuGet/ConfigTableTool/obj/ConfigTableTool.csproj.nuget.g.props new file mode 100644 index 0000000..48c36f1 --- /dev/null +++ b/聊天系统课程代码/NuGet/ConfigTableTool/obj/ConfigTableTool.csproj.nuget.g.props @@ -0,0 +1,18 @@ + + + + True + NuGet + $(MSBuildThisFileDirectory)project.assets.json + /Users/fantasy/.nuget/packages/ + /Users/fantasy/.nuget/packages/ + PackageReference + 6.12.0 + + + + + + /Users/fantasy/.nuget/packages/fantasy-net.tools.exporterconfigtable/2024.1.8 + + \ No newline at end of file diff --git a/聊天系统课程代码/NuGet/ConfigTableTool/obj/ConfigTableTool.csproj.nuget.g.targets b/聊天系统课程代码/NuGet/ConfigTableTool/obj/ConfigTableTool.csproj.nuget.g.targets new file mode 100644 index 0000000..5f6df71 --- /dev/null +++ b/聊天系统课程代码/NuGet/ConfigTableTool/obj/ConfigTableTool.csproj.nuget.g.targets @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/聊天系统课程代码/NuGet/ConfigTableTool/obj/Debug/net8.0/.NETCoreApp,Version=v8.0.AssemblyAttributes.cs b/聊天系统课程代码/NuGet/ConfigTableTool/obj/Debug/net8.0/.NETCoreApp,Version=v8.0.AssemblyAttributes.cs new file mode 100644 index 0000000..2217181 --- /dev/null +++ b/聊天系统课程代码/NuGet/ConfigTableTool/obj/Debug/net8.0/.NETCoreApp,Version=v8.0.AssemblyAttributes.cs @@ -0,0 +1,4 @@ +// +using System; +using System.Reflection; +[assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute(".NETCoreApp,Version=v8.0", FrameworkDisplayName = ".NET 8.0")] diff --git a/聊天系统课程代码/NuGet/ConfigTableTool/obj/Debug/net8.0/ConfigTableTool.AssemblyInfo.cs b/聊天系统课程代码/NuGet/ConfigTableTool/obj/Debug/net8.0/ConfigTableTool.AssemblyInfo.cs new file mode 100644 index 0000000..b56e7ef --- /dev/null +++ b/聊天系统课程代码/NuGet/ConfigTableTool/obj/Debug/net8.0/ConfigTableTool.AssemblyInfo.cs @@ -0,0 +1,22 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +using System; +using System.Reflection; + +[assembly: System.Reflection.AssemblyCompanyAttribute("ConfigTableTool")] +[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")] +[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")] +[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0")] +[assembly: System.Reflection.AssemblyProductAttribute("ConfigTableTool")] +[assembly: System.Reflection.AssemblyTitleAttribute("ConfigTableTool")] +[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")] + +// 由 MSBuild WriteCodeFragment 类生成。 + diff --git a/聊天系统课程代码/NuGet/ConfigTableTool/obj/Debug/net8.0/ConfigTableTool.AssemblyInfoInputs.cache b/聊天系统课程代码/NuGet/ConfigTableTool/obj/Debug/net8.0/ConfigTableTool.AssemblyInfoInputs.cache new file mode 100644 index 0000000..0a9cf6d --- /dev/null +++ b/聊天系统课程代码/NuGet/ConfigTableTool/obj/Debug/net8.0/ConfigTableTool.AssemblyInfoInputs.cache @@ -0,0 +1 @@ +5797e27b57c35a74b47554e28067cbd97c8e5074e10199735c15d2f28e65f31c diff --git a/聊天系统课程代码/NuGet/ConfigTableTool/obj/Debug/net8.0/ConfigTableTool.GeneratedMSBuildEditorConfig.editorconfig b/聊天系统课程代码/NuGet/ConfigTableTool/obj/Debug/net8.0/ConfigTableTool.GeneratedMSBuildEditorConfig.editorconfig new file mode 100644 index 0000000..cc52d24 --- /dev/null +++ b/聊天系统课程代码/NuGet/ConfigTableTool/obj/Debug/net8.0/ConfigTableTool.GeneratedMSBuildEditorConfig.editorconfig @@ -0,0 +1,15 @@ +is_global = true +build_property.TargetFramework = net8.0 +build_property.TargetPlatformMinVersion = +build_property.UsingMicrosoftNETSdkWeb = +build_property.ProjectTypeGuids = +build_property.InvariantGlobalization = +build_property.PlatformNeutralAssembly = +build_property.EnforceExtendedAnalyzerRules = +build_property._SupportedPlatformList = Linux,macOS,Windows +build_property.RootNamespace = ConfigTableTool +build_property.ProjectDir = /Users/fantasy/Code/ServerLessions/Chat/NuGet/ConfigTableTool/ +build_property.EnableComHosting = +build_property.EnableGeneratedComInterfaceComImportInterop = +build_property.EffectiveAnalysisLevelStyle = 8.0 +build_property.EnableCodeStyleSeverity = diff --git a/聊天系统课程代码/NuGet/ConfigTableTool/obj/Debug/net8.0/ConfigTableTool.GlobalUsings.g.cs b/聊天系统课程代码/NuGet/ConfigTableTool/obj/Debug/net8.0/ConfigTableTool.GlobalUsings.g.cs new file mode 100644 index 0000000..8578f3d --- /dev/null +++ b/聊天系统课程代码/NuGet/ConfigTableTool/obj/Debug/net8.0/ConfigTableTool.GlobalUsings.g.cs @@ -0,0 +1,8 @@ +// +global using global::System; +global using global::System.Collections.Generic; +global using global::System.IO; +global using global::System.Linq; +global using global::System.Net.Http; +global using global::System.Threading; +global using global::System.Threading.Tasks; diff --git a/聊天系统课程代码/NuGet/ConfigTableTool/obj/Debug/net8.0/ConfigTableTool.assets.cache b/聊天系统课程代码/NuGet/ConfigTableTool/obj/Debug/net8.0/ConfigTableTool.assets.cache new file mode 100644 index 0000000..0725fd7 Binary files /dev/null and b/聊天系统课程代码/NuGet/ConfigTableTool/obj/Debug/net8.0/ConfigTableTool.assets.cache differ diff --git a/聊天系统课程代码/NuGet/ConfigTableTool/obj/Debug/net8.0/ConfigTableTool.csproj.AssemblyReference.cache b/聊天系统课程代码/NuGet/ConfigTableTool/obj/Debug/net8.0/ConfigTableTool.csproj.AssemblyReference.cache new file mode 100644 index 0000000..04e5450 Binary files /dev/null and b/聊天系统课程代码/NuGet/ConfigTableTool/obj/Debug/net8.0/ConfigTableTool.csproj.AssemblyReference.cache differ diff --git a/聊天系统课程代码/NuGet/ConfigTableTool/obj/project.assets.json b/聊天系统课程代码/NuGet/ConfigTableTool/obj/project.assets.json new file mode 100644 index 0000000..1ec4b42 --- /dev/null +++ b/聊天系统课程代码/NuGet/ConfigTableTool/obj/project.assets.json @@ -0,0 +1,143 @@ +{ + "version": 3, + "targets": { + "net8.0": { + "Fantasy-Net.Tools.ExporterConfigTable/2024.1.8": { + "type": "package", + "compile": { + "lib/net8.0/Fantasy.Tools.ExporterConfigTable.dll": {} + }, + "runtime": { + "lib/net8.0/Fantasy.Tools.ExporterConfigTable.dll": {} + }, + "build": { + "buildTransitive/Fantasy-Net.Tools.ExporterConfigTable.targets": {} + } + } + } + }, + "libraries": { + "Fantasy-Net.Tools.ExporterConfigTable/2024.1.8": { + "sha512": "Tx6wYQLqkdLt79cqGqBUIDY9YIeoFF8sYrrCo3IRqKKaBDfZXYx8RcsurfE3YzKc4WuYxxQskaoBThS0LvJGOQ==", + "type": "package", + "path": "fantasy-net.tools.exporterconfigtable/2024.1.8", + "hasTools": true, + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "buildTransitive/Fantasy-Net.Tools.ExporterConfigTable.targets", + "fantasy-net.tools.exporterconfigtable.2024.1.8.nupkg.sha512", + "fantasy-net.tools.exporterconfigtable.nuspec", + "icon.png", + "lib/net8.0/Fantasy.Tools.ExporterConfigTable.dll", + "tools/output/CommandLine.dll", + "tools/output/EPPlus.Interfaces.dll", + "tools/output/EPPlus.System.Drawing.dll", + "tools/output/EPPlus.dll", + "tools/output/ExporterSettings.json", + "tools/output/Fantasy.Tools.ConfigTable", + "tools/output/Fantasy.Tools.ConfigTable.deps.json", + "tools/output/Fantasy.Tools.ConfigTable.dll", + "tools/output/Fantasy.Tools.ConfigTable.pdb", + "tools/output/Fantasy.Tools.ConfigTable.runtimeconfig.json", + "tools/output/Microsoft.CodeAnalysis.CSharp.dll", + "tools/output/Microsoft.CodeAnalysis.dll", + "tools/output/Microsoft.Extensions.Configuration.Abstractions.dll", + "tools/output/Microsoft.Extensions.Configuration.FileExtensions.dll", + "tools/output/Microsoft.Extensions.Configuration.Json.dll", + "tools/output/Microsoft.Extensions.Configuration.dll", + "tools/output/Microsoft.Extensions.FileProviders.Abstractions.dll", + "tools/output/Microsoft.Extensions.FileProviders.Physical.dll", + "tools/output/Microsoft.Extensions.FileSystemGlobbing.dll", + "tools/output/Microsoft.Extensions.Primitives.dll", + "tools/output/Microsoft.IO.RecyclableMemoryStream.dll", + "tools/output/Microsoft.Win32.SystemEvents.dll", + "tools/output/Newtonsoft.Json.dll", + "tools/output/Run.bat", + "tools/output/Run.sh", + "tools/output/System.Drawing.Common.dll", + "tools/output/System.Formats.Asn1.dll", + "tools/output/System.Security.Cryptography.Pkcs.dll", + "tools/output/System.Text.Json.dll", + "tools/output/protobuf-net.Core.dll", + "tools/output/protobuf-net.dll", + "tools/output/runtimes/win/lib/net7.0/Microsoft.Win32.SystemEvents.dll", + "tools/output/runtimes/win/lib/net7.0/System.Drawing.Common.dll", + "tools/output/runtimes/win/lib/net8.0/System.Security.Cryptography.Pkcs.dll" + ] + } + }, + "projectFileDependencyGroups": { + "net8.0": [ + "Fantasy-Net.Tools.ExporterConfigTable >= 2024.1.8" + ] + }, + "packageFolders": { + "/Users/fantasy/.nuget/packages/": {} + }, + "project": { + "version": "1.0.0", + "restore": { + "projectUniqueName": "/Users/fantasy/Code/ServerLessions/Chat/NuGet/ConfigTableTool/ConfigTableTool.csproj", + "projectName": "ConfigTableTool", + "projectPath": "/Users/fantasy/Code/ServerLessions/Chat/NuGet/ConfigTableTool/ConfigTableTool.csproj", + "packagesPath": "/Users/fantasy/.nuget/packages/", + "outputPath": "/Users/fantasy/Code/ServerLessions/Chat/NuGet/ConfigTableTool/obj/", + "projectStyle": "PackageReference", + "UsingMicrosoftNETSdk": false, + "configFilePaths": [ + "/Users/fantasy/.nuget/NuGet/NuGet.Config" + ], + "originalTargetFrameworks": [ + "net8.0" + ], + "sources": { + "https://api.nuget.org/v3/index.json": {} + }, + "frameworks": { + "net8.0": { + "targetAlias": "net8.0", + "projectReferences": {} + } + }, + "warningProperties": { + "warnAsError": [ + "NU1605" + ] + }, + "restoreAuditProperties": { + "enableAudit": "true", + "auditLevel": "low", + "auditMode": "all" + } + }, + "frameworks": { + "net8.0": { + "targetAlias": "net8.0", + "dependencies": { + "Fantasy-Net.Tools.ExporterConfigTable": { + "target": "Package", + "version": "[2024.1.8, )" + } + }, + "imports": [ + "net461", + "net462", + "net47", + "net471", + "net472", + "net48", + "net481" + ], + "assetTargetFallback": true, + "warn": true, + "frameworkReferences": { + "Microsoft.NETCore.App": { + "privateAssets": "all" + } + }, + "runtimeIdentifierGraphPath": "/usr/local/share/dotnet/sdk/9.0.100/PortableRuntimeIdentifierGraph.json" + } + } + } +} \ No newline at end of file diff --git a/聊天系统课程代码/NuGet/ConfigTableTool/obj/project.nuget.cache b/聊天系统课程代码/NuGet/ConfigTableTool/obj/project.nuget.cache new file mode 100644 index 0000000..303ce4d --- /dev/null +++ b/聊天系统课程代码/NuGet/ConfigTableTool/obj/project.nuget.cache @@ -0,0 +1,10 @@ +{ + "version": 2, + "dgSpecHash": "Xlz10w2fDPc=", + "success": true, + "projectFilePath": "/Users/fantasy/Code/ServerLessions/Chat/NuGet/ConfigTableTool/ConfigTableTool.csproj", + "expectedPackageFiles": [ + "/Users/fantasy/.nuget/packages/fantasy-net.tools.exporterconfigtable/2024.1.8/fantasy-net.tools.exporterconfigtable.2024.1.8.nupkg.sha512" + ], + "logs": [] +} \ No newline at end of file diff --git a/聊天系统课程代码/NuGet/ConfigTableTool/obj/project.packagespec.json b/聊天系统课程代码/NuGet/ConfigTableTool/obj/project.packagespec.json new file mode 100644 index 0000000..459a6cf --- /dev/null +++ b/聊天系统课程代码/NuGet/ConfigTableTool/obj/project.packagespec.json @@ -0,0 +1 @@ +"restore":{"projectUniqueName":"/Users/fantasy/Code/ServerLessions/Chat/NuGet/ConfigTableTool/ConfigTableTool.csproj","projectName":"ConfigTableTool","projectPath":"/Users/fantasy/Code/ServerLessions/Chat/NuGet/ConfigTableTool/ConfigTableTool.csproj","outputPath":"/Users/fantasy/Code/ServerLessions/Chat/NuGet/ConfigTableTool/obj/","projectStyle":"PackageReference","UsingMicrosoftNETSdk":false,"originalTargetFrameworks":["net8.0"],"sources":{"https://api.nuget.org/v3/index.json":{}},"frameworks":{"net8.0":{"targetAlias":"net8.0","projectReferences":{}}},"warningProperties":{"warnAsError":["NU1605"]},"restoreAuditProperties":{"enableAudit":"true","auditLevel":"low","auditMode":"all"}}"frameworks":{"net8.0":{"targetAlias":"net8.0","dependencies":{"Fantasy-Net.Tools.ExporterConfigTable":{"target":"Package","version":"[2024.1.8, )"}},"imports":["net461","net462","net47","net471","net472","net48","net481"],"assetTargetFallback":true,"warn":true,"frameworkReferences":{"Microsoft.NETCore.App":{"privateAssets":"all"}},"runtimeIdentifierGraphPath":"/usr/local/share/dotnet/sdk/9.0.100/PortableRuntimeIdentifierGraph.json"}} \ No newline at end of file diff --git a/聊天系统课程代码/NuGet/ConfigTableTool/obj/rider.project.model.nuget.info b/聊天系统课程代码/NuGet/ConfigTableTool/obj/rider.project.model.nuget.info new file mode 100644 index 0000000..95ccddb --- /dev/null +++ b/聊天系统课程代码/NuGet/ConfigTableTool/obj/rider.project.model.nuget.info @@ -0,0 +1 @@ +17324493181399999 \ No newline at end of file diff --git a/聊天系统课程代码/NuGet/ConfigTableTool/obj/rider.project.restore.info b/聊天系统课程代码/NuGet/ConfigTableTool/obj/rider.project.restore.info new file mode 100644 index 0000000..2c3be70 --- /dev/null +++ b/聊天系统课程代码/NuGet/ConfigTableTool/obj/rider.project.restore.info @@ -0,0 +1 @@ +17331012473219545 \ No newline at end of file diff --git a/聊天系统课程代码/NuGet/NetworkProtocolTools/.DS_Store b/聊天系统课程代码/NuGet/NetworkProtocolTools/.DS_Store new file mode 100644 index 0000000..89ffc31 Binary files /dev/null and b/聊天系统课程代码/NuGet/NetworkProtocolTools/.DS_Store differ diff --git a/聊天系统课程代码/NuGet/NetworkProtocolTools/NetworkProtocolTools.csproj b/聊天系统课程代码/NuGet/NetworkProtocolTools/NetworkProtocolTools.csproj new file mode 100644 index 0000000..1552c5e --- /dev/null +++ b/聊天系统课程代码/NuGet/NetworkProtocolTools/NetworkProtocolTools.csproj @@ -0,0 +1,13 @@ + + + + net8.0 + enable + enable + + + + + + + diff --git a/聊天系统课程代码/NuGet/NetworkProtocolTools/Tools/.DS_Store b/聊天系统课程代码/NuGet/NetworkProtocolTools/Tools/.DS_Store new file mode 100644 index 0000000..a3512b8 Binary files /dev/null and b/聊天系统课程代码/NuGet/NetworkProtocolTools/Tools/.DS_Store differ diff --git a/聊天系统课程代码/NuGet/NetworkProtocolTools/Tools/Exporter/NetworkProtocol/CommandLine.dll b/聊天系统课程代码/NuGet/NetworkProtocolTools/Tools/Exporter/NetworkProtocol/CommandLine.dll new file mode 100644 index 0000000..3eab2be Binary files /dev/null and b/聊天系统课程代码/NuGet/NetworkProtocolTools/Tools/Exporter/NetworkProtocol/CommandLine.dll differ diff --git a/聊天系统课程代码/NuGet/NetworkProtocolTools/Tools/Exporter/NetworkProtocol/ExporterSettings.json b/聊天系统课程代码/NuGet/NetworkProtocolTools/Tools/Exporter/NetworkProtocol/ExporterSettings.json new file mode 100644 index 0000000..f093812 --- /dev/null +++ b/聊天系统课程代码/NuGet/NetworkProtocolTools/Tools/Exporter/NetworkProtocol/ExporterSettings.json @@ -0,0 +1,29 @@ +{ + "Export": { + "NetworkProtocolDirectory": { + "Value": "../../../Examples/Config/NetworkProtocol/", + "Comment": "ProtoBuf文件所在的文件夹位置" + }, + "NetworkProtocolServerDirectory": { + "Value": "../../../Examples/Server/Entity/Generate/NetworkProtocol/", + "Comment": "ProtoBuf生成到服务端的文件夹位置" + }, + "NetworkProtocolClientDirectory": { + "Value": "../../../Examples/Client/Unity/Assets/Scripts/Hotfix/Generate/NetworkProtocol/", + "Comment": "ProtoBuf生成到客户端的文件夹位置" + }, + "Serializes": { + "Value": [ +// { +// "KeyIndex": 0, +// "NameSpace" : "MemoryPack", +// "SerializeName": "MemoryPack", +// "Attribute": "\t[MemoryPackable]", +// "Ignore": "\t\t[MemoryPackIgnore]", +// "Member": "MemoryPackOrder" +// } + ], + "Comment": "自定义序列化器" + } + } +} \ No newline at end of file diff --git a/聊天系统课程代码/NuGet/NetworkProtocolTools/Tools/Exporter/NetworkProtocol/Fantasy.Tools.NetworkProtocol b/聊天系统课程代码/NuGet/NetworkProtocolTools/Tools/Exporter/NetworkProtocol/Fantasy.Tools.NetworkProtocol new file mode 100644 index 0000000..21bd520 Binary files /dev/null and b/聊天系统课程代码/NuGet/NetworkProtocolTools/Tools/Exporter/NetworkProtocol/Fantasy.Tools.NetworkProtocol differ diff --git a/聊天系统课程代码/NuGet/NetworkProtocolTools/Tools/Exporter/NetworkProtocol/Fantasy.Tools.NetworkProtocol.deps.json b/聊天系统课程代码/NuGet/NetworkProtocolTools/Tools/Exporter/NetworkProtocol/Fantasy.Tools.NetworkProtocol.deps.json new file mode 100644 index 0000000..3c053cb --- /dev/null +++ b/聊天系统课程代码/NuGet/NetworkProtocolTools/Tools/Exporter/NetworkProtocol/Fantasy.Tools.NetworkProtocol.deps.json @@ -0,0 +1,227 @@ +{ + "runtimeTarget": { + "name": ".NETCoreApp,Version=v8.0", + "signature": "" + }, + "compilationOptions": {}, + "targets": { + ".NETCoreApp,Version=v8.0": { + "Fantasy.Tools.NetworkProtocol/1.0.0": { + "dependencies": { + "CommandLineParser": "2.9.1", + "Microsoft.Extensions.Configuration.Json": "8.0.0", + "Newtonsoft.Json": "13.0.3" + }, + "runtime": { + "Fantasy.Tools.NetworkProtocol.dll": {} + } + }, + "CommandLineParser/2.9.1": { + "runtime": { + "lib/netstandard2.0/CommandLine.dll": { + "assemblyVersion": "2.9.1.0", + "fileVersion": "2.9.1.0" + } + } + }, + "Microsoft.Extensions.Configuration/8.0.0": { + "dependencies": { + "Microsoft.Extensions.Configuration.Abstractions": "8.0.0", + "Microsoft.Extensions.Primitives": "8.0.0" + }, + "runtime": { + "lib/net8.0/Microsoft.Extensions.Configuration.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.23.53103" + } + } + }, + "Microsoft.Extensions.Configuration.Abstractions/8.0.0": { + "dependencies": { + "Microsoft.Extensions.Primitives": "8.0.0" + }, + "runtime": { + "lib/net8.0/Microsoft.Extensions.Configuration.Abstractions.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.23.53103" + } + } + }, + "Microsoft.Extensions.Configuration.FileExtensions/8.0.0": { + "dependencies": { + "Microsoft.Extensions.Configuration": "8.0.0", + "Microsoft.Extensions.Configuration.Abstractions": "8.0.0", + "Microsoft.Extensions.FileProviders.Abstractions": "8.0.0", + "Microsoft.Extensions.FileProviders.Physical": "8.0.0", + "Microsoft.Extensions.Primitives": "8.0.0" + }, + "runtime": { + "lib/net8.0/Microsoft.Extensions.Configuration.FileExtensions.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.23.53103" + } + } + }, + "Microsoft.Extensions.Configuration.Json/8.0.0": { + "dependencies": { + "Microsoft.Extensions.Configuration": "8.0.0", + "Microsoft.Extensions.Configuration.Abstractions": "8.0.0", + "Microsoft.Extensions.Configuration.FileExtensions": "8.0.0", + "Microsoft.Extensions.FileProviders.Abstractions": "8.0.0", + "System.Text.Json": "8.0.0" + }, + "runtime": { + "lib/net8.0/Microsoft.Extensions.Configuration.Json.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.23.53103" + } + } + }, + "Microsoft.Extensions.FileProviders.Abstractions/8.0.0": { + "dependencies": { + "Microsoft.Extensions.Primitives": "8.0.0" + }, + "runtime": { + "lib/net8.0/Microsoft.Extensions.FileProviders.Abstractions.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.23.53103" + } + } + }, + "Microsoft.Extensions.FileProviders.Physical/8.0.0": { + "dependencies": { + "Microsoft.Extensions.FileProviders.Abstractions": "8.0.0", + "Microsoft.Extensions.FileSystemGlobbing": "8.0.0", + "Microsoft.Extensions.Primitives": "8.0.0" + }, + "runtime": { + "lib/net8.0/Microsoft.Extensions.FileProviders.Physical.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.23.53103" + } + } + }, + "Microsoft.Extensions.FileSystemGlobbing/8.0.0": { + "runtime": { + "lib/net8.0/Microsoft.Extensions.FileSystemGlobbing.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.23.53103" + } + } + }, + "Microsoft.Extensions.Primitives/8.0.0": { + "runtime": { + "lib/net8.0/Microsoft.Extensions.Primitives.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.23.53103" + } + } + }, + "Newtonsoft.Json/13.0.3": { + "runtime": { + "lib/net6.0/Newtonsoft.Json.dll": { + "assemblyVersion": "13.0.0.0", + "fileVersion": "13.0.3.27908" + } + } + }, + "System.Text.Encodings.Web/8.0.0": {}, + "System.Text.Json/8.0.0": { + "dependencies": { + "System.Text.Encodings.Web": "8.0.0" + } + } + } + }, + "libraries": { + "Fantasy.Tools.NetworkProtocol/1.0.0": { + "type": "project", + "serviceable": false, + "sha512": "" + }, + "CommandLineParser/2.9.1": { + "type": "package", + "serviceable": true, + "sha512": "sha512-OE0sl1/sQ37bjVsPKKtwQlWDgqaxWgtme3xZz7JssWUzg5JpMIyHgCTY9MVMxOg48fJ1AgGT3tgdH5m/kQ5xhA==", + "path": "commandlineparser/2.9.1", + "hashPath": "commandlineparser.2.9.1.nupkg.sha512" + }, + "Microsoft.Extensions.Configuration/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-0J/9YNXTMWSZP2p2+nvl8p71zpSwokZXZuJW+VjdErkegAnFdO1XlqtA62SJtgVYHdKu3uPxJHcMR/r35HwFBA==", + "path": "microsoft.extensions.configuration/8.0.0", + "hashPath": "microsoft.extensions.configuration.8.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.Configuration.Abstractions/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-3lE/iLSutpgX1CC0NOW70FJoGARRHbyKmG7dc0klnUZ9Dd9hS6N/POPWhKhMLCEuNN5nXEY5agmlFtH562vqhQ==", + "path": "microsoft.extensions.configuration.abstractions/8.0.0", + "hashPath": "microsoft.extensions.configuration.abstractions.8.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.Configuration.FileExtensions/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-McP+Lz/EKwvtCv48z0YImw+L1gi1gy5rHhNaNIY2CrjloV+XY8gydT8DjMR6zWeL13AFK+DioVpppwAuO1Gi1w==", + "path": "microsoft.extensions.configuration.fileextensions/8.0.0", + "hashPath": "microsoft.extensions.configuration.fileextensions.8.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.Configuration.Json/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-C2wqUoh9OmRL1akaCcKSTmRU8z0kckfImG7zLNI8uyi47Lp+zd5LWAD17waPQEqCz3ioWOCrFUo+JJuoeZLOBw==", + "path": "microsoft.extensions.configuration.json/8.0.0", + "hashPath": "microsoft.extensions.configuration.json.8.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.FileProviders.Abstractions/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-ZbaMlhJlpisjuWbvXr4LdAst/1XxH3vZ6A0BsgTphZ2L4PGuxRLz7Jr/S7mkAAnOn78Vu0fKhEgNF5JO3zfjqQ==", + "path": "microsoft.extensions.fileproviders.abstractions/8.0.0", + "hashPath": "microsoft.extensions.fileproviders.abstractions.8.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.FileProviders.Physical/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-UboiXxpPUpwulHvIAVE36Knq0VSHaAmfrFkegLyBZeaADuKezJ/AIXYAW8F5GBlGk/VaibN2k/Zn1ca8YAfVdA==", + "path": "microsoft.extensions.fileproviders.physical/8.0.0", + "hashPath": "microsoft.extensions.fileproviders.physical.8.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.FileSystemGlobbing/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-OK+670i7esqlQrPjdIKRbsyMCe9g5kSLpRRQGSr4Q58AOYEe/hCnfLZprh7viNisSUUQZmMrbbuDaIrP+V1ebQ==", + "path": "microsoft.extensions.filesystemglobbing/8.0.0", + "hashPath": "microsoft.extensions.filesystemglobbing.8.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.Primitives/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-bXJEZrW9ny8vjMF1JV253WeLhpEVzFo1lyaZu1vQ4ZxWUlVvknZ/+ftFgVheLubb4eZPSwwxBeqS1JkCOjxd8g==", + "path": "microsoft.extensions.primitives/8.0.0", + "hashPath": "microsoft.extensions.primitives.8.0.0.nupkg.sha512" + }, + "Newtonsoft.Json/13.0.3": { + "type": "package", + "serviceable": true, + "sha512": "sha512-HrC5BXdl00IP9zeV+0Z848QWPAoCr9P3bDEZguI+gkLcBKAOxix/tLEAAHC+UvDNPv4a2d18lOReHMOagPa+zQ==", + "path": "newtonsoft.json/13.0.3", + "hashPath": "newtonsoft.json.13.0.3.nupkg.sha512" + }, + "System.Text.Encodings.Web/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-yev/k9GHAEGx2Rg3/tU6MQh4HGBXJs70y7j1LaM1i/ER9po+6nnQ6RRqTJn1E7Xu0fbIFK80Nh5EoODxrbxwBQ==", + "path": "system.text.encodings.web/8.0.0", + "hashPath": "system.text.encodings.web.8.0.0.nupkg.sha512" + }, + "System.Text.Json/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-OdrZO2WjkiEG6ajEFRABTRCi/wuXQPxeV6g8xvUJqdxMvvuCCEk86zPla8UiIQJz3durtUEbNyY/3lIhS0yZvQ==", + "path": "system.text.json/8.0.0", + "hashPath": "system.text.json.8.0.0.nupkg.sha512" + } + } +} \ No newline at end of file diff --git a/聊天系统课程代码/NuGet/NetworkProtocolTools/Tools/Exporter/NetworkProtocol/Fantasy.Tools.NetworkProtocol.dll b/聊天系统课程代码/NuGet/NetworkProtocolTools/Tools/Exporter/NetworkProtocol/Fantasy.Tools.NetworkProtocol.dll new file mode 100644 index 0000000..014a40f Binary files /dev/null and b/聊天系统课程代码/NuGet/NetworkProtocolTools/Tools/Exporter/NetworkProtocol/Fantasy.Tools.NetworkProtocol.dll differ diff --git a/聊天系统课程代码/NuGet/NetworkProtocolTools/Tools/Exporter/NetworkProtocol/Fantasy.Tools.NetworkProtocol.pdb b/聊天系统课程代码/NuGet/NetworkProtocolTools/Tools/Exporter/NetworkProtocol/Fantasy.Tools.NetworkProtocol.pdb new file mode 100644 index 0000000..a64337f Binary files /dev/null and b/聊天系统课程代码/NuGet/NetworkProtocolTools/Tools/Exporter/NetworkProtocol/Fantasy.Tools.NetworkProtocol.pdb differ diff --git a/聊天系统课程代码/NuGet/NetworkProtocolTools/Tools/Exporter/NetworkProtocol/Fantasy.Tools.NetworkProtocol.runtimeconfig.json b/聊天系统课程代码/NuGet/NetworkProtocolTools/Tools/Exporter/NetworkProtocol/Fantasy.Tools.NetworkProtocol.runtimeconfig.json new file mode 100644 index 0000000..becfaea --- /dev/null +++ b/聊天系统课程代码/NuGet/NetworkProtocolTools/Tools/Exporter/NetworkProtocol/Fantasy.Tools.NetworkProtocol.runtimeconfig.json @@ -0,0 +1,12 @@ +{ + "runtimeOptions": { + "tfm": "net8.0", + "framework": { + "name": "Microsoft.NETCore.App", + "version": "8.0.0" + }, + "configProperties": { + "System.Runtime.Serialization.EnableUnsafeBinaryFormatterSerialization": false + } + } +} \ No newline at end of file diff --git a/聊天系统课程代码/NuGet/NetworkProtocolTools/Tools/Exporter/NetworkProtocol/Microsoft.Extensions.Configuration.Abstractions.dll b/聊天系统课程代码/NuGet/NetworkProtocolTools/Tools/Exporter/NetworkProtocol/Microsoft.Extensions.Configuration.Abstractions.dll new file mode 100644 index 0000000..a5ab313 Binary files /dev/null and b/聊天系统课程代码/NuGet/NetworkProtocolTools/Tools/Exporter/NetworkProtocol/Microsoft.Extensions.Configuration.Abstractions.dll differ diff --git a/聊天系统课程代码/NuGet/NetworkProtocolTools/Tools/Exporter/NetworkProtocol/Microsoft.Extensions.Configuration.FileExtensions.dll b/聊天系统课程代码/NuGet/NetworkProtocolTools/Tools/Exporter/NetworkProtocol/Microsoft.Extensions.Configuration.FileExtensions.dll new file mode 100644 index 0000000..4efc1a5 Binary files /dev/null and b/聊天系统课程代码/NuGet/NetworkProtocolTools/Tools/Exporter/NetworkProtocol/Microsoft.Extensions.Configuration.FileExtensions.dll differ diff --git a/聊天系统课程代码/NuGet/NetworkProtocolTools/Tools/Exporter/NetworkProtocol/Microsoft.Extensions.Configuration.Json.dll b/聊天系统课程代码/NuGet/NetworkProtocolTools/Tools/Exporter/NetworkProtocol/Microsoft.Extensions.Configuration.Json.dll new file mode 100644 index 0000000..296db6a Binary files /dev/null and b/聊天系统课程代码/NuGet/NetworkProtocolTools/Tools/Exporter/NetworkProtocol/Microsoft.Extensions.Configuration.Json.dll differ diff --git a/聊天系统课程代码/NuGet/NetworkProtocolTools/Tools/Exporter/NetworkProtocol/Microsoft.Extensions.Configuration.dll b/聊天系统课程代码/NuGet/NetworkProtocolTools/Tools/Exporter/NetworkProtocol/Microsoft.Extensions.Configuration.dll new file mode 100644 index 0000000..d3e5c22 Binary files /dev/null and b/聊天系统课程代码/NuGet/NetworkProtocolTools/Tools/Exporter/NetworkProtocol/Microsoft.Extensions.Configuration.dll differ diff --git a/聊天系统课程代码/NuGet/NetworkProtocolTools/Tools/Exporter/NetworkProtocol/Microsoft.Extensions.FileProviders.Abstractions.dll b/聊天系统课程代码/NuGet/NetworkProtocolTools/Tools/Exporter/NetworkProtocol/Microsoft.Extensions.FileProviders.Abstractions.dll new file mode 100644 index 0000000..f907206 Binary files /dev/null and b/聊天系统课程代码/NuGet/NetworkProtocolTools/Tools/Exporter/NetworkProtocol/Microsoft.Extensions.FileProviders.Abstractions.dll differ diff --git a/聊天系统课程代码/NuGet/NetworkProtocolTools/Tools/Exporter/NetworkProtocol/Microsoft.Extensions.FileProviders.Physical.dll b/聊天系统课程代码/NuGet/NetworkProtocolTools/Tools/Exporter/NetworkProtocol/Microsoft.Extensions.FileProviders.Physical.dll new file mode 100644 index 0000000..6fb7f47 Binary files /dev/null and b/聊天系统课程代码/NuGet/NetworkProtocolTools/Tools/Exporter/NetworkProtocol/Microsoft.Extensions.FileProviders.Physical.dll differ diff --git a/聊天系统课程代码/NuGet/NetworkProtocolTools/Tools/Exporter/NetworkProtocol/Microsoft.Extensions.FileSystemGlobbing.dll b/聊天系统课程代码/NuGet/NetworkProtocolTools/Tools/Exporter/NetworkProtocol/Microsoft.Extensions.FileSystemGlobbing.dll new file mode 100644 index 0000000..e590735 Binary files /dev/null and b/聊天系统课程代码/NuGet/NetworkProtocolTools/Tools/Exporter/NetworkProtocol/Microsoft.Extensions.FileSystemGlobbing.dll differ diff --git a/聊天系统课程代码/NuGet/NetworkProtocolTools/Tools/Exporter/NetworkProtocol/Microsoft.Extensions.Primitives.dll b/聊天系统课程代码/NuGet/NetworkProtocolTools/Tools/Exporter/NetworkProtocol/Microsoft.Extensions.Primitives.dll new file mode 100644 index 0000000..c24f2a0 Binary files /dev/null and b/聊天系统课程代码/NuGet/NetworkProtocolTools/Tools/Exporter/NetworkProtocol/Microsoft.Extensions.Primitives.dll differ diff --git a/聊天系统课程代码/NuGet/NetworkProtocolTools/Tools/Exporter/NetworkProtocol/Newtonsoft.Json.dll b/聊天系统课程代码/NuGet/NetworkProtocolTools/Tools/Exporter/NetworkProtocol/Newtonsoft.Json.dll new file mode 100644 index 0000000..d035c38 Binary files /dev/null and b/聊天系统课程代码/NuGet/NetworkProtocolTools/Tools/Exporter/NetworkProtocol/Newtonsoft.Json.dll differ diff --git a/聊天系统课程代码/NuGet/NetworkProtocolTools/Tools/Exporter/NetworkProtocol/Run.bat b/聊天系统课程代码/NuGet/NetworkProtocolTools/Tools/Exporter/NetworkProtocol/Run.bat new file mode 100644 index 0000000..8551afc --- /dev/null +++ b/聊天系统课程代码/NuGet/NetworkProtocolTools/Tools/Exporter/NetworkProtocol/Run.bat @@ -0,0 +1,21 @@ +@echo off + +echo Please select an option: +echo 1. Client +echo 2. Server +echo 3. All + +set /p choice=Please select an option: + +if "%choice%"=="1" ( + echo Client + dotnet Fantasy.Tools.NetworkProtocol.dll --ExportPlatform 1 +) else if "%choice%"=="2" ( + echo Server + dotnet Fantasy.Tools.NetworkProtocol.dll --ExportPlatform 2 +) else if "%choice%"=="3" ( + echo All + dotnet Fantasy.Tools.NetworkProtocol.dll --ExportPlatform 3 +) else ( + echo Invalid option +) diff --git a/聊天系统课程代码/NuGet/NetworkProtocolTools/Tools/Exporter/NetworkProtocol/Run.sh b/聊天系统课程代码/NuGet/NetworkProtocolTools/Tools/Exporter/NetworkProtocol/Run.sh new file mode 100644 index 0000000..763ce02 --- /dev/null +++ b/聊天系统课程代码/NuGet/NetworkProtocolTools/Tools/Exporter/NetworkProtocol/Run.sh @@ -0,0 +1,23 @@ +#!/bin/bash + +echo "1. Client" +echo "2. Server" +echo "3. All" + +read -n 1 -p "Please select an option:" choice +echo "" +echo "" +case $choice in + 1) + dotnet Fantasy.Tools.NetworkProtocol.dll --ExportPlatform 1 + ;; + 2) + dotnet Fantasy.Tools.NetworkProtocol.dll --ExportPlatform 2 + ;; + 3) + dotnet Fantasy.Tools.NetworkProtocol.dll --ExportPlatform 3 + ;; + *) + echo "Invalid option" + ;; +esac diff --git a/聊天系统课程代码/NuGet/NetworkProtocolTools/obj/Debug/net8.0/.NETCoreApp,Version=v8.0.AssemblyAttributes.cs b/聊天系统课程代码/NuGet/NetworkProtocolTools/obj/Debug/net8.0/.NETCoreApp,Version=v8.0.AssemblyAttributes.cs new file mode 100644 index 0000000..2217181 --- /dev/null +++ b/聊天系统课程代码/NuGet/NetworkProtocolTools/obj/Debug/net8.0/.NETCoreApp,Version=v8.0.AssemblyAttributes.cs @@ -0,0 +1,4 @@ +// +using System; +using System.Reflection; +[assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute(".NETCoreApp,Version=v8.0", FrameworkDisplayName = ".NET 8.0")] diff --git a/聊天系统课程代码/NuGet/NetworkProtocolTools/obj/Debug/net8.0/NetworkProtocolTools.AssemblyInfo.cs b/聊天系统课程代码/NuGet/NetworkProtocolTools/obj/Debug/net8.0/NetworkProtocolTools.AssemblyInfo.cs new file mode 100644 index 0000000..8b2ed46 --- /dev/null +++ b/聊天系统课程代码/NuGet/NetworkProtocolTools/obj/Debug/net8.0/NetworkProtocolTools.AssemblyInfo.cs @@ -0,0 +1,22 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +using System; +using System.Reflection; + +[assembly: System.Reflection.AssemblyCompanyAttribute("NetworkProtocolTools")] +[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")] +[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")] +[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0")] +[assembly: System.Reflection.AssemblyProductAttribute("NetworkProtocolTools")] +[assembly: System.Reflection.AssemblyTitleAttribute("NetworkProtocolTools")] +[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")] + +// 由 MSBuild WriteCodeFragment 类生成。 + diff --git a/聊天系统课程代码/NuGet/NetworkProtocolTools/obj/Debug/net8.0/NetworkProtocolTools.AssemblyInfoInputs.cache b/聊天系统课程代码/NuGet/NetworkProtocolTools/obj/Debug/net8.0/NetworkProtocolTools.AssemblyInfoInputs.cache new file mode 100644 index 0000000..20d3a2b --- /dev/null +++ b/聊天系统课程代码/NuGet/NetworkProtocolTools/obj/Debug/net8.0/NetworkProtocolTools.AssemblyInfoInputs.cache @@ -0,0 +1 @@ +6f469ac73ee78e9cbea0e9bdb2c6c6f79852f034200dbdbfe4ec1833ddb7d132 diff --git a/聊天系统课程代码/NuGet/NetworkProtocolTools/obj/Debug/net8.0/NetworkProtocolTools.GeneratedMSBuildEditorConfig.editorconfig b/聊天系统课程代码/NuGet/NetworkProtocolTools/obj/Debug/net8.0/NetworkProtocolTools.GeneratedMSBuildEditorConfig.editorconfig new file mode 100644 index 0000000..0822edc --- /dev/null +++ b/聊天系统课程代码/NuGet/NetworkProtocolTools/obj/Debug/net8.0/NetworkProtocolTools.GeneratedMSBuildEditorConfig.editorconfig @@ -0,0 +1,15 @@ +is_global = true +build_property.TargetFramework = net8.0 +build_property.TargetPlatformMinVersion = +build_property.UsingMicrosoftNETSdkWeb = +build_property.ProjectTypeGuids = +build_property.InvariantGlobalization = +build_property.PlatformNeutralAssembly = +build_property.EnforceExtendedAnalyzerRules = +build_property._SupportedPlatformList = Linux,macOS,Windows +build_property.RootNamespace = NetworkProtocolTools +build_property.ProjectDir = /Users/fantasy/Code/ServerLessions/Chat/NuGet/NetworkProtocolTools/ +build_property.EnableComHosting = +build_property.EnableGeneratedComInterfaceComImportInterop = +build_property.EffectiveAnalysisLevelStyle = 8.0 +build_property.EnableCodeStyleSeverity = diff --git a/聊天系统课程代码/NuGet/NetworkProtocolTools/obj/Debug/net8.0/NetworkProtocolTools.GlobalUsings.g.cs b/聊天系统课程代码/NuGet/NetworkProtocolTools/obj/Debug/net8.0/NetworkProtocolTools.GlobalUsings.g.cs new file mode 100644 index 0000000..8578f3d --- /dev/null +++ b/聊天系统课程代码/NuGet/NetworkProtocolTools/obj/Debug/net8.0/NetworkProtocolTools.GlobalUsings.g.cs @@ -0,0 +1,8 @@ +// +global using global::System; +global using global::System.Collections.Generic; +global using global::System.IO; +global using global::System.Linq; +global using global::System.Net.Http; +global using global::System.Threading; +global using global::System.Threading.Tasks; diff --git a/聊天系统课程代码/NuGet/NetworkProtocolTools/obj/Debug/net8.0/NetworkProtocolTools.assets.cache b/聊天系统课程代码/NuGet/NetworkProtocolTools/obj/Debug/net8.0/NetworkProtocolTools.assets.cache new file mode 100644 index 0000000..02357e8 Binary files /dev/null and b/聊天系统课程代码/NuGet/NetworkProtocolTools/obj/Debug/net8.0/NetworkProtocolTools.assets.cache differ diff --git a/聊天系统课程代码/NuGet/NetworkProtocolTools/obj/Debug/net8.0/NetworkProtocolTools.csproj.AssemblyReference.cache b/聊天系统课程代码/NuGet/NetworkProtocolTools/obj/Debug/net8.0/NetworkProtocolTools.csproj.AssemblyReference.cache new file mode 100644 index 0000000..40767cd Binary files /dev/null and b/聊天系统课程代码/NuGet/NetworkProtocolTools/obj/Debug/net8.0/NetworkProtocolTools.csproj.AssemblyReference.cache differ diff --git a/聊天系统课程代码/NuGet/NetworkProtocolTools/obj/NetworkProtocolTools.csproj.nuget.dgspec.json b/聊天系统课程代码/NuGet/NetworkProtocolTools/obj/NetworkProtocolTools.csproj.nuget.dgspec.json new file mode 100644 index 0000000..a6de650 --- /dev/null +++ b/聊天系统课程代码/NuGet/NetworkProtocolTools/obj/NetworkProtocolTools.csproj.nuget.dgspec.json @@ -0,0 +1,73 @@ +{ + "format": 1, + "restore": { + "/Users/fantasy/Code/ServerLessions/Chat/NuGet/NetworkProtocolTools/NetworkProtocolTools.csproj": {} + }, + "projects": { + "/Users/fantasy/Code/ServerLessions/Chat/NuGet/NetworkProtocolTools/NetworkProtocolTools.csproj": { + "version": "1.0.0", + "restore": { + "projectUniqueName": "/Users/fantasy/Code/ServerLessions/Chat/NuGet/NetworkProtocolTools/NetworkProtocolTools.csproj", + "projectName": "NetworkProtocolTools", + "projectPath": "/Users/fantasy/Code/ServerLessions/Chat/NuGet/NetworkProtocolTools/NetworkProtocolTools.csproj", + "packagesPath": "/Users/fantasy/.nuget/packages/", + "outputPath": "/Users/fantasy/Code/ServerLessions/Chat/NuGet/NetworkProtocolTools/obj/", + "projectStyle": "PackageReference", + "UsingMicrosoftNETSdk": false, + "configFilePaths": [ + "/Users/fantasy/.nuget/NuGet/NuGet.Config" + ], + "originalTargetFrameworks": [ + "net8.0" + ], + "sources": { + "https://api.nuget.org/v3/index.json": {} + }, + "frameworks": { + "net8.0": { + "targetAlias": "net8.0", + "projectReferences": {} + } + }, + "warningProperties": { + "warnAsError": [ + "NU1605" + ] + }, + "restoreAuditProperties": { + "enableAudit": "true", + "auditLevel": "low", + "auditMode": "all" + } + }, + "frameworks": { + "net8.0": { + "targetAlias": "net8.0", + "dependencies": { + "Fantasy-Net.Tools.ExporterNetworkProtocol": { + "target": "Package", + "version": "[2024.1.7, )" + } + }, + "imports": [ + "net461", + "net462", + "net47", + "net471", + "net472", + "net48", + "net481" + ], + "assetTargetFallback": true, + "warn": true, + "frameworkReferences": { + "Microsoft.NETCore.App": { + "privateAssets": "all" + } + }, + "runtimeIdentifierGraphPath": "/usr/local/share/dotnet/sdk/9.0.100/PortableRuntimeIdentifierGraph.json" + } + } + } + } +} \ No newline at end of file diff --git a/聊天系统课程代码/NuGet/NetworkProtocolTools/obj/NetworkProtocolTools.csproj.nuget.g.props b/聊天系统课程代码/NuGet/NetworkProtocolTools/obj/NetworkProtocolTools.csproj.nuget.g.props new file mode 100644 index 0000000..b5bd0bc --- /dev/null +++ b/聊天系统课程代码/NuGet/NetworkProtocolTools/obj/NetworkProtocolTools.csproj.nuget.g.props @@ -0,0 +1,18 @@ + + + + True + NuGet + $(MSBuildThisFileDirectory)project.assets.json + /Users/fantasy/.nuget/packages/ + /Users/fantasy/.nuget/packages/ + PackageReference + 6.12.0 + + + + + + /Users/fantasy/.nuget/packages/fantasy-net.tools.exporternetworkprotocol/2024.1.7 + + \ No newline at end of file diff --git a/聊天系统课程代码/NuGet/NetworkProtocolTools/obj/NetworkProtocolTools.csproj.nuget.g.targets b/聊天系统课程代码/NuGet/NetworkProtocolTools/obj/NetworkProtocolTools.csproj.nuget.g.targets new file mode 100644 index 0000000..f254cbb --- /dev/null +++ b/聊天系统课程代码/NuGet/NetworkProtocolTools/obj/NetworkProtocolTools.csproj.nuget.g.targets @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/聊天系统课程代码/NuGet/NetworkProtocolTools/obj/project.assets.json b/聊天系统课程代码/NuGet/NetworkProtocolTools/obj/project.assets.json new file mode 100644 index 0000000..1edddbd --- /dev/null +++ b/聊天系统课程代码/NuGet/NetworkProtocolTools/obj/project.assets.json @@ -0,0 +1,127 @@ +{ + "version": 3, + "targets": { + "net8.0": { + "Fantasy-Net.Tools.ExporterNetworkProtocol/2024.1.7": { + "type": "package", + "compile": { + "lib/net8.0/Fantasy.Tools.ExporterNetworkProtocol.dll": {} + }, + "runtime": { + "lib/net8.0/Fantasy.Tools.ExporterNetworkProtocol.dll": {} + }, + "build": { + "buildTransitive/Fantasy-Net.Tools.ExporterNetworkProtocol.targets": {} + } + } + } + }, + "libraries": { + "Fantasy-Net.Tools.ExporterNetworkProtocol/2024.1.7": { + "sha512": "yGtXwXU14UgMHUMwV9qifxU7QHLz/GpuN9xpW5S5Zv4xoCqpmi8u5vFdRwWl5KmitfdjlSs96OVBGUJq3e49rQ==", + "type": "package", + "path": "fantasy-net.tools.exporternetworkprotocol/2024.1.7", + "hasTools": true, + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "buildTransitive/Fantasy-Net.Tools.ExporterNetworkProtocol.targets", + "fantasy-net.tools.exporternetworkprotocol.2024.1.7.nupkg.sha512", + "fantasy-net.tools.exporternetworkprotocol.nuspec", + "icon.png", + "lib/net8.0/Fantasy.Tools.ExporterNetworkProtocol.dll", + "tools/output/CommandLine.dll", + "tools/output/ExporterSettings.json", + "tools/output/Fantasy.Tools.NetworkProtocol", + "tools/output/Fantasy.Tools.NetworkProtocol.deps.json", + "tools/output/Fantasy.Tools.NetworkProtocol.dll", + "tools/output/Fantasy.Tools.NetworkProtocol.pdb", + "tools/output/Fantasy.Tools.NetworkProtocol.runtimeconfig.json", + "tools/output/Microsoft.Extensions.Configuration.Abstractions.dll", + "tools/output/Microsoft.Extensions.Configuration.FileExtensions.dll", + "tools/output/Microsoft.Extensions.Configuration.Json.dll", + "tools/output/Microsoft.Extensions.Configuration.dll", + "tools/output/Microsoft.Extensions.FileProviders.Abstractions.dll", + "tools/output/Microsoft.Extensions.FileProviders.Physical.dll", + "tools/output/Microsoft.Extensions.FileSystemGlobbing.dll", + "tools/output/Microsoft.Extensions.Primitives.dll", + "tools/output/Newtonsoft.Json.dll", + "tools/output/Run.bat", + "tools/output/Run.sh" + ] + } + }, + "projectFileDependencyGroups": { + "net8.0": [ + "Fantasy-Net.Tools.ExporterNetworkProtocol >= 2024.1.7" + ] + }, + "packageFolders": { + "/Users/fantasy/.nuget/packages/": {} + }, + "project": { + "version": "1.0.0", + "restore": { + "projectUniqueName": "/Users/fantasy/Code/ServerLessions/Chat/NuGet/NetworkProtocolTools/NetworkProtocolTools.csproj", + "projectName": "NetworkProtocolTools", + "projectPath": "/Users/fantasy/Code/ServerLessions/Chat/NuGet/NetworkProtocolTools/NetworkProtocolTools.csproj", + "packagesPath": "/Users/fantasy/.nuget/packages/", + "outputPath": "/Users/fantasy/Code/ServerLessions/Chat/NuGet/NetworkProtocolTools/obj/", + "projectStyle": "PackageReference", + "UsingMicrosoftNETSdk": false, + "configFilePaths": [ + "/Users/fantasy/.nuget/NuGet/NuGet.Config" + ], + "originalTargetFrameworks": [ + "net8.0" + ], + "sources": { + "https://api.nuget.org/v3/index.json": {} + }, + "frameworks": { + "net8.0": { + "targetAlias": "net8.0", + "projectReferences": {} + } + }, + "warningProperties": { + "warnAsError": [ + "NU1605" + ] + }, + "restoreAuditProperties": { + "enableAudit": "true", + "auditLevel": "low", + "auditMode": "all" + } + }, + "frameworks": { + "net8.0": { + "targetAlias": "net8.0", + "dependencies": { + "Fantasy-Net.Tools.ExporterNetworkProtocol": { + "target": "Package", + "version": "[2024.1.7, )" + } + }, + "imports": [ + "net461", + "net462", + "net47", + "net471", + "net472", + "net48", + "net481" + ], + "assetTargetFallback": true, + "warn": true, + "frameworkReferences": { + "Microsoft.NETCore.App": { + "privateAssets": "all" + } + }, + "runtimeIdentifierGraphPath": "/usr/local/share/dotnet/sdk/9.0.100/PortableRuntimeIdentifierGraph.json" + } + } + } +} \ No newline at end of file diff --git a/聊天系统课程代码/NuGet/NetworkProtocolTools/obj/project.nuget.cache b/聊天系统课程代码/NuGet/NetworkProtocolTools/obj/project.nuget.cache new file mode 100644 index 0000000..d7b8b3b --- /dev/null +++ b/聊天系统课程代码/NuGet/NetworkProtocolTools/obj/project.nuget.cache @@ -0,0 +1,10 @@ +{ + "version": 2, + "dgSpecHash": "GSq0O7PQwe0=", + "success": true, + "projectFilePath": "/Users/fantasy/Code/ServerLessions/Chat/NuGet/NetworkProtocolTools/NetworkProtocolTools.csproj", + "expectedPackageFiles": [ + "/Users/fantasy/.nuget/packages/fantasy-net.tools.exporternetworkprotocol/2024.1.7/fantasy-net.tools.exporternetworkprotocol.2024.1.7.nupkg.sha512" + ], + "logs": [] +} \ No newline at end of file diff --git a/聊天系统课程代码/NuGet/NetworkProtocolTools/obj/project.packagespec.json b/聊天系统课程代码/NuGet/NetworkProtocolTools/obj/project.packagespec.json new file mode 100644 index 0000000..0f5dbc5 --- /dev/null +++ b/聊天系统课程代码/NuGet/NetworkProtocolTools/obj/project.packagespec.json @@ -0,0 +1 @@ +"restore":{"projectUniqueName":"/Users/fantasy/Code/ServerLessions/Chat/NuGet/NetworkProtocolTools/NetworkProtocolTools.csproj","projectName":"NetworkProtocolTools","projectPath":"/Users/fantasy/Code/ServerLessions/Chat/NuGet/NetworkProtocolTools/NetworkProtocolTools.csproj","outputPath":"/Users/fantasy/Code/ServerLessions/Chat/NuGet/NetworkProtocolTools/obj/","projectStyle":"PackageReference","UsingMicrosoftNETSdk":false,"originalTargetFrameworks":["net8.0"],"sources":{"https://api.nuget.org/v3/index.json":{}},"frameworks":{"net8.0":{"targetAlias":"net8.0","projectReferences":{}}},"warningProperties":{"warnAsError":["NU1605"]},"restoreAuditProperties":{"enableAudit":"true","auditLevel":"low","auditMode":"all"}}"frameworks":{"net8.0":{"targetAlias":"net8.0","dependencies":{"Fantasy-Net.Tools.ExporterNetworkProtocol":{"target":"Package","version":"[2024.1.7, )"}},"imports":["net461","net462","net47","net471","net472","net48","net481"],"assetTargetFallback":true,"warn":true,"frameworkReferences":{"Microsoft.NETCore.App":{"privateAssets":"all"}},"runtimeIdentifierGraphPath":"/usr/local/share/dotnet/sdk/9.0.100/PortableRuntimeIdentifierGraph.json"}} \ No newline at end of file diff --git a/聊天系统课程代码/NuGet/NetworkProtocolTools/obj/rider.project.model.nuget.info b/聊天系统课程代码/NuGet/NetworkProtocolTools/obj/rider.project.model.nuget.info new file mode 100644 index 0000000..95ccddb --- /dev/null +++ b/聊天系统课程代码/NuGet/NetworkProtocolTools/obj/rider.project.model.nuget.info @@ -0,0 +1 @@ +17324493181399999 \ No newline at end of file diff --git a/聊天系统课程代码/NuGet/NetworkProtocolTools/obj/rider.project.restore.info b/聊天系统课程代码/NuGet/NetworkProtocolTools/obj/rider.project.restore.info new file mode 100644 index 0000000..f34f6f0 --- /dev/null +++ b/聊天系统课程代码/NuGet/NetworkProtocolTools/obj/rider.project.restore.info @@ -0,0 +1 @@ +17331012464952330 \ No newline at end of file diff --git a/聊天系统课程代码/Server/.DS_Store b/聊天系统课程代码/Server/.DS_Store new file mode 100644 index 0000000..c7345f3 Binary files /dev/null and b/聊天系统课程代码/Server/.DS_Store differ diff --git a/聊天系统课程代码/Server/Entity/AssemblyHelper.cs b/聊天系统课程代码/Server/Entity/AssemblyHelper.cs new file mode 100644 index 0000000..9d4b9d3 --- /dev/null +++ b/聊天系统课程代码/Server/Entity/AssemblyHelper.cs @@ -0,0 +1,34 @@ +using System.Runtime.Loader; + +namespace Fantasy; + +public static class AssemblyHelper +{ + private const string HotfixDll = "Hotfix"; + private static AssemblyLoadContext? _context = null; + + public static System.Reflection.Assembly[] Assemblies + { + get + { + var assemblies = new System.Reflection.Assembly[2]; + assemblies[0] = typeof(AssemblyHelper).Assembly; + assemblies[1] = LoadHotfixAssembly(); + return assemblies; + } + } + + private static System.Reflection.Assembly LoadHotfixAssembly() + { + if (_context != null) + { + _context.Unload(); + System.GC.Collect(); + } + + _context = new AssemblyLoadContext(HotfixDll, true); + var dllBytes = File.ReadAllBytes(Path.Combine(Environment.CurrentDirectory, $"{HotfixDll}.dll")); + var pdbBytes = File.ReadAllBytes(Path.Combine(Environment.CurrentDirectory, $"{HotfixDll}.pdb")); + return _context.LoadFromStream(new MemoryStream(dllBytes), new MemoryStream(pdbBytes)); + } +} \ No newline at end of file diff --git a/聊天系统课程代码/Server/Entity/Chat/Components/ChatChannelCenterComponent.cs b/聊天系统课程代码/Server/Entity/Chat/Components/ChatChannelCenterComponent.cs new file mode 100644 index 0000000..9b98a18 --- /dev/null +++ b/聊天系统课程代码/Server/Entity/Chat/Components/ChatChannelCenterComponent.cs @@ -0,0 +1,14 @@ +using Fantasy.Entitas; + +namespace Fantasy; + +/// +/// 聊天中控中心 +/// 1、申请、创建、解散聊天频道。 +/// 2、管理聊天频道成员。 +/// 3、根据频道ID找到对应的频道。 +/// +public class ChatChannelCenterComponent : Entity +{ + public readonly Dictionary Channels = new(); +} \ No newline at end of file diff --git a/聊天系统课程代码/Server/Entity/Chat/Components/ChatChannelComponent.cs b/聊天系统课程代码/Server/Entity/Chat/Components/ChatChannelComponent.cs new file mode 100644 index 0000000..e8c8f79 --- /dev/null +++ b/聊天系统课程代码/Server/Entity/Chat/Components/ChatChannelComponent.cs @@ -0,0 +1,16 @@ +using Fantasy.Entitas; +// ReSharper disable ArrangeObjectCreationWhenTypeEvident +// ReSharper disable UsageOfDefaultStructEquality + +namespace Fantasy; + +/// +/// 聊天频道实体 +/// 1、根据频道内的玩家进行广播聊天信息。 +/// 2、当前频道如果没有玩家的话,则自动销毁。 +/// 3、存放当前频道的玩家信息。 +/// +public sealed class ChatChannelComponent : Entity +{ + public readonly HashSet Units = new HashSet(); +} \ No newline at end of file diff --git a/聊天系统课程代码/Server/Entity/Chat/Components/ChatUnitManageComponent.cs b/聊天系统课程代码/Server/Entity/Chat/Components/ChatUnitManageComponent.cs new file mode 100644 index 0000000..168e4e2 --- /dev/null +++ b/聊天系统课程代码/Server/Entity/Chat/Components/ChatUnitManageComponent.cs @@ -0,0 +1,8 @@ +using Fantasy.Entitas; + +namespace Fantasy; + +public sealed class ChatUnitManageComponent : Entity +{ + public readonly Dictionary Units = new(); +} \ No newline at end of file diff --git a/聊天系统课程代码/Server/Entity/Chat/Enum/ChatChannelType.cs b/聊天系统课程代码/Server/Entity/Chat/Enum/ChatChannelType.cs new file mode 100644 index 0000000..b540ef7 --- /dev/null +++ b/聊天系统课程代码/Server/Entity/Chat/Enum/ChatChannelType.cs @@ -0,0 +1,49 @@ +namespace Fantasy; + +/// +/// 聊天频道类型 +/// +[Flags] +public enum ChatChannelType +{ + None = 0, + World = 1 << 1, // 世界频道 + Private = 1 << 2, // 私聊频道 + System = 1 << 3, // 系统频道 + Broadcast = 1 << 4, // 广播频道 + Notice = 1 << 5, // 公告频道 + Team = 1 << 6, // 队伍频道 + Near = 1 << 7, // 附近频道 + CurrentMap = 1 << 8, // 当前地图频道 + + // 所有频道 + All = World | Private | System | Broadcast | Notice | Team | Near, + // 其他聊天栏显示的频道 + Display = World | Private | System | Broadcast | Notice | Team | Near | CurrentMap +} + +/// +/// 聊天节点类型 +/// +public enum ChatNodeType +{ + None = 0, + Position = 1, // 位置节点 + OpenUI = 2, // 打开UI节点 + Link = 3, // 链接节点 + Item = 4, // 物品节点 + Text = 5, // 文本节点 + Image = 6, // 图片节点 +} + +/// +/// 聊天节点事件类型 +/// +public enum ChatNodeEvent +{ + None = 0, + OpenUI = 1, // 打开UI节点 + OpenLink = 2, // 点击链接节点 + UseItem = 3, // 使用物品节点 + Position = 4, // 位置节点 +} diff --git a/聊天系统课程代码/Server/Entity/Chat/Model/ChatInfoTree.cs b/聊天系统课程代码/Server/Entity/Chat/Model/ChatInfoTree.cs new file mode 100644 index 0000000..70f3330 --- /dev/null +++ b/聊天系统课程代码/Server/Entity/Chat/Model/ChatInfoTree.cs @@ -0,0 +1,15 @@ +using System.Runtime.Serialization; +using MongoDB.Bson.Serialization.Attributes; +using Newtonsoft.Json; +using ProtoBuf; + +namespace Fantasy; + +public partial class ChatInfoTree +{ + [BsonIgnore] + [JsonIgnore] + [ProtoIgnore] + [IgnoreDataMember] + public Scene Scene { get; set; } +} \ No newline at end of file diff --git a/聊天系统课程代码/Server/Entity/Chat/Model/ChatUnit.cs b/聊天系统课程代码/Server/Entity/Chat/Model/ChatUnit.cs new file mode 100644 index 0000000..fac1c27 --- /dev/null +++ b/聊天系统课程代码/Server/Entity/Chat/Model/ChatUnit.cs @@ -0,0 +1,11 @@ +using Fantasy.Entitas; + +namespace Fantasy; + +public sealed class ChatUnit : Entity +{ + public string UserName; + public long GateRouteId; + public readonly Dictionary Channels = new(); + public readonly Dictionary SendTime = new Dictionary(); +} \ No newline at end of file diff --git a/聊天系统课程代码/Server/Entity/Entity.csproj b/聊天系统课程代码/Server/Entity/Entity.csproj new file mode 100644 index 0000000..9e08380 --- /dev/null +++ b/聊天系统课程代码/Server/Entity/Entity.csproj @@ -0,0 +1,13 @@ + + + + net8.0 + enable + enable + + + + + + + diff --git a/聊天系统课程代码/Server/Entity/Gate/Components/GateUnitFlagComponent.cs b/聊天系统课程代码/Server/Entity/Gate/Components/GateUnitFlagComponent.cs new file mode 100644 index 0000000..5f25eba --- /dev/null +++ b/聊天系统课程代码/Server/Entity/Gate/Components/GateUnitFlagComponent.cs @@ -0,0 +1,8 @@ +using Fantasy.Entitas; + +namespace Fantasy; + +public sealed class GateUnitFlagComponent : Entity +{ + public long GateUnitId { get; set; } +} \ No newline at end of file diff --git a/聊天系统课程代码/Server/Entity/Gate/Components/GateUnitManageComponent.cs b/聊天系统课程代码/Server/Entity/Gate/Components/GateUnitManageComponent.cs new file mode 100644 index 0000000..ede71d6 --- /dev/null +++ b/聊天系统课程代码/Server/Entity/Gate/Components/GateUnitManageComponent.cs @@ -0,0 +1,9 @@ +using Fantasy.Entitas; + +namespace Fantasy; + +public sealed class GateUnitManageComponent : Entity +{ + public readonly Dictionary Units = new Dictionary(); + public readonly Dictionary UnitsByUserName = new Dictionary(); +} \ No newline at end of file diff --git a/聊天系统课程代码/Server/Entity/Gate/Model/GateUnit.cs b/聊天系统课程代码/Server/Entity/Gate/Model/GateUnit.cs new file mode 100644 index 0000000..cea2cc5 --- /dev/null +++ b/聊天系统课程代码/Server/Entity/Gate/Model/GateUnit.cs @@ -0,0 +1,11 @@ +using Fantasy.Entitas; +using Fantasy.Network; + +namespace Fantasy; + +public sealed class GateUnit : Entity +{ + public EntityReference Session; + public string UserName { get; set; } + public readonly Dictionary Routes = new Dictionary(); +} \ No newline at end of file diff --git a/聊天系统课程代码/Server/Entity/Generate/CustomExport/SceneType.cs b/聊天系统课程代码/Server/Entity/Generate/CustomExport/SceneType.cs new file mode 100644 index 0000000..de34ed9 --- /dev/null +++ b/聊天系统课程代码/Server/Entity/Generate/CustomExport/SceneType.cs @@ -0,0 +1,27 @@ +namespace Fantasy +{ + // 生成器自动生成,请不要手动编辑。 + public static class SceneType + { + public const int Authentication = 1; + public const int Addressable = 2; + public const int Gate = 3; + public const int Map = 4; + public const int CopyDispatcher = 5; + public const int CopyManager = 6; + public const int Copy = 7; + public const int Chat = 8; + + public static readonly Dictionary SceneTypeDic = new Dictionary() + { + { "Authentication", 1 }, + { "Addressable", 2 }, + { "Gate", 3 }, + { "Map", 4 }, + { "CopyDispatcher", 5 }, + { "CopyManager", 6 }, + { "Copy", 7 }, + { "Chat", 8 }, + }; + } +} diff --git a/聊天系统课程代码/Server/Entity/Generate/NetworkProtocol/InnerMessage.cs b/聊天系统课程代码/Server/Entity/Generate/NetworkProtocol/InnerMessage.cs new file mode 100644 index 0000000..1f17d82 --- /dev/null +++ b/聊天系统课程代码/Server/Entity/Generate/NetworkProtocol/InnerMessage.cs @@ -0,0 +1,194 @@ +using ProtoBuf; + +using System.Collections.Generic; +using MongoDB.Bson.Serialization.Attributes; +using Fantasy; +using Fantasy.Network.Interface; +using Fantasy.Serialize; +// ReSharper disable InconsistentNaming +// ReSharper disable RedundantUsingDirective +// ReSharper disable RedundantOverriddenMember +// ReSharper disable PartialTypeWithSinglePart +// ReSharper disable UnusedAutoPropertyAccessor.Global +// ReSharper disable MemberCanBePrivate.Global +// ReSharper disable CheckNamespace +#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. +#pragma warning disable CS8618 + +namespace Fantasy +{ + /// + /// Gate登录到Chat服务器 + /// + [ProtoContract] + public partial class G2Chat_LoginRequest : AMessage, IRouteRequest, IProto + { + public static G2Chat_LoginRequest Create(Scene scene) + { + return scene.MessagePoolComponent.Rent(); + } + public override void Dispose() + { + UserName = default; + UnitId = default; + GateRouteId = default; +#if FANTASY_NET || FANTASY_UNITY + GetScene().MessagePoolComponent.Return(this); +#endif + } + [ProtoIgnore] + public Chat2G_LoginResponse ResponseType { get; set; } + public uint OpCode() { return InnerOpcode.G2Chat_LoginRequest; } + [ProtoMember(1)] + public string UserName { get; set; } + [ProtoMember(2)] + public long UnitId { get; set; } + [ProtoMember(3)] + public long GateRouteId { get; set; } + } + [ProtoContract] + public partial class Chat2G_LoginResponse : AMessage, IRouteResponse, IProto + { + public static Chat2G_LoginResponse Create(Scene scene) + { + return scene.MessagePoolComponent.Rent(); + } + public override void Dispose() + { + ErrorCode = default; + ChatRouteId = default; +#if FANTASY_NET || FANTASY_UNITY + GetScene().MessagePoolComponent.Return(this); +#endif + } + public uint OpCode() { return InnerOpcode.Chat2G_LoginResponse; } + [ProtoMember(1)] + public long ChatRouteId { get; set; } + [ProtoMember(2)] + public uint ErrorCode { get; set; } + } + /// + /// Gate通知Chat服务器下线 + /// + [ProtoContract] + public partial class G2Chat_OfflineRequest : AMessage, IRouteRequest, IProto + { + public static G2Chat_OfflineRequest Create(Scene scene) + { + return scene.MessagePoolComponent.Rent(); + } + public override void Dispose() + { +#if FANTASY_NET || FANTASY_UNITY + GetScene().MessagePoolComponent.Return(this); +#endif + } + [ProtoIgnore] + public Chat2G_OfflineResponse ResponseType { get; set; } + public uint OpCode() { return InnerOpcode.G2Chat_OfflineRequest; } + } + [ProtoContract] + public partial class Chat2G_OfflineResponse : AMessage, IRouteResponse, IProto + { + public static Chat2G_OfflineResponse Create(Scene scene) + { + return scene.MessagePoolComponent.Rent(); + } + public override void Dispose() + { + ErrorCode = default; +#if FANTASY_NET || FANTASY_UNITY + GetScene().MessagePoolComponent.Return(this); +#endif + } + public uint OpCode() { return InnerOpcode.Chat2G_OfflineResponse; } + [ProtoMember(1)] + public uint ErrorCode { get; set; } + } + /// + /// Chat通知Gate发送一个全服广播的聊天信息 + /// + [ProtoContract] + public partial class Chat2G_ChatMessage : AMessage, IRouteMessage, IProto + { + public static Chat2G_ChatMessage Create(Scene scene) + { + return scene.MessagePoolComponent.Rent(); + } + public override void Dispose() + { + ChatInfoTree = default; +#if FANTASY_NET || FANTASY_UNITY + GetScene().MessagePoolComponent.Return(this); +#endif + } + public uint OpCode() { return InnerOpcode.Chat2G_ChatMessage; } + [ProtoMember(1)] + public ChatInfoTree ChatInfoTree { get; set; } + } + /// + /// 其他服务器发送聊天消息到Chat + /// + [ProtoContract] + public partial class Other2Chat_ChatMessage : AMessage, IRouteMessage, IProto + { + public static Other2Chat_ChatMessage Create(Scene scene) + { + return scene.MessagePoolComponent.Rent(); + } + public override void Dispose() + { + ChatInfoTree = default; +#if FANTASY_NET || FANTASY_UNITY + GetScene().MessagePoolComponent.Return(this); +#endif + } + public uint OpCode() { return InnerOpcode.Other2Chat_ChatMessage; } + [ProtoMember(1)] + public ChatInfoTree ChatInfoTree { get; set; } + } + /// + /// Gate登录到Map服务器 + /// + [ProtoContract] + public partial class G2M_LoginRequest : AMessage, IRouteRequest, IProto + { + public static G2M_LoginRequest Create(Scene scene) + { + return scene.MessagePoolComponent.Rent(); + } + public override void Dispose() + { + ChatUnitRouteId = default; +#if FANTASY_NET || FANTASY_UNITY + GetScene().MessagePoolComponent.Return(this); +#endif + } + [ProtoIgnore] + public M2G_LoginResponse ResponseType { get; set; } + public uint OpCode() { return InnerOpcode.G2M_LoginRequest; } + [ProtoMember(1)] + public long ChatUnitRouteId { get; set; } + } + [ProtoContract] + public partial class M2G_LoginResponse : AMessage, IRouteResponse, IProto + { + public static M2G_LoginResponse Create(Scene scene) + { + return scene.MessagePoolComponent.Rent(); + } + public override void Dispose() + { + ErrorCode = default; + MapRouteId = default; +#if FANTASY_NET || FANTASY_UNITY + GetScene().MessagePoolComponent.Return(this); +#endif + } + public uint OpCode() { return InnerOpcode.M2G_LoginResponse; } + [ProtoMember(1)] + public long MapRouteId { get; set; } + [ProtoMember(2)] + public uint ErrorCode { get; set; } + } +} diff --git a/聊天系统课程代码/Server/Entity/Generate/NetworkProtocol/InnerOpcode.cs b/聊天系统课程代码/Server/Entity/Generate/NetworkProtocol/InnerOpcode.cs new file mode 100644 index 0000000..4150532 --- /dev/null +++ b/聊天系统课程代码/Server/Entity/Generate/NetworkProtocol/InnerOpcode.cs @@ -0,0 +1,14 @@ +namespace Fantasy +{ + public static partial class InnerOpcode + { + public const uint G2Chat_LoginRequest = 1073751825; + public const uint Chat2G_LoginResponse = 1207969553; + public const uint G2Chat_OfflineRequest = 1073751826; + public const uint Chat2G_OfflineResponse = 1207969554; + public const uint Chat2G_ChatMessage = 939534097; + public const uint Other2Chat_ChatMessage = 939534098; + public const uint G2M_LoginRequest = 1073751827; + public const uint M2G_LoginResponse = 1207969555; + } +} diff --git a/聊天系统课程代码/Server/Entity/Generate/NetworkProtocol/OuterMessage.cs b/聊天系统课程代码/Server/Entity/Generate/NetworkProtocol/OuterMessage.cs new file mode 100644 index 0000000..3681ca0 --- /dev/null +++ b/聊天系统课程代码/Server/Entity/Generate/NetworkProtocol/OuterMessage.cs @@ -0,0 +1,327 @@ +using ProtoBuf; + +using System.Collections.Generic; +using MongoDB.Bson.Serialization.Attributes; +using Fantasy; +using Fantasy.Network.Interface; +using Fantasy.Serialize; +// ReSharper disable InconsistentNaming +// ReSharper disable RedundantUsingDirective +// ReSharper disable RedundantOverriddenMember +// ReSharper disable PartialTypeWithSinglePart +// ReSharper disable UnusedAutoPropertyAccessor.Global +// ReSharper disable MemberCanBePrivate.Global +// ReSharper disable CheckNamespace +#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. +#pragma warning disable CS8618 + +namespace Fantasy +{ + /// + /// 登录游戏 + /// + [ProtoContract] + public partial class C2G_LoginRequest : AMessage, IRequest, IProto + { + public static C2G_LoginRequest Create(Scene scene) + { + return scene.MessagePoolComponent.Rent(); + } + public override void Dispose() + { + UserName = default; +#if FANTASY_NET || FANTASY_UNITY + GetScene().MessagePoolComponent.Return(this); +#endif + } + [ProtoIgnore] + public G2C_LoginResponse ResponseType { get; set; } + public uint OpCode() { return OuterOpcode.C2G_LoginRequest; } + [ProtoMember(1)] + public string UserName { get; set; } + } + [ProtoContract] + public partial class G2C_LoginResponse : AMessage, IResponse, IProto + { + public static G2C_LoginResponse Create(Scene scene) + { + return scene.MessagePoolComponent.Rent(); + } + public override void Dispose() + { + ErrorCode = default; +#if FANTASY_NET || FANTASY_UNITY + GetScene().MessagePoolComponent.Return(this); +#endif + } + public uint OpCode() { return OuterOpcode.G2C_LoginResponse; } + [ProtoMember(1)] + public uint ErrorCode { get; set; } + } + /// + /// 退出游戏 + /// + [ProtoContract] + public partial class C2G_ExitRequest : AMessage, IRequest, IProto + { + public static C2G_ExitRequest Create(Scene scene) + { + return scene.MessagePoolComponent.Rent(); + } + public override void Dispose() + { +#if FANTASY_NET || FANTASY_UNITY + GetScene().MessagePoolComponent.Return(this); +#endif + } + [ProtoIgnore] + public G2C_ExitResponse ResponseType { get; set; } + public uint OpCode() { return OuterOpcode.C2G_ExitRequest; } + } + [ProtoContract] + public partial class G2C_ExitResponse : AMessage, IResponse, IProto + { + public static G2C_ExitResponse Create(Scene scene) + { + return scene.MessagePoolComponent.Rent(); + } + public override void Dispose() + { + ErrorCode = default; +#if FANTASY_NET || FANTASY_UNITY + GetScene().MessagePoolComponent.Return(this); +#endif + } + public uint OpCode() { return OuterOpcode.G2C_ExitResponse; } + [ProtoMember(1)] + public uint ErrorCode { get; set; } + } + /// + /// 发送一个聊天消息给Chat服务器,中间是经过Gate中转的 + /// + [ProtoContract] + public partial class C2Chat_SendMessageRequest : AMessage, ICustomRouteRequest, IProto + { + public static C2Chat_SendMessageRequest Create(Scene scene) + { + return scene.MessagePoolComponent.Rent(); + } + public override void Dispose() + { + ChatInfoTree = default; +#if FANTASY_NET || FANTASY_UNITY + GetScene().MessagePoolComponent.Return(this); +#endif + } + [ProtoIgnore] + public Chat2C_SendMessageResponse ResponseType { get; set; } + public uint OpCode() { return OuterOpcode.C2Chat_SendMessageRequest; } + [ProtoIgnore] + public int RouteType => Fantasy.RouteType.ChatRoute; + [ProtoMember(1)] + public ChatInfoTree ChatInfoTree { get; set; } + } + [ProtoContract] + public partial class Chat2C_SendMessageResponse : AMessage, ICustomRouteResponse, IProto + { + public static Chat2C_SendMessageResponse Create(Scene scene) + { + return scene.MessagePoolComponent.Rent(); + } + public override void Dispose() + { + ErrorCode = default; +#if FANTASY_NET || FANTASY_UNITY + GetScene().MessagePoolComponent.Return(this); +#endif + } + public uint OpCode() { return OuterOpcode.Chat2C_SendMessageResponse; } + [ProtoMember(1)] + public uint ErrorCode { get; set; } + } + [ProtoContract] + public partial class Chat2C_Message : AMessage, ICustomRouteMessage, IProto + { + public static Chat2C_Message Create(Scene scene) + { + return scene.MessagePoolComponent.Rent(); + } + public override void Dispose() + { + ChatInfoTree = default; +#if FANTASY_NET || FANTASY_UNITY + GetScene().MessagePoolComponent.Return(this); +#endif + } + public uint OpCode() { return OuterOpcode.Chat2C_Message; } + [ProtoIgnore] + public int RouteType => Fantasy.RouteType.ChatRoute; + [ProtoMember(1)] + public ChatInfoTree ChatInfoTree { get; set; } + } + /// + /// 聊天消息树 + /// + [ProtoContract] + public partial class ChatInfoTree : AMessage, IProto + { + public static ChatInfoTree Create(Scene scene) + { + return scene.MessagePoolComponent.Rent(); + } + public override void Dispose() + { + ChatChannelType = default; + ChatChannelId = default; + UnitId = default; + UserName = default; + Target.Clear(); + Node.Clear(); +#if FANTASY_NET || FANTASY_UNITY + GetScene().MessagePoolComponent.Return(this); +#endif + } + [ProtoMember(1)] + public int ChatChannelType { get; set; } + [ProtoMember(2)] + public long ChatChannelId { get; set; } + [ProtoMember(3)] + public long UnitId { get; set; } + [ProtoMember(4)] + public string UserName { get; set; } + [ProtoMember(5)] + public List Target = new List(); + [ProtoMember(6)] + public List Node = new List(); + } + /// + /// 聊天信息节点 + /// + [ProtoContract] + public partial class ChatInfoNode : AMessage, IProto + { + public static ChatInfoNode Create(Scene scene) + { + return scene.MessagePoolComponent.Rent(); + } + public override void Dispose() + { + ChatNodeType = default; + ChatNodeEvent = default; + Content = default; + Color = default; + Data = default; +#if FANTASY_NET || FANTASY_UNITY + GetScene().MessagePoolComponent.Return(this); +#endif + } + [ProtoMember(1)] + public int ChatNodeType { get; set; } + [ProtoMember(2)] + public int ChatNodeEvent { get; set; } + [ProtoMember(3)] + public string Content { get; set; } + [ProtoMember(4)] + public string Color { get; set; } + [ProtoMember(5)] + public byte[] Data { get; set; } + } + /// + /// 聊天位置信息节点 + /// + [ProtoContract] + public partial class ChatPositionNode : AMessage, IProto + { + public static ChatPositionNode Create(Scene scene) + { + return scene.MessagePoolComponent.Rent(); + } + public override void Dispose() + { + MapName = default; + PosX = default; + PosY = default; + PosZ = default; +#if FANTASY_NET || FANTASY_UNITY + GetScene().MessagePoolComponent.Return(this); +#endif + } + [ProtoMember(1)] + public string MapName { get; set; } + [ProtoMember(2)] + public float PosX { get; set; } + [ProtoMember(3)] + public float PosY { get; set; } + [ProtoMember(4)] + public float PosZ { get; set; } + } + /// + /// 聊天位置信息节点 + /// + [ProtoContract] + public partial class ChatOpenUINode : AMessage, IProto + { + public static ChatOpenUINode Create(Scene scene) + { + return scene.MessagePoolComponent.Rent(); + } + public override void Dispose() + { + UIName = default; +#if FANTASY_NET || FANTASY_UNITY + GetScene().MessagePoolComponent.Return(this); +#endif + } + [ProtoMember(1)] + public string UIName { get; set; } + } + /// + /// 聊天连接信息节点 + /// + [ProtoContract] + public partial class ChatLinkNode : AMessage, IProto + { + public static ChatLinkNode Create(Scene scene) + { + return scene.MessagePoolComponent.Rent(); + } + public override void Dispose() + { + Link = default; +#if FANTASY_NET || FANTASY_UNITY + GetScene().MessagePoolComponent.Return(this); +#endif + } + [ProtoMember(1)] + public string Link { get; set; } + } + /// + /// 装备信息实体 + /// + [ProtoContract] + public partial class Item : AMessage, IProto + { + public static Item Create(Scene scene) + { + return scene.MessagePoolComponent.Rent(); + } + public override void Dispose() + { + Level = default; + Name = default; + HP = default; + MP = default; +#if FANTASY_NET || FANTASY_UNITY + GetScene().MessagePoolComponent.Return(this); +#endif + } + [ProtoMember(1)] + public string Level { get; set; } + [ProtoMember(2)] + public string Name { get; set; } + [ProtoMember(3)] + public string HP { get; set; } + [ProtoMember(4)] + public string MP { get; set; } + } +} diff --git a/聊天系统课程代码/Server/Entity/Generate/NetworkProtocol/OuterOpcode.cs b/聊天系统课程代码/Server/Entity/Generate/NetworkProtocol/OuterOpcode.cs new file mode 100644 index 0000000..5ea474b --- /dev/null +++ b/聊天系统课程代码/Server/Entity/Generate/NetworkProtocol/OuterOpcode.cs @@ -0,0 +1,13 @@ +namespace Fantasy +{ + public static partial class OuterOpcode + { + public const uint C2G_LoginRequest = 268445457; + public const uint G2C_LoginResponse = 402663185; + public const uint C2G_ExitRequest = 268445458; + public const uint G2C_ExitResponse = 402663186; + public const uint C2Chat_SendMessageRequest = 2281711377; + public const uint Chat2C_SendMessageResponse = 2415929105; + public const uint Chat2C_Message = 2147493649; + } +} diff --git a/聊天系统课程代码/Server/Entity/Generate/NetworkProtocol/RouteType.cs b/聊天系统课程代码/Server/Entity/Generate/NetworkProtocol/RouteType.cs new file mode 100644 index 0000000..cdd0df0 --- /dev/null +++ b/聊天系统课程代码/Server/Entity/Generate/NetworkProtocol/RouteType.cs @@ -0,0 +1,9 @@ +namespace Fantasy +{ + // Route协议定义(需要定义1000以上、因为1000以内的框架预留) + public static class RouteType + { + public const int GateRoute = 1001; // Gate + public const int ChatRoute = 1002; // Chat + } +} diff --git a/聊天系统课程代码/Server/Entity/Share/Components/EntityTimeoutComponent.cs b/聊天系统课程代码/Server/Entity/Share/Components/EntityTimeoutComponent.cs new file mode 100644 index 0000000..1f1f293 --- /dev/null +++ b/聊天系统课程代码/Server/Entity/Share/Components/EntityTimeoutComponent.cs @@ -0,0 +1,8 @@ +using Fantasy.Entitas; + +namespace Fantasy; + +public sealed class EntityTimeoutComponent : Entity +{ + public long TimerId; +} \ No newline at end of file diff --git a/聊天系统课程代码/Server/Entity/Share/Components/SerializerComponent.cs b/聊天系统课程代码/Server/Entity/Share/Components/SerializerComponent.cs new file mode 100644 index 0000000..0dab79e --- /dev/null +++ b/聊天系统课程代码/Server/Entity/Share/Components/SerializerComponent.cs @@ -0,0 +1,12 @@ +using Fantasy.Entitas; +using Fantasy.Network; +using Fantasy.Serialize; +using ProtoBuf.Serializers; + +namespace Fantasy; + +public class SerializerComponent : Entity +{ + public ISerialize Serialize; + public readonly MemoryStreamBufferPool BufferPool = new MemoryStreamBufferPool(); +} \ No newline at end of file diff --git a/聊天系统课程代码/Server/Entity/bin/Debug/net8.0/Entity.deps.json b/聊天系统课程代码/Server/Entity/bin/Debug/net8.0/Entity.deps.json new file mode 100644 index 0000000..b6d7cb1 --- /dev/null +++ b/聊天系统课程代码/Server/Entity/bin/Debug/net8.0/Entity.deps.json @@ -0,0 +1,311 @@ +{ + "runtimeTarget": { + "name": ".NETCoreApp,Version=v8.0", + "signature": "" + }, + "compilationOptions": {}, + "targets": { + ".NETCoreApp,Version=v8.0": { + "Entity/1.0.0": { + "dependencies": { + "Fantasy-Net": "2024.1.17" + }, + "runtime": { + "Entity.dll": {} + } + }, + "CommandLineParser/2.9.1": { + "runtime": { + "lib/netstandard2.0/CommandLine.dll": { + "assemblyVersion": "2.9.1.0", + "fileVersion": "2.9.1.0" + } + } + }, + "DnsClient/1.6.1": { + "dependencies": { + "Microsoft.Win32.Registry": "5.0.0" + }, + "runtime": { + "lib/net5.0/DnsClient.dll": { + "assemblyVersion": "1.6.1.0", + "fileVersion": "1.6.1.0" + } + } + }, + "Fantasy-Net/2024.1.17": { + "dependencies": { + "CommandLineParser": "2.9.1", + "MongoDB.Bson": "3.0.0", + "MongoDB.Driver": "3.0.0", + "Newtonsoft.Json": "13.0.3", + "System.IO.Pipelines": "8.0.0", + "protobuf-net": "3.2.45" + }, + "runtime": { + "lib/net8.0/Fantasy-Net.dll": { + "assemblyVersion": "1.0.0.0", + "fileVersion": "1.0.0.0" + } + } + }, + "Microsoft.Extensions.Logging.Abstractions/2.0.0": {}, + "Microsoft.NETCore.Platforms/5.0.0": {}, + "Microsoft.Win32.Registry/5.0.0": { + "dependencies": { + "System.Security.AccessControl": "5.0.0", + "System.Security.Principal.Windows": "5.0.0" + } + }, + "MongoDB.Bson/3.0.0": { + "dependencies": { + "System.Memory": "4.5.5", + "System.Runtime.CompilerServices.Unsafe": "5.0.0" + }, + "runtime": { + "lib/net6.0/MongoDB.Bson.dll": { + "assemblyVersion": "3.0.0.0", + "fileVersion": "3.0.0.0" + } + } + }, + "MongoDB.Driver/3.0.0": { + "dependencies": { + "DnsClient": "1.6.1", + "Microsoft.Extensions.Logging.Abstractions": "2.0.0", + "MongoDB.Bson": "3.0.0", + "SharpCompress": "0.30.1", + "Snappier": "1.0.0", + "System.Buffers": "4.5.1", + "ZstdSharp.Port": "0.7.3" + }, + "runtime": { + "lib/net6.0/MongoDB.Driver.dll": { + "assemblyVersion": "3.0.0.0", + "fileVersion": "3.0.0.0" + } + } + }, + "Newtonsoft.Json/13.0.3": { + "runtime": { + "lib/net6.0/Newtonsoft.Json.dll": { + "assemblyVersion": "13.0.0.0", + "fileVersion": "13.0.3.27908" + } + } + }, + "protobuf-net/3.2.45": { + "dependencies": { + "protobuf-net.Core": "3.2.45" + }, + "runtime": { + "lib/net6.0/protobuf-net.dll": { + "assemblyVersion": "3.0.0.0", + "fileVersion": "3.2.45.36865" + } + } + }, + "protobuf-net.Core/3.2.45": { + "dependencies": { + "System.Collections.Immutable": "7.0.0" + }, + "runtime": { + "lib/net6.0/protobuf-net.Core.dll": { + "assemblyVersion": "3.0.0.0", + "fileVersion": "3.2.45.36865" + } + } + }, + "SharpCompress/0.30.1": { + "runtime": { + "lib/net5.0/SharpCompress.dll": { + "assemblyVersion": "0.30.1.0", + "fileVersion": "0.30.1.0" + } + } + }, + "Snappier/1.0.0": { + "runtime": { + "lib/net5.0/Snappier.dll": { + "assemblyVersion": "1.0.0.0", + "fileVersion": "1.0.0.0" + } + } + }, + "System.Buffers/4.5.1": {}, + "System.Collections.Immutable/7.0.0": {}, + "System.IO.Pipelines/8.0.0": {}, + "System.Memory/4.5.5": {}, + "System.Runtime.CompilerServices.Unsafe/5.0.0": {}, + "System.Security.AccessControl/5.0.0": { + "dependencies": { + "Microsoft.NETCore.Platforms": "5.0.0", + "System.Security.Principal.Windows": "5.0.0" + } + }, + "System.Security.Principal.Windows/5.0.0": {}, + "ZstdSharp.Port/0.7.3": { + "runtime": { + "lib/net7.0/ZstdSharp.dll": { + "assemblyVersion": "0.7.3.0", + "fileVersion": "0.7.3.0" + } + } + } + } + }, + "libraries": { + "Entity/1.0.0": { + "type": "project", + "serviceable": false, + "sha512": "" + }, + "CommandLineParser/2.9.1": { + "type": "package", + "serviceable": true, + "sha512": "sha512-OE0sl1/sQ37bjVsPKKtwQlWDgqaxWgtme3xZz7JssWUzg5JpMIyHgCTY9MVMxOg48fJ1AgGT3tgdH5m/kQ5xhA==", + "path": "commandlineparser/2.9.1", + "hashPath": "commandlineparser.2.9.1.nupkg.sha512" + }, + "DnsClient/1.6.1": { + "type": "package", + "serviceable": true, + "sha512": "sha512-4H/f2uYJOZ+YObZjpY9ABrKZI+JNw3uizp6oMzTXwDw6F+2qIPhpRl/1t68O/6e98+vqNiYGu+lswmwdYUy3gg==", + "path": "dnsclient/1.6.1", + "hashPath": "dnsclient.1.6.1.nupkg.sha512" + }, + "Fantasy-Net/2024.1.17": { + "type": "package", + "serviceable": true, + "sha512": "sha512-06mxvByfEvF/ELAiAjaea4aWI5IBbBDyH9sVdPxEOEEtpAbcguaiydUNi2CVBE+ppW+CYsznTXalN0Xk0vAMKQ==", + "path": "fantasy-net/2024.1.17", + "hashPath": "fantasy-net.2024.1.17.nupkg.sha512" + }, + "Microsoft.Extensions.Logging.Abstractions/2.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-6ZCllUYGFukkymSTx3Yr0G/ajRxoNJp7/FqSxSB4fGISST54ifBhgu4Nc0ItGi3i6DqwuNd8SUyObmiC++AO2Q==", + "path": "microsoft.extensions.logging.abstractions/2.0.0", + "hashPath": "microsoft.extensions.logging.abstractions.2.0.0.nupkg.sha512" + }, + "Microsoft.NETCore.Platforms/5.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-VyPlqzH2wavqquTcYpkIIAQ6WdenuKoFN0BdYBbCWsclXacSOHNQn66Gt4z5NBqEYW0FAPm5rlvki9ZiCij5xQ==", + "path": "microsoft.netcore.platforms/5.0.0", + "hashPath": "microsoft.netcore.platforms.5.0.0.nupkg.sha512" + }, + "Microsoft.Win32.Registry/5.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-dDoKi0PnDz31yAyETfRntsLArTlVAVzUzCIvvEDsDsucrl33Dl8pIJG06ePTJTI3tGpeyHS9Cq7Foc/s4EeKcg==", + "path": "microsoft.win32.registry/5.0.0", + "hashPath": "microsoft.win32.registry.5.0.0.nupkg.sha512" + }, + "MongoDB.Bson/3.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-qnPRJ58HXDh7C4oxTf6YB7BJhlCGJIa6TMXhzImw6zk44lrAomQXTB6AtoQ5lNJbkyrgQcT7+smsKFMnXmLXhw==", + "path": "mongodb.bson/3.0.0", + "hashPath": "mongodb.bson.3.0.0.nupkg.sha512" + }, + "MongoDB.Driver/3.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-udcP8rOhyuhLDn3sGVdNUgQSXfKGPaIP4w09XVKf4xdy66YSXinhkIuQSuOeZVHdTFsG2PpUbRx2wyFm7E0EMg==", + "path": "mongodb.driver/3.0.0", + "hashPath": "mongodb.driver.3.0.0.nupkg.sha512" + }, + "Newtonsoft.Json/13.0.3": { + "type": "package", + "serviceable": true, + "sha512": "sha512-HrC5BXdl00IP9zeV+0Z848QWPAoCr9P3bDEZguI+gkLcBKAOxix/tLEAAHC+UvDNPv4a2d18lOReHMOagPa+zQ==", + "path": "newtonsoft.json/13.0.3", + "hashPath": "newtonsoft.json.13.0.3.nupkg.sha512" + }, + "protobuf-net/3.2.45": { + "type": "package", + "serviceable": true, + "sha512": "sha512-5UZ/ukUHcGbFSl7vNMrHsfjqdxusdd9w7w0fCEXzf3UUtsrGNVCzV5SmF+sCHAbnRV2qPcD1ixiDP7Aj8lX/HA==", + "path": "protobuf-net/3.2.45", + "hashPath": "protobuf-net.3.2.45.nupkg.sha512" + }, + "protobuf-net.Core/3.2.45": { + "type": "package", + "serviceable": true, + "sha512": "sha512-PMWatW2NrT1uTXD7etJ4VdQ0wWZLFrIfdRGppD2QX7nzZ0+kIzqhq551u6ZiXJHWJgG4hWFEkSnUnt2aB6posg==", + "path": "protobuf-net.core/3.2.45", + "hashPath": "protobuf-net.core.3.2.45.nupkg.sha512" + }, + "SharpCompress/0.30.1": { + "type": "package", + "serviceable": true, + "sha512": "sha512-XqD4TpfyYGa7QTPzaGlMVbcecKnXy4YmYLDWrU+JIj7IuRNl7DH2END+Ll7ekWIY8o3dAMWLFDE1xdhfIWD1nw==", + "path": "sharpcompress/0.30.1", + "hashPath": "sharpcompress.0.30.1.nupkg.sha512" + }, + "Snappier/1.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-rFtK2KEI9hIe8gtx3a0YDXdHOpedIf9wYCEYtBEmtlyiWVX3XlCNV03JrmmAi/Cdfn7dxK+k0sjjcLv4fpHnqA==", + "path": "snappier/1.0.0", + "hashPath": "snappier.1.0.0.nupkg.sha512" + }, + "System.Buffers/4.5.1": { + "type": "package", + "serviceable": true, + "sha512": "sha512-Rw7ijyl1qqRS0YQD/WycNst8hUUMgrMH4FCn1nNm27M4VxchZ1js3fVjQaANHO5f3sN4isvP4a+Met9Y4YomAg==", + "path": "system.buffers/4.5.1", + "hashPath": "system.buffers.4.5.1.nupkg.sha512" + }, + "System.Collections.Immutable/7.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-dQPcs0U1IKnBdRDBkrCTi1FoajSTBzLcVTpjO4MBCMC7f4pDOIPzgBoX8JjG7X6uZRJ8EBxsi8+DR1JuwjnzOQ==", + "path": "system.collections.immutable/7.0.0", + "hashPath": "system.collections.immutable.7.0.0.nupkg.sha512" + }, + "System.IO.Pipelines/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-FHNOatmUq0sqJOkTx+UF/9YK1f180cnW5FVqnQMvYUN0elp6wFzbtPSiqbo1/ru8ICp43JM1i7kKkk6GsNGHlA==", + "path": "system.io.pipelines/8.0.0", + "hashPath": "system.io.pipelines.8.0.0.nupkg.sha512" + }, + "System.Memory/4.5.5": { + "type": "package", + "serviceable": true, + "sha512": "sha512-XIWiDvKPXaTveaB7HVganDlOCRoj03l+jrwNvcge/t8vhGYKvqV+dMv6G4SAX2NoNmN0wZfVPTAlFwZcZvVOUw==", + "path": "system.memory/4.5.5", + "hashPath": "system.memory.4.5.5.nupkg.sha512" + }, + "System.Runtime.CompilerServices.Unsafe/5.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-ZD9TMpsmYJLrxbbmdvhwt9YEgG5WntEnZ/d1eH8JBX9LBp+Ju8BSBhUGbZMNVHHomWo2KVImJhTDl2hIgw/6MA==", + "path": "system.runtime.compilerservices.unsafe/5.0.0", + "hashPath": "system.runtime.compilerservices.unsafe.5.0.0.nupkg.sha512" + }, + "System.Security.AccessControl/5.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-dagJ1mHZO3Ani8GH0PHpPEe/oYO+rVdbQjvjJkBRNQkX4t0r1iaeGn8+/ybkSLEan3/slM0t59SVdHzuHf2jmw==", + "path": "system.security.accesscontrol/5.0.0", + "hashPath": "system.security.accesscontrol.5.0.0.nupkg.sha512" + }, + "System.Security.Principal.Windows/5.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-t0MGLukB5WAVU9bO3MGzvlGnyJPgUlcwerXn1kzBRjwLKixT96XV0Uza41W49gVd8zEMFu9vQEFlv0IOrytICA==", + "path": "system.security.principal.windows/5.0.0", + "hashPath": "system.security.principal.windows.5.0.0.nupkg.sha512" + }, + "ZstdSharp.Port/0.7.3": { + "type": "package", + "serviceable": true, + "sha512": "sha512-U9Ix4l4cl58Kzz1rJzj5hoVTjmbx1qGMwzAcbv1j/d3NzrFaESIurQyg+ow4mivCgkE3S413y+U9k4WdnEIkRA==", + "path": "zstdsharp.port/0.7.3", + "hashPath": "zstdsharp.port.0.7.3.nupkg.sha512" + } + } +} \ No newline at end of file diff --git a/聊天系统课程代码/Server/Entity/bin/Debug/net8.0/Entity.dll b/聊天系统课程代码/Server/Entity/bin/Debug/net8.0/Entity.dll new file mode 100644 index 0000000..79a12c8 Binary files /dev/null and b/聊天系统课程代码/Server/Entity/bin/Debug/net8.0/Entity.dll differ diff --git a/聊天系统课程代码/Server/Entity/bin/Debug/net8.0/Entity.pdb b/聊天系统课程代码/Server/Entity/bin/Debug/net8.0/Entity.pdb new file mode 100644 index 0000000..cd98b44 Binary files /dev/null and b/聊天系统课程代码/Server/Entity/bin/Debug/net8.0/Entity.pdb differ diff --git a/聊天系统课程代码/Server/Entity/obj/Debug/net8.0/.NETCoreApp,Version=v8.0.AssemblyAttributes.cs b/聊天系统课程代码/Server/Entity/obj/Debug/net8.0/.NETCoreApp,Version=v8.0.AssemblyAttributes.cs new file mode 100644 index 0000000..2217181 --- /dev/null +++ b/聊天系统课程代码/Server/Entity/obj/Debug/net8.0/.NETCoreApp,Version=v8.0.AssemblyAttributes.cs @@ -0,0 +1,4 @@ +// +using System; +using System.Reflection; +[assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute(".NETCoreApp,Version=v8.0", FrameworkDisplayName = ".NET 8.0")] diff --git a/聊天系统课程代码/Server/Entity/obj/Debug/net8.0/Entity.AssemblyInfo.cs b/聊天系统课程代码/Server/Entity/obj/Debug/net8.0/Entity.AssemblyInfo.cs new file mode 100644 index 0000000..b1f9a04 --- /dev/null +++ b/聊天系统课程代码/Server/Entity/obj/Debug/net8.0/Entity.AssemblyInfo.cs @@ -0,0 +1,22 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +using System; +using System.Reflection; + +[assembly: System.Reflection.AssemblyCompanyAttribute("Entity")] +[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")] +[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")] +[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0")] +[assembly: System.Reflection.AssemblyProductAttribute("Entity")] +[assembly: System.Reflection.AssemblyTitleAttribute("Entity")] +[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")] + +// 由 MSBuild WriteCodeFragment 类生成。 + diff --git a/聊天系统课程代码/Server/Entity/obj/Debug/net8.0/Entity.AssemblyInfoInputs.cache b/聊天系统课程代码/Server/Entity/obj/Debug/net8.0/Entity.AssemblyInfoInputs.cache new file mode 100644 index 0000000..b4d28d5 --- /dev/null +++ b/聊天系统课程代码/Server/Entity/obj/Debug/net8.0/Entity.AssemblyInfoInputs.cache @@ -0,0 +1 @@ +b7ceabf79c524d6ee0475da740239235018950a5f2c92d51c77f832004e64e6c diff --git a/聊天系统课程代码/Server/Entity/obj/Debug/net8.0/Entity.GeneratedMSBuildEditorConfig.editorconfig b/聊天系统课程代码/Server/Entity/obj/Debug/net8.0/Entity.GeneratedMSBuildEditorConfig.editorconfig new file mode 100644 index 0000000..bcb9529 --- /dev/null +++ b/聊天系统课程代码/Server/Entity/obj/Debug/net8.0/Entity.GeneratedMSBuildEditorConfig.editorconfig @@ -0,0 +1,15 @@ +is_global = true +build_property.TargetFramework = net8.0 +build_property.TargetPlatformMinVersion = +build_property.UsingMicrosoftNETSdkWeb = +build_property.ProjectTypeGuids = +build_property.InvariantGlobalization = +build_property.PlatformNeutralAssembly = +build_property.EnforceExtendedAnalyzerRules = +build_property._SupportedPlatformList = Linux,macOS,Windows +build_property.RootNamespace = Entity +build_property.ProjectDir = /Users/fantasy/Code/ServerLessions/Chat/Server/Entity/ +build_property.EnableComHosting = +build_property.EnableGeneratedComInterfaceComImportInterop = +build_property.EffectiveAnalysisLevelStyle = 8.0 +build_property.EnableCodeStyleSeverity = diff --git a/聊天系统课程代码/Server/Entity/obj/Debug/net8.0/Entity.GlobalUsings.g.cs b/聊天系统课程代码/Server/Entity/obj/Debug/net8.0/Entity.GlobalUsings.g.cs new file mode 100644 index 0000000..8578f3d --- /dev/null +++ b/聊天系统课程代码/Server/Entity/obj/Debug/net8.0/Entity.GlobalUsings.g.cs @@ -0,0 +1,8 @@ +// +global using global::System; +global using global::System.Collections.Generic; +global using global::System.IO; +global using global::System.Linq; +global using global::System.Net.Http; +global using global::System.Threading; +global using global::System.Threading.Tasks; diff --git a/聊天系统课程代码/Server/Entity/obj/Debug/net8.0/Entity.assets.cache b/聊天系统课程代码/Server/Entity/obj/Debug/net8.0/Entity.assets.cache new file mode 100644 index 0000000..917afba Binary files /dev/null and b/聊天系统课程代码/Server/Entity/obj/Debug/net8.0/Entity.assets.cache differ diff --git a/聊天系统课程代码/Server/Entity/obj/Debug/net8.0/Entity.csproj.AssemblyReference.cache b/聊天系统课程代码/Server/Entity/obj/Debug/net8.0/Entity.csproj.AssemblyReference.cache new file mode 100644 index 0000000..e4344a8 Binary files /dev/null and b/聊天系统课程代码/Server/Entity/obj/Debug/net8.0/Entity.csproj.AssemblyReference.cache differ diff --git a/聊天系统课程代码/Server/Entity/obj/Debug/net8.0/Entity.csproj.CoreCompileInputs.cache b/聊天系统课程代码/Server/Entity/obj/Debug/net8.0/Entity.csproj.CoreCompileInputs.cache new file mode 100644 index 0000000..353549b --- /dev/null +++ b/聊天系统课程代码/Server/Entity/obj/Debug/net8.0/Entity.csproj.CoreCompileInputs.cache @@ -0,0 +1 @@ +fcf69390a646cc62907e4e23c3937a1cd98d98ea8d71ba412b22b845c334256c diff --git a/聊天系统课程代码/Server/Entity/obj/Debug/net8.0/Entity.csproj.FileListAbsolute.txt b/聊天系统课程代码/Server/Entity/obj/Debug/net8.0/Entity.csproj.FileListAbsolute.txt new file mode 100644 index 0000000..bcaca3a --- /dev/null +++ b/聊天系统课程代码/Server/Entity/obj/Debug/net8.0/Entity.csproj.FileListAbsolute.txt @@ -0,0 +1,12 @@ +/Users/sining/Code/ServerLessions/Chat/Server/Entity/bin/Debug/net8.0/Entity.deps.json +/Users/sining/Code/ServerLessions/Chat/Server/Entity/bin/Debug/net8.0/Entity.dll +/Users/sining/Code/ServerLessions/Chat/Server/Entity/bin/Debug/net8.0/Entity.pdb +/Users/sining/Code/ServerLessions/Chat/Server/Entity/obj/Debug/net8.0/Entity.csproj.AssemblyReference.cache +/Users/sining/Code/ServerLessions/Chat/Server/Entity/obj/Debug/net8.0/Entity.GeneratedMSBuildEditorConfig.editorconfig +/Users/sining/Code/ServerLessions/Chat/Server/Entity/obj/Debug/net8.0/Entity.AssemblyInfoInputs.cache +/Users/sining/Code/ServerLessions/Chat/Server/Entity/obj/Debug/net8.0/Entity.AssemblyInfo.cs +/Users/sining/Code/ServerLessions/Chat/Server/Entity/obj/Debug/net8.0/Entity.csproj.CoreCompileInputs.cache +/Users/sining/Code/ServerLessions/Chat/Server/Entity/obj/Debug/net8.0/Entity.dll +/Users/sining/Code/ServerLessions/Chat/Server/Entity/obj/Debug/net8.0/refint/Entity.dll +/Users/sining/Code/ServerLessions/Chat/Server/Entity/obj/Debug/net8.0/Entity.pdb +/Users/sining/Code/ServerLessions/Chat/Server/Entity/obj/Debug/net8.0/ref/Entity.dll diff --git a/聊天系统课程代码/Server/Entity/obj/Debug/net8.0/Entity.dll b/聊天系统课程代码/Server/Entity/obj/Debug/net8.0/Entity.dll new file mode 100644 index 0000000..79a12c8 Binary files /dev/null and b/聊天系统课程代码/Server/Entity/obj/Debug/net8.0/Entity.dll differ diff --git a/聊天系统课程代码/Server/Entity/obj/Debug/net8.0/Entity.pdb b/聊天系统课程代码/Server/Entity/obj/Debug/net8.0/Entity.pdb new file mode 100644 index 0000000..cd98b44 Binary files /dev/null and b/聊天系统课程代码/Server/Entity/obj/Debug/net8.0/Entity.pdb differ diff --git a/聊天系统课程代码/Server/Entity/obj/Debug/net8.0/ref/Entity.dll b/聊天系统课程代码/Server/Entity/obj/Debug/net8.0/ref/Entity.dll new file mode 100644 index 0000000..22f47e1 Binary files /dev/null and b/聊天系统课程代码/Server/Entity/obj/Debug/net8.0/ref/Entity.dll differ diff --git a/聊天系统课程代码/Server/Entity/obj/Debug/net8.0/refint/Entity.dll b/聊天系统课程代码/Server/Entity/obj/Debug/net8.0/refint/Entity.dll new file mode 100644 index 0000000..22f47e1 Binary files /dev/null and b/聊天系统课程代码/Server/Entity/obj/Debug/net8.0/refint/Entity.dll differ diff --git a/聊天系统课程代码/Server/Entity/obj/Entity.csproj.nuget.dgspec.json b/聊天系统课程代码/Server/Entity/obj/Entity.csproj.nuget.dgspec.json new file mode 100644 index 0000000..0d91b70 --- /dev/null +++ b/聊天系统课程代码/Server/Entity/obj/Entity.csproj.nuget.dgspec.json @@ -0,0 +1,73 @@ +{ + "format": 1, + "restore": { + "/Users/fantasy/Code/ServerLessions/Chat/Server/Entity/Entity.csproj": {} + }, + "projects": { + "/Users/fantasy/Code/ServerLessions/Chat/Server/Entity/Entity.csproj": { + "version": "1.0.0", + "restore": { + "projectUniqueName": "/Users/fantasy/Code/ServerLessions/Chat/Server/Entity/Entity.csproj", + "projectName": "Entity", + "projectPath": "/Users/fantasy/Code/ServerLessions/Chat/Server/Entity/Entity.csproj", + "packagesPath": "/Users/fantasy/.nuget/packages/", + "outputPath": "/Users/fantasy/Code/ServerLessions/Chat/Server/Entity/obj/", + "projectStyle": "PackageReference", + "UsingMicrosoftNETSdk": false, + "configFilePaths": [ + "/Users/fantasy/.nuget/NuGet/NuGet.Config" + ], + "originalTargetFrameworks": [ + "net8.0" + ], + "sources": { + "https://api.nuget.org/v3/index.json": {} + }, + "frameworks": { + "net8.0": { + "targetAlias": "net8.0", + "projectReferences": {} + } + }, + "warningProperties": { + "warnAsError": [ + "NU1605" + ] + }, + "restoreAuditProperties": { + "enableAudit": "true", + "auditLevel": "low", + "auditMode": "all" + } + }, + "frameworks": { + "net8.0": { + "targetAlias": "net8.0", + "dependencies": { + "Fantasy-Net": { + "target": "Package", + "version": "[2024.1.17, )" + } + }, + "imports": [ + "net461", + "net462", + "net47", + "net471", + "net472", + "net48", + "net481" + ], + "assetTargetFallback": true, + "warn": true, + "frameworkReferences": { + "Microsoft.NETCore.App": { + "privateAssets": "all" + } + }, + "runtimeIdentifierGraphPath": "/usr/local/share/dotnet/sdk/9.0.100/PortableRuntimeIdentifierGraph.json" + } + } + } + } +} \ No newline at end of file diff --git a/聊天系统课程代码/Server/Entity/obj/Entity.csproj.nuget.g.props b/聊天系统课程代码/Server/Entity/obj/Entity.csproj.nuget.g.props new file mode 100644 index 0000000..6515977 --- /dev/null +++ b/聊天系统课程代码/Server/Entity/obj/Entity.csproj.nuget.g.props @@ -0,0 +1,15 @@ + + + + True + NuGet + $(MSBuildThisFileDirectory)project.assets.json + /Users/fantasy/.nuget/packages/ + /Users/fantasy/.nuget/packages/ + PackageReference + 6.12.0 + + + + + \ No newline at end of file diff --git a/聊天系统课程代码/Server/Entity/obj/Entity.csproj.nuget.g.targets b/聊天系统课程代码/Server/Entity/obj/Entity.csproj.nuget.g.targets new file mode 100644 index 0000000..9fc693e --- /dev/null +++ b/聊天系统课程代码/Server/Entity/obj/Entity.csproj.nuget.g.targets @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/聊天系统课程代码/Server/Entity/obj/project.assets.json b/聊天系统课程代码/Server/Entity/obj/project.assets.json new file mode 100644 index 0000000..403116c --- /dev/null +++ b/聊天系统课程代码/Server/Entity/obj/project.assets.json @@ -0,0 +1,949 @@ +{ + "version": 3, + "targets": { + "net8.0": { + "CommandLineParser/2.9.1": { + "type": "package", + "compile": { + "lib/netstandard2.0/CommandLine.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netstandard2.0/CommandLine.dll": { + "related": ".xml" + } + } + }, + "DnsClient/1.6.1": { + "type": "package", + "dependencies": { + "Microsoft.Win32.Registry": "5.0.0" + }, + "compile": { + "lib/net5.0/DnsClient.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net5.0/DnsClient.dll": { + "related": ".xml" + } + } + }, + "Fantasy-Net/2024.1.17": { + "type": "package", + "dependencies": { + "CommandLineParser": "2.9.1", + "MongoDB.Bson": "3.0.0", + "MongoDB.Driver": "3.0.0", + "Newtonsoft.Json": "13.0.3", + "System.IO.Pipelines": "8.0.0", + "protobuf-net": "3.2.45" + }, + "compile": { + "lib/net8.0/Fantasy-Net.dll": {} + }, + "runtime": { + "lib/net8.0/Fantasy-Net.dll": {} + }, + "frameworkReferences": [ + "Microsoft.AspNetCore.App" + ], + "build": { + "buildTransitive/Fantasy-Net.targets": {} + } + }, + "Microsoft.Extensions.Logging.Abstractions/2.0.0": { + "type": "package", + "compile": { + "lib/netstandard2.0/Microsoft.Extensions.Logging.Abstractions.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netstandard2.0/Microsoft.Extensions.Logging.Abstractions.dll": { + "related": ".xml" + } + } + }, + "Microsoft.NETCore.Platforms/5.0.0": { + "type": "package", + "compile": { + "lib/netstandard1.0/_._": {} + }, + "runtime": { + "lib/netstandard1.0/_._": {} + } + }, + "Microsoft.Win32.Registry/5.0.0": { + "type": "package", + "dependencies": { + "System.Security.AccessControl": "5.0.0", + "System.Security.Principal.Windows": "5.0.0" + }, + "compile": { + "ref/netstandard2.0/Microsoft.Win32.Registry.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netstandard2.0/Microsoft.Win32.Registry.dll": { + "related": ".xml" + } + }, + "runtimeTargets": { + "runtimes/win/lib/netstandard2.0/Microsoft.Win32.Registry.dll": { + "assetType": "runtime", + "rid": "win" + } + } + }, + "MongoDB.Bson/3.0.0": { + "type": "package", + "dependencies": { + "System.Memory": "4.5.5", + "System.Runtime.CompilerServices.Unsafe": "5.0.0" + }, + "compile": { + "lib/net6.0/MongoDB.Bson.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net6.0/MongoDB.Bson.dll": { + "related": ".xml" + } + } + }, + "MongoDB.Driver/3.0.0": { + "type": "package", + "dependencies": { + "DnsClient": "1.6.1", + "Microsoft.Extensions.Logging.Abstractions": "2.0.0", + "MongoDB.Bson": "3.0.0", + "SharpCompress": "0.30.1", + "Snappier": "1.0.0", + "System.Buffers": "4.5.1", + "ZstdSharp.Port": "0.7.3" + }, + "compile": { + "lib/net6.0/MongoDB.Driver.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net6.0/MongoDB.Driver.dll": { + "related": ".xml" + } + } + }, + "Newtonsoft.Json/13.0.3": { + "type": "package", + "compile": { + "lib/net6.0/Newtonsoft.Json.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net6.0/Newtonsoft.Json.dll": { + "related": ".xml" + } + } + }, + "protobuf-net/3.2.45": { + "type": "package", + "dependencies": { + "protobuf-net.Core": "3.2.45" + }, + "compile": { + "lib/net6.0/protobuf-net.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net6.0/protobuf-net.dll": { + "related": ".xml" + } + } + }, + "protobuf-net.Core/3.2.45": { + "type": "package", + "dependencies": { + "System.Collections.Immutable": "7.0.0" + }, + "compile": { + "lib/net6.0/protobuf-net.Core.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net6.0/protobuf-net.Core.dll": { + "related": ".xml" + } + } + }, + "SharpCompress/0.30.1": { + "type": "package", + "compile": { + "lib/net5.0/SharpCompress.dll": {} + }, + "runtime": { + "lib/net5.0/SharpCompress.dll": {} + } + }, + "Snappier/1.0.0": { + "type": "package", + "compile": { + "lib/net5.0/Snappier.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net5.0/Snappier.dll": { + "related": ".xml" + } + } + }, + "System.Buffers/4.5.1": { + "type": "package", + "compile": { + "ref/netcoreapp2.0/_._": {} + }, + "runtime": { + "lib/netcoreapp2.0/_._": {} + } + }, + "System.Collections.Immutable/7.0.0": { + "type": "package", + "compile": { + "lib/net7.0/System.Collections.Immutable.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net7.0/System.Collections.Immutable.dll": { + "related": ".xml" + } + }, + "build": { + "buildTransitive/net6.0/_._": {} + } + }, + "System.IO.Pipelines/8.0.0": { + "type": "package", + "compile": { + "lib/net8.0/System.IO.Pipelines.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net8.0/System.IO.Pipelines.dll": { + "related": ".xml" + } + }, + "build": { + "buildTransitive/net6.0/_._": {} + } + }, + "System.Memory/4.5.5": { + "type": "package", + "compile": { + "ref/netcoreapp2.1/_._": {} + }, + "runtime": { + "lib/netcoreapp2.1/_._": {} + } + }, + "System.Runtime.CompilerServices.Unsafe/5.0.0": { + "type": "package", + "compile": { + "ref/netstandard2.1/System.Runtime.CompilerServices.Unsafe.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netcoreapp2.0/System.Runtime.CompilerServices.Unsafe.dll": { + "related": ".xml" + } + } + }, + "System.Security.AccessControl/5.0.0": { + "type": "package", + "dependencies": { + "Microsoft.NETCore.Platforms": "5.0.0", + "System.Security.Principal.Windows": "5.0.0" + }, + "compile": { + "ref/netstandard2.0/System.Security.AccessControl.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netstandard2.0/System.Security.AccessControl.dll": { + "related": ".xml" + } + }, + "runtimeTargets": { + "runtimes/win/lib/netcoreapp2.0/System.Security.AccessControl.dll": { + "assetType": "runtime", + "rid": "win" + } + } + }, + "System.Security.Principal.Windows/5.0.0": { + "type": "package", + "compile": { + "ref/netcoreapp3.0/System.Security.Principal.Windows.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netstandard2.0/System.Security.Principal.Windows.dll": { + "related": ".xml" + } + }, + "runtimeTargets": { + "runtimes/unix/lib/netcoreapp2.1/System.Security.Principal.Windows.dll": { + "assetType": "runtime", + "rid": "unix" + }, + "runtimes/win/lib/netcoreapp2.1/System.Security.Principal.Windows.dll": { + "assetType": "runtime", + "rid": "win" + } + } + }, + "ZstdSharp.Port/0.7.3": { + "type": "package", + "compile": { + "lib/net7.0/ZstdSharp.dll": {} + }, + "runtime": { + "lib/net7.0/ZstdSharp.dll": {} + } + } + } + }, + "libraries": { + "CommandLineParser/2.9.1": { + "sha512": "OE0sl1/sQ37bjVsPKKtwQlWDgqaxWgtme3xZz7JssWUzg5JpMIyHgCTY9MVMxOg48fJ1AgGT3tgdH5m/kQ5xhA==", + "type": "package", + "path": "commandlineparser/2.9.1", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "CommandLine20.png", + "License.md", + "README.md", + "commandlineparser.2.9.1.nupkg.sha512", + "commandlineparser.nuspec", + "lib/net40/CommandLine.dll", + "lib/net40/CommandLine.xml", + "lib/net45/CommandLine.dll", + "lib/net45/CommandLine.xml", + "lib/net461/CommandLine.dll", + "lib/net461/CommandLine.xml", + "lib/netstandard2.0/CommandLine.dll", + "lib/netstandard2.0/CommandLine.xml" + ] + }, + "DnsClient/1.6.1": { + "sha512": "4H/f2uYJOZ+YObZjpY9ABrKZI+JNw3uizp6oMzTXwDw6F+2qIPhpRl/1t68O/6e98+vqNiYGu+lswmwdYUy3gg==", + "type": "package", + "path": "dnsclient/1.6.1", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "dnsclient.1.6.1.nupkg.sha512", + "dnsclient.nuspec", + "icon.png", + "lib/net45/DnsClient.dll", + "lib/net45/DnsClient.xml", + "lib/net471/DnsClient.dll", + "lib/net471/DnsClient.xml", + "lib/net5.0/DnsClient.dll", + "lib/net5.0/DnsClient.xml", + "lib/netstandard1.3/DnsClient.dll", + "lib/netstandard1.3/DnsClient.xml", + "lib/netstandard2.0/DnsClient.dll", + "lib/netstandard2.0/DnsClient.xml", + "lib/netstandard2.1/DnsClient.dll", + "lib/netstandard2.1/DnsClient.xml" + ] + }, + "Fantasy-Net/2024.1.17": { + "sha512": "06mxvByfEvF/ELAiAjaea4aWI5IBbBDyH9sVdPxEOEEtpAbcguaiydUNi2CVBE+ppW+CYsznTXalN0Xk0vAMKQ==", + "type": "package", + "path": "fantasy-net/2024.1.17", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "LICENSE", + "README.md", + "buildTransitive/Fantasy-Net.targets", + "fantasy-net.2024.1.17.nupkg.sha512", + "fantasy-net.nuspec", + "icon.png", + "lib/net8.0/Fantasy-Net.dll" + ] + }, + "Microsoft.Extensions.Logging.Abstractions/2.0.0": { + "sha512": "6ZCllUYGFukkymSTx3Yr0G/ajRxoNJp7/FqSxSB4fGISST54ifBhgu4Nc0ItGi3i6DqwuNd8SUyObmiC++AO2Q==", + "type": "package", + "path": "microsoft.extensions.logging.abstractions/2.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "lib/netstandard2.0/Microsoft.Extensions.Logging.Abstractions.dll", + "lib/netstandard2.0/Microsoft.Extensions.Logging.Abstractions.xml", + "microsoft.extensions.logging.abstractions.2.0.0.nupkg.sha512", + "microsoft.extensions.logging.abstractions.nuspec" + ] + }, + "Microsoft.NETCore.Platforms/5.0.0": { + "sha512": "VyPlqzH2wavqquTcYpkIIAQ6WdenuKoFN0BdYBbCWsclXacSOHNQn66Gt4z5NBqEYW0FAPm5rlvki9ZiCij5xQ==", + "type": "package", + "path": "microsoft.netcore.platforms/5.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "LICENSE.TXT", + "THIRD-PARTY-NOTICES.TXT", + "lib/netstandard1.0/_._", + "microsoft.netcore.platforms.5.0.0.nupkg.sha512", + "microsoft.netcore.platforms.nuspec", + "runtime.json", + "useSharedDesignerContext.txt", + "version.txt" + ] + }, + "Microsoft.Win32.Registry/5.0.0": { + "sha512": "dDoKi0PnDz31yAyETfRntsLArTlVAVzUzCIvvEDsDsucrl33Dl8pIJG06ePTJTI3tGpeyHS9Cq7Foc/s4EeKcg==", + "type": "package", + "path": "microsoft.win32.registry/5.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "LICENSE.TXT", + "THIRD-PARTY-NOTICES.TXT", + "lib/net46/Microsoft.Win32.Registry.dll", + "lib/net461/Microsoft.Win32.Registry.dll", + "lib/net461/Microsoft.Win32.Registry.xml", + "lib/netstandard1.3/Microsoft.Win32.Registry.dll", + "lib/netstandard2.0/Microsoft.Win32.Registry.dll", + "lib/netstandard2.0/Microsoft.Win32.Registry.xml", + "microsoft.win32.registry.5.0.0.nupkg.sha512", + "microsoft.win32.registry.nuspec", + "ref/net46/Microsoft.Win32.Registry.dll", + "ref/net461/Microsoft.Win32.Registry.dll", + "ref/net461/Microsoft.Win32.Registry.xml", + "ref/netstandard1.3/Microsoft.Win32.Registry.dll", + "ref/netstandard1.3/Microsoft.Win32.Registry.xml", + "ref/netstandard1.3/de/Microsoft.Win32.Registry.xml", + "ref/netstandard1.3/es/Microsoft.Win32.Registry.xml", + "ref/netstandard1.3/fr/Microsoft.Win32.Registry.xml", + "ref/netstandard1.3/it/Microsoft.Win32.Registry.xml", + "ref/netstandard1.3/ja/Microsoft.Win32.Registry.xml", + "ref/netstandard1.3/ko/Microsoft.Win32.Registry.xml", + "ref/netstandard1.3/ru/Microsoft.Win32.Registry.xml", + "ref/netstandard1.3/zh-hans/Microsoft.Win32.Registry.xml", + "ref/netstandard1.3/zh-hant/Microsoft.Win32.Registry.xml", + "ref/netstandard2.0/Microsoft.Win32.Registry.dll", + "ref/netstandard2.0/Microsoft.Win32.Registry.xml", + "runtimes/win/lib/net46/Microsoft.Win32.Registry.dll", + "runtimes/win/lib/net461/Microsoft.Win32.Registry.dll", + "runtimes/win/lib/net461/Microsoft.Win32.Registry.xml", + "runtimes/win/lib/netstandard1.3/Microsoft.Win32.Registry.dll", + "runtimes/win/lib/netstandard2.0/Microsoft.Win32.Registry.dll", + "runtimes/win/lib/netstandard2.0/Microsoft.Win32.Registry.xml", + "useSharedDesignerContext.txt", + "version.txt" + ] + }, + "MongoDB.Bson/3.0.0": { + "sha512": "qnPRJ58HXDh7C4oxTf6YB7BJhlCGJIa6TMXhzImw6zk44lrAomQXTB6AtoQ5lNJbkyrgQcT7+smsKFMnXmLXhw==", + "type": "package", + "path": "mongodb.bson/3.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "README.md", + "lib/net472/MongoDB.Bson.dll", + "lib/net472/MongoDB.Bson.xml", + "lib/net6.0/MongoDB.Bson.dll", + "lib/net6.0/MongoDB.Bson.xml", + "lib/netstandard2.1/MongoDB.Bson.dll", + "lib/netstandard2.1/MongoDB.Bson.xml", + "mongodb.bson.3.0.0.nupkg.sha512", + "mongodb.bson.nuspec", + "packageIcon.png" + ] + }, + "MongoDB.Driver/3.0.0": { + "sha512": "udcP8rOhyuhLDn3sGVdNUgQSXfKGPaIP4w09XVKf4xdy66YSXinhkIuQSuOeZVHdTFsG2PpUbRx2wyFm7E0EMg==", + "type": "package", + "path": "mongodb.driver/3.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "README.md", + "lib/net472/MongoDB.Driver.dll", + "lib/net472/MongoDB.Driver.xml", + "lib/net6.0/MongoDB.Driver.dll", + "lib/net6.0/MongoDB.Driver.xml", + "lib/netstandard2.1/MongoDB.Driver.dll", + "lib/netstandard2.1/MongoDB.Driver.xml", + "mongodb.driver.3.0.0.nupkg.sha512", + "mongodb.driver.nuspec", + "packageIcon.png" + ] + }, + "Newtonsoft.Json/13.0.3": { + "sha512": "HrC5BXdl00IP9zeV+0Z848QWPAoCr9P3bDEZguI+gkLcBKAOxix/tLEAAHC+UvDNPv4a2d18lOReHMOagPa+zQ==", + "type": "package", + "path": "newtonsoft.json/13.0.3", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "LICENSE.md", + "README.md", + "lib/net20/Newtonsoft.Json.dll", + "lib/net20/Newtonsoft.Json.xml", + "lib/net35/Newtonsoft.Json.dll", + "lib/net35/Newtonsoft.Json.xml", + "lib/net40/Newtonsoft.Json.dll", + "lib/net40/Newtonsoft.Json.xml", + "lib/net45/Newtonsoft.Json.dll", + "lib/net45/Newtonsoft.Json.xml", + "lib/net6.0/Newtonsoft.Json.dll", + "lib/net6.0/Newtonsoft.Json.xml", + "lib/netstandard1.0/Newtonsoft.Json.dll", + "lib/netstandard1.0/Newtonsoft.Json.xml", + "lib/netstandard1.3/Newtonsoft.Json.dll", + "lib/netstandard1.3/Newtonsoft.Json.xml", + "lib/netstandard2.0/Newtonsoft.Json.dll", + "lib/netstandard2.0/Newtonsoft.Json.xml", + "newtonsoft.json.13.0.3.nupkg.sha512", + "newtonsoft.json.nuspec", + "packageIcon.png" + ] + }, + "protobuf-net/3.2.45": { + "sha512": "5UZ/ukUHcGbFSl7vNMrHsfjqdxusdd9w7w0fCEXzf3UUtsrGNVCzV5SmF+sCHAbnRV2qPcD1ixiDP7Aj8lX/HA==", + "type": "package", + "path": "protobuf-net/3.2.45", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "lib/net462/protobuf-net.dll", + "lib/net462/protobuf-net.xml", + "lib/net6.0/protobuf-net.dll", + "lib/net6.0/protobuf-net.xml", + "lib/netstandard2.0/protobuf-net.dll", + "lib/netstandard2.0/protobuf-net.xml", + "lib/netstandard2.1/protobuf-net.dll", + "lib/netstandard2.1/protobuf-net.xml", + "protobuf-net.3.2.45.nupkg.sha512", + "protobuf-net.nuspec", + "protobuf-net.png", + "readme.md" + ] + }, + "protobuf-net.Core/3.2.45": { + "sha512": "PMWatW2NrT1uTXD7etJ4VdQ0wWZLFrIfdRGppD2QX7nzZ0+kIzqhq551u6ZiXJHWJgG4hWFEkSnUnt2aB6posg==", + "type": "package", + "path": "protobuf-net.core/3.2.45", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "lib/net462/protobuf-net.Core.dll", + "lib/net462/protobuf-net.Core.xml", + "lib/net6.0/protobuf-net.Core.dll", + "lib/net6.0/protobuf-net.Core.xml", + "lib/netstandard2.0/protobuf-net.Core.dll", + "lib/netstandard2.0/protobuf-net.Core.xml", + "lib/netstandard2.1/protobuf-net.Core.dll", + "lib/netstandard2.1/protobuf-net.Core.xml", + "protobuf-net.core.3.2.45.nupkg.sha512", + "protobuf-net.core.nuspec", + "protobuf-net.png", + "readme.md" + ] + }, + "SharpCompress/0.30.1": { + "sha512": "XqD4TpfyYGa7QTPzaGlMVbcecKnXy4YmYLDWrU+JIj7IuRNl7DH2END+Ll7ekWIY8o3dAMWLFDE1xdhfIWD1nw==", + "type": "package", + "path": "sharpcompress/0.30.1", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "lib/net461/SharpCompress.dll", + "lib/net5.0/SharpCompress.dll", + "lib/netcoreapp3.1/SharpCompress.dll", + "lib/netstandard2.0/SharpCompress.dll", + "lib/netstandard2.1/SharpCompress.dll", + "sharpcompress.0.30.1.nupkg.sha512", + "sharpcompress.nuspec" + ] + }, + "Snappier/1.0.0": { + "sha512": "rFtK2KEI9hIe8gtx3a0YDXdHOpedIf9wYCEYtBEmtlyiWVX3XlCNV03JrmmAi/Cdfn7dxK+k0sjjcLv4fpHnqA==", + "type": "package", + "path": "snappier/1.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "COPYING.txt", + "lib/net5.0/Snappier.dll", + "lib/net5.0/Snappier.xml", + "lib/netcoreapp3.0/Snappier.dll", + "lib/netcoreapp3.0/Snappier.xml", + "lib/netstandard2.0/Snappier.dll", + "lib/netstandard2.0/Snappier.xml", + "lib/netstandard2.1/Snappier.dll", + "lib/netstandard2.1/Snappier.xml", + "snappier.1.0.0.nupkg.sha512", + "snappier.nuspec" + ] + }, + "System.Buffers/4.5.1": { + "sha512": "Rw7ijyl1qqRS0YQD/WycNst8hUUMgrMH4FCn1nNm27M4VxchZ1js3fVjQaANHO5f3sN4isvP4a+Met9Y4YomAg==", + "type": "package", + "path": "system.buffers/4.5.1", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "LICENSE.TXT", + "THIRD-PARTY-NOTICES.TXT", + "lib/net461/System.Buffers.dll", + "lib/net461/System.Buffers.xml", + "lib/netcoreapp2.0/_._", + "lib/netstandard1.1/System.Buffers.dll", + "lib/netstandard1.1/System.Buffers.xml", + "lib/netstandard2.0/System.Buffers.dll", + "lib/netstandard2.0/System.Buffers.xml", + "lib/uap10.0.16299/_._", + "ref/net45/System.Buffers.dll", + "ref/net45/System.Buffers.xml", + "ref/netcoreapp2.0/_._", + "ref/netstandard1.1/System.Buffers.dll", + "ref/netstandard1.1/System.Buffers.xml", + "ref/netstandard2.0/System.Buffers.dll", + "ref/netstandard2.0/System.Buffers.xml", + "ref/uap10.0.16299/_._", + "system.buffers.4.5.1.nupkg.sha512", + "system.buffers.nuspec", + "useSharedDesignerContext.txt", + "version.txt" + ] + }, + "System.Collections.Immutable/7.0.0": { + "sha512": "dQPcs0U1IKnBdRDBkrCTi1FoajSTBzLcVTpjO4MBCMC7f4pDOIPzgBoX8JjG7X6uZRJ8EBxsi8+DR1JuwjnzOQ==", + "type": "package", + "path": "system.collections.immutable/7.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "LICENSE.TXT", + "README.md", + "THIRD-PARTY-NOTICES.TXT", + "buildTransitive/net461/System.Collections.Immutable.targets", + "buildTransitive/net462/_._", + "buildTransitive/net6.0/_._", + "buildTransitive/netcoreapp2.0/System.Collections.Immutable.targets", + "lib/net462/System.Collections.Immutable.dll", + "lib/net462/System.Collections.Immutable.xml", + "lib/net6.0/System.Collections.Immutable.dll", + "lib/net6.0/System.Collections.Immutable.xml", + "lib/net7.0/System.Collections.Immutable.dll", + "lib/net7.0/System.Collections.Immutable.xml", + "lib/netstandard2.0/System.Collections.Immutable.dll", + "lib/netstandard2.0/System.Collections.Immutable.xml", + "system.collections.immutable.7.0.0.nupkg.sha512", + "system.collections.immutable.nuspec", + "useSharedDesignerContext.txt" + ] + }, + "System.IO.Pipelines/8.0.0": { + "sha512": "FHNOatmUq0sqJOkTx+UF/9YK1f180cnW5FVqnQMvYUN0elp6wFzbtPSiqbo1/ru8ICp43JM1i7kKkk6GsNGHlA==", + "type": "package", + "path": "system.io.pipelines/8.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "LICENSE.TXT", + "THIRD-PARTY-NOTICES.TXT", + "buildTransitive/net461/System.IO.Pipelines.targets", + "buildTransitive/net462/_._", + "buildTransitive/net6.0/_._", + "buildTransitive/netcoreapp2.0/System.IO.Pipelines.targets", + "lib/net462/System.IO.Pipelines.dll", + "lib/net462/System.IO.Pipelines.xml", + "lib/net6.0/System.IO.Pipelines.dll", + "lib/net6.0/System.IO.Pipelines.xml", + "lib/net7.0/System.IO.Pipelines.dll", + "lib/net7.0/System.IO.Pipelines.xml", + "lib/net8.0/System.IO.Pipelines.dll", + "lib/net8.0/System.IO.Pipelines.xml", + "lib/netstandard2.0/System.IO.Pipelines.dll", + "lib/netstandard2.0/System.IO.Pipelines.xml", + "system.io.pipelines.8.0.0.nupkg.sha512", + "system.io.pipelines.nuspec", + "useSharedDesignerContext.txt" + ] + }, + "System.Memory/4.5.5": { + "sha512": "XIWiDvKPXaTveaB7HVganDlOCRoj03l+jrwNvcge/t8vhGYKvqV+dMv6G4SAX2NoNmN0wZfVPTAlFwZcZvVOUw==", + "type": "package", + "path": "system.memory/4.5.5", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "LICENSE.TXT", + "THIRD-PARTY-NOTICES.TXT", + "lib/net461/System.Memory.dll", + "lib/net461/System.Memory.xml", + "lib/netcoreapp2.1/_._", + "lib/netstandard1.1/System.Memory.dll", + "lib/netstandard1.1/System.Memory.xml", + "lib/netstandard2.0/System.Memory.dll", + "lib/netstandard2.0/System.Memory.xml", + "ref/netcoreapp2.1/_._", + "system.memory.4.5.5.nupkg.sha512", + "system.memory.nuspec", + "useSharedDesignerContext.txt", + "version.txt" + ] + }, + "System.Runtime.CompilerServices.Unsafe/5.0.0": { + "sha512": "ZD9TMpsmYJLrxbbmdvhwt9YEgG5WntEnZ/d1eH8JBX9LBp+Ju8BSBhUGbZMNVHHomWo2KVImJhTDl2hIgw/6MA==", + "type": "package", + "path": "system.runtime.compilerservices.unsafe/5.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "LICENSE.TXT", + "THIRD-PARTY-NOTICES.TXT", + "lib/net45/System.Runtime.CompilerServices.Unsafe.dll", + "lib/net45/System.Runtime.CompilerServices.Unsafe.xml", + "lib/netcoreapp2.0/System.Runtime.CompilerServices.Unsafe.dll", + "lib/netcoreapp2.0/System.Runtime.CompilerServices.Unsafe.xml", + "lib/netstandard1.0/System.Runtime.CompilerServices.Unsafe.dll", + "lib/netstandard1.0/System.Runtime.CompilerServices.Unsafe.xml", + "lib/netstandard2.0/System.Runtime.CompilerServices.Unsafe.dll", + "lib/netstandard2.0/System.Runtime.CompilerServices.Unsafe.xml", + "ref/net461/System.Runtime.CompilerServices.Unsafe.dll", + "ref/net461/System.Runtime.CompilerServices.Unsafe.xml", + "ref/netstandard1.0/System.Runtime.CompilerServices.Unsafe.dll", + "ref/netstandard1.0/System.Runtime.CompilerServices.Unsafe.xml", + "ref/netstandard2.0/System.Runtime.CompilerServices.Unsafe.dll", + "ref/netstandard2.0/System.Runtime.CompilerServices.Unsafe.xml", + "ref/netstandard2.1/System.Runtime.CompilerServices.Unsafe.dll", + "ref/netstandard2.1/System.Runtime.CompilerServices.Unsafe.xml", + "system.runtime.compilerservices.unsafe.5.0.0.nupkg.sha512", + "system.runtime.compilerservices.unsafe.nuspec", + "useSharedDesignerContext.txt", + "version.txt" + ] + }, + "System.Security.AccessControl/5.0.0": { + "sha512": "dagJ1mHZO3Ani8GH0PHpPEe/oYO+rVdbQjvjJkBRNQkX4t0r1iaeGn8+/ybkSLEan3/slM0t59SVdHzuHf2jmw==", + "type": "package", + "path": "system.security.accesscontrol/5.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "LICENSE.TXT", + "THIRD-PARTY-NOTICES.TXT", + "lib/net46/System.Security.AccessControl.dll", + "lib/net461/System.Security.AccessControl.dll", + "lib/net461/System.Security.AccessControl.xml", + "lib/netstandard1.3/System.Security.AccessControl.dll", + "lib/netstandard2.0/System.Security.AccessControl.dll", + "lib/netstandard2.0/System.Security.AccessControl.xml", + "lib/uap10.0.16299/_._", + "ref/net46/System.Security.AccessControl.dll", + "ref/net461/System.Security.AccessControl.dll", + "ref/net461/System.Security.AccessControl.xml", + "ref/netstandard1.3/System.Security.AccessControl.dll", + "ref/netstandard1.3/System.Security.AccessControl.xml", + "ref/netstandard1.3/de/System.Security.AccessControl.xml", + "ref/netstandard1.3/es/System.Security.AccessControl.xml", + "ref/netstandard1.3/fr/System.Security.AccessControl.xml", + "ref/netstandard1.3/it/System.Security.AccessControl.xml", + "ref/netstandard1.3/ja/System.Security.AccessControl.xml", + "ref/netstandard1.3/ko/System.Security.AccessControl.xml", + "ref/netstandard1.3/ru/System.Security.AccessControl.xml", + "ref/netstandard1.3/zh-hans/System.Security.AccessControl.xml", + "ref/netstandard1.3/zh-hant/System.Security.AccessControl.xml", + "ref/netstandard2.0/System.Security.AccessControl.dll", + "ref/netstandard2.0/System.Security.AccessControl.xml", + "ref/uap10.0.16299/_._", + "runtimes/win/lib/net46/System.Security.AccessControl.dll", + "runtimes/win/lib/net461/System.Security.AccessControl.dll", + "runtimes/win/lib/net461/System.Security.AccessControl.xml", + "runtimes/win/lib/netcoreapp2.0/System.Security.AccessControl.dll", + "runtimes/win/lib/netcoreapp2.0/System.Security.AccessControl.xml", + "runtimes/win/lib/netstandard1.3/System.Security.AccessControl.dll", + "runtimes/win/lib/uap10.0.16299/_._", + "system.security.accesscontrol.5.0.0.nupkg.sha512", + "system.security.accesscontrol.nuspec", + "useSharedDesignerContext.txt", + "version.txt" + ] + }, + "System.Security.Principal.Windows/5.0.0": { + "sha512": "t0MGLukB5WAVU9bO3MGzvlGnyJPgUlcwerXn1kzBRjwLKixT96XV0Uza41W49gVd8zEMFu9vQEFlv0IOrytICA==", + "type": "package", + "path": "system.security.principal.windows/5.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "LICENSE.TXT", + "THIRD-PARTY-NOTICES.TXT", + "lib/net46/System.Security.Principal.Windows.dll", + "lib/net461/System.Security.Principal.Windows.dll", + "lib/net461/System.Security.Principal.Windows.xml", + "lib/netstandard1.3/System.Security.Principal.Windows.dll", + "lib/netstandard2.0/System.Security.Principal.Windows.dll", + "lib/netstandard2.0/System.Security.Principal.Windows.xml", + "lib/uap10.0.16299/_._", + "ref/net46/System.Security.Principal.Windows.dll", + "ref/net461/System.Security.Principal.Windows.dll", + "ref/net461/System.Security.Principal.Windows.xml", + "ref/netcoreapp3.0/System.Security.Principal.Windows.dll", + "ref/netcoreapp3.0/System.Security.Principal.Windows.xml", + "ref/netstandard1.3/System.Security.Principal.Windows.dll", + "ref/netstandard1.3/System.Security.Principal.Windows.xml", + "ref/netstandard1.3/de/System.Security.Principal.Windows.xml", + "ref/netstandard1.3/es/System.Security.Principal.Windows.xml", + "ref/netstandard1.3/fr/System.Security.Principal.Windows.xml", + "ref/netstandard1.3/it/System.Security.Principal.Windows.xml", + "ref/netstandard1.3/ja/System.Security.Principal.Windows.xml", + "ref/netstandard1.3/ko/System.Security.Principal.Windows.xml", + "ref/netstandard1.3/ru/System.Security.Principal.Windows.xml", + "ref/netstandard1.3/zh-hans/System.Security.Principal.Windows.xml", + "ref/netstandard1.3/zh-hant/System.Security.Principal.Windows.xml", + "ref/netstandard2.0/System.Security.Principal.Windows.dll", + "ref/netstandard2.0/System.Security.Principal.Windows.xml", + "ref/uap10.0.16299/_._", + "runtimes/unix/lib/netcoreapp2.0/System.Security.Principal.Windows.dll", + "runtimes/unix/lib/netcoreapp2.0/System.Security.Principal.Windows.xml", + "runtimes/unix/lib/netcoreapp2.1/System.Security.Principal.Windows.dll", + "runtimes/unix/lib/netcoreapp2.1/System.Security.Principal.Windows.xml", + "runtimes/win/lib/net46/System.Security.Principal.Windows.dll", + "runtimes/win/lib/net461/System.Security.Principal.Windows.dll", + "runtimes/win/lib/net461/System.Security.Principal.Windows.xml", + "runtimes/win/lib/netcoreapp2.0/System.Security.Principal.Windows.dll", + "runtimes/win/lib/netcoreapp2.0/System.Security.Principal.Windows.xml", + "runtimes/win/lib/netcoreapp2.1/System.Security.Principal.Windows.dll", + "runtimes/win/lib/netcoreapp2.1/System.Security.Principal.Windows.xml", + "runtimes/win/lib/netstandard1.3/System.Security.Principal.Windows.dll", + "runtimes/win/lib/uap10.0.16299/_._", + "system.security.principal.windows.5.0.0.nupkg.sha512", + "system.security.principal.windows.nuspec", + "useSharedDesignerContext.txt", + "version.txt" + ] + }, + "ZstdSharp.Port/0.7.3": { + "sha512": "U9Ix4l4cl58Kzz1rJzj5hoVTjmbx1qGMwzAcbv1j/d3NzrFaESIurQyg+ow4mivCgkE3S413y+U9k4WdnEIkRA==", + "type": "package", + "path": "zstdsharp.port/0.7.3", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "lib/net461/ZstdSharp.dll", + "lib/net5.0/ZstdSharp.dll", + "lib/net6.0/ZstdSharp.dll", + "lib/net7.0/ZstdSharp.dll", + "lib/netcoreapp3.1/ZstdSharp.dll", + "lib/netstandard2.0/ZstdSharp.dll", + "lib/netstandard2.1/ZstdSharp.dll", + "zstdsharp.port.0.7.3.nupkg.sha512", + "zstdsharp.port.nuspec" + ] + } + }, + "projectFileDependencyGroups": { + "net8.0": [ + "Fantasy-Net >= 2024.1.17" + ] + }, + "packageFolders": { + "/Users/fantasy/.nuget/packages/": {} + }, + "project": { + "version": "1.0.0", + "restore": { + "projectUniqueName": "/Users/fantasy/Code/ServerLessions/Chat/Server/Entity/Entity.csproj", + "projectName": "Entity", + "projectPath": "/Users/fantasy/Code/ServerLessions/Chat/Server/Entity/Entity.csproj", + "packagesPath": "/Users/fantasy/.nuget/packages/", + "outputPath": "/Users/fantasy/Code/ServerLessions/Chat/Server/Entity/obj/", + "projectStyle": "PackageReference", + "UsingMicrosoftNETSdk": false, + "configFilePaths": [ + "/Users/fantasy/.nuget/NuGet/NuGet.Config" + ], + "originalTargetFrameworks": [ + "net8.0" + ], + "sources": { + "https://api.nuget.org/v3/index.json": {} + }, + "frameworks": { + "net8.0": { + "targetAlias": "net8.0", + "projectReferences": {} + } + }, + "warningProperties": { + "warnAsError": [ + "NU1605" + ] + }, + "restoreAuditProperties": { + "enableAudit": "true", + "auditLevel": "low", + "auditMode": "all" + } + }, + "frameworks": { + "net8.0": { + "targetAlias": "net8.0", + "dependencies": { + "Fantasy-Net": { + "target": "Package", + "version": "[2024.1.17, )" + } + }, + "imports": [ + "net461", + "net462", + "net47", + "net471", + "net472", + "net48", + "net481" + ], + "assetTargetFallback": true, + "warn": true, + "frameworkReferences": { + "Microsoft.NETCore.App": { + "privateAssets": "all" + } + }, + "runtimeIdentifierGraphPath": "/usr/local/share/dotnet/sdk/9.0.100/PortableRuntimeIdentifierGraph.json" + } + } + } +} \ No newline at end of file diff --git a/聊天系统课程代码/Server/Entity/obj/project.nuget.cache b/聊天系统课程代码/Server/Entity/obj/project.nuget.cache new file mode 100644 index 0000000..9d0e9a2 --- /dev/null +++ b/聊天系统课程代码/Server/Entity/obj/project.nuget.cache @@ -0,0 +1,30 @@ +{ + "version": 2, + "dgSpecHash": "bL6AX114Taw=", + "success": true, + "projectFilePath": "/Users/fantasy/Code/ServerLessions/Chat/Server/Entity/Entity.csproj", + "expectedPackageFiles": [ + "/Users/fantasy/.nuget/packages/commandlineparser/2.9.1/commandlineparser.2.9.1.nupkg.sha512", + "/Users/fantasy/.nuget/packages/dnsclient/1.6.1/dnsclient.1.6.1.nupkg.sha512", + "/Users/fantasy/.nuget/packages/fantasy-net/2024.1.17/fantasy-net.2024.1.17.nupkg.sha512", + "/Users/fantasy/.nuget/packages/microsoft.extensions.logging.abstractions/2.0.0/microsoft.extensions.logging.abstractions.2.0.0.nupkg.sha512", + "/Users/fantasy/.nuget/packages/microsoft.netcore.platforms/5.0.0/microsoft.netcore.platforms.5.0.0.nupkg.sha512", + "/Users/fantasy/.nuget/packages/microsoft.win32.registry/5.0.0/microsoft.win32.registry.5.0.0.nupkg.sha512", + "/Users/fantasy/.nuget/packages/mongodb.bson/3.0.0/mongodb.bson.3.0.0.nupkg.sha512", + "/Users/fantasy/.nuget/packages/mongodb.driver/3.0.0/mongodb.driver.3.0.0.nupkg.sha512", + "/Users/fantasy/.nuget/packages/newtonsoft.json/13.0.3/newtonsoft.json.13.0.3.nupkg.sha512", + "/Users/fantasy/.nuget/packages/protobuf-net/3.2.45/protobuf-net.3.2.45.nupkg.sha512", + "/Users/fantasy/.nuget/packages/protobuf-net.core/3.2.45/protobuf-net.core.3.2.45.nupkg.sha512", + "/Users/fantasy/.nuget/packages/sharpcompress/0.30.1/sharpcompress.0.30.1.nupkg.sha512", + "/Users/fantasy/.nuget/packages/snappier/1.0.0/snappier.1.0.0.nupkg.sha512", + "/Users/fantasy/.nuget/packages/system.buffers/4.5.1/system.buffers.4.5.1.nupkg.sha512", + "/Users/fantasy/.nuget/packages/system.collections.immutable/7.0.0/system.collections.immutable.7.0.0.nupkg.sha512", + "/Users/fantasy/.nuget/packages/system.io.pipelines/8.0.0/system.io.pipelines.8.0.0.nupkg.sha512", + "/Users/fantasy/.nuget/packages/system.memory/4.5.5/system.memory.4.5.5.nupkg.sha512", + "/Users/fantasy/.nuget/packages/system.runtime.compilerservices.unsafe/5.0.0/system.runtime.compilerservices.unsafe.5.0.0.nupkg.sha512", + "/Users/fantasy/.nuget/packages/system.security.accesscontrol/5.0.0/system.security.accesscontrol.5.0.0.nupkg.sha512", + "/Users/fantasy/.nuget/packages/system.security.principal.windows/5.0.0/system.security.principal.windows.5.0.0.nupkg.sha512", + "/Users/fantasy/.nuget/packages/zstdsharp.port/0.7.3/zstdsharp.port.0.7.3.nupkg.sha512" + ], + "logs": [] +} \ No newline at end of file diff --git a/聊天系统课程代码/Server/Entity/obj/project.packagespec.json b/聊天系统课程代码/Server/Entity/obj/project.packagespec.json new file mode 100644 index 0000000..54be366 --- /dev/null +++ b/聊天系统课程代码/Server/Entity/obj/project.packagespec.json @@ -0,0 +1 @@ +"restore":{"projectUniqueName":"/Users/fantasy/Code/ServerLessions/Chat/Server/Entity/Entity.csproj","projectName":"Entity","projectPath":"/Users/fantasy/Code/ServerLessions/Chat/Server/Entity/Entity.csproj","outputPath":"/Users/fantasy/Code/ServerLessions/Chat/Server/Entity/obj/","projectStyle":"PackageReference","UsingMicrosoftNETSdk":false,"originalTargetFrameworks":["net8.0"],"sources":{"https://api.nuget.org/v3/index.json":{}},"frameworks":{"net8.0":{"targetAlias":"net8.0","projectReferences":{}}},"warningProperties":{"warnAsError":["NU1605"]},"restoreAuditProperties":{"enableAudit":"true","auditLevel":"low","auditMode":"all"}}"frameworks":{"net8.0":{"targetAlias":"net8.0","dependencies":{"Fantasy-Net":{"target":"Package","version":"[2024.1.17, )"}},"imports":["net461","net462","net47","net471","net472","net48","net481"],"assetTargetFallback":true,"warn":true,"frameworkReferences":{"Microsoft.NETCore.App":{"privateAssets":"all"}},"runtimeIdentifierGraphPath":"/usr/local/share/dotnet/sdk/9.0.100/PortableRuntimeIdentifierGraph.json"}} \ No newline at end of file diff --git a/聊天系统课程代码/Server/Entity/obj/rider.project.model.nuget.info b/聊天系统课程代码/Server/Entity/obj/rider.project.model.nuget.info new file mode 100644 index 0000000..95ccddb --- /dev/null +++ b/聊天系统课程代码/Server/Entity/obj/rider.project.model.nuget.info @@ -0,0 +1 @@ +17324493181399999 \ No newline at end of file diff --git a/聊天系统课程代码/Server/Entity/obj/rider.project.restore.info b/聊天系统课程代码/Server/Entity/obj/rider.project.restore.info new file mode 100644 index 0000000..320c8ff --- /dev/null +++ b/聊天系统课程代码/Server/Entity/obj/rider.project.restore.info @@ -0,0 +1 @@ +17331012454241067 \ No newline at end of file diff --git a/聊天系统课程代码/Server/Hotfix/Chat/Handler/Inner/G2Chat_LoginRequestHandler.cs b/聊天系统课程代码/Server/Hotfix/Chat/Handler/Inner/G2Chat_LoginRequestHandler.cs new file mode 100644 index 0000000..3418709 --- /dev/null +++ b/聊天系统课程代码/Server/Hotfix/Chat/Handler/Inner/G2Chat_LoginRequestHandler.cs @@ -0,0 +1,20 @@ +using Fantasy.Async; +using Fantasy.Entitas; +using Fantasy.Network.Interface; + +namespace Fantasy; + +public sealed class G2Chat_LoginRequestHandler : RouteRPC +{ + protected override async FTask Run(Scene scene, G2Chat_LoginRequest request, Chat2G_LoginResponse response, Action reply) + { + var chatUnit = scene.GetComponent().Add(request.UnitId, request.UserName, request.GateRouteId); + response.ChatRouteId = chatUnit.RunTimeId; + // 这里模拟创建一个频道用于测试用 + var chatChannelCenterComponent = scene.GetComponent(); + var chatChannelComponent = chatChannelCenterComponent.Apply(1); + // 加入到聊天频道 + chatChannelComponent.JoinChannel(request.UnitId); + await FTask.CompletedTask; + } +} \ No newline at end of file diff --git a/聊天系统课程代码/Server/Hotfix/Chat/Handler/Inner/G2Chat_OfflineRequestHandler.cs b/聊天系统课程代码/Server/Hotfix/Chat/Handler/Inner/G2Chat_OfflineRequestHandler.cs new file mode 100644 index 0000000..ce21caa --- /dev/null +++ b/聊天系统课程代码/Server/Hotfix/Chat/Handler/Inner/G2Chat_OfflineRequestHandler.cs @@ -0,0 +1,13 @@ +using Fantasy.Async; +using Fantasy.Network.Interface; + +namespace Fantasy; + +public sealed class G2Chat_OfflineRequestHandler : RouteRPC +{ + protected override async FTask Run(ChatUnit chatUnit, G2Chat_OfflineRequest request, Chat2G_OfflineResponse response, Action reply) + { + await FTask.CompletedTask; + chatUnit.Scene.GetComponent().Remove(chatUnit.Id); + } +} \ No newline at end of file diff --git a/聊天系统课程代码/Server/Hotfix/Chat/Handler/Inner/Other2Chat_ChatMessageHandler.cs b/聊天系统课程代码/Server/Hotfix/Chat/Handler/Inner/Other2Chat_ChatMessageHandler.cs new file mode 100644 index 0000000..32897e4 --- /dev/null +++ b/聊天系统课程代码/Server/Hotfix/Chat/Handler/Inner/Other2Chat_ChatMessageHandler.cs @@ -0,0 +1,19 @@ +using Fantasy.Async; +using Fantasy.Network.Interface; + +namespace Fantasy; + +public sealed class Other2Chat_ChatMessageHandler : Route +{ + protected override async FTask Run(ChatUnit chatUnit, Other2Chat_ChatMessage message) + { + var result = ChatSceneHelper.Distribution(chatUnit, message.ChatInfoTree, false); + + if (result != 0) + { + Log.Warning($"Other2Chat_ChatMessageHandler: Distribution failed, result: {result}"); + } + + await FTask.CompletedTask; + } +} \ No newline at end of file diff --git a/聊天系统课程代码/Server/Hotfix/Chat/Handler/Outer/C2Chat_SendMessageRequestHandler.cs b/聊天系统课程代码/Server/Hotfix/Chat/Handler/Outer/C2Chat_SendMessageRequestHandler.cs new file mode 100644 index 0000000..097ae79 --- /dev/null +++ b/聊天系统课程代码/Server/Hotfix/Chat/Handler/Outer/C2Chat_SendMessageRequestHandler.cs @@ -0,0 +1,13 @@ +using Fantasy.Async; +using Fantasy.Network.Interface; + +namespace Fantasy; + +public sealed class C2Chat_SendMessageRequestHandler : RouteRPC +{ + protected override async FTask Run(ChatUnit chatUnit, C2Chat_SendMessageRequest request, Chat2C_SendMessageResponse response, Action reply) + { + response.ErrorCode = ChatSceneHelper.Distribution(chatUnit, request.ChatInfoTree); + await FTask.CompletedTask; + } +} \ No newline at end of file diff --git a/聊天系统课程代码/Server/Hotfix/Chat/Helper/ChatChannelCenterHelper.cs b/聊天系统课程代码/Server/Hotfix/Chat/Helper/ChatChannelCenterHelper.cs new file mode 100644 index 0000000..54a4b98 --- /dev/null +++ b/聊天系统课程代码/Server/Hotfix/Chat/Helper/ChatChannelCenterHelper.cs @@ -0,0 +1,37 @@ +namespace Fantasy; + +public static class ChatChannelCenterHelper +{ + /// + /// 申请一个频道 + /// + /// + /// + /// + public static ChatChannelComponent Apply(Scene scene, long channelId) + { + return scene.GetComponent().Apply(channelId); + } + + /// + /// 尝试获取一个频道 + /// + /// + /// + /// + /// + public static bool TryGet(Scene scene, long channelId, out ChatChannelComponent channel) + { + return scene.GetComponent().TryGet(channelId, out channel); + } + + /// + /// 解散一个频道 + /// + /// + /// + public static void Disband(Scene scene, long channelId) + { + scene.GetComponent().Disband(channelId); + } +} \ No newline at end of file diff --git a/聊天系统课程代码/Server/Hotfix/Chat/Helper/ChatHelper.cs b/聊天系统课程代码/Server/Hotfix/Chat/Helper/ChatHelper.cs new file mode 100644 index 0000000..06466fd --- /dev/null +++ b/聊天系统课程代码/Server/Hotfix/Chat/Helper/ChatHelper.cs @@ -0,0 +1,28 @@ +using Fantasy.Platform.Net; + +namespace Fantasy; + +public static class ChatHelper +{ + /// + /// 发送一个聊天消息给ChatScene(不能在ChatScene中调用) + /// + /// + /// + /// + public static void SendChatMessage(Scene scene, long chatUnitRouteId, ChatInfoTree tree) + { + if (scene.SceneType == SceneType.Chat) + { + Log.Warning("ChatHelper.SendChatMessage: scene is not a chat scene."); + return; + } + + var other2ChatChatMessage = new Other2Chat_ChatMessage() + { + ChatInfoTree = tree + }; + + scene.NetworkMessagingComponent.SendInnerRoute(chatUnitRouteId, other2ChatChatMessage); + } +} \ No newline at end of file diff --git a/聊天系统课程代码/Server/Hotfix/Chat/Helper/ChatNodeFactory.cs b/聊天系统课程代码/Server/Hotfix/Chat/Helper/ChatNodeFactory.cs new file mode 100644 index 0000000..a4cec46 --- /dev/null +++ b/聊天系统课程代码/Server/Hotfix/Chat/Helper/ChatNodeFactory.cs @@ -0,0 +1,126 @@ +namespace Fantasy +{ + /// + /// 聊天信息节点 + /// + public static class ChatNodeFactory + { + /// + /// 添加文本节点 + /// + /// + /// + /// + public static ChatInfoTree AddendTextNode(this ChatInfoTree chatInfoTree, string content) + { + var chatInfoNode = new ChatInfoNode() + { + ChatNodeType = (int)ChatNodeType.Text, + Content = content + }; + chatInfoTree.Node.Add(chatInfoNode); + return chatInfoTree; + } + + /// + /// 添加链接节点 + /// + /// + /// + /// + /// + public static ChatInfoTree AddendLinkNode(this ChatInfoTree chatInfoTree, string content,string link) + { + var chatLinkNode = new ChatLinkNode() + { + Link = link + }; + var serializerComponent = chatInfoTree.Scene.GetComponent(); + var chatInfoNode = new ChatInfoNode() + { + ChatNodeType = (int)ChatNodeType.Link, + ChatNodeEvent = (int)ChatNodeEvent.OpenLink, + Content = content, + Data = serializerComponent.Serialize(chatLinkNode) + }; + chatInfoTree.Node.Add(chatInfoNode); + return chatInfoTree; + } + + /// + /// 添加图片节点 + /// + /// + /// + /// + public static ChatInfoTree AddendImageNode(this ChatInfoTree chatInfoTree, string content) + { + var chatInfoNode = new ChatInfoNode() + { + ChatNodeType = (int)ChatNodeType.Image, + Content = content + }; + chatInfoTree.Node.Add(chatInfoNode); + return chatInfoTree; + } + + /// + /// 添加打开UI节点 + /// + /// + /// + /// + /// + public static ChatInfoTree AddendOpenUINode(this ChatInfoTree chatInfoTree, string content,string uiName) + { + var chatOpenUINode = new ChatOpenUINode() + { + UIName = uiName + }; + var serializerComponent = chatInfoTree.Scene.GetComponent(); + var chatInfoNode = new ChatInfoNode() + { + ChatNodeType = (int)ChatNodeType.OpenUI, + ChatNodeEvent = (int)ChatNodeEvent.OpenUI, + Content = content, + Data = serializerComponent.Serialize(chatOpenUINode) + }; + chatInfoTree.Node.Add(chatInfoNode); + return chatInfoTree; + } + + /// + /// 添加位置节点 + /// + /// + /// + /// + /// + /// + /// + /// + public static ChatInfoTree AddendPositionNode(this ChatInfoTree chatInfoTree, string content, string mapName, + float mapX, float mapY, float mapZ) + { + var chatPositionNode = new ChatPositionNode() + { + MapName = mapName, + PosX = mapX, + PosY = mapY, + PosZ = mapZ, + }; + + var serializerComponent = chatInfoTree.Scene.GetComponent(); + var chatInfoNode = new ChatInfoNode() + { + ChatNodeType = (int)ChatNodeType.Position, + ChatNodeEvent = (int)ChatNodeEvent.Position, + Content = content, + Data = serializerComponent.Serialize(chatPositionNode) + }; + + chatInfoTree.Node.Add(chatInfoNode); + return chatInfoTree; + } + } +} \ No newline at end of file diff --git a/聊天系统课程代码/Server/Hotfix/Chat/Helper/ChatSceneHelper.cs b/聊天系统课程代码/Server/Hotfix/Chat/Helper/ChatSceneHelper.cs new file mode 100644 index 0000000..4f65498 --- /dev/null +++ b/聊天系统课程代码/Server/Hotfix/Chat/Helper/ChatSceneHelper.cs @@ -0,0 +1,248 @@ +using System.Threading.Channels; +using Fantasy.Helper; +using Fantasy.Platform.Net; +// ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract + +namespace Fantasy; + +public static class ChatSceneHelper +{ + private const int ChatCD = 1000; + private const int MaxTextLength = 10; + private const int MaxShowItemCount = 2; + + /// + /// 聊天消息分发入口 + /// + /// + /// + /// + /// + public static uint Distribution(ChatUnit chatUnit, ChatInfoTree tree, bool isCheckSendTime = true) + { + var result = Condition(chatUnit, tree, isCheckSendTime); + + if (result != 0) + { + return result; + } + + switch ((ChatChannelType)tree.ChatChannelType) + { + case ChatChannelType.Broadcast: + { + Broadcast(chatUnit.Scene, tree); + return 0; + } + case ChatChannelType.Team: + { + return Channel(chatUnit, tree); + } + case ChatChannelType.Private: + { + return Private(chatUnit, tree); + } + default: + { + // 这个1代表当前频道不存在。 + return 1; + } + } + } + + /// + /// 聊天消息条件判断 + /// + /// + /// + /// + /// + private static uint Condition(ChatUnit chatUnit, ChatInfoTree tree, bool isCheckSendTime = true) + { + // 每个频道可能聊天的间隔都不一样。 + // 这里的条件判断,是根据频道的类型,来判断是否到达了聊天的间隔。 + var now = TimeHelper.Now; + + if (isCheckSendTime) + { + // 这里的间隔时间,是根据频道的类型,来获取的。 + chatUnit.SendTime.TryGetValue(tree.ChatChannelType, out var sendTime); + // 判定聊天间隔是否到达 + // 其实的话,这个ChatCD应该是根据频道的类型,来获取的。 + // 一般的话都是做一个配置表,通过配置表来获取不同频道的时间间隔。 + if (now - sendTime < ChatCD) + { + // 这个1代表当前频道聊天的间隔过短 + return 1; + } + } + + // 判定聊天内容是否超长 + + var itemCount = 0; + var chatTextSize = 0; + + foreach (var chatInfoNode in tree.Node) + { + switch ((ChatNodeType)chatInfoNode.ChatNodeType) + { + case ChatNodeType.Text: + { + chatTextSize += chatInfoNode.Content.Length; + break; + } + case ChatNodeType.Image: + { + // 规定图片占聊天消息的5个字符长度 + chatTextSize += 5; + break; + } + case ChatNodeType.OpenUI: + { + // 规定OpenUI占聊天消息的10个字符长度 + chatTextSize += 10; + break; + } + case ChatNodeType.Item: + { + itemCount++; + break; + } + } + } + + if (chatTextSize > MaxTextLength) + { + // 这个2代表当前频道聊天内容超长 + return 2; + } + + if (itemCount > MaxShowItemCount) + { + // 这个3代表当前频道聊天里道具数量过多 + return 3; + } + + if (isCheckSendTime) + { + // 更新当前频道的发送时间 + chatUnit.SendTime[tree.ChatChannelType] = now; + } + + return 0; + } + + #region 不同聊天频道的实现 + + /// + /// 广播消息 + /// + /// + /// + private static void Broadcast(Scene scene, ChatInfoTree tree) + { + var networkMessagingComponent = scene.NetworkMessagingComponent; + var chatMessage = new Chat2G_ChatMessage() + { + ChatInfoTree = tree + }; + + if (tree.Target.Count > 0) + { + var chatUnitManageComponent = scene.GetComponent(); + // 给一部分人广播消息 + foreach (var chatUnitId in tree.Target) + { + if (!chatUnitManageComponent.TryGet(chatUnitId, out var chatUnit)) + { + continue; + } + + networkMessagingComponent.SendInnerRoute(chatUnit.GateRouteId, chatMessage); + } + return; + } + + // 发送给所有Gate服务器,让Gate服务器转发给其他客户端 + var gateConfigs = SceneConfigData.Instance.GetSceneBySceneType(SceneType.Gate); + foreach (var gateSceneConfig in gateConfigs) + { + // 这里是要发送一个消息给Gate服务器,Gate服务器再转发给其他客户端 + networkMessagingComponent.SendInnerRoute(gateSceneConfig.RouteId, chatMessage); + } + } + + /// + /// 发送频道消息 + /// + /// + /// + private static uint Channel(ChatUnit chatUnit, ChatInfoTree tree) + { + // 那组队,公会、地图、等这个的聊天,如何使用频道呢? + // 这里的频道,是指一个频道,比如一个公会的频道,一个队伍的频道,一个地图的频道。 + // 1、一般组队工会、地图等,都是有一个创建的一个逻辑,咱们个在这个创建的逻辑中,根据队伍、公会、地图的ID + // 把这些ID当做频道ID,然后发送到Chat服务器,先申请一个频道,把这个频道ID返回给创建公会队伍的逻辑。 + // 这时候,队伍公会、发送聊天消息的时候,就会根据这个ID来进行发送。 + // 2、地图同样道理,创建地图的时候,也会有一个创建的逻辑,这个逻辑会返回一个地图的ID,这个ID就是地图的频道ID。 + // 3、这这些ID根据频道类型,发送给客户端,客户端发送的时候,根据频道不同,拿不同的ID来发送。 + + // 课外: + // 客户端创建一个频道、拿到这个频道号,告诉其他人,其他人通过这个频道ID加入到这个频道。 + // 客户端创建一个频道,邀请其他人加入到这个频道,其他人可能客户端会接收一个协议,就是邀请你加入到这个频道,如果同意, + // 你就加入到这个频道(你点同意后,会发送一个消息给聊天服务器,聊天服务器会把你加入到这个频道)。 + + if (!chatUnit.Channels.TryGetValue(tree.ChatChannelId, out var channel)) + { + // 这个1代表当前频道不存在。 + return 1; + } + + channel.Send(tree); + return 0; + } + + /// + /// 发送私聊消息 + /// + /// + /// + /// + private static uint Private(ChatUnit chatUnit, ChatInfoTree tree) + { + // 私聊,就是两个玩家之间,直接聊天。 + // 1、首先,客户端需要知道对方的ID,这个ID是通过什么方式获取的呢? + // 2、客户端需要发送一个私聊消息给聊天服务器,聊天服务器需要把这个消息转发给对方。 + // 3、对方收到消息后,需要显示出来。 + // 4、聊天服务器需要记录这个私聊消息,并把这个消息转发给两个玩家。 + // 5、两个玩家收到消息后,需要显示出来。 + + if (tree.Target == null || tree.Target.Count <= 0) + { + // 这个1代表对方ID不的合法的。 + return 1; + } + + var targetChatUnitId = tree.Target[0]; + var scene = chatUnit.Scene; + if (!scene.GetComponent().TryGet(targetChatUnitId, out var targetChatUnit)) + { + // 这个2代表对方不在线。 + return 2; + } + + var networkMessagingComponent = scene.NetworkMessagingComponent; + var chatMessage = new Chat2C_Message() + { + ChatInfoTree = tree + }; + + // 先给自己发送一个聊天消息。 + networkMessagingComponent.SendInnerRoute(chatUnit.GateRouteId, chatMessage); + // 然后再给对方发送一个聊天消息。 + networkMessagingComponent.SendInnerRoute(targetChatUnit.GateRouteId, chatMessage); + return 0; + } + + #endregion +} \ No newline at end of file diff --git a/聊天系统课程代码/Server/Hotfix/Chat/Helper/ChatTreeFactory.cs b/聊天系统课程代码/Server/Hotfix/Chat/Helper/ChatTreeFactory.cs new file mode 100644 index 0000000..e11926e --- /dev/null +++ b/聊天系统课程代码/Server/Hotfix/Chat/Helper/ChatTreeFactory.cs @@ -0,0 +1,119 @@ +namespace Fantasy; + +/// +/// 创建聊天树的总入口 +/// +public static class ChatTreeFactory +{ + /// + /// 创建世界聊天树 + /// + /// + /// + public static ChatInfoTree World(Scene scene) + { + return new ChatInfoTree() + { + Scene = scene, + ChatChannelType = (int)ChatChannelType.World, + }; + } + + /// + /// 创建私聊聊天树 + /// + /// + /// + public static ChatInfoTree Private(Scene scene) + { + return new ChatInfoTree() + { + Scene = scene, + ChatChannelType = (int)ChatChannelType.Private, + }; + } + + /// + /// 创建系统聊天树 + /// + /// + /// + public static ChatInfoTree System(Scene scene) + { + return new ChatInfoTree() + { + Scene = scene, + ChatChannelType = (int)ChatChannelType.System, + }; + } + + /// + /// 创建公广播聊天树 + /// + /// + /// + public static ChatInfoTree Broadcast(Scene scene) + { + return new ChatInfoTree() + { + Scene = scene, + ChatChannelType = (int)ChatChannelType.Broadcast, + }; + } + + /// + /// 创建公告聊天树 + /// + /// + /// + public static ChatInfoTree Notice(Scene scene) + { + return new ChatInfoTree() + { + Scene = scene, + ChatChannelType = (int)ChatChannelType.Notice, + }; + } + + /// + /// 创建队伍聊天树 + /// + /// + /// + public static ChatInfoTree Team(Scene scene) + { + return new ChatInfoTree() + { + Scene = scene, + ChatChannelType = (int)ChatChannelType.Team, + }; + } + + /// + /// 创建附近人聊天树 + /// + /// + /// + public static ChatInfoTree Near(Scene scene) + { + return new ChatInfoTree() + { + Scene = scene, + ChatChannelType = (int)ChatChannelType.Near, + }; + } + + /// + /// 创建当前地图聊天树 + /// + /// + /// + public static ChatInfoTree CurrentMap(Scene scene) + { + return new ChatInfoTree() + { + Scene = scene, + ChatChannelType = (int)ChatChannelType.CurrentMap, + }; + } +} \ No newline at end of file diff --git a/聊天系统课程代码/Server/Hotfix/Chat/System/ChatChannelCenterComponentSystem.cs b/聊天系统课程代码/Server/Hotfix/Chat/System/ChatChannelCenterComponentSystem.cs new file mode 100644 index 0000000..0b196d0 --- /dev/null +++ b/聊天系统课程代码/Server/Hotfix/Chat/System/ChatChannelCenterComponentSystem.cs @@ -0,0 +1,49 @@ +using Fantasy.Entitas; +using Fantasy.Entitas.Interface; + +#pragma warning disable CS8602 // Dereference of a possibly null reference. +#pragma warning disable CS8601 // Possible null reference assignment. + +namespace Fantasy; + +public sealed class ChatChannelCenterComponentDestroySystem : DestroySystem +{ + protected override void Destroy(ChatChannelCenterComponent self) + { + foreach (var chatChannelComponent in self.Channels.Values.ToArray()) + { + chatChannelComponent.Dispose(); + } + self.Channels.Clear(); + } +} + +public static class ChatChannelCenterComponentSystem +{ + public static ChatChannelComponent Apply(this ChatChannelCenterComponent self, long channelId) + { + if (self.Channels.TryGetValue(channelId, out var channel)) + { + return channel; + } + + channel = Entity.Create(self.Scene, channelId, true, true); + self.Channels.Add(channelId, channel); + return channel; + } + + public static bool TryGet(this ChatChannelCenterComponent self, long channelId, out ChatChannelComponent channel) + { + return self.Channels.TryGetValue(channelId, out channel); + } + + public static void Disband(this ChatChannelCenterComponent self, long channelId) + { + if (self.Channels.Remove(channelId, out var channel)) + { + return; + } + + channel.Dispose(); + } +} \ No newline at end of file diff --git a/聊天系统课程代码/Server/Hotfix/Chat/System/ChatChannelComponentSystem.cs b/聊天系统课程代码/Server/Hotfix/Chat/System/ChatChannelComponentSystem.cs new file mode 100644 index 0000000..c06de45 --- /dev/null +++ b/聊天系统课程代码/Server/Hotfix/Chat/System/ChatChannelComponentSystem.cs @@ -0,0 +1,86 @@ +using Fantasy.Entitas; + +namespace Fantasy; + +public class MemoryEntity : Entity +{ + +} + + +public static class ChatChannelComponentSystem +{ + public static void Send(this ChatChannelComponent self, ChatInfoTree tree) + { + var chatUnitManageComponent = self.Scene.GetComponent(); + var networkMessagingComponent = self.Scene.NetworkMessagingComponent; + var chatMessage = new Chat2C_Message() + { + ChatInfoTree = tree + }; + + foreach (var unitId in self.Units) + { + if (!chatUnitManageComponent.Units.TryGetValue(unitId, out var chatUnit)) + { + continue; + } + + networkMessagingComponent.SendInnerRoute(chatUnit.GateRouteId, chatMessage); + } + } + + public static bool JoinChannel(this ChatChannelComponent self, long chatUnitId) + { + var chatUnitManageComponent = self.Scene.GetComponent(); + + if (!chatUnitManageComponent.TryGet(chatUnitId, out var chatUnit)) + { + return false; + } + + // 将当前频道中加入该用户。 + self.Units.Add(chatUnitId); + // 给用户添加频道。 + if (!chatUnit.Channels.ContainsKey(self.Id)) + { + chatUnit.Channels.Add(self.Id, self); + } + // 可以在这里给客户端发送一个加入频道成功的消息。 + return true; + } + + public static bool IsJoinedChannel(this ChatChannelComponent self, long chatUnitId) + { + return self.Units.Contains(chatUnitId); + } + + public static void ExitChannel(this ChatChannelComponent self, long chatUnitId, bool isRemoveUnitChannel = true) + { + if (!self.Units.Contains(chatUnitId)) + { + return; + } + + var chatUnitManageComponent = self.Scene.GetComponent(); + + if (!chatUnitManageComponent.TryGet(chatUnitId, out var chatUnit)) + { + return; + } + + if (isRemoveUnitChannel) + { + // 给用户移除频道。 + chatUnit.Channels.Remove(self.Id); + } + + // 在当前频道中移除该用户。 + self.Units.Remove(chatUnitId); + // 如果当前频道中没有用户了,则销毁该频道。 + if (self.Units.Count == 0) + { + self.Dispose(); + } + } +} \ No newline at end of file diff --git a/聊天系统课程代码/Server/Hotfix/Chat/System/ChatUnitManageComponentSystem.cs b/聊天系统课程代码/Server/Hotfix/Chat/System/ChatUnitManageComponentSystem.cs new file mode 100644 index 0000000..33bd5f1 --- /dev/null +++ b/聊天系统课程代码/Server/Hotfix/Chat/System/ChatUnitManageComponentSystem.cs @@ -0,0 +1,67 @@ +using Fantasy.Entitas; +using Fantasy.Entitas.Interface; +#pragma warning disable CS8601 // Possible null reference assignment. + +namespace Fantasy; + +public sealed class ChatUnitManageComponentDestroySystem : DestroySystem +{ + protected override void Destroy(ChatUnitManageComponent self) + { + foreach (var chatUnit in self.Units.Values.ToArray()) + { + chatUnit.Dispose(); + } + + self.Units.Clear(); + } +} + +public static class ChatUnitManageComponentSystem +{ + public static ChatUnit Add(this ChatUnitManageComponent self, long unitId, string userName, long gateRouteId) + { + if (!self.Units.TryGetValue(unitId, out var chatUnit)) + { + chatUnit = Entity.Create(self.Scene, unitId, true, true); + self.Units.Add(unitId, chatUnit); + Log.Debug($"Add ChatUnit Count: {self.Units.Count} UnitId: {unitId} UserName: {userName} GateRouteId: {gateRouteId}"); + } + else + { + Log.Debug($"ChatUnit: {chatUnit.UserName}({chatUnit.GateRouteId})"); + } + + chatUnit.UserName = userName; + chatUnit.GateRouteId = gateRouteId; + return chatUnit; + } + + public static ChatUnit? Get(this ChatUnitManageComponent self, long unitId) + { + return self.Units.GetValueOrDefault(unitId); + } + + public static bool TryGet(this ChatUnitManageComponent self, long unitId, out ChatUnit chatUnit) + { + return self.Units.TryGetValue(unitId, out chatUnit); + } + + public static void Remove(this ChatUnitManageComponent self, long unitId, bool isDispose = true) + { + // 由于退出频道的时候,也会检查该玩家是否在ChatUnitManageComponent中,所以这里不做移除操作。 + if (!self.Units.TryGetValue(unitId, out var chatUnit)) + { + return; + } + + if (isDispose) + { + chatUnit.Dispose(); + } + + // 因为玩家已经执行了退出频道的操作了,所以要清除一下这个数据。 + self.Units.Remove(unitId); + Log.Debug($"Remove ChatUnit: {chatUnit.UserName}({chatUnit.GateRouteId}) Count: {self.Units.Count}"); + } +} \ No newline at end of file diff --git a/聊天系统课程代码/Server/Hotfix/Chat/System/ChatUnitSystem.cs b/聊天系统课程代码/Server/Hotfix/Chat/System/ChatUnitSystem.cs new file mode 100644 index 0000000..96200d0 --- /dev/null +++ b/聊天系统课程代码/Server/Hotfix/Chat/System/ChatUnitSystem.cs @@ -0,0 +1,21 @@ +using Fantasy.Entitas.Interface; +#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. + +namespace Fantasy; + +public sealed class ChatUnitDestroySystem : DestroySystem +{ + protected override void Destroy(ChatUnit self) + { + self.UserName = null; + self.GateRouteId = 0; + // 退出当前ChatUnit拥有的所有频道 + foreach (var (_,chatChannelComponent) in self.Channels) + { + chatChannelComponent.ExitChannel(self.Id, false); + } + // 理论情况下,这个self.Channels不会存在因为数据的,因为上面已经给清空掉了。 + // 但是self.Channels.Clear();还是加上吧,防止以后忘记了。 + self.Channels.Clear(); + } +} \ No newline at end of file diff --git a/聊天系统课程代码/Server/Hotfix/Gate/Handler/Inner/Chat2G_ChatMessageHandler.cs b/聊天系统课程代码/Server/Hotfix/Gate/Handler/Inner/Chat2G_ChatMessageHandler.cs new file mode 100644 index 0000000..19fff5d --- /dev/null +++ b/聊天系统课程代码/Server/Hotfix/Gate/Handler/Inner/Chat2G_ChatMessageHandler.cs @@ -0,0 +1,20 @@ +using Fantasy.Async; +using Fantasy.Network.Interface; + +namespace Fantasy; + +public sealed class Chat2G_ChatMessageHandler : Route +{ + protected override async FTask Run(Scene scene, Chat2G_ChatMessage message) + { + var chatMessage = new Chat2C_Message() + { + ChatInfoTree = message.ChatInfoTree + }; + foreach (var session in scene.GetComponent().ForEachUnitSession()) + { + session.Send(chatMessage); + } + await FTask.CompletedTask; + } +} \ No newline at end of file diff --git a/聊天系统课程代码/Server/Hotfix/Gate/Handler/Outer/C2G_ExitRequestHandler.cs b/聊天系统课程代码/Server/Hotfix/Gate/Handler/Outer/C2G_ExitRequestHandler.cs new file mode 100644 index 0000000..886f073 --- /dev/null +++ b/聊天系统课程代码/Server/Hotfix/Gate/Handler/Outer/C2G_ExitRequestHandler.cs @@ -0,0 +1,15 @@ +using Fantasy.Async; +using Fantasy.Network; +using Fantasy.Network.Interface; +// ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract + +namespace Fantasy; + +public sealed class C2G_ExitRequestHandler : MessageRPC +{ + protected override async FTask Run(Session session, C2G_ExitRequest request, G2C_ExitResponse response, Action reply) + { + session.RemoveComponent(); + await FTask.CompletedTask; + } +} \ No newline at end of file diff --git a/聊天系统课程代码/Server/Hotfix/Gate/Handler/Outer/C2G_LoginRequestHandler.cs b/聊天系统课程代码/Server/Hotfix/Gate/Handler/Outer/C2G_LoginRequestHandler.cs new file mode 100644 index 0000000..c66d2fd --- /dev/null +++ b/聊天系统课程代码/Server/Hotfix/Gate/Handler/Outer/C2G_LoginRequestHandler.cs @@ -0,0 +1,30 @@ +using Fantasy.Async; +using Fantasy.Network; +using Fantasy.Network.Interface; + +namespace Fantasy; + +public sealed class C2G_LoginRequestHandler : MessageRPC +{ + protected override async FTask Run(Session session, C2G_LoginRequest request, G2C_LoginResponse response, Action reply) + { + if (string.IsNullOrEmpty(request.UserName)) + { + // 这里返回的1代表账号信息是空的。 + response.ErrorCode = 1; + return; + } + + var scene = session.Scene; + // 添加一个GateUnitFlagComponent组件,用来Session断开、或者传递数据时使用。 + var gateUnitFlagComponent = session.GetOrAddComponent(); + // 上线到Gate + var gateUnit = GateUnitHelper.Online(scene, request.UserName, session); + // 设置GateUnitFlagComponent的GateUnitId + gateUnitFlagComponent.GateUnitId = gateUnit.Id; + // 登录到其他服务器 + await GateLoginHelper.Online(session, gateUnit, session.RunTimeId); + Log.Debug($"gateUnit : {gateUnit.UserName}"); + await FTask.CompletedTask; + } +} \ No newline at end of file diff --git a/聊天系统课程代码/Server/Hotfix/Gate/Helper/GateLoginHelper.cs b/聊天系统课程代码/Server/Hotfix/Gate/Helper/GateLoginHelper.cs new file mode 100644 index 0000000..56d997b --- /dev/null +++ b/聊天系统课程代码/Server/Hotfix/Gate/Helper/GateLoginHelper.cs @@ -0,0 +1,117 @@ +using Fantasy.Async; +using Fantasy.Network; +using Fantasy.Platform.Net; + +namespace Fantasy; + +public static class GateLoginHelper +{ + private static readonly List>> Scenes = + new List>>() + { + // 聊天服务器上线 + { OnlineChat }, + // 游戏服务器上线 + { OnlineGame } + }; + + /// + /// 上线到其他服务器 + /// + /// + /// + /// + public static async FTask Online(Session session, GateUnit gateUnit, long gateRouteId) + { + var scene = session.Scene; + // 要实现自动Route转发协议,必须要给Session添加一个RouteComponent,然后通过它来转发消息。 + var routeComponent = session.GetOrAddComponent(); + // 这里是登录的总入口,在这里会陆续的登录其他服务器,如:聊天服务器、游戏服务器等 + foreach (var sceneHandler in Scenes) + { + var (errorCode, routeId, routeType) = await sceneHandler(scene, gateUnit, gateRouteId); + if (errorCode != 0) + { + return errorCode; + } + // 保存上线过的RouteId,用于下线时通知其他服务器下线 + gateUnit.Routes[routeType] = routeId; + // 添加到路由地址中,只有添加了这个路由映射地址,才会自动的从Gate转发到Chat + routeComponent.AddAddress(routeType, routeId); + } + return 0; + } + + /// + /// 通知其他服务器下线 + /// + + /// + public static async FTask Offline(GateUnit gateUnit) + { + var networkMessagingComponent = gateUnit.Scene.NetworkMessagingComponent; + + foreach (var (routeType, routeId) in gateUnit.Routes) + { + switch (routeType) + { + case RouteType.ChatRoute: + { + var response = + (Chat2G_OfflineResponse)await networkMessagingComponent.CallInnerRoute(routeId, + new G2Chat_OfflineRequest()); + if (response.ErrorCode != 0) + { + return response.ErrorCode; + } + + continue; + } + } + } + + gateUnit.Routes.Clear(); + return 0; + } + + /// + /// 聊天服务器上线 + /// + /// + /// + /// + /// + private static async FTask<(uint errorCode, long routeId, int routeType)> OnlineChat(Scene scene, GateUnit gateUnit, long gateRouteId) + { + // 登录聊天服务器 + var chatConfig = SceneConfigData.Instance.GetSceneBySceneType(SceneType.Chat)[0]; + // 咱们框架中,如果要Scene和Scene之间通讯,必须要用到NetworkMessagingComponent,通过它来发送,没有其他办法。 + var response = (Chat2G_LoginResponse)await scene.NetworkMessagingComponent.CallInnerRoute(chatConfig.RouteId, + new G2Chat_LoginRequest() + { + UserName = gateUnit.UserName, + UnitId = gateUnit.Id, + GateRouteId = gateRouteId + }); + return (response.ErrorCode, response.ChatRouteId, RouteType.ChatRoute); + } + + /// + /// 游戏服务器上线 + /// + /// + /// + /// + /// + private static async FTask<(uint errorCode, long routeId, int routeType)> OnlineGame(Scene scene, GateUnit gateUnit, long gateRouteId) + { + // 登录聊天服务器 + var mapConfig = SceneConfigData.Instance.GetSceneBySceneType(SceneType.Map)[0]; + var response = (M2G_LoginResponse)await scene.NetworkMessagingComponent.CallInnerRoute(mapConfig.RouteId, + new G2M_LoginRequest() + { + ChatUnitRouteId = gateUnit.Routes[RouteType.ChatRoute] + }); + return (response.ErrorCode, response.MapRouteId, RouteType.GateRoute); + } +} \ No newline at end of file diff --git a/聊天系统课程代码/Server/Hotfix/Gate/Helper/GateUnitHelper.cs b/聊天系统课程代码/Server/Hotfix/Gate/Helper/GateUnitHelper.cs new file mode 100644 index 0000000..c1b90fa --- /dev/null +++ b/聊天系统课程代码/Server/Hotfix/Gate/Helper/GateUnitHelper.cs @@ -0,0 +1,105 @@ +using Fantasy.Async; +using Fantasy.Network; +// ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract + +#pragma warning disable CS8602 // Dereference of a possibly null reference. +namespace Fantasy; + +public static class GateUnitHelper +{ + /// + /// GateUnit上线 + /// + /// + /// + /// + /// + public static GateUnit Online(Scene scene, string userName, Session session) + { + // 增加一个GateUnit到缓存中、如果缓存中已经存在直接返回缓存中的实体数据 + return scene.GetComponent().Add(userName, session); + } + + /// + /// GateUnit下线 + /// + /// + /// + public static void Offline(Scene scene, long gateUnitId) + { + if (!scene.GetComponent().TryGet(gateUnitId, out var gateUnit)) + { + return; + } + + gateUnit.GetOrAddComponent().SetTimeout(5000); + } + + /// + /// 缓存中获取一个GateUnit + /// + /// + /// + /// + public static GateUnit? Get(Scene scene, string userName) + { + return scene.GetComponent().Get(userName); + } + + /// + /// 缓存中获取一个GateUnit + /// + /// + /// + /// + public static GateUnit? Get(Scene scene, long gateUnitId) + { + return scene.GetComponent().Get(gateUnitId); + } + + /// + /// 尝试获取一个GateUnit + /// + /// + /// + /// + /// + public static bool TryGet(Scene scene, string userName, out GateUnit? gateUnit) + { + return scene.GetComponent().TryGet(userName, out gateUnit); + } + + /// + /// 尝试获取一个GateUnit + /// + /// + /// + /// + /// + public static bool TryGet(Scene scene, long gateUnitId, out GateUnit? gateUnit) + { + return scene.GetComponent().TryGet(gateUnitId, out gateUnit); + } + + /// + /// 在缓存中移除一个GateUnit + /// + /// + /// + /// + public static FTask Remove(Scene scene, string userName, bool isDispose = true) + { + return scene.GetComponent().Remove(userName, isDispose); + } + + /// + /// 在缓存中移除一个GateUnit + /// + /// + /// + /// + public static FTask Remove(Scene scene, long gateUnitId, bool isDispose = true) + { + return scene.GetComponent().Remove(gateUnitId, isDispose); + } +} \ No newline at end of file diff --git a/聊天系统课程代码/Server/Hotfix/Gate/System/GateUnitFlagComponentSystem.cs b/聊天系统课程代码/Server/Hotfix/Gate/System/GateUnitFlagComponentSystem.cs new file mode 100644 index 0000000..4c97ce5 --- /dev/null +++ b/聊天系统课程代码/Server/Hotfix/Gate/System/GateUnitFlagComponentSystem.cs @@ -0,0 +1,15 @@ +using Fantasy.Entitas.Interface; + +namespace Fantasy; + +public sealed class GateUnitFlagComponentDestroySystem : DestroySystem +{ + protected override void Destroy(GateUnitFlagComponent self) + { + var selfGateUnitId = self.GateUnitId; + // 执行下线操作 + GateUnitHelper.Offline(self.Scene, selfGateUnitId); + // 清理垃圾数据 + self.GateUnitId = 0; + } +} \ No newline at end of file diff --git a/聊天系统课程代码/Server/Hotfix/Gate/System/GateUnitManageComponentSystem.cs b/聊天系统课程代码/Server/Hotfix/Gate/System/GateUnitManageComponentSystem.cs new file mode 100644 index 0000000..b954515 --- /dev/null +++ b/聊天系统课程代码/Server/Hotfix/Gate/System/GateUnitManageComponentSystem.cs @@ -0,0 +1,135 @@ +using Fantasy.Async; +using Fantasy.Entitas; +using Fantasy.Entitas.Interface; +using Fantasy.Network; +// ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract +#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. + +namespace Fantasy; + +public sealed class GateUnitManageComponentDestroySystem : DestroySystem +{ + protected override void Destroy(GateUnitManageComponent self) + { + foreach (var gateUnit in self.Units.Values.ToArray()) + { + gateUnit.Dispose(); + } + + self.Units.Clear(); + self.UnitsByUserName.Clear(); + } +} + +public static class GateUnitManageComponentSystem +{ + public static GateUnit Add(this GateUnitManageComponent self, string userName, Session session) + { + if (self.UnitsByUserName.TryGetValue(userName, out var gateUnit)) + { + gateUnit.Session = session; + // 如果缓存中已经存在了该名字,那就直接从缓存中返回就可以了 + Log.Debug($"在缓存中获取的数据 userName:{userName}"); + return gateUnit; + } + + // 创建一个新的实体 + gateUnit = Entity.Create(self.Scene, true, true); + gateUnit.UserName = userName; + gateUnit.Session = session; + // 添加到缓存中 + self.Units.Add(gateUnit.Id, gateUnit); + self.UnitsByUserName.Add(userName, gateUnit); + + Log.Debug($"新创建的数据 userName:{userName}"); + return gateUnit; + } + + public static GateUnit? Get(this GateUnitManageComponent self, string userName) + { + return self.UnitsByUserName.GetValueOrDefault(userName); + } + + public static GateUnit? Get(this GateUnitManageComponent self, long gateUnitId) + { + return self.Units.GetValueOrDefault(gateUnitId); + } + + public static bool TryGet(this GateUnitManageComponent self, string userName, out GateUnit? gateUnit) + { + return self.UnitsByUserName.TryGetValue(userName, out gateUnit); + } + + public static bool TryGet(this GateUnitManageComponent self, long gateUnitId, out GateUnit? gateUnit) + { + return self.Units.TryGetValue(gateUnitId, out gateUnit); + } + + public static async FTask Remove(this GateUnitManageComponent self, string userName, bool isDispose = true) + { + if (!self.UnitsByUserName.TryGetValue(userName, out var gateUnit)) + { + return; + } + + // 通知其他服务器下线 + var result = await GateLoginHelper.Offline(gateUnit); + if (result != 0) + { + Log.Error($"通知其他服务器下线失败,错误码:{result}"); + return; + } + // 如果其他服务器都已经下线了,那就直接移除本地数据 + self.Units.Remove(gateUnit.Id); + self.UnitsByUserName.Remove(userName); + + if (isDispose) + { + gateUnit.Dispose(); + } + + gateUnit.Session = null; + gateUnit.UserName = null; + } + + public static async FTask Remove(this GateUnitManageComponent self, long gateUnitId, bool isDispose = true) + { + if (!self.Units.TryGetValue(gateUnitId, out var gateUnit)) + { + return; + } + // 通知其他服务器下线 + var result = await GateLoginHelper.Offline(gateUnit); + if (result != 0) + { + Log.Error($"通知其他服务器下线失败,错误码:{result}"); + return; + } + // 如果其他服务器都已经下线了,那就直接移除本地数据 + self.Units.Remove(gateUnitId); + self.UnitsByUserName.Remove(gateUnit.UserName); + + if (isDispose) + { + gateUnit.Dispose(); + } + + gateUnit.Session = null; + gateUnit.UserName = null; + } + + public static IEnumerable ForEachUnitSession(this GateUnitManageComponent self) + { + foreach (var (_, gateUnit) in self.Units) + { + Session gateUnitSession = gateUnit.Session; + + if (gateUnitSession == null) + { + continue; + } + + yield return gateUnitSession; + } + } +} \ No newline at end of file diff --git a/聊天系统课程代码/Server/Hotfix/Gate/System/GateUnitSystem.cs b/聊天系统课程代码/Server/Hotfix/Gate/System/GateUnitSystem.cs new file mode 100644 index 0000000..a660189 --- /dev/null +++ b/聊天系统课程代码/Server/Hotfix/Gate/System/GateUnitSystem.cs @@ -0,0 +1,14 @@ +using Fantasy.Entitas.Interface; +#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. + +namespace Fantasy; + +public sealed class GateUnitDestroySystem : DestroySystem +{ + protected override void Destroy(GateUnit self) + { + // 移除缓存中的GateUnit + // 这里的销毁,只能是通过EntityTimeoutComponent超时来触发的销毁,不能通过直接调用Dispose来触发的销毁 + GateUnitHelper.Remove(self.Scene, self.Id, false).Coroutine(); + } +} \ No newline at end of file diff --git a/聊天系统课程代码/Server/Hotfix/Hotfix.csproj b/聊天系统课程代码/Server/Hotfix/Hotfix.csproj new file mode 100644 index 0000000..4f09b61 --- /dev/null +++ b/聊天系统课程代码/Server/Hotfix/Hotfix.csproj @@ -0,0 +1,13 @@ + + + + net8.0 + enable + enable + + + + + + + diff --git a/聊天系统课程代码/Server/Hotfix/Map/G2M_LoginRequestHandler.cs b/聊天系统课程代码/Server/Hotfix/Map/G2M_LoginRequestHandler.cs new file mode 100644 index 0000000..20e1290 --- /dev/null +++ b/聊天系统课程代码/Server/Hotfix/Map/G2M_LoginRequestHandler.cs @@ -0,0 +1,17 @@ +using Fantasy.Async; +using Fantasy.Network.Interface; + +namespace Fantasy.Map; + +public class G2M_LoginRequestHandler : RouteRPC +{ + protected override async FTask Run(Scene scene, G2M_LoginRequest request, M2G_LoginResponse response, Action reply) + { + var chatInfoTree = ChatTreeFactory.Broadcast(scene).AddendTextNode("您杀死了奥格瑞玛!"); + scene.TimerComponent.Net.RepeatedTimer(2000, () => + { + ChatHelper.SendChatMessage(scene, request.ChatUnitRouteId, chatInfoTree); + }); + await FTask.CompletedTask; + } +} \ No newline at end of file diff --git a/聊天系统课程代码/Server/Hotfix/OnSceneCreate_Init.cs b/聊天系统课程代码/Server/Hotfix/OnSceneCreate_Init.cs new file mode 100644 index 0000000..5432e48 --- /dev/null +++ b/聊天系统课程代码/Server/Hotfix/OnSceneCreate_Init.cs @@ -0,0 +1,32 @@ +using Fantasy.Async; +using Fantasy.Event; + +namespace Fantasy; + +public sealed class OnSceneCreate_Init : AsyncEventSystem +{ + protected override async FTask Handler(OnCreateScene self) + { + var scene = self.Scene; + + switch (scene.SceneType) + { + case SceneType.Gate: + { + // GateUnit管理组件。 + scene.AddComponent(); + break; + } + case SceneType.Chat: + { + // 序列化组件。 + scene.AddComponent().Initialize(); + // ChatUnit管理组件。 + scene.AddComponent(); + // 聊天频道中控中心组件。 + scene.AddComponent(); + break; + } + } + } +} \ No newline at end of file diff --git a/聊天系统课程代码/Server/Hotfix/Share/System/EntityTimeoutComponentSystem.cs b/聊天系统课程代码/Server/Hotfix/Share/System/EntityTimeoutComponentSystem.cs new file mode 100644 index 0000000..5b28494 --- /dev/null +++ b/聊天系统课程代码/Server/Hotfix/Share/System/EntityTimeoutComponentSystem.cs @@ -0,0 +1,50 @@ +// ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract + +using Fantasy.Entitas.Interface; + +namespace Fantasy; +public sealed class EntityTimeoutComponentDestroySystem : DestroySystem +{ + protected override void Destroy(EntityTimeoutComponent self) + { + self.CancelTimeout(); + } +} + +public static class EntityTimeoutComponentSystem +{ + // 这个组件会挂载到目标组件上 + // 当这个组件的超时时间到了,会自动销毁这个组件的父亲 + + public static void SetTimeout(this EntityTimeoutComponent self, int time) + { + var selfParent = self.Parent; + if (selfParent == null) + { + Log.Error("EntityTimeoutComponent's parent is null."); + return; + } + + var selfParentRunTimeId = selfParent.RunTimeId; + self.TimerId = self.Scene.TimerComponent.Net.OnceTimer(time, () => + { + if (selfParent.RunTimeId != selfParentRunTimeId) + { + return; + } + + self.TimerId = 0; + selfParent.Dispose(); + }); + } + + public static void CancelTimeout(this EntityTimeoutComponent self) + { + if (self.TimerId == 0) + { + return; + } + + self.Scene.TimerComponent.Net.Remove(ref self.TimerId); + } +} \ No newline at end of file diff --git a/聊天系统课程代码/Server/Hotfix/Share/System/SerializerComponentSystem.cs b/聊天系统课程代码/Server/Hotfix/Share/System/SerializerComponentSystem.cs new file mode 100644 index 0000000..5298280 --- /dev/null +++ b/聊天系统课程代码/Server/Hotfix/Share/System/SerializerComponentSystem.cs @@ -0,0 +1,24 @@ +using Fantasy.Serialize; +#pragma warning disable CS8604 // Possible null reference argument. + +namespace Fantasy; + +public static class SerializerComponentSystem +{ + public static void Initialize(this SerializerComponent self) + { + self.Serialize = SerializerManager.GetSerializer(FantasySerializerType.ProtoBuf); + } + + public static byte[] Serialize(this SerializerComponent self, T @object) + { + using var memoryStreamBuffer = self.BufferPool.RentMemoryStream(MemoryStreamBufferSource.None); + self.Serialize.Serialize(typeof(T), @object, memoryStreamBuffer); + return memoryStreamBuffer.ToArray(); + } + + public static T Deserialize(this SerializerComponent self, byte[] bytes) + { + return self.Serialize.Deserialize(bytes); + } +} \ No newline at end of file diff --git a/聊天系统课程代码/Server/Hotfix/bin/Debug/net8.0/Entity.dll b/聊天系统课程代码/Server/Hotfix/bin/Debug/net8.0/Entity.dll new file mode 100644 index 0000000..79a12c8 Binary files /dev/null and b/聊天系统课程代码/Server/Hotfix/bin/Debug/net8.0/Entity.dll differ diff --git a/聊天系统课程代码/Server/Hotfix/bin/Debug/net8.0/Entity.pdb b/聊天系统课程代码/Server/Hotfix/bin/Debug/net8.0/Entity.pdb new file mode 100644 index 0000000..cd98b44 Binary files /dev/null and b/聊天系统课程代码/Server/Hotfix/bin/Debug/net8.0/Entity.pdb differ diff --git a/聊天系统课程代码/Server/Hotfix/bin/Debug/net8.0/Hotfix.deps.json b/聊天系统课程代码/Server/Hotfix/bin/Debug/net8.0/Hotfix.deps.json new file mode 100644 index 0000000..15e8d87 --- /dev/null +++ b/聊天系统课程代码/Server/Hotfix/bin/Debug/net8.0/Hotfix.deps.json @@ -0,0 +1,324 @@ +{ + "runtimeTarget": { + "name": ".NETCoreApp,Version=v8.0", + "signature": "" + }, + "compilationOptions": {}, + "targets": { + ".NETCoreApp,Version=v8.0": { + "Hotfix/1.0.0": { + "dependencies": { + "Entity": "1.0.0" + }, + "runtime": { + "Hotfix.dll": {} + } + }, + "CommandLineParser/2.9.1": { + "runtime": { + "lib/netstandard2.0/CommandLine.dll": { + "assemblyVersion": "2.9.1.0", + "fileVersion": "2.9.1.0" + } + } + }, + "DnsClient/1.6.1": { + "dependencies": { + "Microsoft.Win32.Registry": "5.0.0" + }, + "runtime": { + "lib/net5.0/DnsClient.dll": { + "assemblyVersion": "1.6.1.0", + "fileVersion": "1.6.1.0" + } + } + }, + "Fantasy-Net/2024.1.17": { + "dependencies": { + "CommandLineParser": "2.9.1", + "MongoDB.Bson": "3.0.0", + "MongoDB.Driver": "3.0.0", + "Newtonsoft.Json": "13.0.3", + "System.IO.Pipelines": "8.0.0", + "protobuf-net": "3.2.45" + }, + "runtime": { + "lib/net8.0/Fantasy-Net.dll": { + "assemblyVersion": "1.0.0.0", + "fileVersion": "1.0.0.0" + } + } + }, + "Microsoft.Extensions.Logging.Abstractions/2.0.0": {}, + "Microsoft.NETCore.Platforms/5.0.0": {}, + "Microsoft.Win32.Registry/5.0.0": { + "dependencies": { + "System.Security.AccessControl": "5.0.0", + "System.Security.Principal.Windows": "5.0.0" + } + }, + "MongoDB.Bson/3.0.0": { + "dependencies": { + "System.Memory": "4.5.5", + "System.Runtime.CompilerServices.Unsafe": "5.0.0" + }, + "runtime": { + "lib/net6.0/MongoDB.Bson.dll": { + "assemblyVersion": "3.0.0.0", + "fileVersion": "3.0.0.0" + } + } + }, + "MongoDB.Driver/3.0.0": { + "dependencies": { + "DnsClient": "1.6.1", + "Microsoft.Extensions.Logging.Abstractions": "2.0.0", + "MongoDB.Bson": "3.0.0", + "SharpCompress": "0.30.1", + "Snappier": "1.0.0", + "System.Buffers": "4.5.1", + "ZstdSharp.Port": "0.7.3" + }, + "runtime": { + "lib/net6.0/MongoDB.Driver.dll": { + "assemblyVersion": "3.0.0.0", + "fileVersion": "3.0.0.0" + } + } + }, + "Newtonsoft.Json/13.0.3": { + "runtime": { + "lib/net6.0/Newtonsoft.Json.dll": { + "assemblyVersion": "13.0.0.0", + "fileVersion": "13.0.3.27908" + } + } + }, + "protobuf-net/3.2.45": { + "dependencies": { + "protobuf-net.Core": "3.2.45" + }, + "runtime": { + "lib/net6.0/protobuf-net.dll": { + "assemblyVersion": "3.0.0.0", + "fileVersion": "3.2.45.36865" + } + } + }, + "protobuf-net.Core/3.2.45": { + "dependencies": { + "System.Collections.Immutable": "7.0.0" + }, + "runtime": { + "lib/net6.0/protobuf-net.Core.dll": { + "assemblyVersion": "3.0.0.0", + "fileVersion": "3.2.45.36865" + } + } + }, + "SharpCompress/0.30.1": { + "runtime": { + "lib/net5.0/SharpCompress.dll": { + "assemblyVersion": "0.30.1.0", + "fileVersion": "0.30.1.0" + } + } + }, + "Snappier/1.0.0": { + "runtime": { + "lib/net5.0/Snappier.dll": { + "assemblyVersion": "1.0.0.0", + "fileVersion": "1.0.0.0" + } + } + }, + "System.Buffers/4.5.1": {}, + "System.Collections.Immutable/7.0.0": {}, + "System.IO.Pipelines/8.0.0": {}, + "System.Memory/4.5.5": {}, + "System.Runtime.CompilerServices.Unsafe/5.0.0": {}, + "System.Security.AccessControl/5.0.0": { + "dependencies": { + "Microsoft.NETCore.Platforms": "5.0.0", + "System.Security.Principal.Windows": "5.0.0" + } + }, + "System.Security.Principal.Windows/5.0.0": {}, + "ZstdSharp.Port/0.7.3": { + "runtime": { + "lib/net7.0/ZstdSharp.dll": { + "assemblyVersion": "0.7.3.0", + "fileVersion": "0.7.3.0" + } + } + }, + "Entity/1.0.0": { + "dependencies": { + "Fantasy-Net": "2024.1.17" + }, + "runtime": { + "Entity.dll": {} + } + } + } + }, + "libraries": { + "Hotfix/1.0.0": { + "type": "project", + "serviceable": false, + "sha512": "" + }, + "CommandLineParser/2.9.1": { + "type": "package", + "serviceable": true, + "sha512": "sha512-OE0sl1/sQ37bjVsPKKtwQlWDgqaxWgtme3xZz7JssWUzg5JpMIyHgCTY9MVMxOg48fJ1AgGT3tgdH5m/kQ5xhA==", + "path": "commandlineparser/2.9.1", + "hashPath": "commandlineparser.2.9.1.nupkg.sha512" + }, + "DnsClient/1.6.1": { + "type": "package", + "serviceable": true, + "sha512": "sha512-4H/f2uYJOZ+YObZjpY9ABrKZI+JNw3uizp6oMzTXwDw6F+2qIPhpRl/1t68O/6e98+vqNiYGu+lswmwdYUy3gg==", + "path": "dnsclient/1.6.1", + "hashPath": "dnsclient.1.6.1.nupkg.sha512" + }, + "Fantasy-Net/2024.1.17": { + "type": "package", + "serviceable": true, + "sha512": "sha512-06mxvByfEvF/ELAiAjaea4aWI5IBbBDyH9sVdPxEOEEtpAbcguaiydUNi2CVBE+ppW+CYsznTXalN0Xk0vAMKQ==", + "path": "fantasy-net/2024.1.17", + "hashPath": "fantasy-net.2024.1.17.nupkg.sha512" + }, + "Microsoft.Extensions.Logging.Abstractions/2.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-6ZCllUYGFukkymSTx3Yr0G/ajRxoNJp7/FqSxSB4fGISST54ifBhgu4Nc0ItGi3i6DqwuNd8SUyObmiC++AO2Q==", + "path": "microsoft.extensions.logging.abstractions/2.0.0", + "hashPath": "microsoft.extensions.logging.abstractions.2.0.0.nupkg.sha512" + }, + "Microsoft.NETCore.Platforms/5.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-VyPlqzH2wavqquTcYpkIIAQ6WdenuKoFN0BdYBbCWsclXacSOHNQn66Gt4z5NBqEYW0FAPm5rlvki9ZiCij5xQ==", + "path": "microsoft.netcore.platforms/5.0.0", + "hashPath": "microsoft.netcore.platforms.5.0.0.nupkg.sha512" + }, + "Microsoft.Win32.Registry/5.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-dDoKi0PnDz31yAyETfRntsLArTlVAVzUzCIvvEDsDsucrl33Dl8pIJG06ePTJTI3tGpeyHS9Cq7Foc/s4EeKcg==", + "path": "microsoft.win32.registry/5.0.0", + "hashPath": "microsoft.win32.registry.5.0.0.nupkg.sha512" + }, + "MongoDB.Bson/3.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-qnPRJ58HXDh7C4oxTf6YB7BJhlCGJIa6TMXhzImw6zk44lrAomQXTB6AtoQ5lNJbkyrgQcT7+smsKFMnXmLXhw==", + "path": "mongodb.bson/3.0.0", + "hashPath": "mongodb.bson.3.0.0.nupkg.sha512" + }, + "MongoDB.Driver/3.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-udcP8rOhyuhLDn3sGVdNUgQSXfKGPaIP4w09XVKf4xdy66YSXinhkIuQSuOeZVHdTFsG2PpUbRx2wyFm7E0EMg==", + "path": "mongodb.driver/3.0.0", + "hashPath": "mongodb.driver.3.0.0.nupkg.sha512" + }, + "Newtonsoft.Json/13.0.3": { + "type": "package", + "serviceable": true, + "sha512": "sha512-HrC5BXdl00IP9zeV+0Z848QWPAoCr9P3bDEZguI+gkLcBKAOxix/tLEAAHC+UvDNPv4a2d18lOReHMOagPa+zQ==", + "path": "newtonsoft.json/13.0.3", + "hashPath": "newtonsoft.json.13.0.3.nupkg.sha512" + }, + "protobuf-net/3.2.45": { + "type": "package", + "serviceable": true, + "sha512": "sha512-5UZ/ukUHcGbFSl7vNMrHsfjqdxusdd9w7w0fCEXzf3UUtsrGNVCzV5SmF+sCHAbnRV2qPcD1ixiDP7Aj8lX/HA==", + "path": "protobuf-net/3.2.45", + "hashPath": "protobuf-net.3.2.45.nupkg.sha512" + }, + "protobuf-net.Core/3.2.45": { + "type": "package", + "serviceable": true, + "sha512": "sha512-PMWatW2NrT1uTXD7etJ4VdQ0wWZLFrIfdRGppD2QX7nzZ0+kIzqhq551u6ZiXJHWJgG4hWFEkSnUnt2aB6posg==", + "path": "protobuf-net.core/3.2.45", + "hashPath": "protobuf-net.core.3.2.45.nupkg.sha512" + }, + "SharpCompress/0.30.1": { + "type": "package", + "serviceable": true, + "sha512": "sha512-XqD4TpfyYGa7QTPzaGlMVbcecKnXy4YmYLDWrU+JIj7IuRNl7DH2END+Ll7ekWIY8o3dAMWLFDE1xdhfIWD1nw==", + "path": "sharpcompress/0.30.1", + "hashPath": "sharpcompress.0.30.1.nupkg.sha512" + }, + "Snappier/1.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-rFtK2KEI9hIe8gtx3a0YDXdHOpedIf9wYCEYtBEmtlyiWVX3XlCNV03JrmmAi/Cdfn7dxK+k0sjjcLv4fpHnqA==", + "path": "snappier/1.0.0", + "hashPath": "snappier.1.0.0.nupkg.sha512" + }, + "System.Buffers/4.5.1": { + "type": "package", + "serviceable": true, + "sha512": "sha512-Rw7ijyl1qqRS0YQD/WycNst8hUUMgrMH4FCn1nNm27M4VxchZ1js3fVjQaANHO5f3sN4isvP4a+Met9Y4YomAg==", + "path": "system.buffers/4.5.1", + "hashPath": "system.buffers.4.5.1.nupkg.sha512" + }, + "System.Collections.Immutable/7.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-dQPcs0U1IKnBdRDBkrCTi1FoajSTBzLcVTpjO4MBCMC7f4pDOIPzgBoX8JjG7X6uZRJ8EBxsi8+DR1JuwjnzOQ==", + "path": "system.collections.immutable/7.0.0", + "hashPath": "system.collections.immutable.7.0.0.nupkg.sha512" + }, + "System.IO.Pipelines/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-FHNOatmUq0sqJOkTx+UF/9YK1f180cnW5FVqnQMvYUN0elp6wFzbtPSiqbo1/ru8ICp43JM1i7kKkk6GsNGHlA==", + "path": "system.io.pipelines/8.0.0", + "hashPath": "system.io.pipelines.8.0.0.nupkg.sha512" + }, + "System.Memory/4.5.5": { + "type": "package", + "serviceable": true, + "sha512": "sha512-XIWiDvKPXaTveaB7HVganDlOCRoj03l+jrwNvcge/t8vhGYKvqV+dMv6G4SAX2NoNmN0wZfVPTAlFwZcZvVOUw==", + "path": "system.memory/4.5.5", + "hashPath": "system.memory.4.5.5.nupkg.sha512" + }, + "System.Runtime.CompilerServices.Unsafe/5.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-ZD9TMpsmYJLrxbbmdvhwt9YEgG5WntEnZ/d1eH8JBX9LBp+Ju8BSBhUGbZMNVHHomWo2KVImJhTDl2hIgw/6MA==", + "path": "system.runtime.compilerservices.unsafe/5.0.0", + "hashPath": "system.runtime.compilerservices.unsafe.5.0.0.nupkg.sha512" + }, + "System.Security.AccessControl/5.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-dagJ1mHZO3Ani8GH0PHpPEe/oYO+rVdbQjvjJkBRNQkX4t0r1iaeGn8+/ybkSLEan3/slM0t59SVdHzuHf2jmw==", + "path": "system.security.accesscontrol/5.0.0", + "hashPath": "system.security.accesscontrol.5.0.0.nupkg.sha512" + }, + "System.Security.Principal.Windows/5.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-t0MGLukB5WAVU9bO3MGzvlGnyJPgUlcwerXn1kzBRjwLKixT96XV0Uza41W49gVd8zEMFu9vQEFlv0IOrytICA==", + "path": "system.security.principal.windows/5.0.0", + "hashPath": "system.security.principal.windows.5.0.0.nupkg.sha512" + }, + "ZstdSharp.Port/0.7.3": { + "type": "package", + "serviceable": true, + "sha512": "sha512-U9Ix4l4cl58Kzz1rJzj5hoVTjmbx1qGMwzAcbv1j/d3NzrFaESIurQyg+ow4mivCgkE3S413y+U9k4WdnEIkRA==", + "path": "zstdsharp.port/0.7.3", + "hashPath": "zstdsharp.port.0.7.3.nupkg.sha512" + }, + "Entity/1.0.0": { + "type": "project", + "serviceable": false, + "sha512": "" + } + } +} \ No newline at end of file diff --git a/聊天系统课程代码/Server/Hotfix/bin/Debug/net8.0/Hotfix.dll b/聊天系统课程代码/Server/Hotfix/bin/Debug/net8.0/Hotfix.dll new file mode 100644 index 0000000..e08f924 Binary files /dev/null and b/聊天系统课程代码/Server/Hotfix/bin/Debug/net8.0/Hotfix.dll differ diff --git a/聊天系统课程代码/Server/Hotfix/bin/Debug/net8.0/Hotfix.pdb b/聊天系统课程代码/Server/Hotfix/bin/Debug/net8.0/Hotfix.pdb new file mode 100644 index 0000000..1a58795 Binary files /dev/null and b/聊天系统课程代码/Server/Hotfix/bin/Debug/net8.0/Hotfix.pdb differ diff --git a/聊天系统课程代码/Server/Hotfix/obj/Debug/net8.0/.NETCoreApp,Version=v8.0.AssemblyAttributes.cs b/聊天系统课程代码/Server/Hotfix/obj/Debug/net8.0/.NETCoreApp,Version=v8.0.AssemblyAttributes.cs new file mode 100644 index 0000000..2217181 --- /dev/null +++ b/聊天系统课程代码/Server/Hotfix/obj/Debug/net8.0/.NETCoreApp,Version=v8.0.AssemblyAttributes.cs @@ -0,0 +1,4 @@ +// +using System; +using System.Reflection; +[assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute(".NETCoreApp,Version=v8.0", FrameworkDisplayName = ".NET 8.0")] diff --git a/聊天系统课程代码/Server/Hotfix/obj/Debug/net8.0/Hotfix.AssemblyInfo.cs b/聊天系统课程代码/Server/Hotfix/obj/Debug/net8.0/Hotfix.AssemblyInfo.cs new file mode 100644 index 0000000..10dae85 --- /dev/null +++ b/聊天系统课程代码/Server/Hotfix/obj/Debug/net8.0/Hotfix.AssemblyInfo.cs @@ -0,0 +1,22 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +using System; +using System.Reflection; + +[assembly: System.Reflection.AssemblyCompanyAttribute("Hotfix")] +[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")] +[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")] +[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0")] +[assembly: System.Reflection.AssemblyProductAttribute("Hotfix")] +[assembly: System.Reflection.AssemblyTitleAttribute("Hotfix")] +[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")] + +// 由 MSBuild WriteCodeFragment 类生成。 + diff --git a/聊天系统课程代码/Server/Hotfix/obj/Debug/net8.0/Hotfix.AssemblyInfoInputs.cache b/聊天系统课程代码/Server/Hotfix/obj/Debug/net8.0/Hotfix.AssemblyInfoInputs.cache new file mode 100644 index 0000000..fba9c22 --- /dev/null +++ b/聊天系统课程代码/Server/Hotfix/obj/Debug/net8.0/Hotfix.AssemblyInfoInputs.cache @@ -0,0 +1 @@ +28c7ffb99846e407a4d90a66ddc760b2a3412294f39e5810dd7ee1d10f0462a6 diff --git a/聊天系统课程代码/Server/Hotfix/obj/Debug/net8.0/Hotfix.GeneratedMSBuildEditorConfig.editorconfig b/聊天系统课程代码/Server/Hotfix/obj/Debug/net8.0/Hotfix.GeneratedMSBuildEditorConfig.editorconfig new file mode 100644 index 0000000..05328b2 --- /dev/null +++ b/聊天系统课程代码/Server/Hotfix/obj/Debug/net8.0/Hotfix.GeneratedMSBuildEditorConfig.editorconfig @@ -0,0 +1,15 @@ +is_global = true +build_property.TargetFramework = net8.0 +build_property.TargetPlatformMinVersion = +build_property.UsingMicrosoftNETSdkWeb = +build_property.ProjectTypeGuids = +build_property.InvariantGlobalization = +build_property.PlatformNeutralAssembly = +build_property.EnforceExtendedAnalyzerRules = +build_property._SupportedPlatformList = Linux,macOS,Windows +build_property.RootNamespace = Hotfix +build_property.ProjectDir = /Users/fantasy/Code/ServerLessions/Chat/Server/Hotfix/ +build_property.EnableComHosting = +build_property.EnableGeneratedComInterfaceComImportInterop = +build_property.EffectiveAnalysisLevelStyle = 8.0 +build_property.EnableCodeStyleSeverity = diff --git a/聊天系统课程代码/Server/Hotfix/obj/Debug/net8.0/Hotfix.GlobalUsings.g.cs b/聊天系统课程代码/Server/Hotfix/obj/Debug/net8.0/Hotfix.GlobalUsings.g.cs new file mode 100644 index 0000000..8578f3d --- /dev/null +++ b/聊天系统课程代码/Server/Hotfix/obj/Debug/net8.0/Hotfix.GlobalUsings.g.cs @@ -0,0 +1,8 @@ +// +global using global::System; +global using global::System.Collections.Generic; +global using global::System.IO; +global using global::System.Linq; +global using global::System.Net.Http; +global using global::System.Threading; +global using global::System.Threading.Tasks; diff --git a/聊天系统课程代码/Server/Hotfix/obj/Debug/net8.0/Hotfix.assets.cache b/聊天系统课程代码/Server/Hotfix/obj/Debug/net8.0/Hotfix.assets.cache new file mode 100644 index 0000000..3ec6046 Binary files /dev/null and b/聊天系统课程代码/Server/Hotfix/obj/Debug/net8.0/Hotfix.assets.cache differ diff --git a/聊天系统课程代码/Server/Hotfix/obj/Debug/net8.0/Hotfix.csproj.AssemblyReference.cache b/聊天系统课程代码/Server/Hotfix/obj/Debug/net8.0/Hotfix.csproj.AssemblyReference.cache new file mode 100644 index 0000000..d5c288b Binary files /dev/null and b/聊天系统课程代码/Server/Hotfix/obj/Debug/net8.0/Hotfix.csproj.AssemblyReference.cache differ diff --git a/聊天系统课程代码/Server/Hotfix/obj/Debug/net8.0/Hotfix.csproj.CopyComplete b/聊天系统课程代码/Server/Hotfix/obj/Debug/net8.0/Hotfix.csproj.CopyComplete new file mode 100644 index 0000000..e69de29 diff --git a/聊天系统课程代码/Server/Hotfix/obj/Debug/net8.0/Hotfix.csproj.CoreCompileInputs.cache b/聊天系统课程代码/Server/Hotfix/obj/Debug/net8.0/Hotfix.csproj.CoreCompileInputs.cache new file mode 100644 index 0000000..8a39757 --- /dev/null +++ b/聊天系统课程代码/Server/Hotfix/obj/Debug/net8.0/Hotfix.csproj.CoreCompileInputs.cache @@ -0,0 +1 @@ +db031dae618f2e362a528e6b2e15efd97c27daebca134f658fc2c17b89aba129 diff --git a/聊天系统课程代码/Server/Hotfix/obj/Debug/net8.0/Hotfix.csproj.FileListAbsolute.txt b/聊天系统课程代码/Server/Hotfix/obj/Debug/net8.0/Hotfix.csproj.FileListAbsolute.txt new file mode 100644 index 0000000..9f51f8f --- /dev/null +++ b/聊天系统课程代码/Server/Hotfix/obj/Debug/net8.0/Hotfix.csproj.FileListAbsolute.txt @@ -0,0 +1,15 @@ +/Users/sining/Code/ServerLessions/Chat/Server/Hotfix/bin/Debug/net8.0/Hotfix.deps.json +/Users/sining/Code/ServerLessions/Chat/Server/Hotfix/bin/Debug/net8.0/Hotfix.dll +/Users/sining/Code/ServerLessions/Chat/Server/Hotfix/bin/Debug/net8.0/Hotfix.pdb +/Users/sining/Code/ServerLessions/Chat/Server/Hotfix/bin/Debug/net8.0/Entity.dll +/Users/sining/Code/ServerLessions/Chat/Server/Hotfix/bin/Debug/net8.0/Entity.pdb +/Users/sining/Code/ServerLessions/Chat/Server/Hotfix/obj/Debug/net8.0/Hotfix.csproj.AssemblyReference.cache +/Users/sining/Code/ServerLessions/Chat/Server/Hotfix/obj/Debug/net8.0/Hotfix.GeneratedMSBuildEditorConfig.editorconfig +/Users/sining/Code/ServerLessions/Chat/Server/Hotfix/obj/Debug/net8.0/Hotfix.AssemblyInfoInputs.cache +/Users/sining/Code/ServerLessions/Chat/Server/Hotfix/obj/Debug/net8.0/Hotfix.AssemblyInfo.cs +/Users/sining/Code/ServerLessions/Chat/Server/Hotfix/obj/Debug/net8.0/Hotfix.csproj.CoreCompileInputs.cache +/Users/sining/Code/ServerLessions/Chat/Server/Hotfix/obj/Debug/net8.0/Hotfix.csproj.CopyComplete +/Users/sining/Code/ServerLessions/Chat/Server/Hotfix/obj/Debug/net8.0/Hotfix.dll +/Users/sining/Code/ServerLessions/Chat/Server/Hotfix/obj/Debug/net8.0/refint/Hotfix.dll +/Users/sining/Code/ServerLessions/Chat/Server/Hotfix/obj/Debug/net8.0/Hotfix.pdb +/Users/sining/Code/ServerLessions/Chat/Server/Hotfix/obj/Debug/net8.0/ref/Hotfix.dll diff --git a/聊天系统课程代码/Server/Hotfix/obj/Debug/net8.0/Hotfix.dll b/聊天系统课程代码/Server/Hotfix/obj/Debug/net8.0/Hotfix.dll new file mode 100644 index 0000000..e08f924 Binary files /dev/null and b/聊天系统课程代码/Server/Hotfix/obj/Debug/net8.0/Hotfix.dll differ diff --git a/聊天系统课程代码/Server/Hotfix/obj/Debug/net8.0/Hotfix.pdb b/聊天系统课程代码/Server/Hotfix/obj/Debug/net8.0/Hotfix.pdb new file mode 100644 index 0000000..1a58795 Binary files /dev/null and b/聊天系统课程代码/Server/Hotfix/obj/Debug/net8.0/Hotfix.pdb differ diff --git a/聊天系统课程代码/Server/Hotfix/obj/Debug/net8.0/ref/Hotfix.dll b/聊天系统课程代码/Server/Hotfix/obj/Debug/net8.0/ref/Hotfix.dll new file mode 100644 index 0000000..d0ae171 Binary files /dev/null and b/聊天系统课程代码/Server/Hotfix/obj/Debug/net8.0/ref/Hotfix.dll differ diff --git a/聊天系统课程代码/Server/Hotfix/obj/Debug/net8.0/refint/Hotfix.dll b/聊天系统课程代码/Server/Hotfix/obj/Debug/net8.0/refint/Hotfix.dll new file mode 100644 index 0000000..d0ae171 Binary files /dev/null and b/聊天系统课程代码/Server/Hotfix/obj/Debug/net8.0/refint/Hotfix.dll differ diff --git a/聊天系统课程代码/Server/Hotfix/obj/Hotfix.csproj.nuget.dgspec.json b/聊天系统课程代码/Server/Hotfix/obj/Hotfix.csproj.nuget.dgspec.json new file mode 100644 index 0000000..f38cbf5 --- /dev/null +++ b/聊天系统课程代码/Server/Hotfix/obj/Hotfix.csproj.nuget.dgspec.json @@ -0,0 +1,136 @@ +{ + "format": 1, + "restore": { + "/Users/fantasy/Code/ServerLessions/Chat/Server/Hotfix/Hotfix.csproj": {} + }, + "projects": { + "/Users/fantasy/Code/ServerLessions/Chat/Server/Entity/Entity.csproj": { + "version": "1.0.0", + "restore": { + "projectUniqueName": "/Users/fantasy/Code/ServerLessions/Chat/Server/Entity/Entity.csproj", + "projectName": "Entity", + "projectPath": "/Users/fantasy/Code/ServerLessions/Chat/Server/Entity/Entity.csproj", + "packagesPath": "/Users/fantasy/.nuget/packages/", + "outputPath": "/Users/fantasy/Code/ServerLessions/Chat/Server/Entity/obj/", + "projectStyle": "PackageReference", + "UsingMicrosoftNETSdk": false, + "configFilePaths": [ + "/Users/fantasy/.nuget/NuGet/NuGet.Config" + ], + "originalTargetFrameworks": [ + "net8.0" + ], + "sources": { + "https://api.nuget.org/v3/index.json": {} + }, + "frameworks": { + "net8.0": { + "targetAlias": "net8.0", + "projectReferences": {} + } + }, + "warningProperties": { + "warnAsError": [ + "NU1605" + ] + }, + "restoreAuditProperties": { + "enableAudit": "true", + "auditLevel": "low", + "auditMode": "all" + } + }, + "frameworks": { + "net8.0": { + "targetAlias": "net8.0", + "dependencies": { + "Fantasy-Net": { + "target": "Package", + "version": "[2024.1.17, )" + } + }, + "imports": [ + "net461", + "net462", + "net47", + "net471", + "net472", + "net48", + "net481" + ], + "assetTargetFallback": true, + "warn": true, + "frameworkReferences": { + "Microsoft.NETCore.App": { + "privateAssets": "all" + } + }, + "runtimeIdentifierGraphPath": "/usr/local/share/dotnet/sdk/9.0.100/PortableRuntimeIdentifierGraph.json" + } + } + }, + "/Users/fantasy/Code/ServerLessions/Chat/Server/Hotfix/Hotfix.csproj": { + "version": "1.0.0", + "restore": { + "projectUniqueName": "/Users/fantasy/Code/ServerLessions/Chat/Server/Hotfix/Hotfix.csproj", + "projectName": "Hotfix", + "projectPath": "/Users/fantasy/Code/ServerLessions/Chat/Server/Hotfix/Hotfix.csproj", + "packagesPath": "/Users/fantasy/.nuget/packages/", + "outputPath": "/Users/fantasy/Code/ServerLessions/Chat/Server/Hotfix/obj/", + "projectStyle": "PackageReference", + "UsingMicrosoftNETSdk": false, + "configFilePaths": [ + "/Users/fantasy/.nuget/NuGet/NuGet.Config" + ], + "originalTargetFrameworks": [ + "net8.0" + ], + "sources": { + "https://api.nuget.org/v3/index.json": {} + }, + "frameworks": { + "net8.0": { + "targetAlias": "net8.0", + "projectReferences": { + "/Users/fantasy/Code/ServerLessions/Chat/Server/Entity/Entity.csproj": { + "projectPath": "/Users/fantasy/Code/ServerLessions/Chat/Server/Entity/Entity.csproj" + } + } + } + }, + "warningProperties": { + "warnAsError": [ + "NU1605" + ] + }, + "restoreAuditProperties": { + "enableAudit": "true", + "auditLevel": "low", + "auditMode": "all" + } + }, + "frameworks": { + "net8.0": { + "targetAlias": "net8.0", + "imports": [ + "net461", + "net462", + "net47", + "net471", + "net472", + "net48", + "net481" + ], + "assetTargetFallback": true, + "warn": true, + "frameworkReferences": { + "Microsoft.NETCore.App": { + "privateAssets": "all" + } + }, + "runtimeIdentifierGraphPath": "/usr/local/share/dotnet/sdk/9.0.100/PortableRuntimeIdentifierGraph.json" + } + } + } + } +} \ No newline at end of file diff --git a/聊天系统课程代码/Server/Hotfix/obj/Hotfix.csproj.nuget.g.props b/聊天系统课程代码/Server/Hotfix/obj/Hotfix.csproj.nuget.g.props new file mode 100644 index 0000000..6515977 --- /dev/null +++ b/聊天系统课程代码/Server/Hotfix/obj/Hotfix.csproj.nuget.g.props @@ -0,0 +1,15 @@ + + + + True + NuGet + $(MSBuildThisFileDirectory)project.assets.json + /Users/fantasy/.nuget/packages/ + /Users/fantasy/.nuget/packages/ + PackageReference + 6.12.0 + + + + + \ No newline at end of file diff --git a/聊天系统课程代码/Server/Hotfix/obj/Hotfix.csproj.nuget.g.targets b/聊天系统课程代码/Server/Hotfix/obj/Hotfix.csproj.nuget.g.targets new file mode 100644 index 0000000..9fc693e --- /dev/null +++ b/聊天系统课程代码/Server/Hotfix/obj/Hotfix.csproj.nuget.g.targets @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/聊天系统课程代码/Server/Hotfix/obj/project.assets.json b/聊天系统课程代码/Server/Hotfix/obj/project.assets.json new file mode 100644 index 0000000..92568c1 --- /dev/null +++ b/聊天系统课程代码/Server/Hotfix/obj/project.assets.json @@ -0,0 +1,965 @@ +{ + "version": 3, + "targets": { + "net8.0": { + "CommandLineParser/2.9.1": { + "type": "package", + "compile": { + "lib/netstandard2.0/CommandLine.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netstandard2.0/CommandLine.dll": { + "related": ".xml" + } + } + }, + "DnsClient/1.6.1": { + "type": "package", + "dependencies": { + "Microsoft.Win32.Registry": "5.0.0" + }, + "compile": { + "lib/net5.0/DnsClient.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net5.0/DnsClient.dll": { + "related": ".xml" + } + } + }, + "Fantasy-Net/2024.1.17": { + "type": "package", + "dependencies": { + "CommandLineParser": "2.9.1", + "MongoDB.Bson": "3.0.0", + "MongoDB.Driver": "3.0.0", + "Newtonsoft.Json": "13.0.3", + "System.IO.Pipelines": "8.0.0", + "protobuf-net": "3.2.45" + }, + "compile": { + "lib/net8.0/Fantasy-Net.dll": {} + }, + "runtime": { + "lib/net8.0/Fantasy-Net.dll": {} + }, + "frameworkReferences": [ + "Microsoft.AspNetCore.App" + ], + "build": { + "buildTransitive/Fantasy-Net.targets": {} + } + }, + "Microsoft.Extensions.Logging.Abstractions/2.0.0": { + "type": "package", + "compile": { + "lib/netstandard2.0/Microsoft.Extensions.Logging.Abstractions.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netstandard2.0/Microsoft.Extensions.Logging.Abstractions.dll": { + "related": ".xml" + } + } + }, + "Microsoft.NETCore.Platforms/5.0.0": { + "type": "package", + "compile": { + "lib/netstandard1.0/_._": {} + }, + "runtime": { + "lib/netstandard1.0/_._": {} + } + }, + "Microsoft.Win32.Registry/5.0.0": { + "type": "package", + "dependencies": { + "System.Security.AccessControl": "5.0.0", + "System.Security.Principal.Windows": "5.0.0" + }, + "compile": { + "ref/netstandard2.0/Microsoft.Win32.Registry.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netstandard2.0/Microsoft.Win32.Registry.dll": { + "related": ".xml" + } + }, + "runtimeTargets": { + "runtimes/win/lib/netstandard2.0/Microsoft.Win32.Registry.dll": { + "assetType": "runtime", + "rid": "win" + } + } + }, + "MongoDB.Bson/3.0.0": { + "type": "package", + "dependencies": { + "System.Memory": "4.5.5", + "System.Runtime.CompilerServices.Unsafe": "5.0.0" + }, + "compile": { + "lib/net6.0/MongoDB.Bson.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net6.0/MongoDB.Bson.dll": { + "related": ".xml" + } + } + }, + "MongoDB.Driver/3.0.0": { + "type": "package", + "dependencies": { + "DnsClient": "1.6.1", + "Microsoft.Extensions.Logging.Abstractions": "2.0.0", + "MongoDB.Bson": "3.0.0", + "SharpCompress": "0.30.1", + "Snappier": "1.0.0", + "System.Buffers": "4.5.1", + "ZstdSharp.Port": "0.7.3" + }, + "compile": { + "lib/net6.0/MongoDB.Driver.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net6.0/MongoDB.Driver.dll": { + "related": ".xml" + } + } + }, + "Newtonsoft.Json/13.0.3": { + "type": "package", + "compile": { + "lib/net6.0/Newtonsoft.Json.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net6.0/Newtonsoft.Json.dll": { + "related": ".xml" + } + } + }, + "protobuf-net/3.2.45": { + "type": "package", + "dependencies": { + "protobuf-net.Core": "3.2.45" + }, + "compile": { + "lib/net6.0/protobuf-net.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net6.0/protobuf-net.dll": { + "related": ".xml" + } + } + }, + "protobuf-net.Core/3.2.45": { + "type": "package", + "dependencies": { + "System.Collections.Immutable": "7.0.0" + }, + "compile": { + "lib/net6.0/protobuf-net.Core.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net6.0/protobuf-net.Core.dll": { + "related": ".xml" + } + } + }, + "SharpCompress/0.30.1": { + "type": "package", + "compile": { + "lib/net5.0/SharpCompress.dll": {} + }, + "runtime": { + "lib/net5.0/SharpCompress.dll": {} + } + }, + "Snappier/1.0.0": { + "type": "package", + "compile": { + "lib/net5.0/Snappier.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net5.0/Snappier.dll": { + "related": ".xml" + } + } + }, + "System.Buffers/4.5.1": { + "type": "package", + "compile": { + "ref/netcoreapp2.0/_._": {} + }, + "runtime": { + "lib/netcoreapp2.0/_._": {} + } + }, + "System.Collections.Immutable/7.0.0": { + "type": "package", + "compile": { + "lib/net7.0/System.Collections.Immutable.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net7.0/System.Collections.Immutable.dll": { + "related": ".xml" + } + }, + "build": { + "buildTransitive/net6.0/_._": {} + } + }, + "System.IO.Pipelines/8.0.0": { + "type": "package", + "compile": { + "lib/net8.0/System.IO.Pipelines.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net8.0/System.IO.Pipelines.dll": { + "related": ".xml" + } + }, + "build": { + "buildTransitive/net6.0/_._": {} + } + }, + "System.Memory/4.5.5": { + "type": "package", + "compile": { + "ref/netcoreapp2.1/_._": {} + }, + "runtime": { + "lib/netcoreapp2.1/_._": {} + } + }, + "System.Runtime.CompilerServices.Unsafe/5.0.0": { + "type": "package", + "compile": { + "ref/netstandard2.1/System.Runtime.CompilerServices.Unsafe.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netcoreapp2.0/System.Runtime.CompilerServices.Unsafe.dll": { + "related": ".xml" + } + } + }, + "System.Security.AccessControl/5.0.0": { + "type": "package", + "dependencies": { + "Microsoft.NETCore.Platforms": "5.0.0", + "System.Security.Principal.Windows": "5.0.0" + }, + "compile": { + "ref/netstandard2.0/System.Security.AccessControl.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netstandard2.0/System.Security.AccessControl.dll": { + "related": ".xml" + } + }, + "runtimeTargets": { + "runtimes/win/lib/netcoreapp2.0/System.Security.AccessControl.dll": { + "assetType": "runtime", + "rid": "win" + } + } + }, + "System.Security.Principal.Windows/5.0.0": { + "type": "package", + "compile": { + "ref/netcoreapp3.0/System.Security.Principal.Windows.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netstandard2.0/System.Security.Principal.Windows.dll": { + "related": ".xml" + } + }, + "runtimeTargets": { + "runtimes/unix/lib/netcoreapp2.1/System.Security.Principal.Windows.dll": { + "assetType": "runtime", + "rid": "unix" + }, + "runtimes/win/lib/netcoreapp2.1/System.Security.Principal.Windows.dll": { + "assetType": "runtime", + "rid": "win" + } + } + }, + "ZstdSharp.Port/0.7.3": { + "type": "package", + "compile": { + "lib/net7.0/ZstdSharp.dll": {} + }, + "runtime": { + "lib/net7.0/ZstdSharp.dll": {} + } + }, + "Entity/1.0.0": { + "type": "project", + "framework": ".NETCoreApp,Version=v8.0", + "dependencies": { + "Fantasy-Net": "2024.1.17" + }, + "compile": { + "bin/placeholder/Entity.dll": {} + }, + "runtime": { + "bin/placeholder/Entity.dll": {} + } + } + } + }, + "libraries": { + "CommandLineParser/2.9.1": { + "sha512": "OE0sl1/sQ37bjVsPKKtwQlWDgqaxWgtme3xZz7JssWUzg5JpMIyHgCTY9MVMxOg48fJ1AgGT3tgdH5m/kQ5xhA==", + "type": "package", + "path": "commandlineparser/2.9.1", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "CommandLine20.png", + "License.md", + "README.md", + "commandlineparser.2.9.1.nupkg.sha512", + "commandlineparser.nuspec", + "lib/net40/CommandLine.dll", + "lib/net40/CommandLine.xml", + "lib/net45/CommandLine.dll", + "lib/net45/CommandLine.xml", + "lib/net461/CommandLine.dll", + "lib/net461/CommandLine.xml", + "lib/netstandard2.0/CommandLine.dll", + "lib/netstandard2.0/CommandLine.xml" + ] + }, + "DnsClient/1.6.1": { + "sha512": "4H/f2uYJOZ+YObZjpY9ABrKZI+JNw3uizp6oMzTXwDw6F+2qIPhpRl/1t68O/6e98+vqNiYGu+lswmwdYUy3gg==", + "type": "package", + "path": "dnsclient/1.6.1", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "dnsclient.1.6.1.nupkg.sha512", + "dnsclient.nuspec", + "icon.png", + "lib/net45/DnsClient.dll", + "lib/net45/DnsClient.xml", + "lib/net471/DnsClient.dll", + "lib/net471/DnsClient.xml", + "lib/net5.0/DnsClient.dll", + "lib/net5.0/DnsClient.xml", + "lib/netstandard1.3/DnsClient.dll", + "lib/netstandard1.3/DnsClient.xml", + "lib/netstandard2.0/DnsClient.dll", + "lib/netstandard2.0/DnsClient.xml", + "lib/netstandard2.1/DnsClient.dll", + "lib/netstandard2.1/DnsClient.xml" + ] + }, + "Fantasy-Net/2024.1.17": { + "sha512": "06mxvByfEvF/ELAiAjaea4aWI5IBbBDyH9sVdPxEOEEtpAbcguaiydUNi2CVBE+ppW+CYsznTXalN0Xk0vAMKQ==", + "type": "package", + "path": "fantasy-net/2024.1.17", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "LICENSE", + "README.md", + "buildTransitive/Fantasy-Net.targets", + "fantasy-net.2024.1.17.nupkg.sha512", + "fantasy-net.nuspec", + "icon.png", + "lib/net8.0/Fantasy-Net.dll" + ] + }, + "Microsoft.Extensions.Logging.Abstractions/2.0.0": { + "sha512": "6ZCllUYGFukkymSTx3Yr0G/ajRxoNJp7/FqSxSB4fGISST54ifBhgu4Nc0ItGi3i6DqwuNd8SUyObmiC++AO2Q==", + "type": "package", + "path": "microsoft.extensions.logging.abstractions/2.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "lib/netstandard2.0/Microsoft.Extensions.Logging.Abstractions.dll", + "lib/netstandard2.0/Microsoft.Extensions.Logging.Abstractions.xml", + "microsoft.extensions.logging.abstractions.2.0.0.nupkg.sha512", + "microsoft.extensions.logging.abstractions.nuspec" + ] + }, + "Microsoft.NETCore.Platforms/5.0.0": { + "sha512": "VyPlqzH2wavqquTcYpkIIAQ6WdenuKoFN0BdYBbCWsclXacSOHNQn66Gt4z5NBqEYW0FAPm5rlvki9ZiCij5xQ==", + "type": "package", + "path": "microsoft.netcore.platforms/5.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "LICENSE.TXT", + "THIRD-PARTY-NOTICES.TXT", + "lib/netstandard1.0/_._", + "microsoft.netcore.platforms.5.0.0.nupkg.sha512", + "microsoft.netcore.platforms.nuspec", + "runtime.json", + "useSharedDesignerContext.txt", + "version.txt" + ] + }, + "Microsoft.Win32.Registry/5.0.0": { + "sha512": "dDoKi0PnDz31yAyETfRntsLArTlVAVzUzCIvvEDsDsucrl33Dl8pIJG06ePTJTI3tGpeyHS9Cq7Foc/s4EeKcg==", + "type": "package", + "path": "microsoft.win32.registry/5.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "LICENSE.TXT", + "THIRD-PARTY-NOTICES.TXT", + "lib/net46/Microsoft.Win32.Registry.dll", + "lib/net461/Microsoft.Win32.Registry.dll", + "lib/net461/Microsoft.Win32.Registry.xml", + "lib/netstandard1.3/Microsoft.Win32.Registry.dll", + "lib/netstandard2.0/Microsoft.Win32.Registry.dll", + "lib/netstandard2.0/Microsoft.Win32.Registry.xml", + "microsoft.win32.registry.5.0.0.nupkg.sha512", + "microsoft.win32.registry.nuspec", + "ref/net46/Microsoft.Win32.Registry.dll", + "ref/net461/Microsoft.Win32.Registry.dll", + "ref/net461/Microsoft.Win32.Registry.xml", + "ref/netstandard1.3/Microsoft.Win32.Registry.dll", + "ref/netstandard1.3/Microsoft.Win32.Registry.xml", + "ref/netstandard1.3/de/Microsoft.Win32.Registry.xml", + "ref/netstandard1.3/es/Microsoft.Win32.Registry.xml", + "ref/netstandard1.3/fr/Microsoft.Win32.Registry.xml", + "ref/netstandard1.3/it/Microsoft.Win32.Registry.xml", + "ref/netstandard1.3/ja/Microsoft.Win32.Registry.xml", + "ref/netstandard1.3/ko/Microsoft.Win32.Registry.xml", + "ref/netstandard1.3/ru/Microsoft.Win32.Registry.xml", + "ref/netstandard1.3/zh-hans/Microsoft.Win32.Registry.xml", + "ref/netstandard1.3/zh-hant/Microsoft.Win32.Registry.xml", + "ref/netstandard2.0/Microsoft.Win32.Registry.dll", + "ref/netstandard2.0/Microsoft.Win32.Registry.xml", + "runtimes/win/lib/net46/Microsoft.Win32.Registry.dll", + "runtimes/win/lib/net461/Microsoft.Win32.Registry.dll", + "runtimes/win/lib/net461/Microsoft.Win32.Registry.xml", + "runtimes/win/lib/netstandard1.3/Microsoft.Win32.Registry.dll", + "runtimes/win/lib/netstandard2.0/Microsoft.Win32.Registry.dll", + "runtimes/win/lib/netstandard2.0/Microsoft.Win32.Registry.xml", + "useSharedDesignerContext.txt", + "version.txt" + ] + }, + "MongoDB.Bson/3.0.0": { + "sha512": "qnPRJ58HXDh7C4oxTf6YB7BJhlCGJIa6TMXhzImw6zk44lrAomQXTB6AtoQ5lNJbkyrgQcT7+smsKFMnXmLXhw==", + "type": "package", + "path": "mongodb.bson/3.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "README.md", + "lib/net472/MongoDB.Bson.dll", + "lib/net472/MongoDB.Bson.xml", + "lib/net6.0/MongoDB.Bson.dll", + "lib/net6.0/MongoDB.Bson.xml", + "lib/netstandard2.1/MongoDB.Bson.dll", + "lib/netstandard2.1/MongoDB.Bson.xml", + "mongodb.bson.3.0.0.nupkg.sha512", + "mongodb.bson.nuspec", + "packageIcon.png" + ] + }, + "MongoDB.Driver/3.0.0": { + "sha512": "udcP8rOhyuhLDn3sGVdNUgQSXfKGPaIP4w09XVKf4xdy66YSXinhkIuQSuOeZVHdTFsG2PpUbRx2wyFm7E0EMg==", + "type": "package", + "path": "mongodb.driver/3.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "README.md", + "lib/net472/MongoDB.Driver.dll", + "lib/net472/MongoDB.Driver.xml", + "lib/net6.0/MongoDB.Driver.dll", + "lib/net6.0/MongoDB.Driver.xml", + "lib/netstandard2.1/MongoDB.Driver.dll", + "lib/netstandard2.1/MongoDB.Driver.xml", + "mongodb.driver.3.0.0.nupkg.sha512", + "mongodb.driver.nuspec", + "packageIcon.png" + ] + }, + "Newtonsoft.Json/13.0.3": { + "sha512": "HrC5BXdl00IP9zeV+0Z848QWPAoCr9P3bDEZguI+gkLcBKAOxix/tLEAAHC+UvDNPv4a2d18lOReHMOagPa+zQ==", + "type": "package", + "path": "newtonsoft.json/13.0.3", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "LICENSE.md", + "README.md", + "lib/net20/Newtonsoft.Json.dll", + "lib/net20/Newtonsoft.Json.xml", + "lib/net35/Newtonsoft.Json.dll", + "lib/net35/Newtonsoft.Json.xml", + "lib/net40/Newtonsoft.Json.dll", + "lib/net40/Newtonsoft.Json.xml", + "lib/net45/Newtonsoft.Json.dll", + "lib/net45/Newtonsoft.Json.xml", + "lib/net6.0/Newtonsoft.Json.dll", + "lib/net6.0/Newtonsoft.Json.xml", + "lib/netstandard1.0/Newtonsoft.Json.dll", + "lib/netstandard1.0/Newtonsoft.Json.xml", + "lib/netstandard1.3/Newtonsoft.Json.dll", + "lib/netstandard1.3/Newtonsoft.Json.xml", + "lib/netstandard2.0/Newtonsoft.Json.dll", + "lib/netstandard2.0/Newtonsoft.Json.xml", + "newtonsoft.json.13.0.3.nupkg.sha512", + "newtonsoft.json.nuspec", + "packageIcon.png" + ] + }, + "protobuf-net/3.2.45": { + "sha512": "5UZ/ukUHcGbFSl7vNMrHsfjqdxusdd9w7w0fCEXzf3UUtsrGNVCzV5SmF+sCHAbnRV2qPcD1ixiDP7Aj8lX/HA==", + "type": "package", + "path": "protobuf-net/3.2.45", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "lib/net462/protobuf-net.dll", + "lib/net462/protobuf-net.xml", + "lib/net6.0/protobuf-net.dll", + "lib/net6.0/protobuf-net.xml", + "lib/netstandard2.0/protobuf-net.dll", + "lib/netstandard2.0/protobuf-net.xml", + "lib/netstandard2.1/protobuf-net.dll", + "lib/netstandard2.1/protobuf-net.xml", + "protobuf-net.3.2.45.nupkg.sha512", + "protobuf-net.nuspec", + "protobuf-net.png", + "readme.md" + ] + }, + "protobuf-net.Core/3.2.45": { + "sha512": "PMWatW2NrT1uTXD7etJ4VdQ0wWZLFrIfdRGppD2QX7nzZ0+kIzqhq551u6ZiXJHWJgG4hWFEkSnUnt2aB6posg==", + "type": "package", + "path": "protobuf-net.core/3.2.45", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "lib/net462/protobuf-net.Core.dll", + "lib/net462/protobuf-net.Core.xml", + "lib/net6.0/protobuf-net.Core.dll", + "lib/net6.0/protobuf-net.Core.xml", + "lib/netstandard2.0/protobuf-net.Core.dll", + "lib/netstandard2.0/protobuf-net.Core.xml", + "lib/netstandard2.1/protobuf-net.Core.dll", + "lib/netstandard2.1/protobuf-net.Core.xml", + "protobuf-net.core.3.2.45.nupkg.sha512", + "protobuf-net.core.nuspec", + "protobuf-net.png", + "readme.md" + ] + }, + "SharpCompress/0.30.1": { + "sha512": "XqD4TpfyYGa7QTPzaGlMVbcecKnXy4YmYLDWrU+JIj7IuRNl7DH2END+Ll7ekWIY8o3dAMWLFDE1xdhfIWD1nw==", + "type": "package", + "path": "sharpcompress/0.30.1", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "lib/net461/SharpCompress.dll", + "lib/net5.0/SharpCompress.dll", + "lib/netcoreapp3.1/SharpCompress.dll", + "lib/netstandard2.0/SharpCompress.dll", + "lib/netstandard2.1/SharpCompress.dll", + "sharpcompress.0.30.1.nupkg.sha512", + "sharpcompress.nuspec" + ] + }, + "Snappier/1.0.0": { + "sha512": "rFtK2KEI9hIe8gtx3a0YDXdHOpedIf9wYCEYtBEmtlyiWVX3XlCNV03JrmmAi/Cdfn7dxK+k0sjjcLv4fpHnqA==", + "type": "package", + "path": "snappier/1.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "COPYING.txt", + "lib/net5.0/Snappier.dll", + "lib/net5.0/Snappier.xml", + "lib/netcoreapp3.0/Snappier.dll", + "lib/netcoreapp3.0/Snappier.xml", + "lib/netstandard2.0/Snappier.dll", + "lib/netstandard2.0/Snappier.xml", + "lib/netstandard2.1/Snappier.dll", + "lib/netstandard2.1/Snappier.xml", + "snappier.1.0.0.nupkg.sha512", + "snappier.nuspec" + ] + }, + "System.Buffers/4.5.1": { + "sha512": "Rw7ijyl1qqRS0YQD/WycNst8hUUMgrMH4FCn1nNm27M4VxchZ1js3fVjQaANHO5f3sN4isvP4a+Met9Y4YomAg==", + "type": "package", + "path": "system.buffers/4.5.1", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "LICENSE.TXT", + "THIRD-PARTY-NOTICES.TXT", + "lib/net461/System.Buffers.dll", + "lib/net461/System.Buffers.xml", + "lib/netcoreapp2.0/_._", + "lib/netstandard1.1/System.Buffers.dll", + "lib/netstandard1.1/System.Buffers.xml", + "lib/netstandard2.0/System.Buffers.dll", + "lib/netstandard2.0/System.Buffers.xml", + "lib/uap10.0.16299/_._", + "ref/net45/System.Buffers.dll", + "ref/net45/System.Buffers.xml", + "ref/netcoreapp2.0/_._", + "ref/netstandard1.1/System.Buffers.dll", + "ref/netstandard1.1/System.Buffers.xml", + "ref/netstandard2.0/System.Buffers.dll", + "ref/netstandard2.0/System.Buffers.xml", + "ref/uap10.0.16299/_._", + "system.buffers.4.5.1.nupkg.sha512", + "system.buffers.nuspec", + "useSharedDesignerContext.txt", + "version.txt" + ] + }, + "System.Collections.Immutable/7.0.0": { + "sha512": "dQPcs0U1IKnBdRDBkrCTi1FoajSTBzLcVTpjO4MBCMC7f4pDOIPzgBoX8JjG7X6uZRJ8EBxsi8+DR1JuwjnzOQ==", + "type": "package", + "path": "system.collections.immutable/7.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "LICENSE.TXT", + "README.md", + "THIRD-PARTY-NOTICES.TXT", + "buildTransitive/net461/System.Collections.Immutable.targets", + "buildTransitive/net462/_._", + "buildTransitive/net6.0/_._", + "buildTransitive/netcoreapp2.0/System.Collections.Immutable.targets", + "lib/net462/System.Collections.Immutable.dll", + "lib/net462/System.Collections.Immutable.xml", + "lib/net6.0/System.Collections.Immutable.dll", + "lib/net6.0/System.Collections.Immutable.xml", + "lib/net7.0/System.Collections.Immutable.dll", + "lib/net7.0/System.Collections.Immutable.xml", + "lib/netstandard2.0/System.Collections.Immutable.dll", + "lib/netstandard2.0/System.Collections.Immutable.xml", + "system.collections.immutable.7.0.0.nupkg.sha512", + "system.collections.immutable.nuspec", + "useSharedDesignerContext.txt" + ] + }, + "System.IO.Pipelines/8.0.0": { + "sha512": "FHNOatmUq0sqJOkTx+UF/9YK1f180cnW5FVqnQMvYUN0elp6wFzbtPSiqbo1/ru8ICp43JM1i7kKkk6GsNGHlA==", + "type": "package", + "path": "system.io.pipelines/8.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "LICENSE.TXT", + "THIRD-PARTY-NOTICES.TXT", + "buildTransitive/net461/System.IO.Pipelines.targets", + "buildTransitive/net462/_._", + "buildTransitive/net6.0/_._", + "buildTransitive/netcoreapp2.0/System.IO.Pipelines.targets", + "lib/net462/System.IO.Pipelines.dll", + "lib/net462/System.IO.Pipelines.xml", + "lib/net6.0/System.IO.Pipelines.dll", + "lib/net6.0/System.IO.Pipelines.xml", + "lib/net7.0/System.IO.Pipelines.dll", + "lib/net7.0/System.IO.Pipelines.xml", + "lib/net8.0/System.IO.Pipelines.dll", + "lib/net8.0/System.IO.Pipelines.xml", + "lib/netstandard2.0/System.IO.Pipelines.dll", + "lib/netstandard2.0/System.IO.Pipelines.xml", + "system.io.pipelines.8.0.0.nupkg.sha512", + "system.io.pipelines.nuspec", + "useSharedDesignerContext.txt" + ] + }, + "System.Memory/4.5.5": { + "sha512": "XIWiDvKPXaTveaB7HVganDlOCRoj03l+jrwNvcge/t8vhGYKvqV+dMv6G4SAX2NoNmN0wZfVPTAlFwZcZvVOUw==", + "type": "package", + "path": "system.memory/4.5.5", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "LICENSE.TXT", + "THIRD-PARTY-NOTICES.TXT", + "lib/net461/System.Memory.dll", + "lib/net461/System.Memory.xml", + "lib/netcoreapp2.1/_._", + "lib/netstandard1.1/System.Memory.dll", + "lib/netstandard1.1/System.Memory.xml", + "lib/netstandard2.0/System.Memory.dll", + "lib/netstandard2.0/System.Memory.xml", + "ref/netcoreapp2.1/_._", + "system.memory.4.5.5.nupkg.sha512", + "system.memory.nuspec", + "useSharedDesignerContext.txt", + "version.txt" + ] + }, + "System.Runtime.CompilerServices.Unsafe/5.0.0": { + "sha512": "ZD9TMpsmYJLrxbbmdvhwt9YEgG5WntEnZ/d1eH8JBX9LBp+Ju8BSBhUGbZMNVHHomWo2KVImJhTDl2hIgw/6MA==", + "type": "package", + "path": "system.runtime.compilerservices.unsafe/5.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "LICENSE.TXT", + "THIRD-PARTY-NOTICES.TXT", + "lib/net45/System.Runtime.CompilerServices.Unsafe.dll", + "lib/net45/System.Runtime.CompilerServices.Unsafe.xml", + "lib/netcoreapp2.0/System.Runtime.CompilerServices.Unsafe.dll", + "lib/netcoreapp2.0/System.Runtime.CompilerServices.Unsafe.xml", + "lib/netstandard1.0/System.Runtime.CompilerServices.Unsafe.dll", + "lib/netstandard1.0/System.Runtime.CompilerServices.Unsafe.xml", + "lib/netstandard2.0/System.Runtime.CompilerServices.Unsafe.dll", + "lib/netstandard2.0/System.Runtime.CompilerServices.Unsafe.xml", + "ref/net461/System.Runtime.CompilerServices.Unsafe.dll", + "ref/net461/System.Runtime.CompilerServices.Unsafe.xml", + "ref/netstandard1.0/System.Runtime.CompilerServices.Unsafe.dll", + "ref/netstandard1.0/System.Runtime.CompilerServices.Unsafe.xml", + "ref/netstandard2.0/System.Runtime.CompilerServices.Unsafe.dll", + "ref/netstandard2.0/System.Runtime.CompilerServices.Unsafe.xml", + "ref/netstandard2.1/System.Runtime.CompilerServices.Unsafe.dll", + "ref/netstandard2.1/System.Runtime.CompilerServices.Unsafe.xml", + "system.runtime.compilerservices.unsafe.5.0.0.nupkg.sha512", + "system.runtime.compilerservices.unsafe.nuspec", + "useSharedDesignerContext.txt", + "version.txt" + ] + }, + "System.Security.AccessControl/5.0.0": { + "sha512": "dagJ1mHZO3Ani8GH0PHpPEe/oYO+rVdbQjvjJkBRNQkX4t0r1iaeGn8+/ybkSLEan3/slM0t59SVdHzuHf2jmw==", + "type": "package", + "path": "system.security.accesscontrol/5.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "LICENSE.TXT", + "THIRD-PARTY-NOTICES.TXT", + "lib/net46/System.Security.AccessControl.dll", + "lib/net461/System.Security.AccessControl.dll", + "lib/net461/System.Security.AccessControl.xml", + "lib/netstandard1.3/System.Security.AccessControl.dll", + "lib/netstandard2.0/System.Security.AccessControl.dll", + "lib/netstandard2.0/System.Security.AccessControl.xml", + "lib/uap10.0.16299/_._", + "ref/net46/System.Security.AccessControl.dll", + "ref/net461/System.Security.AccessControl.dll", + "ref/net461/System.Security.AccessControl.xml", + "ref/netstandard1.3/System.Security.AccessControl.dll", + "ref/netstandard1.3/System.Security.AccessControl.xml", + "ref/netstandard1.3/de/System.Security.AccessControl.xml", + "ref/netstandard1.3/es/System.Security.AccessControl.xml", + "ref/netstandard1.3/fr/System.Security.AccessControl.xml", + "ref/netstandard1.3/it/System.Security.AccessControl.xml", + "ref/netstandard1.3/ja/System.Security.AccessControl.xml", + "ref/netstandard1.3/ko/System.Security.AccessControl.xml", + "ref/netstandard1.3/ru/System.Security.AccessControl.xml", + "ref/netstandard1.3/zh-hans/System.Security.AccessControl.xml", + "ref/netstandard1.3/zh-hant/System.Security.AccessControl.xml", + "ref/netstandard2.0/System.Security.AccessControl.dll", + "ref/netstandard2.0/System.Security.AccessControl.xml", + "ref/uap10.0.16299/_._", + "runtimes/win/lib/net46/System.Security.AccessControl.dll", + "runtimes/win/lib/net461/System.Security.AccessControl.dll", + "runtimes/win/lib/net461/System.Security.AccessControl.xml", + "runtimes/win/lib/netcoreapp2.0/System.Security.AccessControl.dll", + "runtimes/win/lib/netcoreapp2.0/System.Security.AccessControl.xml", + "runtimes/win/lib/netstandard1.3/System.Security.AccessControl.dll", + "runtimes/win/lib/uap10.0.16299/_._", + "system.security.accesscontrol.5.0.0.nupkg.sha512", + "system.security.accesscontrol.nuspec", + "useSharedDesignerContext.txt", + "version.txt" + ] + }, + "System.Security.Principal.Windows/5.0.0": { + "sha512": "t0MGLukB5WAVU9bO3MGzvlGnyJPgUlcwerXn1kzBRjwLKixT96XV0Uza41W49gVd8zEMFu9vQEFlv0IOrytICA==", + "type": "package", + "path": "system.security.principal.windows/5.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "LICENSE.TXT", + "THIRD-PARTY-NOTICES.TXT", + "lib/net46/System.Security.Principal.Windows.dll", + "lib/net461/System.Security.Principal.Windows.dll", + "lib/net461/System.Security.Principal.Windows.xml", + "lib/netstandard1.3/System.Security.Principal.Windows.dll", + "lib/netstandard2.0/System.Security.Principal.Windows.dll", + "lib/netstandard2.0/System.Security.Principal.Windows.xml", + "lib/uap10.0.16299/_._", + "ref/net46/System.Security.Principal.Windows.dll", + "ref/net461/System.Security.Principal.Windows.dll", + "ref/net461/System.Security.Principal.Windows.xml", + "ref/netcoreapp3.0/System.Security.Principal.Windows.dll", + "ref/netcoreapp3.0/System.Security.Principal.Windows.xml", + "ref/netstandard1.3/System.Security.Principal.Windows.dll", + "ref/netstandard1.3/System.Security.Principal.Windows.xml", + "ref/netstandard1.3/de/System.Security.Principal.Windows.xml", + "ref/netstandard1.3/es/System.Security.Principal.Windows.xml", + "ref/netstandard1.3/fr/System.Security.Principal.Windows.xml", + "ref/netstandard1.3/it/System.Security.Principal.Windows.xml", + "ref/netstandard1.3/ja/System.Security.Principal.Windows.xml", + "ref/netstandard1.3/ko/System.Security.Principal.Windows.xml", + "ref/netstandard1.3/ru/System.Security.Principal.Windows.xml", + "ref/netstandard1.3/zh-hans/System.Security.Principal.Windows.xml", + "ref/netstandard1.3/zh-hant/System.Security.Principal.Windows.xml", + "ref/netstandard2.0/System.Security.Principal.Windows.dll", + "ref/netstandard2.0/System.Security.Principal.Windows.xml", + "ref/uap10.0.16299/_._", + "runtimes/unix/lib/netcoreapp2.0/System.Security.Principal.Windows.dll", + "runtimes/unix/lib/netcoreapp2.0/System.Security.Principal.Windows.xml", + "runtimes/unix/lib/netcoreapp2.1/System.Security.Principal.Windows.dll", + "runtimes/unix/lib/netcoreapp2.1/System.Security.Principal.Windows.xml", + "runtimes/win/lib/net46/System.Security.Principal.Windows.dll", + "runtimes/win/lib/net461/System.Security.Principal.Windows.dll", + "runtimes/win/lib/net461/System.Security.Principal.Windows.xml", + "runtimes/win/lib/netcoreapp2.0/System.Security.Principal.Windows.dll", + "runtimes/win/lib/netcoreapp2.0/System.Security.Principal.Windows.xml", + "runtimes/win/lib/netcoreapp2.1/System.Security.Principal.Windows.dll", + "runtimes/win/lib/netcoreapp2.1/System.Security.Principal.Windows.xml", + "runtimes/win/lib/netstandard1.3/System.Security.Principal.Windows.dll", + "runtimes/win/lib/uap10.0.16299/_._", + "system.security.principal.windows.5.0.0.nupkg.sha512", + "system.security.principal.windows.nuspec", + "useSharedDesignerContext.txt", + "version.txt" + ] + }, + "ZstdSharp.Port/0.7.3": { + "sha512": "U9Ix4l4cl58Kzz1rJzj5hoVTjmbx1qGMwzAcbv1j/d3NzrFaESIurQyg+ow4mivCgkE3S413y+U9k4WdnEIkRA==", + "type": "package", + "path": "zstdsharp.port/0.7.3", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "lib/net461/ZstdSharp.dll", + "lib/net5.0/ZstdSharp.dll", + "lib/net6.0/ZstdSharp.dll", + "lib/net7.0/ZstdSharp.dll", + "lib/netcoreapp3.1/ZstdSharp.dll", + "lib/netstandard2.0/ZstdSharp.dll", + "lib/netstandard2.1/ZstdSharp.dll", + "zstdsharp.port.0.7.3.nupkg.sha512", + "zstdsharp.port.nuspec" + ] + }, + "Entity/1.0.0": { + "type": "project", + "path": "../Entity/Entity.csproj", + "msbuildProject": "../Entity/Entity.csproj" + } + }, + "projectFileDependencyGroups": { + "net8.0": [ + "Entity >= 1.0.0" + ] + }, + "packageFolders": { + "/Users/fantasy/.nuget/packages/": {} + }, + "project": { + "version": "1.0.0", + "restore": { + "projectUniqueName": "/Users/fantasy/Code/ServerLessions/Chat/Server/Hotfix/Hotfix.csproj", + "projectName": "Hotfix", + "projectPath": "/Users/fantasy/Code/ServerLessions/Chat/Server/Hotfix/Hotfix.csproj", + "packagesPath": "/Users/fantasy/.nuget/packages/", + "outputPath": "/Users/fantasy/Code/ServerLessions/Chat/Server/Hotfix/obj/", + "projectStyle": "PackageReference", + "UsingMicrosoftNETSdk": false, + "configFilePaths": [ + "/Users/fantasy/.nuget/NuGet/NuGet.Config" + ], + "originalTargetFrameworks": [ + "net8.0" + ], + "sources": { + "https://api.nuget.org/v3/index.json": {} + }, + "frameworks": { + "net8.0": { + "targetAlias": "net8.0", + "projectReferences": { + "/Users/fantasy/Code/ServerLessions/Chat/Server/Entity/Entity.csproj": { + "projectPath": "/Users/fantasy/Code/ServerLessions/Chat/Server/Entity/Entity.csproj" + } + } + } + }, + "warningProperties": { + "warnAsError": [ + "NU1605" + ] + }, + "restoreAuditProperties": { + "enableAudit": "true", + "auditLevel": "low", + "auditMode": "all" + } + }, + "frameworks": { + "net8.0": { + "targetAlias": "net8.0", + "imports": [ + "net461", + "net462", + "net47", + "net471", + "net472", + "net48", + "net481" + ], + "assetTargetFallback": true, + "warn": true, + "frameworkReferences": { + "Microsoft.NETCore.App": { + "privateAssets": "all" + } + }, + "runtimeIdentifierGraphPath": "/usr/local/share/dotnet/sdk/9.0.100/PortableRuntimeIdentifierGraph.json" + } + } + } +} \ No newline at end of file diff --git a/聊天系统课程代码/Server/Hotfix/obj/project.nuget.cache b/聊天系统课程代码/Server/Hotfix/obj/project.nuget.cache new file mode 100644 index 0000000..3d91358 --- /dev/null +++ b/聊天系统课程代码/Server/Hotfix/obj/project.nuget.cache @@ -0,0 +1,30 @@ +{ + "version": 2, + "dgSpecHash": "1odcgIZCGY0=", + "success": true, + "projectFilePath": "/Users/fantasy/Code/ServerLessions/Chat/Server/Hotfix/Hotfix.csproj", + "expectedPackageFiles": [ + "/Users/fantasy/.nuget/packages/commandlineparser/2.9.1/commandlineparser.2.9.1.nupkg.sha512", + "/Users/fantasy/.nuget/packages/dnsclient/1.6.1/dnsclient.1.6.1.nupkg.sha512", + "/Users/fantasy/.nuget/packages/fantasy-net/2024.1.17/fantasy-net.2024.1.17.nupkg.sha512", + "/Users/fantasy/.nuget/packages/microsoft.extensions.logging.abstractions/2.0.0/microsoft.extensions.logging.abstractions.2.0.0.nupkg.sha512", + "/Users/fantasy/.nuget/packages/microsoft.netcore.platforms/5.0.0/microsoft.netcore.platforms.5.0.0.nupkg.sha512", + "/Users/fantasy/.nuget/packages/microsoft.win32.registry/5.0.0/microsoft.win32.registry.5.0.0.nupkg.sha512", + "/Users/fantasy/.nuget/packages/mongodb.bson/3.0.0/mongodb.bson.3.0.0.nupkg.sha512", + "/Users/fantasy/.nuget/packages/mongodb.driver/3.0.0/mongodb.driver.3.0.0.nupkg.sha512", + "/Users/fantasy/.nuget/packages/newtonsoft.json/13.0.3/newtonsoft.json.13.0.3.nupkg.sha512", + "/Users/fantasy/.nuget/packages/protobuf-net/3.2.45/protobuf-net.3.2.45.nupkg.sha512", + "/Users/fantasy/.nuget/packages/protobuf-net.core/3.2.45/protobuf-net.core.3.2.45.nupkg.sha512", + "/Users/fantasy/.nuget/packages/sharpcompress/0.30.1/sharpcompress.0.30.1.nupkg.sha512", + "/Users/fantasy/.nuget/packages/snappier/1.0.0/snappier.1.0.0.nupkg.sha512", + "/Users/fantasy/.nuget/packages/system.buffers/4.5.1/system.buffers.4.5.1.nupkg.sha512", + "/Users/fantasy/.nuget/packages/system.collections.immutable/7.0.0/system.collections.immutable.7.0.0.nupkg.sha512", + "/Users/fantasy/.nuget/packages/system.io.pipelines/8.0.0/system.io.pipelines.8.0.0.nupkg.sha512", + "/Users/fantasy/.nuget/packages/system.memory/4.5.5/system.memory.4.5.5.nupkg.sha512", + "/Users/fantasy/.nuget/packages/system.runtime.compilerservices.unsafe/5.0.0/system.runtime.compilerservices.unsafe.5.0.0.nupkg.sha512", + "/Users/fantasy/.nuget/packages/system.security.accesscontrol/5.0.0/system.security.accesscontrol.5.0.0.nupkg.sha512", + "/Users/fantasy/.nuget/packages/system.security.principal.windows/5.0.0/system.security.principal.windows.5.0.0.nupkg.sha512", + "/Users/fantasy/.nuget/packages/zstdsharp.port/0.7.3/zstdsharp.port.0.7.3.nupkg.sha512" + ], + "logs": [] +} \ No newline at end of file diff --git a/聊天系统课程代码/Server/Hotfix/obj/project.packagespec.json b/聊天系统课程代码/Server/Hotfix/obj/project.packagespec.json new file mode 100644 index 0000000..0722532 --- /dev/null +++ b/聊天系统课程代码/Server/Hotfix/obj/project.packagespec.json @@ -0,0 +1 @@ +"restore":{"projectUniqueName":"/Users/fantasy/Code/ServerLessions/Chat/Server/Hotfix/Hotfix.csproj","projectName":"Hotfix","projectPath":"/Users/fantasy/Code/ServerLessions/Chat/Server/Hotfix/Hotfix.csproj","outputPath":"/Users/fantasy/Code/ServerLessions/Chat/Server/Hotfix/obj/","projectStyle":"PackageReference","UsingMicrosoftNETSdk":false,"originalTargetFrameworks":["net8.0"],"sources":{"https://api.nuget.org/v3/index.json":{}},"frameworks":{"net8.0":{"targetAlias":"net8.0","projectReferences":{"/Users/fantasy/Code/ServerLessions/Chat/Server/Entity/Entity.csproj":{"projectPath":"/Users/fantasy/Code/ServerLessions/Chat/Server/Entity/Entity.csproj"}}}},"warningProperties":{"warnAsError":["NU1605"]},"restoreAuditProperties":{"enableAudit":"true","auditLevel":"low","auditMode":"all"}}"frameworks":{"net8.0":{"targetAlias":"net8.0","imports":["net461","net462","net47","net471","net472","net48","net481"],"assetTargetFallback":true,"warn":true,"frameworkReferences":{"Microsoft.NETCore.App":{"privateAssets":"all"}},"runtimeIdentifierGraphPath":"/usr/local/share/dotnet/sdk/9.0.100/PortableRuntimeIdentifierGraph.json"}} \ No newline at end of file diff --git a/聊天系统课程代码/Server/Hotfix/obj/rider.project.model.nuget.info b/聊天系统课程代码/Server/Hotfix/obj/rider.project.model.nuget.info new file mode 100644 index 0000000..95ccddb --- /dev/null +++ b/聊天系统课程代码/Server/Hotfix/obj/rider.project.model.nuget.info @@ -0,0 +1 @@ +17324493181399999 \ No newline at end of file diff --git a/聊天系统课程代码/Server/Hotfix/obj/rider.project.restore.info b/聊天系统课程代码/Server/Hotfix/obj/rider.project.restore.info new file mode 100644 index 0000000..6c7cf58 --- /dev/null +++ b/聊天系统课程代码/Server/Hotfix/obj/rider.project.restore.info @@ -0,0 +1 @@ +17331012454241289 \ No newline at end of file diff --git a/聊天系统课程代码/Server/Main/.DS_Store b/聊天系统课程代码/Server/Main/.DS_Store new file mode 100644 index 0000000..0e30770 Binary files /dev/null and b/聊天系统课程代码/Server/Main/.DS_Store differ diff --git a/聊天系统课程代码/Server/Main/Main.csproj b/聊天系统课程代码/Server/Main/Main.csproj new file mode 100644 index 0000000..597e2bd --- /dev/null +++ b/聊天系统课程代码/Server/Main/Main.csproj @@ -0,0 +1,27 @@ + + + + Exe + net8.0 + enable + enable + + + + ../../Bin/Debug/ + + + + ../../Bin/Release/ + + + + + + + + + + + + diff --git a/聊天系统课程代码/Server/Main/NLog.config b/聊天系统课程代码/Server/Main/NLog.config new file mode 100644 index 0000000..0d95292 --- /dev/null +++ b/聊天系统课程代码/Server/Main/NLog.config @@ -0,0 +1,90 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/聊天系统课程代码/Server/Main/NLog.xsd b/聊天系统课程代码/Server/Main/NLog.xsd new file mode 100644 index 0000000..63c9a0c --- /dev/null +++ b/聊天系统课程代码/Server/Main/NLog.xsd @@ -0,0 +1,3483 @@ + + + + + + + + + + + + + + + Watch config file for changes and reload automatically. + + + + + Print internal NLog messages to the console. Default value is: false + + + + + Print internal NLog messages to the console error output. Default value is: false + + + + + Write internal NLog messages to the specified file. + + + + + Log level threshold for internal log messages. Default value is: Info. + + + + + Global log level threshold for application log messages. Messages below this level won't be logged. + + + + + Throw an exception when there is an internal error. Default value is: false. Not recommend to set to true in production! + + + + + Throw an exception when there is a configuration error. If not set, determined by throwExceptions. + + + + + Gets or sets a value indicating whether Variables should be kept on configuration reload. Default value is: false. + + + + + Write internal NLog messages to the System.Diagnostics.Trace. Default value is: false. + + + + + Write timestamps for internal NLog messages. Default value is: true. + + + + + Use InvariantCulture as default culture instead of CurrentCulture. Default value is: false. + + + + + Perform message template parsing and formatting of LogEvent messages (true = Always, false = Never, empty = Auto Detect). Default value is: empty. + + + + + + + + + + + + + + Make all targets within this section asynchronous (creates additional threads but the calling thread isn't blocked by any target writes). + + + + + + + + + + + + + + + + + Prefix for targets/layout renderers/filters/conditions loaded from this assembly. + + + + + Load NLog extensions from the specified file (*.dll) + + + + + Load NLog extensions from the specified assembly. Assembly name should be fully qualified. + + + + + + + + + + Filter on the name of the logger. May include wildcard characters ('*' or '?'). + + + + + Comma separated list of levels that this rule matches. + + + + + Minimum level that this rule matches. + + + + + Maximum level that this rule matches. + + + + + Level that this rule matches. + + + + + Comma separated list of target names. + + + + + Ignore further rules if this one matches. + + + + + Enable this rule. Note: disabled rules aren't available from the API. + + + + + Rule identifier to allow rule lookup with Configuration.FindRuleByName and Configuration.RemoveRuleByName. + + + + + Loggers matching will be restricted to specified minimum level for following rules. + + + + + + + + + + + + + + + Default action if none of the filters match. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Name of the file to be included. You could use * wildcard. The name is relative to the name of the current config file. + + + + + Ignore any errors in the include file. + + + + + + + + Variable value. Note, the 'value' attribute has precedence over this one. + + + + + + Variable name. + + + + + Variable value. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Action to be taken when the lazy writer thread request queue count exceeds the set limit. + + + + + Limit on the number of requests in the lazy writer thread request queue. + + + + + Number of log events that should be processed in a batch by the lazy writer thread. + + + + + Whether to use the locking queue, instead of a lock-free concurrent queue + + + + + Number of batches of P:NLog.Targets.Wrappers.AsyncTargetWrapper.BatchSize to write before yielding into P:NLog.Targets.Wrappers.AsyncTargetWrapper.TimeToSleepBetweenBatches + + + + + Time in milliseconds to sleep between batches. (1 or less means trigger on new activity) + + + + + + + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Delay the flush until the LogEvent has been confirmed as written + + + + + Condition expression. Log events who meet this condition will cause a flush on the wrapped target. + + + + + Only flush when LogEvent matches condition. Ignore explicit-flush, config-reload-flush and shutdown-flush + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Number of log events to be buffered. + + + + + Action to take if the buffer overflows. + + + + + Timeout (in milliseconds) after which the contents of buffer will be flushed if there's no write in the specified period of time. Use -1 to disable timed flushes. + + + + + Indicates whether to use sliding timeout. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Separator for T:NLog.ScopeContext operation-states-stack. + + + + + Stack separator for log4j:NDC in output from T:NLog.ScopeContext nested context. + + + + + Renderer for log4j:event logger-xml-attribute (Default ${logger}) + + + + + Whether to include the contents of the T:NLog.ScopeContext properties-dictionary. + + + + + Whether to include log4j:NDC in output from T:NLog.ScopeContext nested context. + + + + + Indicates whether to include source info (file name and line number) in the information sent over the network. + + + + + Whether to include log4j:NDC in output from T:NLog.ScopeContext nested context. + + + + + Option to include all properties from the log events + + + + + Indicates whether to include call site (class and method name) in the information sent over the network. + + + + + AppInfo field. By default it's the friendly name of the current AppDomain. + + + + + Instance of T:NLog.Layouts.Log4JXmlEventLayout that is used to format log messages. + + + + + Indicates whether to include NLog-specific extensions to log4j schema. + + + + + Action that should be taken, when more connections than P:NLog.Targets.NetworkTarget.MaxConnections. + + + + + SSL/TLS protocols. Default no SSL/TLS is used. Currently only implemented for TCP. + + + + + Action that should be taken, when more pending messages than P:NLog.Targets.NetworkTarget.MaxQueueSize. + + + + + Action that should be taken if the message is larger than P:NLog.Targets.NetworkTarget.MaxMessageSize + + + + + Maximum queue size for a single connection. Requires P:NLog.Targets.NetworkTarget.KeepConnection = true + + + + + Network address. + + + + + Indicates whether to keep connection open whenever possible. + + + + + The number of seconds a connection will remain idle before the first keep-alive probe is sent + + + + + Size of the connection cache (number of connections which are kept alive). Requires P:NLog.Targets.NetworkTarget.KeepConnection = true + + + + + Maximum simultaneous connections. Requires P:NLog.Targets.NetworkTarget.KeepConnection = false + + + + + Type of compression for protocol payload. Useful for UDP where datagram max-size is 8192 bytes. + + + + + Skip compression when protocol payload is below limit to reduce overhead in cpu-usage and additional headers + + + + + Maximum message size in bytes. On limit breach then P:NLog.Targets.NetworkTarget.OnOverflow action is activated. + + + + + Encoding to be used. + + + + + End of line value if a newline is appended at the end of log message P:NLog.Targets.NetworkTarget.NewLine. + + + + + Indicates whether to append newline at the end of log message. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Viewer parameter name. + + + + + Layout that should be use to calculate the value for the parameter. + + + + + Whether an attribute with empty value should be included in the output + + + + + + + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Text to be rendered. + + + + + Header. + + + + + Footer. + + + + + Indicates whether to auto-check if the console is available. - Disables console writing if Environment.UserInteractive = False (Windows Service) - Disables console writing if Console Standard Input is not available (Non-Console-App) + + + + + Enables output using ANSI Color Codes + + + + + The encoding for writing messages to the T:System.Console. + + + + + Indicates whether to send the log messages to the standard error instead of the standard output. + + + + + Indicates whether to auto-flush after M:System.Console.WriteLine + + + + + Indicates whether to auto-check if the console has been redirected to file - Disables coloring logic when System.Console.IsOutputRedirected = true + + + + + Indicates whether to use default row highlighting rules. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Background color. + + + + + Condition that must be met in order to set the specified foreground and background color. + + + + + Foreground color. + + + + + + + + + + + + + + + + + Background color. + + + + + Compile the P:NLog.Targets.ConsoleWordHighlightingRule.Regex? This can improve the performance, but at the costs of more memory usage. If false, the Regex Cache is used. + + + + + Condition that must be met before scanning the row for highlight of words + + + + + Foreground color. + + + + + Indicates whether to ignore case when comparing texts. + + + + + Regular expression to be matched. You must specify either text or regex. + + + + + Text to be matched. You must specify either text or regex. + + + + + Indicates whether to match whole words only. + + + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Text to be rendered. + + + + + Header. + + + + + Footer. + + + + + Indicates whether to auto-flush after M:System.Console.WriteLine + + + + + Indicates whether to auto-check if the console is available - Disables console writing if Environment.UserInteractive = False (Windows Service) - Disables console writing if Console Standard Input is not available (Non-Console-App) + + + + + The encoding for writing messages to the T:System.Console. + + + + + Indicates whether to send the log messages to the standard error instead of the standard output. + + + + + Whether to activate internal buffering to allow batch writing, instead of using M:System.Console.WriteLine + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Database user name. If the ConnectionString is not provided this value will be used to construct the "User ID=" part of the connection string. + + + + + Database password. If the ConnectionString is not provided this value will be used to construct the "Password=" part of the connection string. + + + + + Database name. If the ConnectionString is not provided this value will be used to construct the "Database=" part of the connection string. + + + + + Name of the connection string (as specified in <connectionStrings> configuration section. + + + + + Database host name. If the ConnectionString is not provided this value will be used to construct the "Server=" part of the connection string. + + + + + Indicates whether to keep the database connection open between the log events. + + + + + Name of the database provider. + + + + + Connection string. When provided, it overrides the values specified in DBHost, DBUserName, DBPassword, DBDatabase. + + + + + Connection string using for installation and uninstallation. If not provided, regular ConnectionString is being used. + + + + + Configures isolated transaction batch writing. If supported by the database, then it will improve insert performance. + + + + + Text of the SQL command to be run on each log level. + + + + + Type of the SQL command to be run on each log level. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Convert format of the property value + + + + + Culture used for parsing property string-value for type-conversion + + + + + Value to assign on the object-property + + + + + Name for the object-property + + + + + Type of the object-property + + + + + + + + + + + + + + Type of the command. + + + + + Connection string to run the command against. If not provided, connection string from the target is used. + + + + + Indicates whether to ignore failures. + + + + + Command text. + + + + + + + + + + + + + + + + + + + + Database parameter name. + + + + + Layout that should be use to calculate the value for the parameter. + + + + + Database parameter DbType. + + + + + Database parameter size. + + + + + Database parameter precision. + + + + + Database parameter scale. + + + + + Type of the parameter. + + + + + Fallback value when result value is not available + + + + + Convert format of the database parameter value. + + + + + Culture used for parsing parameter string-value for type-conversion + + + + + Whether empty value should translate into DbNull. Requires database column to allow NULL values. + + + + + + + + + + + + + + + Name of the target. + + + + + Text to be rendered. + + + + + Header. + + + + + Footer. + + + + + + + + + + + + + + + + + Name of the target. + + + + + Text to be rendered. + + + + + Header. + + + + + Footer. + + + + + + + + + + + + + + + Name of the target. + + + + + Layout used to format log messages. + + + + + + + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Layout used to format log messages. + + + + + Layout that renders event Category. + + + + + Optional entry type. When not set, or when not convertible to T:System.Diagnostics.EventLogEntryType then determined by T:NLog.LogLevel + + + + + Layout that renders event ID. + + + + + Name of the Event Log to write to. This can be System, Application or any user-defined name. + + + + + Name of the machine on which Event Log service is running. + + + + + Maximum Event log size in kilobytes. + + + + + Message length limit to write to the Event Log. + + + + + Value to be used as the event Source. + + + + + Action to take if the message is larger than the P:NLog.Targets.EventLogTarget.MaxMessageLength option. + + + + + + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Indicates whether to return to the first target after any successful write. + + + + + Whether to enable batching, but fallback will be handled individually + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Name of the file to write to. + + + + + Text to be rendered. + + + + + Header. + + + + + Footer. + + + + + Indicates whether the footer should be written only when the file is archived. + + + + + Maximum number of archive files that should be kept. + + + + + Maximum days of archive files that should be kept. + + + + + Value of the file size threshold to archive old log file on startup. + + + + + Indicates whether to archive old log file on startup. + + + + + Indicates whether to compress archive files into the zip archive format. + + + + + Name of the file to be used for an archive. + + + + + Is the P:NLog.Targets.FileTarget.ArchiveFileName an absolute or relative path? + + + + + Indicates whether to automatically archive log files every time the specified time passes. + + + + + Value specifying the date format to use when archiving files. + + + + + Size in bytes above which log files will be automatically archived. + + + + + Way file archives are numbered. + + + + + Indicates whether to create directories if they do not exist. + + + + + Indicates whether file creation calls should be synchronized by a system global mutex. + + + + + Gets or set a value indicating whether a managed file stream is forced, instead of using the native implementation. + + + + + Is the P:NLog.Targets.FileTarget.FileName an absolute or relative path? + + + + + File attributes (Windows only). + + + + + Cleanup invalid values in a filename, e.g. slashes in a filename. If set to true, this can impact the performance of massive writes. If set to false, nothing gets written when the filename is wrong. + + + + + Indicates whether to write BOM (byte order mark) in created files. Defaults to true for UTF-16 and UTF-32 + + + + + Indicates whether to enable log file(s) to be deleted. + + + + + Indicates whether to delete old log file on startup. + + + + + File encoding. + + + + + Indicates whether to replace file contents on each write instead of appending log message at the end. + + + + + Line ending mode. + + + + + Number of times the write is appended on the file before NLog discards the log message. + + + + + Delay in milliseconds to wait before attempting to write to the file again. + + + + + Maximum number of seconds before open files are flushed. Zero or negative means disabled. + + + + + Maximum number of seconds that files are kept open. Zero or negative means disabled. + + + + + Indicates whether concurrent writes to the log file by multiple processes on different network hosts. + + + + + Log file buffer size in bytes. + + + + + Indicates whether to automatically flush the file buffers after each log message. + + + + + Indicates whether to keep log file open instead of opening and closing it on each logging event. + + + + + Indicates whether concurrent writes to the log file by multiple processes on the same host. + + + + + Whether or not this target should just discard all data that its asked to write. Mostly used for when testing NLog Stack except final write + + + + + Number of files to be kept open. Setting this to a higher value may improve performance in a situation where a single File target is writing to many files (such as splitting by level or by logger). + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Condition expression. Log events who meet this condition will be forwarded to the wrapped target. + + + + + + + + + + + + + + + Name of the target. + + + + + Identifier to perform group-by + + + + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Windows domain name to change context to. + + + + + Required impersonation level. + + + + + Type of the logon provider. + + + + + Logon Type. + + + + + User account password. + + + + + Indicates whether to revert to the credentials of the process instead of impersonating another user. + + + + + Username to change context to. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Interval in which messages will be written up to the P:NLog.Targets.Wrappers.LimitingTargetWrapper.MessageLimit number of messages. + + + + + Maximum allowed number of messages written per P:NLog.Targets.Wrappers.LimitingTargetWrapper.Interval. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Text to be rendered. + + + + + Header. + + + + + Footer. + + + + + Indicates whether NewLine characters in the body should be replaced with tags. + + + + + Priority used for sending mails. + + + + + Encoding to be used for sending e-mail. + + + + + BCC email addresses separated by semicolons (e.g. john@domain.com;jane@domain.com). + + + + + CC email addresses separated by semicolons (e.g. john@domain.com;jane@domain.com). + + + + + Indicates whether to add new lines between log entries. + + + + + Indicates whether to send message as HTML instead of plain text. + + + + + Sender's email address (e.g. joe@domain.com). + + + + + Mail message body (repeated for each log message send in one mail). + + + + + Mail subject. + + + + + Recipients' email addresses separated by semicolons (e.g. john@domain.com;jane@domain.com). + + + + + Specifies how outgoing email messages will be handled. + + + + + SMTP Server to be used for sending. + + + + + SMTP Authentication mode. + + + + + Username used to connect to SMTP server (used when SmtpAuthentication is set to "basic"). + + + + + Password used to authenticate against SMTP server (used when SmtpAuthentication is set to "basic"). + + + + + Indicates whether SSL (secure sockets layer) should be used when communicating with SMTP server. + + + + + Port number that SMTP Server is listening on. + + + + + Indicates whether the default Settings from System.Net.MailSettings should be used. + + + + + Folder where applications save mail messages to be processed by the local SMTP server. + + + + + Indicates the SMTP client timeout. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Text to be rendered. + + + + + Header. + + + + + Footer. + + + + + Max number of items to have in memory + + + + + + + + + + + + + + + + + Name of the target. + + + + + Class name. + + + + + Method name. The method must be public and static. Use the AssemblyQualifiedName , https://msdn.microsoft.com/en-us/library/system.type.assemblyqualifiedname(v=vs.110).aspx e.g. + + + + + + + + + + + + + + + Name of the parameter. + + + + + Layout that should be use to calculate the value for the parameter. + + + + + Fallback value when result value is not available + + + + + Type of the parameter. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Layout used to format log messages. + + + + + SSL/TLS protocols. Default no SSL/TLS is used. Currently only implemented for TCP. + + + + + Action that should be taken, when more pending messages than P:NLog.Targets.NetworkTarget.MaxQueueSize. + + + + + Action that should be taken if the message is larger than P:NLog.Targets.NetworkTarget.MaxMessageSize + + + + + Maximum queue size for a single connection. Requires P:NLog.Targets.NetworkTarget.KeepConnection = true + + + + + Action that should be taken, when more connections than P:NLog.Targets.NetworkTarget.MaxConnections. + + + + + Indicates whether to keep connection open whenever possible. + + + + + The number of seconds a connection will remain idle before the first keep-alive probe is sent + + + + + Size of the connection cache (number of connections which are kept alive). Requires P:NLog.Targets.NetworkTarget.KeepConnection = true + + + + + Network address. + + + + + Maximum simultaneous connections. Requires P:NLog.Targets.NetworkTarget.KeepConnection = false + + + + + Type of compression for protocol payload. Useful for UDP where datagram max-size is 8192 bytes. + + + + + Skip compression when protocol payload is below limit to reduce overhead in cpu-usage and additional headers + + + + + Maximum message size in bytes. On limit breach then P:NLog.Targets.NetworkTarget.OnOverflow action is activated. + + + + + Encoding to be used. + + + + + End of line value if a newline is appended at the end of log message P:NLog.Targets.NetworkTarget.NewLine. + + + + + Indicates whether to append newline at the end of log message. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Separator for T:NLog.ScopeContext operation-states-stack. + + + + + Stack separator for log4j:NDC in output from T:NLog.ScopeContext nested context. + + + + + Renderer for log4j:event logger-xml-attribute (Default ${logger}) + + + + + Whether to include the contents of the T:NLog.ScopeContext properties-dictionary. + + + + + Whether to include log4j:NDC in output from T:NLog.ScopeContext nested context. + + + + + Indicates whether to include source info (file name and line number) in the information sent over the network. + + + + + Whether to include log4j:NDC in output from T:NLog.ScopeContext nested context. + + + + + Option to include all properties from the log events + + + + + Indicates whether to include call site (class and method name) in the information sent over the network. + + + + + AppInfo field. By default it's the friendly name of the current AppDomain. + + + + + Instance of T:NLog.Layouts.Log4JXmlEventLayout that is used to format log messages. + + + + + Indicates whether to include NLog-specific extensions to log4j schema. + + + + + Action that should be taken, when more connections than P:NLog.Targets.NetworkTarget.MaxConnections. + + + + + SSL/TLS protocols. Default no SSL/TLS is used. Currently only implemented for TCP. + + + + + Action that should be taken, when more pending messages than P:NLog.Targets.NetworkTarget.MaxQueueSize. + + + + + Action that should be taken if the message is larger than P:NLog.Targets.NetworkTarget.MaxMessageSize + + + + + Maximum queue size for a single connection. Requires P:NLog.Targets.NetworkTarget.KeepConnection = true + + + + + Network address. + + + + + Indicates whether to keep connection open whenever possible. + + + + + The number of seconds a connection will remain idle before the first keep-alive probe is sent + + + + + Size of the connection cache (number of connections which are kept alive). Requires P:NLog.Targets.NetworkTarget.KeepConnection = true + + + + + Maximum simultaneous connections. Requires P:NLog.Targets.NetworkTarget.KeepConnection = false + + + + + Type of compression for protocol payload. Useful for UDP where datagram max-size is 8192 bytes. + + + + + Skip compression when protocol payload is below limit to reduce overhead in cpu-usage and additional headers + + + + + Maximum message size in bytes. On limit breach then P:NLog.Targets.NetworkTarget.OnOverflow action is activated. + + + + + Encoding to be used. + + + + + End of line value if a newline is appended at the end of log message P:NLog.Targets.NetworkTarget.NewLine. + + + + + Indicates whether to append newline at the end of log message. + + + + + + + + + + + + + + + + Name of the target. + + + + + Layout used to format log messages. + + + + + Indicates whether to perform layout calculation. + + + + + + + + + + + + + + + + Name of the target. + + + + + Default filter to be applied when no specific rule matches. + + + + + + + + + + + + + Condition to be tested. + + + + + Resulting filter to be applied when the condition matches. + + + + + + + + + + + + Name of the target. + + + + + + + + + + + + + + + Name of the target. + + + + + Number of times to repeat each log message. + + + + + + + + + + + + + + + + + Name of the target. + + + + + Whether to enable batching, and only apply single delay when a whole batch fails + + + + + Number of retries that should be attempted on the wrapped target in case of a failure. + + + + + Time to wait between retries in milliseconds. + + + + + + + + + + + + + + Name of the target. + + + + + + + + + + + + + + Name of the target. + + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Text to be rendered. + + + + + Header. + + + + + Footer. + + + + + Forward F:NLog.LogLevel.Fatal to M:System.Diagnostics.Trace.Fail(System.String) (Instead of M:System.Diagnostics.Trace.TraceError(System.String)) + + + + + Force use M:System.Diagnostics.Trace.WriteLine(System.String) independent of T:NLog.LogLevel + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Indicates whether to pre-authenticate the HttpWebRequest (Requires 'Authorization' in P:NLog.Targets.WebServiceTarget.Headers parameters) + + + + + Value whether escaping be done according to Rfc3986 (Supports Internationalized Resource Identifiers - IRIs) + + + + + Value whether escaping be done according to the old NLog style (Very non-standard) + + + + + Value of the User-agent HTTP header. + + + + + Web service URL. + + + + + Proxy configuration when calling web service + + + + + Custom proxy address, include port separated by a colon + + + + + Protocol to be used when calling web service. + + + + + Web service namespace. Only used with Soap. + + + + + Web service method name. Only used with Soap. + + + + + Should we include the BOM (Byte-order-mark) for UTF? Influences the P:NLog.Targets.WebServiceTarget.Encoding property. This will only work for UTF-8. + + + + + Encoding. + + + + + Name of the root XML element, if POST of XML document chosen. If so, this property must not be null. (see P:NLog.Targets.WebServiceTarget.Protocol and F:NLog.Targets.WebServiceProtocol.XmlPost). + + + + + (optional) root namespace of the XML document, if POST of XML document chosen. (see P:NLog.Targets.WebServiceTarget.Protocol and F:NLog.Targets.WebServiceProtocol.XmlPost). + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Custom column delimiter value (valid when ColumnDelimiter is set to 'Custom'). + + + + + Column delimiter. + + + + + Footer layout. + + + + + Header layout. + + + + + Body layout (can be repeated multiple times). + + + + + Quote Character. + + + + + Quoting mode. + + + + + Indicates whether CVS should include header. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Name of the column. + + + + + Layout of the column. + + + + + Override of Quoting mode + + + + + + + + + + + + + + Option to render the empty object value {} + + + + + Option to suppress the extra spaces in the output json + + + + + + + + + + + + + + + + + + + + + + + Option to include all properties from the log event (as JSON) + + + + + Indicates whether to include contents of the T:NLog.GlobalDiagnosticsContext dictionary. + + + + + Whether to include the contents of the T:NLog.ScopeContext dictionary. + + + + + Should forward slashes be escaped? If true, / will be converted to \/ + + + + + Option to exclude null/empty properties from the log event (as JSON) + + + + + List of property names to exclude when P:NLog.Layouts.JsonLayout.IncludeAllProperties is true + + + + + How far should the JSON serializer follow object references before backing off + + + + + Option to render the empty object value {} + + + + + Option to suppress the extra spaces in the output json + + + + + + + + + + + + + + + + + + + Name of the attribute. + + + + + Layout that will be rendered as the attribute's value. + + + + + Fallback value when result value is not available + + + + + Determines whether or not this attribute will be Json encoded. + + + + + Should forward slashes be escaped? If true, / will be converted to \/ + + + + + Indicates whether to escape non-ascii characters + + + + + Whether an attribute with empty value should be included in the output + + + + + Result value type, for conversion of layout rendering output + + + + + + + + + + + + + + Footer layout. + + + + + Header layout. + + + + + Body layout (can be repeated multiple times). + + + + + + + + + + + + + + + + + + + + + + + Option to include all properties from the log events + + + + + Whether to include log4j:NDC in output from T:NLog.ScopeContext nested context. + + + + + Whether to include log4j:NDC in output from T:NLog.ScopeContext nested context. + + + + + Whether to include the contents of the T:NLog.ScopeContext properties-dictionary. + + + + + AppInfo field. By default it's the friendly name of the current AppDomain. + + + + + Indicates whether to include call site (class and method name) in the information sent over the network. + + + + + Indicates whether to include source info (file name and line number) in the information sent over the network. + + + + + Log4j:event logger-xml-attribute (Default ${logger}) + + + + + Whether the log4j:throwable xml-element should be written as CDATA + + + + + + + + + + + + + + Layout text. + + + + + + + + + + + + + + + + + + + + + + + + + + + + Name of the root XML element + + + + + Value inside the root XML element + + + + + Whether to include the contents of the T:NLog.ScopeContext dictionary. + + + + + Determines whether or not this attribute will be Xml encoded. + + + + + List of property names to exclude when P:NLog.Layouts.XmlElementBase.IncludeAllProperties is true + + + + + Whether a ElementValue with empty value should be included in the output + + + + + Auto indent and create new lines + + + + + How far should the XML serializer follow object references before backing off + + + + + XML element name to use for rendering IList-collections items + + + + + XML attribute name to use when rendering property-key When null (or empty) then key-attribute is not included + + + + + XML element name to use when rendering properties + + + + + XML attribute name to use when rendering property-value When null (or empty) then value-attribute is not included and value is formatted as XML-element-value + + + + + Option to include all properties from the log event (as XML) + + + + + + + + + + + + + + + + + Name of the attribute. + + + + + Layout that will be rendered as the attribute's value. + + + + + Fallback value when result value is not available + + + + + Determines whether or not this attribute will be Xml encoded. + + + + + Whether an attribute with empty value should be included in the output + + + + + Result value type, for conversion of layout rendering output + + + + + + + + + + + + + + + + + + + + + + + + Name of the element + + + + + Whether to include the contents of the T:NLog.ScopeContext dictionary. + + + + + Value inside the element + + + + + Determines whether or not this attribute will be Xml encoded. + + + + + List of property names to exclude when P:NLog.Layouts.XmlElementBase.IncludeAllProperties is true + + + + + Whether a ElementValue with empty value should be included in the output + + + + + Auto indent and create new lines + + + + + How far should the XML serializer follow object references before backing off + + + + + XML element name to use for rendering IList-collections items + + + + + XML attribute name to use when rendering property-key When null (or empty) then key-attribute is not included + + + + + XML element name to use when rendering properties + + + + + XML attribute name to use when rendering property-value When null (or empty) then value-attribute is not included and value is formatted as XML-element-value + + + + + Option to include all properties from the log event (as XML) + + + + + + + + + + + + + Action to be taken when filter matches. + + + + + Condition expression. + + + + + + + + + + + + + + + + + + + + + + + + + + Action to be taken when filter matches. + + + + + Indicates whether to ignore case when comparing strings. + + + + + Layout to be used to filter log messages. + + + + + Substring to be matched. + + + + + + + + + + + + + + + + + Action to be taken when filter matches. + + + + + String to compare the layout to. + + + + + Indicates whether to ignore case when comparing strings. + + + + + Layout to be used to filter log messages. + + + + + + + + + + + + + + + + + Action to be taken when filter matches. + + + + + Indicates whether to ignore case when comparing strings. + + + + + Layout to be used to filter log messages. + + + + + Substring to be matched. + + + + + + + + + + + + + + + + + Action to be taken when filter matches. + + + + + String to compare the layout to. + + + + + Indicates whether to ignore case when comparing strings. + + + + + Layout to be used to filter log messages. + + + + + + + + + + + + + + + + + + + + + + + Action to be taken when filter matches. + + + + + Append FilterCount to the P:NLog.LogEventInfo.Message when an event is no longer filtered + + + + + Insert FilterCount value into P:NLog.LogEventInfo.Properties when an event is no longer filtered + + + + + Applies the configured action to the initial logevent that starts the timeout period. Used to configure that it should ignore all events until timeout. + + + + + Layout to be used to filter log messages. + + + + + Max length of filter values, will truncate if above limit + + + + + How long before a filter expires, and logging is accepted again + + + + + Default number of unique filter values to expect, will automatically increase if needed + + + + + Max number of unique filter values to expect simultaneously + + + + + Default buffer size for the internal buffers + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/聊天系统课程代码/Server/Main/Program.cs b/聊天系统课程代码/Server/Main/Program.cs new file mode 100644 index 0000000..fff24da --- /dev/null +++ b/聊天系统课程代码/Server/Main/Program.cs @@ -0,0 +1,22 @@ +using Fantasy.Helper; +using Fantasy.Platform.Net; + +// 获取配置文件,这里我就是用的相对路径来拿了,大家实际的项目可以远程都可以。 +var machineConfigText = await FileHelper.GetTextByRelativePath("../../../Config/Json/Server/MachineConfigData.Json"); +var processConfigText = await FileHelper.GetTextByRelativePath("../../../Config/Json/Server/ProcessConfigData.Json"); +var worldConfigText = await FileHelper.GetTextByRelativePath("../../../Config/Json/Server/WorldConfigData.Json"); +var sceneConfigText = await FileHelper.GetTextByRelativePath("../../../Config/Json/Server/SceneConfigData.Json"); +// 初始化配置文件 +// 如果重复初始化方法会覆盖掉上一次的数据,非常适合热重载时使用 +MachineConfigData.Initialize(machineConfigText); +ProcessConfigData.Initialize(processConfigText); +WorldConfigData.Initialize(worldConfigText); +SceneConfigData.Initialize(sceneConfigText); +// 注册日志模块到框架 +// 开发者可以自己注册日志系统到框架,只要实现Fantasy.ILog接口就可以。 +// 这里用的是NLog日志系统注册到框架中。 +Fantasy.Log.Register(new Fantasy.NLog("Server")); +// 初始化框架,添加程序集到框架中 +Fantasy.Platform.Net.Entry.Initialize(Fantasy.AssemblyHelper.Assemblies); +// 启动Fantasy.Net +await Fantasy.Platform.Net.Entry.Start(); \ No newline at end of file diff --git a/聊天系统课程代码/Server/Main/Properties/launchSettings.json b/聊天系统课程代码/Server/Main/Properties/launchSettings.json new file mode 100644 index 0000000..cd8b993 --- /dev/null +++ b/聊天系统课程代码/Server/Main/Properties/launchSettings.json @@ -0,0 +1,10 @@ +{ + "$schema": "http://json.schemastore.org/launchsettings.json", + "profiles": { + "Main": { + "commandName": "Project", + "environmentVariables": {}, + "commandLineArgs": "--m Develop" + } + } +} diff --git a/聊天系统课程代码/Server/Main/bin/.DS_Store b/聊天系统课程代码/Server/Main/bin/.DS_Store new file mode 100644 index 0000000..c7836a3 Binary files /dev/null and b/聊天系统课程代码/Server/Main/bin/.DS_Store differ diff --git a/聊天系统课程代码/Server/Main/bin/Debug/.DS_Store b/聊天系统课程代码/Server/Main/bin/Debug/.DS_Store new file mode 100644 index 0000000..59109f2 Binary files /dev/null and b/聊天系统课程代码/Server/Main/bin/Debug/.DS_Store differ diff --git a/聊天系统课程代码/Server/Main/obj/Debug/net8.0/.NETCoreApp,Version=v8.0.AssemblyAttributes.cs b/聊天系统课程代码/Server/Main/obj/Debug/net8.0/.NETCoreApp,Version=v8.0.AssemblyAttributes.cs new file mode 100644 index 0000000..2217181 --- /dev/null +++ b/聊天系统课程代码/Server/Main/obj/Debug/net8.0/.NETCoreApp,Version=v8.0.AssemblyAttributes.cs @@ -0,0 +1,4 @@ +// +using System; +using System.Reflection; +[assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute(".NETCoreApp,Version=v8.0", FrameworkDisplayName = ".NET 8.0")] diff --git a/聊天系统课程代码/Server/Main/obj/Debug/net8.0/Main.AssemblyInfo.cs b/聊天系统课程代码/Server/Main/obj/Debug/net8.0/Main.AssemblyInfo.cs new file mode 100644 index 0000000..6d4ddcc --- /dev/null +++ b/聊天系统课程代码/Server/Main/obj/Debug/net8.0/Main.AssemblyInfo.cs @@ -0,0 +1,22 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +using System; +using System.Reflection; + +[assembly: System.Reflection.AssemblyCompanyAttribute("Main")] +[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")] +[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")] +[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0")] +[assembly: System.Reflection.AssemblyProductAttribute("Main")] +[assembly: System.Reflection.AssemblyTitleAttribute("Main")] +[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")] + +// 由 MSBuild WriteCodeFragment 类生成。 + diff --git a/聊天系统课程代码/Server/Main/obj/Debug/net8.0/Main.AssemblyInfoInputs.cache b/聊天系统课程代码/Server/Main/obj/Debug/net8.0/Main.AssemblyInfoInputs.cache new file mode 100644 index 0000000..46a1044 --- /dev/null +++ b/聊天系统课程代码/Server/Main/obj/Debug/net8.0/Main.AssemblyInfoInputs.cache @@ -0,0 +1 @@ +73a846e799d8ee769f4e4dc02756eb24673accb05fd3a22128b4b3e41a505989 diff --git a/聊天系统课程代码/Server/Main/obj/Debug/net8.0/Main.GeneratedMSBuildEditorConfig.editorconfig b/聊天系统课程代码/Server/Main/obj/Debug/net8.0/Main.GeneratedMSBuildEditorConfig.editorconfig new file mode 100644 index 0000000..f89fb4e --- /dev/null +++ b/聊天系统课程代码/Server/Main/obj/Debug/net8.0/Main.GeneratedMSBuildEditorConfig.editorconfig @@ -0,0 +1,15 @@ +is_global = true +build_property.TargetFramework = net8.0 +build_property.TargetPlatformMinVersion = +build_property.UsingMicrosoftNETSdkWeb = +build_property.ProjectTypeGuids = +build_property.InvariantGlobalization = +build_property.PlatformNeutralAssembly = +build_property.EnforceExtendedAnalyzerRules = +build_property._SupportedPlatformList = Linux,macOS,Windows +build_property.RootNamespace = Main +build_property.ProjectDir = /Users/fantasy/Code/ServerLessions/Chat/Server/Main/ +build_property.EnableComHosting = +build_property.EnableGeneratedComInterfaceComImportInterop = +build_property.EffectiveAnalysisLevelStyle = 8.0 +build_property.EnableCodeStyleSeverity = diff --git a/聊天系统课程代码/Server/Main/obj/Debug/net8.0/Main.GlobalUsings.g.cs b/聊天系统课程代码/Server/Main/obj/Debug/net8.0/Main.GlobalUsings.g.cs new file mode 100644 index 0000000..8578f3d --- /dev/null +++ b/聊天系统课程代码/Server/Main/obj/Debug/net8.0/Main.GlobalUsings.g.cs @@ -0,0 +1,8 @@ +// +global using global::System; +global using global::System.Collections.Generic; +global using global::System.IO; +global using global::System.Linq; +global using global::System.Net.Http; +global using global::System.Threading; +global using global::System.Threading.Tasks; diff --git a/聊天系统课程代码/Server/Main/obj/Debug/net8.0/Main.assets.cache b/聊天系统课程代码/Server/Main/obj/Debug/net8.0/Main.assets.cache new file mode 100644 index 0000000..bd79238 Binary files /dev/null and b/聊天系统课程代码/Server/Main/obj/Debug/net8.0/Main.assets.cache differ diff --git a/聊天系统课程代码/Server/Main/obj/Debug/net8.0/Main.csproj.AssemblyReference.cache b/聊天系统课程代码/Server/Main/obj/Debug/net8.0/Main.csproj.AssemblyReference.cache new file mode 100644 index 0000000..72f4ac0 Binary files /dev/null and b/聊天系统课程代码/Server/Main/obj/Debug/net8.0/Main.csproj.AssemblyReference.cache differ diff --git a/聊天系统课程代码/Server/Main/obj/Debug/net8.0/Main.csproj.CopyComplete b/聊天系统课程代码/Server/Main/obj/Debug/net8.0/Main.csproj.CopyComplete new file mode 100644 index 0000000..e69de29 diff --git a/聊天系统课程代码/Server/Main/obj/Debug/net8.0/Main.csproj.CoreCompileInputs.cache b/聊天系统课程代码/Server/Main/obj/Debug/net8.0/Main.csproj.CoreCompileInputs.cache new file mode 100644 index 0000000..a983c84 --- /dev/null +++ b/聊天系统课程代码/Server/Main/obj/Debug/net8.0/Main.csproj.CoreCompileInputs.cache @@ -0,0 +1 @@ +be8fd1b3dc0ac6bdaaed1e2ad5f9a3508f4e059f166db58f3c17a381ebc5149c diff --git a/聊天系统课程代码/Server/Main/obj/Debug/net8.0/Main.csproj.FileListAbsolute.txt b/聊天系统课程代码/Server/Main/obj/Debug/net8.0/Main.csproj.FileListAbsolute.txt new file mode 100644 index 0000000..09c972d --- /dev/null +++ b/聊天系统课程代码/Server/Main/obj/Debug/net8.0/Main.csproj.FileListAbsolute.txt @@ -0,0 +1,18 @@ +/Users/sining/Code/ServerLessions/Chat/Bin/Debug/net8.0/Main +/Users/sining/Code/ServerLessions/Chat/Bin/Debug/net8.0/NLog.config +/Users/sining/Code/ServerLessions/Chat/Bin/Debug/net8.0/NLog.xsd +/Users/sining/Code/ServerLessions/Chat/Bin/Debug/net8.0/Main.deps.json +/Users/sining/Code/ServerLessions/Chat/Bin/Debug/net8.0/Main.runtimeconfig.json +/Users/sining/Code/ServerLessions/Chat/Bin/Debug/net8.0/Main.dll +/Users/sining/Code/ServerLessions/Chat/Bin/Debug/net8.0/Main.pdb +/Users/sining/Code/ServerLessions/Chat/Server/Main/obj/Debug/net8.0/Main.csproj.AssemblyReference.cache +/Users/sining/Code/ServerLessions/Chat/Server/Main/obj/Debug/net8.0/Main.GeneratedMSBuildEditorConfig.editorconfig +/Users/sining/Code/ServerLessions/Chat/Server/Main/obj/Debug/net8.0/Main.AssemblyInfoInputs.cache +/Users/sining/Code/ServerLessions/Chat/Server/Main/obj/Debug/net8.0/Main.AssemblyInfo.cs +/Users/sining/Code/ServerLessions/Chat/Server/Main/obj/Debug/net8.0/Main.csproj.CoreCompileInputs.cache +/Users/sining/Code/ServerLessions/Chat/Server/Main/obj/Debug/net8.0/Main.csproj.CopyComplete +/Users/sining/Code/ServerLessions/Chat/Server/Main/obj/Debug/net8.0/Main.dll +/Users/sining/Code/ServerLessions/Chat/Server/Main/obj/Debug/net8.0/refint/Main.dll +/Users/sining/Code/ServerLessions/Chat/Server/Main/obj/Debug/net8.0/Main.pdb +/Users/sining/Code/ServerLessions/Chat/Server/Main/obj/Debug/net8.0/Main.genruntimeconfig.cache +/Users/sining/Code/ServerLessions/Chat/Server/Main/obj/Debug/net8.0/ref/Main.dll diff --git a/聊天系统课程代码/Server/Main/obj/Debug/net8.0/Main.dll b/聊天系统课程代码/Server/Main/obj/Debug/net8.0/Main.dll new file mode 100644 index 0000000..3062a9d Binary files /dev/null and b/聊天系统课程代码/Server/Main/obj/Debug/net8.0/Main.dll differ diff --git a/聊天系统课程代码/Server/Main/obj/Debug/net8.0/Main.genruntimeconfig.cache b/聊天系统课程代码/Server/Main/obj/Debug/net8.0/Main.genruntimeconfig.cache new file mode 100644 index 0000000..8bb1419 --- /dev/null +++ b/聊天系统课程代码/Server/Main/obj/Debug/net8.0/Main.genruntimeconfig.cache @@ -0,0 +1 @@ +a60b4562e51ea826cbb69d1cf0ce5b1f897bf8d324560430d7d9e9e82a705e3d diff --git a/聊天系统课程代码/Server/Main/obj/Debug/net8.0/Main.pdb b/聊天系统课程代码/Server/Main/obj/Debug/net8.0/Main.pdb new file mode 100644 index 0000000..79c1f28 Binary files /dev/null and b/聊天系统课程代码/Server/Main/obj/Debug/net8.0/Main.pdb differ diff --git a/聊天系统课程代码/Server/Main/obj/Debug/net8.0/apphost b/聊天系统课程代码/Server/Main/obj/Debug/net8.0/apphost new file mode 100644 index 0000000..1d3265f Binary files /dev/null and b/聊天系统课程代码/Server/Main/obj/Debug/net8.0/apphost differ diff --git a/聊天系统课程代码/Server/Main/obj/Debug/net8.0/ref/Main.dll b/聊天系统课程代码/Server/Main/obj/Debug/net8.0/ref/Main.dll new file mode 100644 index 0000000..b0fde69 Binary files /dev/null and b/聊天系统课程代码/Server/Main/obj/Debug/net8.0/ref/Main.dll differ diff --git a/聊天系统课程代码/Server/Main/obj/Debug/net8.0/refint/Main.dll b/聊天系统课程代码/Server/Main/obj/Debug/net8.0/refint/Main.dll new file mode 100644 index 0000000..b0fde69 Binary files /dev/null and b/聊天系统课程代码/Server/Main/obj/Debug/net8.0/refint/Main.dll differ diff --git a/聊天系统课程代码/Server/Main/obj/Main.csproj.nuget.dgspec.json b/聊天系统课程代码/Server/Main/obj/Main.csproj.nuget.dgspec.json new file mode 100644 index 0000000..a7b19be --- /dev/null +++ b/聊天系统课程代码/Server/Main/obj/Main.csproj.nuget.dgspec.json @@ -0,0 +1,208 @@ +{ + "format": 1, + "restore": { + "/Users/fantasy/Code/ServerLessions/Chat/Server/Main/Main.csproj": {} + }, + "projects": { + "/Users/fantasy/Code/ServerLessions/Chat/Server/Entity/Entity.csproj": { + "version": "1.0.0", + "restore": { + "projectUniqueName": "/Users/fantasy/Code/ServerLessions/Chat/Server/Entity/Entity.csproj", + "projectName": "Entity", + "projectPath": "/Users/fantasy/Code/ServerLessions/Chat/Server/Entity/Entity.csproj", + "packagesPath": "/Users/fantasy/.nuget/packages/", + "outputPath": "/Users/fantasy/Code/ServerLessions/Chat/Server/Entity/obj/", + "projectStyle": "PackageReference", + "UsingMicrosoftNETSdk": false, + "configFilePaths": [ + "/Users/fantasy/.nuget/NuGet/NuGet.Config" + ], + "originalTargetFrameworks": [ + "net8.0" + ], + "sources": { + "https://api.nuget.org/v3/index.json": {} + }, + "frameworks": { + "net8.0": { + "targetAlias": "net8.0", + "projectReferences": {} + } + }, + "warningProperties": { + "warnAsError": [ + "NU1605" + ] + }, + "restoreAuditProperties": { + "enableAudit": "true", + "auditLevel": "low", + "auditMode": "all" + } + }, + "frameworks": { + "net8.0": { + "targetAlias": "net8.0", + "dependencies": { + "Fantasy-Net": { + "target": "Package", + "version": "[2024.1.17, )" + } + }, + "imports": [ + "net461", + "net462", + "net47", + "net471", + "net472", + "net48", + "net481" + ], + "assetTargetFallback": true, + "warn": true, + "frameworkReferences": { + "Microsoft.NETCore.App": { + "privateAssets": "all" + } + }, + "runtimeIdentifierGraphPath": "/usr/local/share/dotnet/sdk/9.0.100/PortableRuntimeIdentifierGraph.json" + } + } + }, + "/Users/fantasy/Code/ServerLessions/Chat/Server/Hotfix/Hotfix.csproj": { + "version": "1.0.0", + "restore": { + "projectUniqueName": "/Users/fantasy/Code/ServerLessions/Chat/Server/Hotfix/Hotfix.csproj", + "projectName": "Hotfix", + "projectPath": "/Users/fantasy/Code/ServerLessions/Chat/Server/Hotfix/Hotfix.csproj", + "packagesPath": "/Users/fantasy/.nuget/packages/", + "outputPath": "/Users/fantasy/Code/ServerLessions/Chat/Server/Hotfix/obj/", + "projectStyle": "PackageReference", + "UsingMicrosoftNETSdk": false, + "configFilePaths": [ + "/Users/fantasy/.nuget/NuGet/NuGet.Config" + ], + "originalTargetFrameworks": [ + "net8.0" + ], + "sources": { + "https://api.nuget.org/v3/index.json": {} + }, + "frameworks": { + "net8.0": { + "targetAlias": "net8.0", + "projectReferences": { + "/Users/fantasy/Code/ServerLessions/Chat/Server/Entity/Entity.csproj": { + "projectPath": "/Users/fantasy/Code/ServerLessions/Chat/Server/Entity/Entity.csproj" + } + } + } + }, + "warningProperties": { + "warnAsError": [ + "NU1605" + ] + }, + "restoreAuditProperties": { + "enableAudit": "true", + "auditLevel": "low", + "auditMode": "all" + } + }, + "frameworks": { + "net8.0": { + "targetAlias": "net8.0", + "imports": [ + "net461", + "net462", + "net47", + "net471", + "net472", + "net48", + "net481" + ], + "assetTargetFallback": true, + "warn": true, + "frameworkReferences": { + "Microsoft.NETCore.App": { + "privateAssets": "all" + } + }, + "runtimeIdentifierGraphPath": "/usr/local/share/dotnet/sdk/9.0.100/PortableRuntimeIdentifierGraph.json" + } + } + }, + "/Users/fantasy/Code/ServerLessions/Chat/Server/Main/Main.csproj": { + "version": "1.0.0", + "restore": { + "projectUniqueName": "/Users/fantasy/Code/ServerLessions/Chat/Server/Main/Main.csproj", + "projectName": "Main", + "projectPath": "/Users/fantasy/Code/ServerLessions/Chat/Server/Main/Main.csproj", + "packagesPath": "/Users/fantasy/.nuget/packages/", + "outputPath": "/Users/fantasy/Code/ServerLessions/Chat/Server/Main/obj/", + "projectStyle": "PackageReference", + "UsingMicrosoftNETSdk": false, + "configFilePaths": [ + "/Users/fantasy/.nuget/NuGet/NuGet.Config" + ], + "originalTargetFrameworks": [ + "net8.0" + ], + "sources": { + "https://api.nuget.org/v3/index.json": {} + }, + "frameworks": { + "net8.0": { + "targetAlias": "net8.0", + "projectReferences": { + "/Users/fantasy/Code/ServerLessions/Chat/Server/Entity/Entity.csproj": { + "projectPath": "/Users/fantasy/Code/ServerLessions/Chat/Server/Entity/Entity.csproj" + }, + "/Users/fantasy/Code/ServerLessions/Chat/Server/Hotfix/Hotfix.csproj": { + "projectPath": "/Users/fantasy/Code/ServerLessions/Chat/Server/Hotfix/Hotfix.csproj" + } + } + } + }, + "warningProperties": { + "warnAsError": [ + "NU1605" + ] + }, + "restoreAuditProperties": { + "enableAudit": "true", + "auditLevel": "low", + "auditMode": "all" + } + }, + "frameworks": { + "net8.0": { + "targetAlias": "net8.0", + "dependencies": { + "Fantasy-Net.NLog": { + "target": "Package", + "version": "[2024.1.3, )" + } + }, + "imports": [ + "net461", + "net462", + "net47", + "net471", + "net472", + "net48", + "net481" + ], + "assetTargetFallback": true, + "warn": true, + "frameworkReferences": { + "Microsoft.NETCore.App": { + "privateAssets": "all" + } + }, + "runtimeIdentifierGraphPath": "/usr/local/share/dotnet/sdk/9.0.100/PortableRuntimeIdentifierGraph.json" + } + } + } + } +} \ No newline at end of file diff --git a/聊天系统课程代码/Server/Main/obj/Main.csproj.nuget.g.props b/聊天系统课程代码/Server/Main/obj/Main.csproj.nuget.g.props new file mode 100644 index 0000000..6515977 --- /dev/null +++ b/聊天系统课程代码/Server/Main/obj/Main.csproj.nuget.g.props @@ -0,0 +1,15 @@ + + + + True + NuGet + $(MSBuildThisFileDirectory)project.assets.json + /Users/fantasy/.nuget/packages/ + /Users/fantasy/.nuget/packages/ + PackageReference + 6.12.0 + + + + + \ No newline at end of file diff --git a/聊天系统课程代码/Server/Main/obj/Main.csproj.nuget.g.targets b/聊天系统课程代码/Server/Main/obj/Main.csproj.nuget.g.targets new file mode 100644 index 0000000..3e8f5e9 --- /dev/null +++ b/聊天系统课程代码/Server/Main/obj/Main.csproj.nuget.g.targets @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/聊天系统课程代码/Server/Main/obj/project.assets.json b/聊天系统课程代码/Server/Main/obj/project.assets.json new file mode 100644 index 0000000..88907d4 --- /dev/null +++ b/聊天系统课程代码/Server/Main/obj/project.assets.json @@ -0,0 +1,1063 @@ +{ + "version": 3, + "targets": { + "net8.0": { + "CommandLineParser/2.9.1": { + "type": "package", + "compile": { + "lib/netstandard2.0/CommandLine.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netstandard2.0/CommandLine.dll": { + "related": ".xml" + } + } + }, + "DnsClient/1.6.1": { + "type": "package", + "dependencies": { + "Microsoft.Win32.Registry": "5.0.0" + }, + "compile": { + "lib/net5.0/DnsClient.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net5.0/DnsClient.dll": { + "related": ".xml" + } + } + }, + "Fantasy-Net/2024.1.17": { + "type": "package", + "dependencies": { + "CommandLineParser": "2.9.1", + "MongoDB.Bson": "3.0.0", + "MongoDB.Driver": "3.0.0", + "Newtonsoft.Json": "13.0.3", + "System.IO.Pipelines": "8.0.0", + "protobuf-net": "3.2.45" + }, + "compile": { + "lib/net8.0/Fantasy-Net.dll": {} + }, + "runtime": { + "lib/net8.0/Fantasy-Net.dll": {} + }, + "frameworkReferences": [ + "Microsoft.AspNetCore.App" + ], + "build": { + "buildTransitive/Fantasy-Net.targets": {} + } + }, + "Fantasy-Net.NLog/2024.1.3": { + "type": "package", + "dependencies": { + "Fantasy-Net": "2024.1.3", + "NLog": "5.3.4" + }, + "compile": { + "lib/net8.0/Fantasy-Net.NLog.dll": {} + }, + "runtime": { + "lib/net8.0/Fantasy-Net.NLog.dll": {} + }, + "build": { + "buildTransitive/Fantasy-Net.NLog.targets": {} + } + }, + "Microsoft.Extensions.Logging.Abstractions/2.0.0": { + "type": "package", + "compile": { + "lib/netstandard2.0/Microsoft.Extensions.Logging.Abstractions.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netstandard2.0/Microsoft.Extensions.Logging.Abstractions.dll": { + "related": ".xml" + } + } + }, + "Microsoft.NETCore.Platforms/5.0.0": { + "type": "package", + "compile": { + "lib/netstandard1.0/_._": {} + }, + "runtime": { + "lib/netstandard1.0/_._": {} + } + }, + "Microsoft.Win32.Registry/5.0.0": { + "type": "package", + "dependencies": { + "System.Security.AccessControl": "5.0.0", + "System.Security.Principal.Windows": "5.0.0" + }, + "compile": { + "ref/netstandard2.0/Microsoft.Win32.Registry.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netstandard2.0/Microsoft.Win32.Registry.dll": { + "related": ".xml" + } + }, + "runtimeTargets": { + "runtimes/win/lib/netstandard2.0/Microsoft.Win32.Registry.dll": { + "assetType": "runtime", + "rid": "win" + } + } + }, + "MongoDB.Bson/3.0.0": { + "type": "package", + "dependencies": { + "System.Memory": "4.5.5", + "System.Runtime.CompilerServices.Unsafe": "5.0.0" + }, + "compile": { + "lib/net6.0/MongoDB.Bson.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net6.0/MongoDB.Bson.dll": { + "related": ".xml" + } + } + }, + "MongoDB.Driver/3.0.0": { + "type": "package", + "dependencies": { + "DnsClient": "1.6.1", + "Microsoft.Extensions.Logging.Abstractions": "2.0.0", + "MongoDB.Bson": "3.0.0", + "SharpCompress": "0.30.1", + "Snappier": "1.0.0", + "System.Buffers": "4.5.1", + "ZstdSharp.Port": "0.7.3" + }, + "compile": { + "lib/net6.0/MongoDB.Driver.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net6.0/MongoDB.Driver.dll": { + "related": ".xml" + } + } + }, + "Newtonsoft.Json/13.0.3": { + "type": "package", + "compile": { + "lib/net6.0/Newtonsoft.Json.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net6.0/Newtonsoft.Json.dll": { + "related": ".xml" + } + } + }, + "NLog/5.3.4": { + "type": "package", + "compile": { + "lib/netstandard2.0/NLog.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netstandard2.0/NLog.dll": { + "related": ".xml" + } + } + }, + "protobuf-net/3.2.45": { + "type": "package", + "dependencies": { + "protobuf-net.Core": "3.2.45" + }, + "compile": { + "lib/net6.0/protobuf-net.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net6.0/protobuf-net.dll": { + "related": ".xml" + } + } + }, + "protobuf-net.Core/3.2.45": { + "type": "package", + "dependencies": { + "System.Collections.Immutable": "7.0.0" + }, + "compile": { + "lib/net6.0/protobuf-net.Core.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net6.0/protobuf-net.Core.dll": { + "related": ".xml" + } + } + }, + "SharpCompress/0.30.1": { + "type": "package", + "compile": { + "lib/net5.0/SharpCompress.dll": {} + }, + "runtime": { + "lib/net5.0/SharpCompress.dll": {} + } + }, + "Snappier/1.0.0": { + "type": "package", + "compile": { + "lib/net5.0/Snappier.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net5.0/Snappier.dll": { + "related": ".xml" + } + } + }, + "System.Buffers/4.5.1": { + "type": "package", + "compile": { + "ref/netcoreapp2.0/_._": {} + }, + "runtime": { + "lib/netcoreapp2.0/_._": {} + } + }, + "System.Collections.Immutable/7.0.0": { + "type": "package", + "compile": { + "lib/net7.0/System.Collections.Immutable.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net7.0/System.Collections.Immutable.dll": { + "related": ".xml" + } + }, + "build": { + "buildTransitive/net6.0/_._": {} + } + }, + "System.IO.Pipelines/8.0.0": { + "type": "package", + "compile": { + "lib/net8.0/System.IO.Pipelines.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net8.0/System.IO.Pipelines.dll": { + "related": ".xml" + } + }, + "build": { + "buildTransitive/net6.0/_._": {} + } + }, + "System.Memory/4.5.5": { + "type": "package", + "compile": { + "ref/netcoreapp2.1/_._": {} + }, + "runtime": { + "lib/netcoreapp2.1/_._": {} + } + }, + "System.Runtime.CompilerServices.Unsafe/5.0.0": { + "type": "package", + "compile": { + "ref/netstandard2.1/System.Runtime.CompilerServices.Unsafe.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netcoreapp2.0/System.Runtime.CompilerServices.Unsafe.dll": { + "related": ".xml" + } + } + }, + "System.Security.AccessControl/5.0.0": { + "type": "package", + "dependencies": { + "Microsoft.NETCore.Platforms": "5.0.0", + "System.Security.Principal.Windows": "5.0.0" + }, + "compile": { + "ref/netstandard2.0/System.Security.AccessControl.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netstandard2.0/System.Security.AccessControl.dll": { + "related": ".xml" + } + }, + "runtimeTargets": { + "runtimes/win/lib/netcoreapp2.0/System.Security.AccessControl.dll": { + "assetType": "runtime", + "rid": "win" + } + } + }, + "System.Security.Principal.Windows/5.0.0": { + "type": "package", + "compile": { + "ref/netcoreapp3.0/System.Security.Principal.Windows.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netstandard2.0/System.Security.Principal.Windows.dll": { + "related": ".xml" + } + }, + "runtimeTargets": { + "runtimes/unix/lib/netcoreapp2.1/System.Security.Principal.Windows.dll": { + "assetType": "runtime", + "rid": "unix" + }, + "runtimes/win/lib/netcoreapp2.1/System.Security.Principal.Windows.dll": { + "assetType": "runtime", + "rid": "win" + } + } + }, + "ZstdSharp.Port/0.7.3": { + "type": "package", + "compile": { + "lib/net7.0/ZstdSharp.dll": {} + }, + "runtime": { + "lib/net7.0/ZstdSharp.dll": {} + } + }, + "Entity/1.0.0": { + "type": "project", + "framework": ".NETCoreApp,Version=v8.0", + "dependencies": { + "Fantasy-Net": "2024.1.17" + }, + "compile": { + "bin/placeholder/Entity.dll": {} + }, + "runtime": { + "bin/placeholder/Entity.dll": {} + } + }, + "Hotfix/1.0.0": { + "type": "project", + "framework": ".NETCoreApp,Version=v8.0", + "dependencies": { + "Entity": "1.0.0" + }, + "compile": { + "bin/placeholder/Hotfix.dll": {} + }, + "runtime": { + "bin/placeholder/Hotfix.dll": {} + } + } + } + }, + "libraries": { + "CommandLineParser/2.9.1": { + "sha512": "OE0sl1/sQ37bjVsPKKtwQlWDgqaxWgtme3xZz7JssWUzg5JpMIyHgCTY9MVMxOg48fJ1AgGT3tgdH5m/kQ5xhA==", + "type": "package", + "path": "commandlineparser/2.9.1", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "CommandLine20.png", + "License.md", + "README.md", + "commandlineparser.2.9.1.nupkg.sha512", + "commandlineparser.nuspec", + "lib/net40/CommandLine.dll", + "lib/net40/CommandLine.xml", + "lib/net45/CommandLine.dll", + "lib/net45/CommandLine.xml", + "lib/net461/CommandLine.dll", + "lib/net461/CommandLine.xml", + "lib/netstandard2.0/CommandLine.dll", + "lib/netstandard2.0/CommandLine.xml" + ] + }, + "DnsClient/1.6.1": { + "sha512": "4H/f2uYJOZ+YObZjpY9ABrKZI+JNw3uizp6oMzTXwDw6F+2qIPhpRl/1t68O/6e98+vqNiYGu+lswmwdYUy3gg==", + "type": "package", + "path": "dnsclient/1.6.1", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "dnsclient.1.6.1.nupkg.sha512", + "dnsclient.nuspec", + "icon.png", + "lib/net45/DnsClient.dll", + "lib/net45/DnsClient.xml", + "lib/net471/DnsClient.dll", + "lib/net471/DnsClient.xml", + "lib/net5.0/DnsClient.dll", + "lib/net5.0/DnsClient.xml", + "lib/netstandard1.3/DnsClient.dll", + "lib/netstandard1.3/DnsClient.xml", + "lib/netstandard2.0/DnsClient.dll", + "lib/netstandard2.0/DnsClient.xml", + "lib/netstandard2.1/DnsClient.dll", + "lib/netstandard2.1/DnsClient.xml" + ] + }, + "Fantasy-Net/2024.1.17": { + "sha512": "06mxvByfEvF/ELAiAjaea4aWI5IBbBDyH9sVdPxEOEEtpAbcguaiydUNi2CVBE+ppW+CYsznTXalN0Xk0vAMKQ==", + "type": "package", + "path": "fantasy-net/2024.1.17", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "LICENSE", + "README.md", + "buildTransitive/Fantasy-Net.targets", + "fantasy-net.2024.1.17.nupkg.sha512", + "fantasy-net.nuspec", + "icon.png", + "lib/net8.0/Fantasy-Net.dll" + ] + }, + "Fantasy-Net.NLog/2024.1.3": { + "sha512": "wcOeXUgG1pMy6k1yX04+aoBGSdxcrcyUcbm1X1wUIhFFTbizbP1h+3l9RiTw9YOkqzjss4HGz+reZCPGFJkYFA==", + "type": "package", + "path": "fantasy-net.nlog/2024.1.3", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "build/NLog.config", + "build/NLog.xsd", + "buildTransitive/Fantasy-Net.NLog.targets", + "fantasy-net.nlog.2024.1.3.nupkg.sha512", + "fantasy-net.nlog.nuspec", + "icon.png", + "lib/net8.0/Fantasy-Net.NLog.dll" + ] + }, + "Microsoft.Extensions.Logging.Abstractions/2.0.0": { + "sha512": "6ZCllUYGFukkymSTx3Yr0G/ajRxoNJp7/FqSxSB4fGISST54ifBhgu4Nc0ItGi3i6DqwuNd8SUyObmiC++AO2Q==", + "type": "package", + "path": "microsoft.extensions.logging.abstractions/2.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "lib/netstandard2.0/Microsoft.Extensions.Logging.Abstractions.dll", + "lib/netstandard2.0/Microsoft.Extensions.Logging.Abstractions.xml", + "microsoft.extensions.logging.abstractions.2.0.0.nupkg.sha512", + "microsoft.extensions.logging.abstractions.nuspec" + ] + }, + "Microsoft.NETCore.Platforms/5.0.0": { + "sha512": "VyPlqzH2wavqquTcYpkIIAQ6WdenuKoFN0BdYBbCWsclXacSOHNQn66Gt4z5NBqEYW0FAPm5rlvki9ZiCij5xQ==", + "type": "package", + "path": "microsoft.netcore.platforms/5.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "LICENSE.TXT", + "THIRD-PARTY-NOTICES.TXT", + "lib/netstandard1.0/_._", + "microsoft.netcore.platforms.5.0.0.nupkg.sha512", + "microsoft.netcore.platforms.nuspec", + "runtime.json", + "useSharedDesignerContext.txt", + "version.txt" + ] + }, + "Microsoft.Win32.Registry/5.0.0": { + "sha512": "dDoKi0PnDz31yAyETfRntsLArTlVAVzUzCIvvEDsDsucrl33Dl8pIJG06ePTJTI3tGpeyHS9Cq7Foc/s4EeKcg==", + "type": "package", + "path": "microsoft.win32.registry/5.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "LICENSE.TXT", + "THIRD-PARTY-NOTICES.TXT", + "lib/net46/Microsoft.Win32.Registry.dll", + "lib/net461/Microsoft.Win32.Registry.dll", + "lib/net461/Microsoft.Win32.Registry.xml", + "lib/netstandard1.3/Microsoft.Win32.Registry.dll", + "lib/netstandard2.0/Microsoft.Win32.Registry.dll", + "lib/netstandard2.0/Microsoft.Win32.Registry.xml", + "microsoft.win32.registry.5.0.0.nupkg.sha512", + "microsoft.win32.registry.nuspec", + "ref/net46/Microsoft.Win32.Registry.dll", + "ref/net461/Microsoft.Win32.Registry.dll", + "ref/net461/Microsoft.Win32.Registry.xml", + "ref/netstandard1.3/Microsoft.Win32.Registry.dll", + "ref/netstandard1.3/Microsoft.Win32.Registry.xml", + "ref/netstandard1.3/de/Microsoft.Win32.Registry.xml", + "ref/netstandard1.3/es/Microsoft.Win32.Registry.xml", + "ref/netstandard1.3/fr/Microsoft.Win32.Registry.xml", + "ref/netstandard1.3/it/Microsoft.Win32.Registry.xml", + "ref/netstandard1.3/ja/Microsoft.Win32.Registry.xml", + "ref/netstandard1.3/ko/Microsoft.Win32.Registry.xml", + "ref/netstandard1.3/ru/Microsoft.Win32.Registry.xml", + "ref/netstandard1.3/zh-hans/Microsoft.Win32.Registry.xml", + "ref/netstandard1.3/zh-hant/Microsoft.Win32.Registry.xml", + "ref/netstandard2.0/Microsoft.Win32.Registry.dll", + "ref/netstandard2.0/Microsoft.Win32.Registry.xml", + "runtimes/win/lib/net46/Microsoft.Win32.Registry.dll", + "runtimes/win/lib/net461/Microsoft.Win32.Registry.dll", + "runtimes/win/lib/net461/Microsoft.Win32.Registry.xml", + "runtimes/win/lib/netstandard1.3/Microsoft.Win32.Registry.dll", + "runtimes/win/lib/netstandard2.0/Microsoft.Win32.Registry.dll", + "runtimes/win/lib/netstandard2.0/Microsoft.Win32.Registry.xml", + "useSharedDesignerContext.txt", + "version.txt" + ] + }, + "MongoDB.Bson/3.0.0": { + "sha512": "qnPRJ58HXDh7C4oxTf6YB7BJhlCGJIa6TMXhzImw6zk44lrAomQXTB6AtoQ5lNJbkyrgQcT7+smsKFMnXmLXhw==", + "type": "package", + "path": "mongodb.bson/3.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "README.md", + "lib/net472/MongoDB.Bson.dll", + "lib/net472/MongoDB.Bson.xml", + "lib/net6.0/MongoDB.Bson.dll", + "lib/net6.0/MongoDB.Bson.xml", + "lib/netstandard2.1/MongoDB.Bson.dll", + "lib/netstandard2.1/MongoDB.Bson.xml", + "mongodb.bson.3.0.0.nupkg.sha512", + "mongodb.bson.nuspec", + "packageIcon.png" + ] + }, + "MongoDB.Driver/3.0.0": { + "sha512": "udcP8rOhyuhLDn3sGVdNUgQSXfKGPaIP4w09XVKf4xdy66YSXinhkIuQSuOeZVHdTFsG2PpUbRx2wyFm7E0EMg==", + "type": "package", + "path": "mongodb.driver/3.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "README.md", + "lib/net472/MongoDB.Driver.dll", + "lib/net472/MongoDB.Driver.xml", + "lib/net6.0/MongoDB.Driver.dll", + "lib/net6.0/MongoDB.Driver.xml", + "lib/netstandard2.1/MongoDB.Driver.dll", + "lib/netstandard2.1/MongoDB.Driver.xml", + "mongodb.driver.3.0.0.nupkg.sha512", + "mongodb.driver.nuspec", + "packageIcon.png" + ] + }, + "Newtonsoft.Json/13.0.3": { + "sha512": "HrC5BXdl00IP9zeV+0Z848QWPAoCr9P3bDEZguI+gkLcBKAOxix/tLEAAHC+UvDNPv4a2d18lOReHMOagPa+zQ==", + "type": "package", + "path": "newtonsoft.json/13.0.3", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "LICENSE.md", + "README.md", + "lib/net20/Newtonsoft.Json.dll", + "lib/net20/Newtonsoft.Json.xml", + "lib/net35/Newtonsoft.Json.dll", + "lib/net35/Newtonsoft.Json.xml", + "lib/net40/Newtonsoft.Json.dll", + "lib/net40/Newtonsoft.Json.xml", + "lib/net45/Newtonsoft.Json.dll", + "lib/net45/Newtonsoft.Json.xml", + "lib/net6.0/Newtonsoft.Json.dll", + "lib/net6.0/Newtonsoft.Json.xml", + "lib/netstandard1.0/Newtonsoft.Json.dll", + "lib/netstandard1.0/Newtonsoft.Json.xml", + "lib/netstandard1.3/Newtonsoft.Json.dll", + "lib/netstandard1.3/Newtonsoft.Json.xml", + "lib/netstandard2.0/Newtonsoft.Json.dll", + "lib/netstandard2.0/Newtonsoft.Json.xml", + "newtonsoft.json.13.0.3.nupkg.sha512", + "newtonsoft.json.nuspec", + "packageIcon.png" + ] + }, + "NLog/5.3.4": { + "sha512": "gLy7+O1hEYJXIlcTr1/VWjGXrZTQFZzYNO18IWasD64pNwz0BreV+nHLxWKXWZzERRzoKnsk2XYtwLkTVk7J1A==", + "type": "package", + "path": "nlog/5.3.4", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "N.png", + "lib/net35/NLog.dll", + "lib/net35/NLog.xml", + "lib/net45/NLog.dll", + "lib/net45/NLog.xml", + "lib/net46/NLog.dll", + "lib/net46/NLog.xml", + "lib/netstandard1.3/NLog.dll", + "lib/netstandard1.3/NLog.xml", + "lib/netstandard1.5/NLog.dll", + "lib/netstandard1.5/NLog.xml", + "lib/netstandard2.0/NLog.dll", + "lib/netstandard2.0/NLog.xml", + "nlog.5.3.4.nupkg.sha512", + "nlog.nuspec" + ] + }, + "protobuf-net/3.2.45": { + "sha512": "5UZ/ukUHcGbFSl7vNMrHsfjqdxusdd9w7w0fCEXzf3UUtsrGNVCzV5SmF+sCHAbnRV2qPcD1ixiDP7Aj8lX/HA==", + "type": "package", + "path": "protobuf-net/3.2.45", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "lib/net462/protobuf-net.dll", + "lib/net462/protobuf-net.xml", + "lib/net6.0/protobuf-net.dll", + "lib/net6.0/protobuf-net.xml", + "lib/netstandard2.0/protobuf-net.dll", + "lib/netstandard2.0/protobuf-net.xml", + "lib/netstandard2.1/protobuf-net.dll", + "lib/netstandard2.1/protobuf-net.xml", + "protobuf-net.3.2.45.nupkg.sha512", + "protobuf-net.nuspec", + "protobuf-net.png", + "readme.md" + ] + }, + "protobuf-net.Core/3.2.45": { + "sha512": "PMWatW2NrT1uTXD7etJ4VdQ0wWZLFrIfdRGppD2QX7nzZ0+kIzqhq551u6ZiXJHWJgG4hWFEkSnUnt2aB6posg==", + "type": "package", + "path": "protobuf-net.core/3.2.45", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "lib/net462/protobuf-net.Core.dll", + "lib/net462/protobuf-net.Core.xml", + "lib/net6.0/protobuf-net.Core.dll", + "lib/net6.0/protobuf-net.Core.xml", + "lib/netstandard2.0/protobuf-net.Core.dll", + "lib/netstandard2.0/protobuf-net.Core.xml", + "lib/netstandard2.1/protobuf-net.Core.dll", + "lib/netstandard2.1/protobuf-net.Core.xml", + "protobuf-net.core.3.2.45.nupkg.sha512", + "protobuf-net.core.nuspec", + "protobuf-net.png", + "readme.md" + ] + }, + "SharpCompress/0.30.1": { + "sha512": "XqD4TpfyYGa7QTPzaGlMVbcecKnXy4YmYLDWrU+JIj7IuRNl7DH2END+Ll7ekWIY8o3dAMWLFDE1xdhfIWD1nw==", + "type": "package", + "path": "sharpcompress/0.30.1", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "lib/net461/SharpCompress.dll", + "lib/net5.0/SharpCompress.dll", + "lib/netcoreapp3.1/SharpCompress.dll", + "lib/netstandard2.0/SharpCompress.dll", + "lib/netstandard2.1/SharpCompress.dll", + "sharpcompress.0.30.1.nupkg.sha512", + "sharpcompress.nuspec" + ] + }, + "Snappier/1.0.0": { + "sha512": "rFtK2KEI9hIe8gtx3a0YDXdHOpedIf9wYCEYtBEmtlyiWVX3XlCNV03JrmmAi/Cdfn7dxK+k0sjjcLv4fpHnqA==", + "type": "package", + "path": "snappier/1.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "COPYING.txt", + "lib/net5.0/Snappier.dll", + "lib/net5.0/Snappier.xml", + "lib/netcoreapp3.0/Snappier.dll", + "lib/netcoreapp3.0/Snappier.xml", + "lib/netstandard2.0/Snappier.dll", + "lib/netstandard2.0/Snappier.xml", + "lib/netstandard2.1/Snappier.dll", + "lib/netstandard2.1/Snappier.xml", + "snappier.1.0.0.nupkg.sha512", + "snappier.nuspec" + ] + }, + "System.Buffers/4.5.1": { + "sha512": "Rw7ijyl1qqRS0YQD/WycNst8hUUMgrMH4FCn1nNm27M4VxchZ1js3fVjQaANHO5f3sN4isvP4a+Met9Y4YomAg==", + "type": "package", + "path": "system.buffers/4.5.1", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "LICENSE.TXT", + "THIRD-PARTY-NOTICES.TXT", + "lib/net461/System.Buffers.dll", + "lib/net461/System.Buffers.xml", + "lib/netcoreapp2.0/_._", + "lib/netstandard1.1/System.Buffers.dll", + "lib/netstandard1.1/System.Buffers.xml", + "lib/netstandard2.0/System.Buffers.dll", + "lib/netstandard2.0/System.Buffers.xml", + "lib/uap10.0.16299/_._", + "ref/net45/System.Buffers.dll", + "ref/net45/System.Buffers.xml", + "ref/netcoreapp2.0/_._", + "ref/netstandard1.1/System.Buffers.dll", + "ref/netstandard1.1/System.Buffers.xml", + "ref/netstandard2.0/System.Buffers.dll", + "ref/netstandard2.0/System.Buffers.xml", + "ref/uap10.0.16299/_._", + "system.buffers.4.5.1.nupkg.sha512", + "system.buffers.nuspec", + "useSharedDesignerContext.txt", + "version.txt" + ] + }, + "System.Collections.Immutable/7.0.0": { + "sha512": "dQPcs0U1IKnBdRDBkrCTi1FoajSTBzLcVTpjO4MBCMC7f4pDOIPzgBoX8JjG7X6uZRJ8EBxsi8+DR1JuwjnzOQ==", + "type": "package", + "path": "system.collections.immutable/7.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "LICENSE.TXT", + "README.md", + "THIRD-PARTY-NOTICES.TXT", + "buildTransitive/net461/System.Collections.Immutable.targets", + "buildTransitive/net462/_._", + "buildTransitive/net6.0/_._", + "buildTransitive/netcoreapp2.0/System.Collections.Immutable.targets", + "lib/net462/System.Collections.Immutable.dll", + "lib/net462/System.Collections.Immutable.xml", + "lib/net6.0/System.Collections.Immutable.dll", + "lib/net6.0/System.Collections.Immutable.xml", + "lib/net7.0/System.Collections.Immutable.dll", + "lib/net7.0/System.Collections.Immutable.xml", + "lib/netstandard2.0/System.Collections.Immutable.dll", + "lib/netstandard2.0/System.Collections.Immutable.xml", + "system.collections.immutable.7.0.0.nupkg.sha512", + "system.collections.immutable.nuspec", + "useSharedDesignerContext.txt" + ] + }, + "System.IO.Pipelines/8.0.0": { + "sha512": "FHNOatmUq0sqJOkTx+UF/9YK1f180cnW5FVqnQMvYUN0elp6wFzbtPSiqbo1/ru8ICp43JM1i7kKkk6GsNGHlA==", + "type": "package", + "path": "system.io.pipelines/8.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "LICENSE.TXT", + "THIRD-PARTY-NOTICES.TXT", + "buildTransitive/net461/System.IO.Pipelines.targets", + "buildTransitive/net462/_._", + "buildTransitive/net6.0/_._", + "buildTransitive/netcoreapp2.0/System.IO.Pipelines.targets", + "lib/net462/System.IO.Pipelines.dll", + "lib/net462/System.IO.Pipelines.xml", + "lib/net6.0/System.IO.Pipelines.dll", + "lib/net6.0/System.IO.Pipelines.xml", + "lib/net7.0/System.IO.Pipelines.dll", + "lib/net7.0/System.IO.Pipelines.xml", + "lib/net8.0/System.IO.Pipelines.dll", + "lib/net8.0/System.IO.Pipelines.xml", + "lib/netstandard2.0/System.IO.Pipelines.dll", + "lib/netstandard2.0/System.IO.Pipelines.xml", + "system.io.pipelines.8.0.0.nupkg.sha512", + "system.io.pipelines.nuspec", + "useSharedDesignerContext.txt" + ] + }, + "System.Memory/4.5.5": { + "sha512": "XIWiDvKPXaTveaB7HVganDlOCRoj03l+jrwNvcge/t8vhGYKvqV+dMv6G4SAX2NoNmN0wZfVPTAlFwZcZvVOUw==", + "type": "package", + "path": "system.memory/4.5.5", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "LICENSE.TXT", + "THIRD-PARTY-NOTICES.TXT", + "lib/net461/System.Memory.dll", + "lib/net461/System.Memory.xml", + "lib/netcoreapp2.1/_._", + "lib/netstandard1.1/System.Memory.dll", + "lib/netstandard1.1/System.Memory.xml", + "lib/netstandard2.0/System.Memory.dll", + "lib/netstandard2.0/System.Memory.xml", + "ref/netcoreapp2.1/_._", + "system.memory.4.5.5.nupkg.sha512", + "system.memory.nuspec", + "useSharedDesignerContext.txt", + "version.txt" + ] + }, + "System.Runtime.CompilerServices.Unsafe/5.0.0": { + "sha512": "ZD9TMpsmYJLrxbbmdvhwt9YEgG5WntEnZ/d1eH8JBX9LBp+Ju8BSBhUGbZMNVHHomWo2KVImJhTDl2hIgw/6MA==", + "type": "package", + "path": "system.runtime.compilerservices.unsafe/5.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "LICENSE.TXT", + "THIRD-PARTY-NOTICES.TXT", + "lib/net45/System.Runtime.CompilerServices.Unsafe.dll", + "lib/net45/System.Runtime.CompilerServices.Unsafe.xml", + "lib/netcoreapp2.0/System.Runtime.CompilerServices.Unsafe.dll", + "lib/netcoreapp2.0/System.Runtime.CompilerServices.Unsafe.xml", + "lib/netstandard1.0/System.Runtime.CompilerServices.Unsafe.dll", + "lib/netstandard1.0/System.Runtime.CompilerServices.Unsafe.xml", + "lib/netstandard2.0/System.Runtime.CompilerServices.Unsafe.dll", + "lib/netstandard2.0/System.Runtime.CompilerServices.Unsafe.xml", + "ref/net461/System.Runtime.CompilerServices.Unsafe.dll", + "ref/net461/System.Runtime.CompilerServices.Unsafe.xml", + "ref/netstandard1.0/System.Runtime.CompilerServices.Unsafe.dll", + "ref/netstandard1.0/System.Runtime.CompilerServices.Unsafe.xml", + "ref/netstandard2.0/System.Runtime.CompilerServices.Unsafe.dll", + "ref/netstandard2.0/System.Runtime.CompilerServices.Unsafe.xml", + "ref/netstandard2.1/System.Runtime.CompilerServices.Unsafe.dll", + "ref/netstandard2.1/System.Runtime.CompilerServices.Unsafe.xml", + "system.runtime.compilerservices.unsafe.5.0.0.nupkg.sha512", + "system.runtime.compilerservices.unsafe.nuspec", + "useSharedDesignerContext.txt", + "version.txt" + ] + }, + "System.Security.AccessControl/5.0.0": { + "sha512": "dagJ1mHZO3Ani8GH0PHpPEe/oYO+rVdbQjvjJkBRNQkX4t0r1iaeGn8+/ybkSLEan3/slM0t59SVdHzuHf2jmw==", + "type": "package", + "path": "system.security.accesscontrol/5.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "LICENSE.TXT", + "THIRD-PARTY-NOTICES.TXT", + "lib/net46/System.Security.AccessControl.dll", + "lib/net461/System.Security.AccessControl.dll", + "lib/net461/System.Security.AccessControl.xml", + "lib/netstandard1.3/System.Security.AccessControl.dll", + "lib/netstandard2.0/System.Security.AccessControl.dll", + "lib/netstandard2.0/System.Security.AccessControl.xml", + "lib/uap10.0.16299/_._", + "ref/net46/System.Security.AccessControl.dll", + "ref/net461/System.Security.AccessControl.dll", + "ref/net461/System.Security.AccessControl.xml", + "ref/netstandard1.3/System.Security.AccessControl.dll", + "ref/netstandard1.3/System.Security.AccessControl.xml", + "ref/netstandard1.3/de/System.Security.AccessControl.xml", + "ref/netstandard1.3/es/System.Security.AccessControl.xml", + "ref/netstandard1.3/fr/System.Security.AccessControl.xml", + "ref/netstandard1.3/it/System.Security.AccessControl.xml", + "ref/netstandard1.3/ja/System.Security.AccessControl.xml", + "ref/netstandard1.3/ko/System.Security.AccessControl.xml", + "ref/netstandard1.3/ru/System.Security.AccessControl.xml", + "ref/netstandard1.3/zh-hans/System.Security.AccessControl.xml", + "ref/netstandard1.3/zh-hant/System.Security.AccessControl.xml", + "ref/netstandard2.0/System.Security.AccessControl.dll", + "ref/netstandard2.0/System.Security.AccessControl.xml", + "ref/uap10.0.16299/_._", + "runtimes/win/lib/net46/System.Security.AccessControl.dll", + "runtimes/win/lib/net461/System.Security.AccessControl.dll", + "runtimes/win/lib/net461/System.Security.AccessControl.xml", + "runtimes/win/lib/netcoreapp2.0/System.Security.AccessControl.dll", + "runtimes/win/lib/netcoreapp2.0/System.Security.AccessControl.xml", + "runtimes/win/lib/netstandard1.3/System.Security.AccessControl.dll", + "runtimes/win/lib/uap10.0.16299/_._", + "system.security.accesscontrol.5.0.0.nupkg.sha512", + "system.security.accesscontrol.nuspec", + "useSharedDesignerContext.txt", + "version.txt" + ] + }, + "System.Security.Principal.Windows/5.0.0": { + "sha512": "t0MGLukB5WAVU9bO3MGzvlGnyJPgUlcwerXn1kzBRjwLKixT96XV0Uza41W49gVd8zEMFu9vQEFlv0IOrytICA==", + "type": "package", + "path": "system.security.principal.windows/5.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "LICENSE.TXT", + "THIRD-PARTY-NOTICES.TXT", + "lib/net46/System.Security.Principal.Windows.dll", + "lib/net461/System.Security.Principal.Windows.dll", + "lib/net461/System.Security.Principal.Windows.xml", + "lib/netstandard1.3/System.Security.Principal.Windows.dll", + "lib/netstandard2.0/System.Security.Principal.Windows.dll", + "lib/netstandard2.0/System.Security.Principal.Windows.xml", + "lib/uap10.0.16299/_._", + "ref/net46/System.Security.Principal.Windows.dll", + "ref/net461/System.Security.Principal.Windows.dll", + "ref/net461/System.Security.Principal.Windows.xml", + "ref/netcoreapp3.0/System.Security.Principal.Windows.dll", + "ref/netcoreapp3.0/System.Security.Principal.Windows.xml", + "ref/netstandard1.3/System.Security.Principal.Windows.dll", + "ref/netstandard1.3/System.Security.Principal.Windows.xml", + "ref/netstandard1.3/de/System.Security.Principal.Windows.xml", + "ref/netstandard1.3/es/System.Security.Principal.Windows.xml", + "ref/netstandard1.3/fr/System.Security.Principal.Windows.xml", + "ref/netstandard1.3/it/System.Security.Principal.Windows.xml", + "ref/netstandard1.3/ja/System.Security.Principal.Windows.xml", + "ref/netstandard1.3/ko/System.Security.Principal.Windows.xml", + "ref/netstandard1.3/ru/System.Security.Principal.Windows.xml", + "ref/netstandard1.3/zh-hans/System.Security.Principal.Windows.xml", + "ref/netstandard1.3/zh-hant/System.Security.Principal.Windows.xml", + "ref/netstandard2.0/System.Security.Principal.Windows.dll", + "ref/netstandard2.0/System.Security.Principal.Windows.xml", + "ref/uap10.0.16299/_._", + "runtimes/unix/lib/netcoreapp2.0/System.Security.Principal.Windows.dll", + "runtimes/unix/lib/netcoreapp2.0/System.Security.Principal.Windows.xml", + "runtimes/unix/lib/netcoreapp2.1/System.Security.Principal.Windows.dll", + "runtimes/unix/lib/netcoreapp2.1/System.Security.Principal.Windows.xml", + "runtimes/win/lib/net46/System.Security.Principal.Windows.dll", + "runtimes/win/lib/net461/System.Security.Principal.Windows.dll", + "runtimes/win/lib/net461/System.Security.Principal.Windows.xml", + "runtimes/win/lib/netcoreapp2.0/System.Security.Principal.Windows.dll", + "runtimes/win/lib/netcoreapp2.0/System.Security.Principal.Windows.xml", + "runtimes/win/lib/netcoreapp2.1/System.Security.Principal.Windows.dll", + "runtimes/win/lib/netcoreapp2.1/System.Security.Principal.Windows.xml", + "runtimes/win/lib/netstandard1.3/System.Security.Principal.Windows.dll", + "runtimes/win/lib/uap10.0.16299/_._", + "system.security.principal.windows.5.0.0.nupkg.sha512", + "system.security.principal.windows.nuspec", + "useSharedDesignerContext.txt", + "version.txt" + ] + }, + "ZstdSharp.Port/0.7.3": { + "sha512": "U9Ix4l4cl58Kzz1rJzj5hoVTjmbx1qGMwzAcbv1j/d3NzrFaESIurQyg+ow4mivCgkE3S413y+U9k4WdnEIkRA==", + "type": "package", + "path": "zstdsharp.port/0.7.3", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "lib/net461/ZstdSharp.dll", + "lib/net5.0/ZstdSharp.dll", + "lib/net6.0/ZstdSharp.dll", + "lib/net7.0/ZstdSharp.dll", + "lib/netcoreapp3.1/ZstdSharp.dll", + "lib/netstandard2.0/ZstdSharp.dll", + "lib/netstandard2.1/ZstdSharp.dll", + "zstdsharp.port.0.7.3.nupkg.sha512", + "zstdsharp.port.nuspec" + ] + }, + "Entity/1.0.0": { + "type": "project", + "path": "../Entity/Entity.csproj", + "msbuildProject": "../Entity/Entity.csproj" + }, + "Hotfix/1.0.0": { + "type": "project", + "path": "../Hotfix/Hotfix.csproj", + "msbuildProject": "../Hotfix/Hotfix.csproj" + } + }, + "projectFileDependencyGroups": { + "net8.0": [ + "Entity >= 1.0.0", + "Fantasy-Net.NLog >= 2024.1.3", + "Hotfix >= 1.0.0" + ] + }, + "packageFolders": { + "/Users/fantasy/.nuget/packages/": {} + }, + "project": { + "version": "1.0.0", + "restore": { + "projectUniqueName": "/Users/fantasy/Code/ServerLessions/Chat/Server/Main/Main.csproj", + "projectName": "Main", + "projectPath": "/Users/fantasy/Code/ServerLessions/Chat/Server/Main/Main.csproj", + "packagesPath": "/Users/fantasy/.nuget/packages/", + "outputPath": "/Users/fantasy/Code/ServerLessions/Chat/Server/Main/obj/", + "projectStyle": "PackageReference", + "UsingMicrosoftNETSdk": false, + "configFilePaths": [ + "/Users/fantasy/.nuget/NuGet/NuGet.Config" + ], + "originalTargetFrameworks": [ + "net8.0" + ], + "sources": { + "https://api.nuget.org/v3/index.json": {} + }, + "frameworks": { + "net8.0": { + "targetAlias": "net8.0", + "projectReferences": { + "/Users/fantasy/Code/ServerLessions/Chat/Server/Entity/Entity.csproj": { + "projectPath": "/Users/fantasy/Code/ServerLessions/Chat/Server/Entity/Entity.csproj" + }, + "/Users/fantasy/Code/ServerLessions/Chat/Server/Hotfix/Hotfix.csproj": { + "projectPath": "/Users/fantasy/Code/ServerLessions/Chat/Server/Hotfix/Hotfix.csproj" + } + } + } + }, + "warningProperties": { + "warnAsError": [ + "NU1605" + ] + }, + "restoreAuditProperties": { + "enableAudit": "true", + "auditLevel": "low", + "auditMode": "all" + } + }, + "frameworks": { + "net8.0": { + "targetAlias": "net8.0", + "dependencies": { + "Fantasy-Net.NLog": { + "target": "Package", + "version": "[2024.1.3, )" + } + }, + "imports": [ + "net461", + "net462", + "net47", + "net471", + "net472", + "net48", + "net481" + ], + "assetTargetFallback": true, + "warn": true, + "frameworkReferences": { + "Microsoft.NETCore.App": { + "privateAssets": "all" + } + }, + "runtimeIdentifierGraphPath": "/usr/local/share/dotnet/sdk/9.0.100/PortableRuntimeIdentifierGraph.json" + } + } + } +} \ No newline at end of file diff --git a/聊天系统课程代码/Server/Main/obj/project.nuget.cache b/聊天系统课程代码/Server/Main/obj/project.nuget.cache new file mode 100644 index 0000000..6a6e25a --- /dev/null +++ b/聊天系统课程代码/Server/Main/obj/project.nuget.cache @@ -0,0 +1,32 @@ +{ + "version": 2, + "dgSpecHash": "+WkSO6wQaaY=", + "success": true, + "projectFilePath": "/Users/fantasy/Code/ServerLessions/Chat/Server/Main/Main.csproj", + "expectedPackageFiles": [ + "/Users/fantasy/.nuget/packages/commandlineparser/2.9.1/commandlineparser.2.9.1.nupkg.sha512", + "/Users/fantasy/.nuget/packages/dnsclient/1.6.1/dnsclient.1.6.1.nupkg.sha512", + "/Users/fantasy/.nuget/packages/fantasy-net/2024.1.17/fantasy-net.2024.1.17.nupkg.sha512", + "/Users/fantasy/.nuget/packages/fantasy-net.nlog/2024.1.3/fantasy-net.nlog.2024.1.3.nupkg.sha512", + "/Users/fantasy/.nuget/packages/microsoft.extensions.logging.abstractions/2.0.0/microsoft.extensions.logging.abstractions.2.0.0.nupkg.sha512", + "/Users/fantasy/.nuget/packages/microsoft.netcore.platforms/5.0.0/microsoft.netcore.platforms.5.0.0.nupkg.sha512", + "/Users/fantasy/.nuget/packages/microsoft.win32.registry/5.0.0/microsoft.win32.registry.5.0.0.nupkg.sha512", + "/Users/fantasy/.nuget/packages/mongodb.bson/3.0.0/mongodb.bson.3.0.0.nupkg.sha512", + "/Users/fantasy/.nuget/packages/mongodb.driver/3.0.0/mongodb.driver.3.0.0.nupkg.sha512", + "/Users/fantasy/.nuget/packages/newtonsoft.json/13.0.3/newtonsoft.json.13.0.3.nupkg.sha512", + "/Users/fantasy/.nuget/packages/nlog/5.3.4/nlog.5.3.4.nupkg.sha512", + "/Users/fantasy/.nuget/packages/protobuf-net/3.2.45/protobuf-net.3.2.45.nupkg.sha512", + "/Users/fantasy/.nuget/packages/protobuf-net.core/3.2.45/protobuf-net.core.3.2.45.nupkg.sha512", + "/Users/fantasy/.nuget/packages/sharpcompress/0.30.1/sharpcompress.0.30.1.nupkg.sha512", + "/Users/fantasy/.nuget/packages/snappier/1.0.0/snappier.1.0.0.nupkg.sha512", + "/Users/fantasy/.nuget/packages/system.buffers/4.5.1/system.buffers.4.5.1.nupkg.sha512", + "/Users/fantasy/.nuget/packages/system.collections.immutable/7.0.0/system.collections.immutable.7.0.0.nupkg.sha512", + "/Users/fantasy/.nuget/packages/system.io.pipelines/8.0.0/system.io.pipelines.8.0.0.nupkg.sha512", + "/Users/fantasy/.nuget/packages/system.memory/4.5.5/system.memory.4.5.5.nupkg.sha512", + "/Users/fantasy/.nuget/packages/system.runtime.compilerservices.unsafe/5.0.0/system.runtime.compilerservices.unsafe.5.0.0.nupkg.sha512", + "/Users/fantasy/.nuget/packages/system.security.accesscontrol/5.0.0/system.security.accesscontrol.5.0.0.nupkg.sha512", + "/Users/fantasy/.nuget/packages/system.security.principal.windows/5.0.0/system.security.principal.windows.5.0.0.nupkg.sha512", + "/Users/fantasy/.nuget/packages/zstdsharp.port/0.7.3/zstdsharp.port.0.7.3.nupkg.sha512" + ], + "logs": [] +} \ No newline at end of file diff --git a/聊天系统课程代码/Server/Main/obj/project.packagespec.json b/聊天系统课程代码/Server/Main/obj/project.packagespec.json new file mode 100644 index 0000000..d56ba53 --- /dev/null +++ b/聊天系统课程代码/Server/Main/obj/project.packagespec.json @@ -0,0 +1 @@ +"restore":{"projectUniqueName":"/Users/fantasy/Code/ServerLessions/Chat/Server/Main/Main.csproj","projectName":"Main","projectPath":"/Users/fantasy/Code/ServerLessions/Chat/Server/Main/Main.csproj","outputPath":"/Users/fantasy/Code/ServerLessions/Chat/Server/Main/obj/","projectStyle":"PackageReference","UsingMicrosoftNETSdk":false,"originalTargetFrameworks":["net8.0"],"sources":{"https://api.nuget.org/v3/index.json":{}},"frameworks":{"net8.0":{"targetAlias":"net8.0","projectReferences":{"/Users/fantasy/Code/ServerLessions/Chat/Server/Entity/Entity.csproj":{"projectPath":"/Users/fantasy/Code/ServerLessions/Chat/Server/Entity/Entity.csproj"},"/Users/fantasy/Code/ServerLessions/Chat/Server/Hotfix/Hotfix.csproj":{"projectPath":"/Users/fantasy/Code/ServerLessions/Chat/Server/Hotfix/Hotfix.csproj"}}}},"warningProperties":{"warnAsError":["NU1605"]},"restoreAuditProperties":{"enableAudit":"true","auditLevel":"low","auditMode":"all"}}"frameworks":{"net8.0":{"targetAlias":"net8.0","dependencies":{"Fantasy-Net.NLog":{"target":"Package","version":"[2024.1.3, )"}},"imports":["net461","net462","net47","net471","net472","net48","net481"],"assetTargetFallback":true,"warn":true,"frameworkReferences":{"Microsoft.NETCore.App":{"privateAssets":"all"}},"runtimeIdentifierGraphPath":"/usr/local/share/dotnet/sdk/9.0.100/PortableRuntimeIdentifierGraph.json"}} \ No newline at end of file diff --git a/聊天系统课程代码/Server/Main/obj/rider.project.model.nuget.info b/聊天系统课程代码/Server/Main/obj/rider.project.model.nuget.info new file mode 100644 index 0000000..95ccddb --- /dev/null +++ b/聊天系统课程代码/Server/Main/obj/rider.project.model.nuget.info @@ -0,0 +1 @@ +17324493181399999 \ No newline at end of file diff --git a/聊天系统课程代码/Server/Main/obj/rider.project.restore.info b/聊天系统课程代码/Server/Main/obj/rider.project.restore.info new file mode 100644 index 0000000..3d64580 --- /dev/null +++ b/聊天系统课程代码/Server/Main/obj/rider.project.restore.info @@ -0,0 +1 @@ +17331012454241645 \ No newline at end of file diff --git a/聊天系统课程代码/Tools/.DS_Store b/聊天系统课程代码/Tools/.DS_Store new file mode 100644 index 0000000..496f385 Binary files /dev/null and b/聊天系统课程代码/Tools/.DS_Store differ diff --git a/聊天系统课程代码/Tools/ConfigTable/CommandLine.dll b/聊天系统课程代码/Tools/ConfigTable/CommandLine.dll new file mode 100644 index 0000000..3eab2be Binary files /dev/null and b/聊天系统课程代码/Tools/ConfigTable/CommandLine.dll differ diff --git a/聊天系统课程代码/Tools/ConfigTable/EPPlus.Interfaces.dll b/聊天系统课程代码/Tools/ConfigTable/EPPlus.Interfaces.dll new file mode 100644 index 0000000..599a767 Binary files /dev/null and b/聊天系统课程代码/Tools/ConfigTable/EPPlus.Interfaces.dll differ diff --git a/聊天系统课程代码/Tools/ConfigTable/EPPlus.System.Drawing.dll b/聊天系统课程代码/Tools/ConfigTable/EPPlus.System.Drawing.dll new file mode 100644 index 0000000..8df125e Binary files /dev/null and b/聊天系统课程代码/Tools/ConfigTable/EPPlus.System.Drawing.dll differ diff --git a/聊天系统课程代码/Tools/ConfigTable/EPPlus.dll b/聊天系统课程代码/Tools/ConfigTable/EPPlus.dll new file mode 100644 index 0000000..b09ea77 Binary files /dev/null and b/聊天系统课程代码/Tools/ConfigTable/EPPlus.dll differ diff --git a/聊天系统课程代码/Tools/ConfigTable/ExporterSettings.json b/聊天系统课程代码/Tools/ConfigTable/ExporterSettings.json new file mode 100644 index 0000000..27287ac --- /dev/null +++ b/聊天系统课程代码/Tools/ConfigTable/ExporterSettings.json @@ -0,0 +1,44 @@ +{ + "Export": { + "ExcelProgramPath": { + "Value": "../../Config/Excel/", + "Comment": "Excel文件夹的根目录" + }, + "ExcelVersionFile": { + "Value": "../../Config/Excel/Version.txt", + "Comment": "Excel的Version文件位置、这个文件用于记录每次导出对比是否需要再次导出的文件" + }, + "ExcelServerFileDirectory": { + "Value": "../../Server/Entity/Generate/ConfigTable/Entity/", + "Comment": "Excel生成的代码文件、在服务端文件夹位置" + }, + "ExcelClientFileDirectory": { + "Value": "../../Client/Unity/Assets/Scripts/Hotfix/Generate/ConfigTable/Entity/", + "Comment": "Excel生成的代码文件、在客户端文件夹位置" + }, + "ExcelServerBinaryDirectory": { + "Value": "../../Config/Binary/", + "Comment": "Excel生成服务器二进制数据文件夹位置" + }, + "ExcelClientBinaryDirectory": { + "Value": "../../Client/Unity/Assets/Bundles/Config/", + "Comment": "Excel生成在客户端的二进制数据文件夹位置" + }, + "ExcelServerJsonDirectory": { + "Value": "../../Config/Json/Server/", + "Comment": "Excel生成在服务端的Json数据文件夹位置" + }, + "ExcelClientJsonDirectory": { + "Value": "../../Config/Json/Client/", + "Comment": "Excel生成在客户端的Json数据文件夹位置" + }, + "ServerCustomExportDirectory": { + "Value": "../../Server/Entity/Generate/CustomExport/", + "Comment": "Excel在服务端生成自定义代码的文件夹位置" + }, + "ClientCustomExportDirectory": { + "Value": "../../Client/Unity/Assets/Scripts/Hotfix/Generate/CustomExport", + "Comment": "Excel在客户端端生成自定义代码的文件夹位置" + } + } +} \ No newline at end of file diff --git a/聊天系统课程代码/Tools/ConfigTable/Fantasy.Tools.ConfigTable b/聊天系统课程代码/Tools/ConfigTable/Fantasy.Tools.ConfigTable new file mode 100644 index 0000000..434496e Binary files /dev/null and b/聊天系统课程代码/Tools/ConfigTable/Fantasy.Tools.ConfigTable differ diff --git a/聊天系统课程代码/Tools/ConfigTable/Fantasy.Tools.ConfigTable.deps.json b/聊天系统课程代码/Tools/ConfigTable/Fantasy.Tools.ConfigTable.deps.json new file mode 100644 index 0000000..b248849 --- /dev/null +++ b/聊天系统课程代码/Tools/ConfigTable/Fantasy.Tools.ConfigTable.deps.json @@ -0,0 +1,521 @@ +{ + "runtimeTarget": { + "name": ".NETCoreApp,Version=v8.0", + "signature": "" + }, + "compilationOptions": {}, + "targets": { + ".NETCoreApp,Version=v8.0": { + "Fantasy.Tools.ConfigTable/1.0.0": { + "dependencies": { + "CommandLineParser": "2.9.1", + "EPPlus": "7.3.2", + "Microsoft.CodeAnalysis.CSharp": "4.11.0", + "Microsoft.Extensions.Configuration.Json": "8.0.0", + "Newtonsoft.Json": "13.0.3", + "protobuf-net": "3.2.30" + }, + "runtime": { + "Fantasy.Tools.ConfigTable.dll": {} + } + }, + "CommandLineParser/2.9.1": { + "runtime": { + "lib/netstandard2.0/CommandLine.dll": { + "assemblyVersion": "2.9.1.0", + "fileVersion": "2.9.1.0" + } + } + }, + "EPPlus/7.3.2": { + "dependencies": { + "EPPlus.System.Drawing": "6.1.1", + "Microsoft.Extensions.Configuration.Json": "8.0.0", + "Microsoft.IO.RecyclableMemoryStream": "3.0.1", + "System.ComponentModel.Annotations": "5.0.0", + "System.Formats.Asn1": "8.0.1", + "System.Security.Cryptography.Pkcs": "8.0.0", + "System.Text.Encoding.CodePages": "8.0.0", + "System.Text.Json": "8.0.4" + }, + "runtime": { + "lib/net8.0/EPPlus.dll": { + "assemblyVersion": "7.3.2.0", + "fileVersion": "7.3.2.0" + } + } + }, + "EPPlus.Interfaces/6.1.1": { + "runtime": { + "lib/net7.0/EPPlus.Interfaces.dll": { + "assemblyVersion": "6.1.1.0", + "fileVersion": "6.1.1.0" + } + } + }, + "EPPlus.System.Drawing/6.1.1": { + "dependencies": { + "EPPlus.Interfaces": "6.1.1", + "System.Drawing.Common": "7.0.0" + }, + "runtime": { + "lib/net7.0/EPPlus.System.Drawing.dll": { + "assemblyVersion": "6.1.1.0", + "fileVersion": "6.1.1.0" + } + } + }, + "Microsoft.CodeAnalysis.Analyzers/3.3.4": {}, + "Microsoft.CodeAnalysis.Common/4.11.0": { + "dependencies": { + "Microsoft.CodeAnalysis.Analyzers": "3.3.4", + "System.Collections.Immutable": "8.0.0", + "System.Reflection.Metadata": "8.0.0" + }, + "runtime": { + "lib/net8.0/Microsoft.CodeAnalysis.dll": { + "assemblyVersion": "4.11.0.0", + "fileVersion": "4.1100.24.37604" + } + } + }, + "Microsoft.CodeAnalysis.CSharp/4.11.0": { + "dependencies": { + "Microsoft.CodeAnalysis.Analyzers": "3.3.4", + "Microsoft.CodeAnalysis.Common": "4.11.0", + "System.Collections.Immutable": "8.0.0", + "System.Reflection.Metadata": "8.0.0" + }, + "runtime": { + "lib/net8.0/Microsoft.CodeAnalysis.CSharp.dll": { + "assemblyVersion": "4.11.0.0", + "fileVersion": "4.1100.24.37604" + } + } + }, + "Microsoft.Extensions.Configuration/8.0.0": { + "dependencies": { + "Microsoft.Extensions.Configuration.Abstractions": "8.0.0", + "Microsoft.Extensions.Primitives": "8.0.0" + }, + "runtime": { + "lib/net8.0/Microsoft.Extensions.Configuration.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.23.53103" + } + } + }, + "Microsoft.Extensions.Configuration.Abstractions/8.0.0": { + "dependencies": { + "Microsoft.Extensions.Primitives": "8.0.0" + }, + "runtime": { + "lib/net8.0/Microsoft.Extensions.Configuration.Abstractions.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.23.53103" + } + } + }, + "Microsoft.Extensions.Configuration.FileExtensions/8.0.0": { + "dependencies": { + "Microsoft.Extensions.Configuration": "8.0.0", + "Microsoft.Extensions.Configuration.Abstractions": "8.0.0", + "Microsoft.Extensions.FileProviders.Abstractions": "8.0.0", + "Microsoft.Extensions.FileProviders.Physical": "8.0.0", + "Microsoft.Extensions.Primitives": "8.0.0" + }, + "runtime": { + "lib/net8.0/Microsoft.Extensions.Configuration.FileExtensions.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.23.53103" + } + } + }, + "Microsoft.Extensions.Configuration.Json/8.0.0": { + "dependencies": { + "Microsoft.Extensions.Configuration": "8.0.0", + "Microsoft.Extensions.Configuration.Abstractions": "8.0.0", + "Microsoft.Extensions.Configuration.FileExtensions": "8.0.0", + "Microsoft.Extensions.FileProviders.Abstractions": "8.0.0", + "System.Text.Json": "8.0.4" + }, + "runtime": { + "lib/net8.0/Microsoft.Extensions.Configuration.Json.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.23.53103" + } + } + }, + "Microsoft.Extensions.FileProviders.Abstractions/8.0.0": { + "dependencies": { + "Microsoft.Extensions.Primitives": "8.0.0" + }, + "runtime": { + "lib/net8.0/Microsoft.Extensions.FileProviders.Abstractions.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.23.53103" + } + } + }, + "Microsoft.Extensions.FileProviders.Physical/8.0.0": { + "dependencies": { + "Microsoft.Extensions.FileProviders.Abstractions": "8.0.0", + "Microsoft.Extensions.FileSystemGlobbing": "8.0.0", + "Microsoft.Extensions.Primitives": "8.0.0" + }, + "runtime": { + "lib/net8.0/Microsoft.Extensions.FileProviders.Physical.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.23.53103" + } + } + }, + "Microsoft.Extensions.FileSystemGlobbing/8.0.0": { + "runtime": { + "lib/net8.0/Microsoft.Extensions.FileSystemGlobbing.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.23.53103" + } + } + }, + "Microsoft.Extensions.Primitives/8.0.0": { + "runtime": { + "lib/net8.0/Microsoft.Extensions.Primitives.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.23.53103" + } + } + }, + "Microsoft.IO.RecyclableMemoryStream/3.0.1": { + "runtime": { + "lib/net6.0/Microsoft.IO.RecyclableMemoryStream.dll": { + "assemblyVersion": "3.0.1.0", + "fileVersion": "3.0.1.0" + } + } + }, + "Microsoft.Win32.SystemEvents/7.0.0": { + "runtime": { + "lib/net7.0/Microsoft.Win32.SystemEvents.dll": { + "assemblyVersion": "7.0.0.0", + "fileVersion": "7.0.22.51805" + } + }, + "runtimeTargets": { + "runtimes/win/lib/net7.0/Microsoft.Win32.SystemEvents.dll": { + "rid": "win", + "assetType": "runtime", + "assemblyVersion": "7.0.0.0", + "fileVersion": "7.0.22.51805" + } + } + }, + "Newtonsoft.Json/13.0.3": { + "runtime": { + "lib/net6.0/Newtonsoft.Json.dll": { + "assemblyVersion": "13.0.0.0", + "fileVersion": "13.0.3.27908" + } + } + }, + "protobuf-net/3.2.30": { + "dependencies": { + "protobuf-net.Core": "3.2.30" + }, + "runtime": { + "lib/net6.0/protobuf-net.dll": { + "assemblyVersion": "3.0.0.0", + "fileVersion": "3.2.30.709" + } + } + }, + "protobuf-net.Core/3.2.30": { + "dependencies": { + "System.Collections.Immutable": "8.0.0" + }, + "runtime": { + "lib/net6.0/protobuf-net.Core.dll": { + "assemblyVersion": "3.0.0.0", + "fileVersion": "3.2.30.709" + } + } + }, + "System.Collections.Immutable/8.0.0": {}, + "System.ComponentModel.Annotations/5.0.0": {}, + "System.Drawing.Common/7.0.0": { + "dependencies": { + "Microsoft.Win32.SystemEvents": "7.0.0" + }, + "runtime": { + "lib/net7.0/System.Drawing.Common.dll": { + "assemblyVersion": "7.0.0.0", + "fileVersion": "7.0.22.51805" + } + }, + "runtimeTargets": { + "runtimes/win/lib/net7.0/System.Drawing.Common.dll": { + "rid": "win", + "assetType": "runtime", + "assemblyVersion": "7.0.0.0", + "fileVersion": "7.0.22.51805" + } + } + }, + "System.Formats.Asn1/8.0.1": { + "runtime": { + "lib/net8.0/System.Formats.Asn1.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.724.31311" + } + } + }, + "System.Reflection.Metadata/8.0.0": { + "dependencies": { + "System.Collections.Immutable": "8.0.0" + } + }, + "System.Security.Cryptography.Pkcs/8.0.0": { + "dependencies": { + "System.Formats.Asn1": "8.0.1" + }, + "runtime": { + "lib/net8.0/System.Security.Cryptography.Pkcs.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.23.53103" + } + }, + "runtimeTargets": { + "runtimes/win/lib/net8.0/System.Security.Cryptography.Pkcs.dll": { + "rid": "win", + "assetType": "runtime", + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.23.53103" + } + } + }, + "System.Text.Encoding.CodePages/8.0.0": {}, + "System.Text.Encodings.Web/8.0.0": {}, + "System.Text.Json/8.0.4": { + "dependencies": { + "System.Text.Encodings.Web": "8.0.0" + }, + "runtime": { + "lib/net8.0/System.Text.Json.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.724.31311" + } + } + } + } + }, + "libraries": { + "Fantasy.Tools.ConfigTable/1.0.0": { + "type": "project", + "serviceable": false, + "sha512": "" + }, + "CommandLineParser/2.9.1": { + "type": "package", + "serviceable": true, + "sha512": "sha512-OE0sl1/sQ37bjVsPKKtwQlWDgqaxWgtme3xZz7JssWUzg5JpMIyHgCTY9MVMxOg48fJ1AgGT3tgdH5m/kQ5xhA==", + "path": "commandlineparser/2.9.1", + "hashPath": "commandlineparser.2.9.1.nupkg.sha512" + }, + "EPPlus/7.3.2": { + "type": "package", + "serviceable": true, + "sha512": "sha512-9DShQD2VuDZ7QLHp+map1r2HdI1G325YGkvRG+qs4N2fgeMF1Uq0TONCEL5gKCWMNDVGO0ZELJTAIzwNyOZQug==", + "path": "epplus/7.3.2", + "hashPath": "epplus.7.3.2.nupkg.sha512" + }, + "EPPlus.Interfaces/6.1.1": { + "type": "package", + "serviceable": true, + "sha512": "sha512-y7dkrOoE1ZR9Vgy1Jf2rEIaTf3SHlUjYt01NklP+F5Qh7S2ruPbzTcpYLRWMeXiG8XL8h2jqX4CyIkFt3NQGZw==", + "path": "epplus.interfaces/6.1.1", + "hashPath": "epplus.interfaces.6.1.1.nupkg.sha512" + }, + "EPPlus.System.Drawing/6.1.1": { + "type": "package", + "serviceable": true, + "sha512": "sha512-lRF5gHYrmkHOOiLMI0t6q8zNYjUrzRgAM5BCXumv5xiqXko8fx3AWI+HCNZfhEqVFGOop+42KfR5GiUcCoyoMw==", + "path": "epplus.system.drawing/6.1.1", + "hashPath": "epplus.system.drawing.6.1.1.nupkg.sha512" + }, + "Microsoft.CodeAnalysis.Analyzers/3.3.4": { + "type": "package", + "serviceable": true, + "sha512": "sha512-AxkxcPR+rheX0SmvpLVIGLhOUXAKG56a64kV9VQZ4y9gR9ZmPXnqZvHJnmwLSwzrEP6junUF11vuc+aqo5r68g==", + "path": "microsoft.codeanalysis.analyzers/3.3.4", + "hashPath": "microsoft.codeanalysis.analyzers.3.3.4.nupkg.sha512" + }, + "Microsoft.CodeAnalysis.Common/4.11.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-djf8ujmqYImFgB04UGtcsEhHrzVqzHowS+EEl/Yunc5LdrYrZhGBWUTXoCF0NzYXJxtfuD+UVQarWpvrNc94Qg==", + "path": "microsoft.codeanalysis.common/4.11.0", + "hashPath": "microsoft.codeanalysis.common.4.11.0.nupkg.sha512" + }, + "Microsoft.CodeAnalysis.CSharp/4.11.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-6XYi2EusI8JT4y2l/F3VVVS+ISoIX9nqHsZRaG6W5aFeJ5BEuBosHfT/ABb73FN0RZ1Z3cj2j7cL28SToJPXOw==", + "path": "microsoft.codeanalysis.csharp/4.11.0", + "hashPath": "microsoft.codeanalysis.csharp.4.11.0.nupkg.sha512" + }, + "Microsoft.Extensions.Configuration/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-0J/9YNXTMWSZP2p2+nvl8p71zpSwokZXZuJW+VjdErkegAnFdO1XlqtA62SJtgVYHdKu3uPxJHcMR/r35HwFBA==", + "path": "microsoft.extensions.configuration/8.0.0", + "hashPath": "microsoft.extensions.configuration.8.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.Configuration.Abstractions/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-3lE/iLSutpgX1CC0NOW70FJoGARRHbyKmG7dc0klnUZ9Dd9hS6N/POPWhKhMLCEuNN5nXEY5agmlFtH562vqhQ==", + "path": "microsoft.extensions.configuration.abstractions/8.0.0", + "hashPath": "microsoft.extensions.configuration.abstractions.8.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.Configuration.FileExtensions/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-McP+Lz/EKwvtCv48z0YImw+L1gi1gy5rHhNaNIY2CrjloV+XY8gydT8DjMR6zWeL13AFK+DioVpppwAuO1Gi1w==", + "path": "microsoft.extensions.configuration.fileextensions/8.0.0", + "hashPath": "microsoft.extensions.configuration.fileextensions.8.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.Configuration.Json/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-C2wqUoh9OmRL1akaCcKSTmRU8z0kckfImG7zLNI8uyi47Lp+zd5LWAD17waPQEqCz3ioWOCrFUo+JJuoeZLOBw==", + "path": "microsoft.extensions.configuration.json/8.0.0", + "hashPath": "microsoft.extensions.configuration.json.8.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.FileProviders.Abstractions/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-ZbaMlhJlpisjuWbvXr4LdAst/1XxH3vZ6A0BsgTphZ2L4PGuxRLz7Jr/S7mkAAnOn78Vu0fKhEgNF5JO3zfjqQ==", + "path": "microsoft.extensions.fileproviders.abstractions/8.0.0", + "hashPath": "microsoft.extensions.fileproviders.abstractions.8.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.FileProviders.Physical/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-UboiXxpPUpwulHvIAVE36Knq0VSHaAmfrFkegLyBZeaADuKezJ/AIXYAW8F5GBlGk/VaibN2k/Zn1ca8YAfVdA==", + "path": "microsoft.extensions.fileproviders.physical/8.0.0", + "hashPath": "microsoft.extensions.fileproviders.physical.8.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.FileSystemGlobbing/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-OK+670i7esqlQrPjdIKRbsyMCe9g5kSLpRRQGSr4Q58AOYEe/hCnfLZprh7viNisSUUQZmMrbbuDaIrP+V1ebQ==", + "path": "microsoft.extensions.filesystemglobbing/8.0.0", + "hashPath": "microsoft.extensions.filesystemglobbing.8.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.Primitives/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-bXJEZrW9ny8vjMF1JV253WeLhpEVzFo1lyaZu1vQ4ZxWUlVvknZ/+ftFgVheLubb4eZPSwwxBeqS1JkCOjxd8g==", + "path": "microsoft.extensions.primitives/8.0.0", + "hashPath": "microsoft.extensions.primitives.8.0.0.nupkg.sha512" + }, + "Microsoft.IO.RecyclableMemoryStream/3.0.1": { + "type": "package", + "serviceable": true, + "sha512": "sha512-s/s20YTVY9r9TPfTrN5g8zPF1YhwxyqO6PxUkrYTGI2B+OGPe9AdajWZrLhFqXIvqIW23fnUE4+ztrUWNU1+9g==", + "path": "microsoft.io.recyclablememorystream/3.0.1", + "hashPath": "microsoft.io.recyclablememorystream.3.0.1.nupkg.sha512" + }, + "Microsoft.Win32.SystemEvents/7.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-2nXPrhdAyAzir0gLl8Yy8S5Mnm/uBSQQA7jEsILOS1MTyS7DbmV1NgViMtvV1sfCD1ebITpNwb1NIinKeJgUVQ==", + "path": "microsoft.win32.systemevents/7.0.0", + "hashPath": "microsoft.win32.systemevents.7.0.0.nupkg.sha512" + }, + "Newtonsoft.Json/13.0.3": { + "type": "package", + "serviceable": true, + "sha512": "sha512-HrC5BXdl00IP9zeV+0Z848QWPAoCr9P3bDEZguI+gkLcBKAOxix/tLEAAHC+UvDNPv4a2d18lOReHMOagPa+zQ==", + "path": "newtonsoft.json/13.0.3", + "hashPath": "newtonsoft.json.13.0.3.nupkg.sha512" + }, + "protobuf-net/3.2.30": { + "type": "package", + "serviceable": true, + "sha512": "sha512-C/UTlmxEJHAHpqm8xQK1UyJKaIynVCSNG4mVrbLgnZ7ccH28nN49O8iMJvKEodTgVbnimvy+3mIiAdW6mATwnw==", + "path": "protobuf-net/3.2.30", + "hashPath": "protobuf-net.3.2.30.nupkg.sha512" + }, + "protobuf-net.Core/3.2.30": { + "type": "package", + "serviceable": true, + "sha512": "sha512-v2ZxxYrz+X212ukSx+uqkLuPu414bvmSAnTyf+PBUKR9ENJxO4P/csorA/27456MCp1JNoMssDj/f91RDiwBfQ==", + "path": "protobuf-net.core/3.2.30", + "hashPath": "protobuf-net.core.3.2.30.nupkg.sha512" + }, + "System.Collections.Immutable/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-AurL6Y5BA1WotzlEvVaIDpqzpIPvYnnldxru8oXJU2yFxFUy3+pNXjXd1ymO+RA0rq0+590Q8gaz2l3Sr7fmqg==", + "path": "system.collections.immutable/8.0.0", + "hashPath": "system.collections.immutable.8.0.0.nupkg.sha512" + }, + "System.ComponentModel.Annotations/5.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-dMkqfy2el8A8/I76n2Hi1oBFEbG1SfxD2l5nhwXV3XjlnOmwxJlQbYpJH4W51odnU9sARCSAgv7S3CyAFMkpYg==", + "path": "system.componentmodel.annotations/5.0.0", + "hashPath": "system.componentmodel.annotations.5.0.0.nupkg.sha512" + }, + "System.Drawing.Common/7.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-KIX+oBU38pxkKPxvLcLfIkOV5Ien8ReN78wro7OF5/erwcmortzeFx+iBswlh2Vz6gVne0khocQudGwaO1Ey6A==", + "path": "system.drawing.common/7.0.0", + "hashPath": "system.drawing.common.7.0.0.nupkg.sha512" + }, + "System.Formats.Asn1/8.0.1": { + "type": "package", + "serviceable": true, + "sha512": "sha512-XqKba7Mm/koKSjKMfW82olQdmfbI5yqeoLV/tidRp7fbh5rmHAQ5raDI/7SU0swTzv+jgqtUGkzmFxuUg0it1A==", + "path": "system.formats.asn1/8.0.1", + "hashPath": "system.formats.asn1.8.0.1.nupkg.sha512" + }, + "System.Reflection.Metadata/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-ptvgrFh7PvWI8bcVqG5rsA/weWM09EnthFHR5SCnS6IN+P4mj6rE1lBDC4U8HL9/57htKAqy4KQ3bBj84cfYyQ==", + "path": "system.reflection.metadata/8.0.0", + "hashPath": "system.reflection.metadata.8.0.0.nupkg.sha512" + }, + "System.Security.Cryptography.Pkcs/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-ULmp3xoOwNYjOYp4JZ2NK/6NdTgiN1GQXzVVN1njQ7LOZ0d0B9vyMnhyqbIi9Qw4JXj1JgCsitkTShboHRx7Eg==", + "path": "system.security.cryptography.pkcs/8.0.0", + "hashPath": "system.security.cryptography.pkcs.8.0.0.nupkg.sha512" + }, + "System.Text.Encoding.CodePages/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-OZIsVplFGaVY90G2SbpgU7EnCoOO5pw1t4ic21dBF3/1omrJFpAGoNAVpPyMVOC90/hvgkGG3VFqR13YgZMQfg==", + "path": "system.text.encoding.codepages/8.0.0", + "hashPath": "system.text.encoding.codepages.8.0.0.nupkg.sha512" + }, + "System.Text.Encodings.Web/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-yev/k9GHAEGx2Rg3/tU6MQh4HGBXJs70y7j1LaM1i/ER9po+6nnQ6RRqTJn1E7Xu0fbIFK80Nh5EoODxrbxwBQ==", + "path": "system.text.encodings.web/8.0.0", + "hashPath": "system.text.encodings.web.8.0.0.nupkg.sha512" + }, + "System.Text.Json/8.0.4": { + "type": "package", + "serviceable": true, + "sha512": "sha512-bAkhgDJ88XTsqczoxEMliSrpijKZHhbJQldhAmObj/RbrN3sU5dcokuXmWJWsdQAhiMJ9bTayWsL1C9fbbCRhw==", + "path": "system.text.json/8.0.4", + "hashPath": "system.text.json.8.0.4.nupkg.sha512" + } + } +} \ No newline at end of file diff --git a/聊天系统课程代码/Tools/ConfigTable/Fantasy.Tools.ConfigTable.dll b/聊天系统课程代码/Tools/ConfigTable/Fantasy.Tools.ConfigTable.dll new file mode 100644 index 0000000..691c3ec Binary files /dev/null and b/聊天系统课程代码/Tools/ConfigTable/Fantasy.Tools.ConfigTable.dll differ diff --git a/聊天系统课程代码/Tools/ConfigTable/Fantasy.Tools.ConfigTable.pdb b/聊天系统课程代码/Tools/ConfigTable/Fantasy.Tools.ConfigTable.pdb new file mode 100644 index 0000000..e28ebf3 Binary files /dev/null and b/聊天系统课程代码/Tools/ConfigTable/Fantasy.Tools.ConfigTable.pdb differ diff --git a/聊天系统课程代码/Tools/ConfigTable/Fantasy.Tools.ConfigTable.runtimeconfig.json b/聊天系统课程代码/Tools/ConfigTable/Fantasy.Tools.ConfigTable.runtimeconfig.json new file mode 100644 index 0000000..becfaea --- /dev/null +++ b/聊天系统课程代码/Tools/ConfigTable/Fantasy.Tools.ConfigTable.runtimeconfig.json @@ -0,0 +1,12 @@ +{ + "runtimeOptions": { + "tfm": "net8.0", + "framework": { + "name": "Microsoft.NETCore.App", + "version": "8.0.0" + }, + "configProperties": { + "System.Runtime.Serialization.EnableUnsafeBinaryFormatterSerialization": false + } + } +} \ No newline at end of file diff --git a/聊天系统课程代码/Tools/ConfigTable/Microsoft.CodeAnalysis.CSharp.dll b/聊天系统课程代码/Tools/ConfigTable/Microsoft.CodeAnalysis.CSharp.dll new file mode 100644 index 0000000..c23db48 Binary files /dev/null and b/聊天系统课程代码/Tools/ConfigTable/Microsoft.CodeAnalysis.CSharp.dll differ diff --git a/聊天系统课程代码/Tools/ConfigTable/Microsoft.CodeAnalysis.dll b/聊天系统课程代码/Tools/ConfigTable/Microsoft.CodeAnalysis.dll new file mode 100644 index 0000000..de7eadd Binary files /dev/null and b/聊天系统课程代码/Tools/ConfigTable/Microsoft.CodeAnalysis.dll differ diff --git a/聊天系统课程代码/Tools/ConfigTable/Microsoft.Extensions.Configuration.Abstractions.dll b/聊天系统课程代码/Tools/ConfigTable/Microsoft.Extensions.Configuration.Abstractions.dll new file mode 100644 index 0000000..a5ab313 Binary files /dev/null and b/聊天系统课程代码/Tools/ConfigTable/Microsoft.Extensions.Configuration.Abstractions.dll differ diff --git a/聊天系统课程代码/Tools/ConfigTable/Microsoft.Extensions.Configuration.FileExtensions.dll b/聊天系统课程代码/Tools/ConfigTable/Microsoft.Extensions.Configuration.FileExtensions.dll new file mode 100644 index 0000000..4efc1a5 Binary files /dev/null and b/聊天系统课程代码/Tools/ConfigTable/Microsoft.Extensions.Configuration.FileExtensions.dll differ diff --git a/聊天系统课程代码/Tools/ConfigTable/Microsoft.Extensions.Configuration.Json.dll b/聊天系统课程代码/Tools/ConfigTable/Microsoft.Extensions.Configuration.Json.dll new file mode 100644 index 0000000..296db6a Binary files /dev/null and b/聊天系统课程代码/Tools/ConfigTable/Microsoft.Extensions.Configuration.Json.dll differ diff --git a/聊天系统课程代码/Tools/ConfigTable/Microsoft.Extensions.Configuration.dll b/聊天系统课程代码/Tools/ConfigTable/Microsoft.Extensions.Configuration.dll new file mode 100644 index 0000000..d3e5c22 Binary files /dev/null and b/聊天系统课程代码/Tools/ConfigTable/Microsoft.Extensions.Configuration.dll differ diff --git a/聊天系统课程代码/Tools/ConfigTable/Microsoft.Extensions.FileProviders.Abstractions.dll b/聊天系统课程代码/Tools/ConfigTable/Microsoft.Extensions.FileProviders.Abstractions.dll new file mode 100644 index 0000000..f907206 Binary files /dev/null and b/聊天系统课程代码/Tools/ConfigTable/Microsoft.Extensions.FileProviders.Abstractions.dll differ diff --git a/聊天系统课程代码/Tools/ConfigTable/Microsoft.Extensions.FileProviders.Physical.dll b/聊天系统课程代码/Tools/ConfigTable/Microsoft.Extensions.FileProviders.Physical.dll new file mode 100644 index 0000000..6fb7f47 Binary files /dev/null and b/聊天系统课程代码/Tools/ConfigTable/Microsoft.Extensions.FileProviders.Physical.dll differ diff --git a/聊天系统课程代码/Tools/ConfigTable/Microsoft.Extensions.FileSystemGlobbing.dll b/聊天系统课程代码/Tools/ConfigTable/Microsoft.Extensions.FileSystemGlobbing.dll new file mode 100644 index 0000000..e590735 Binary files /dev/null and b/聊天系统课程代码/Tools/ConfigTable/Microsoft.Extensions.FileSystemGlobbing.dll differ diff --git a/聊天系统课程代码/Tools/ConfigTable/Microsoft.Extensions.Primitives.dll b/聊天系统课程代码/Tools/ConfigTable/Microsoft.Extensions.Primitives.dll new file mode 100644 index 0000000..c24f2a0 Binary files /dev/null and b/聊天系统课程代码/Tools/ConfigTable/Microsoft.Extensions.Primitives.dll differ diff --git a/聊天系统课程代码/Tools/ConfigTable/Microsoft.IO.RecyclableMemoryStream.dll b/聊天系统课程代码/Tools/ConfigTable/Microsoft.IO.RecyclableMemoryStream.dll new file mode 100644 index 0000000..6e0ea40 Binary files /dev/null and b/聊天系统课程代码/Tools/ConfigTable/Microsoft.IO.RecyclableMemoryStream.dll differ diff --git a/聊天系统课程代码/Tools/ConfigTable/Microsoft.Win32.SystemEvents.dll b/聊天系统课程代码/Tools/ConfigTable/Microsoft.Win32.SystemEvents.dll new file mode 100644 index 0000000..d40a926 Binary files /dev/null and b/聊天系统课程代码/Tools/ConfigTable/Microsoft.Win32.SystemEvents.dll differ diff --git a/聊天系统课程代码/Tools/ConfigTable/Newtonsoft.Json.dll b/聊天系统课程代码/Tools/ConfigTable/Newtonsoft.Json.dll new file mode 100644 index 0000000..d035c38 Binary files /dev/null and b/聊天系统课程代码/Tools/ConfigTable/Newtonsoft.Json.dll differ diff --git a/聊天系统课程代码/Tools/ConfigTable/Run.bat b/聊天系统课程代码/Tools/ConfigTable/Run.bat new file mode 100644 index 0000000..e166f0e --- /dev/null +++ b/聊天系统课程代码/Tools/ConfigTable/Run.bat @@ -0,0 +1,21 @@ +@echo off + +echo Please select an option: +echo 1. Client +echo 2. Server +echo 3. All + +set /p choice=Please select an option: + +if "%choice%"=="1" ( + echo Client + dotnet Fantasy.Tools.ConfigTable.dll --ExportPlatform 1 +) else if "%choice%"=="2" ( + echo Server + dotnet Fantasy.Tools.ConfigTable.dll --ExportPlatform 2 +) else if "%choice%"=="3" ( + echo All + dotnet Fantasy.Tools.ConfigTable.dll --ExportPlatform 3 +) else ( + echo Invalid option +) diff --git a/聊天系统课程代码/Tools/ConfigTable/Run.sh b/聊天系统课程代码/Tools/ConfigTable/Run.sh new file mode 100644 index 0000000..491d8d9 --- /dev/null +++ b/聊天系统课程代码/Tools/ConfigTable/Run.sh @@ -0,0 +1,23 @@ +#!/bin/bash + +echo "1. Client" +echo "2. Server" +echo "3. All" + +read -n 1 -p "Please select an option:" choice +echo "" +echo "" +case $choice in + 1) + dotnet Fantasy.Tools.ConfigTable.dll --ExportPlatform 1 + ;; + 2) + dotnet Fantasy.Tools.ConfigTable.dll --ExportPlatform 2 + ;; + 3) + dotnet Fantasy.Tools.ConfigTable.dll --ExportPlatform 3 + ;; + *) + echo "Invalid option" + ;; +esac diff --git a/聊天系统课程代码/Tools/ConfigTable/System.Drawing.Common.dll b/聊天系统课程代码/Tools/ConfigTable/System.Drawing.Common.dll new file mode 100644 index 0000000..310d5e8 Binary files /dev/null and b/聊天系统课程代码/Tools/ConfigTable/System.Drawing.Common.dll differ diff --git a/聊天系统课程代码/Tools/ConfigTable/System.Formats.Asn1.dll b/聊天系统课程代码/Tools/ConfigTable/System.Formats.Asn1.dll new file mode 100644 index 0000000..16cc849 Binary files /dev/null and b/聊天系统课程代码/Tools/ConfigTable/System.Formats.Asn1.dll differ diff --git a/聊天系统课程代码/Tools/ConfigTable/System.Security.Cryptography.Pkcs.dll b/聊天系统课程代码/Tools/ConfigTable/System.Security.Cryptography.Pkcs.dll new file mode 100644 index 0000000..a76a14a Binary files /dev/null and b/聊天系统课程代码/Tools/ConfigTable/System.Security.Cryptography.Pkcs.dll differ diff --git a/聊天系统课程代码/Tools/ConfigTable/System.Text.Json.dll b/聊天系统课程代码/Tools/ConfigTable/System.Text.Json.dll new file mode 100644 index 0000000..0c6d406 Binary files /dev/null and b/聊天系统课程代码/Tools/ConfigTable/System.Text.Json.dll differ diff --git a/聊天系统课程代码/Tools/ConfigTable/protobuf-net.Core.dll b/聊天系统课程代码/Tools/ConfigTable/protobuf-net.Core.dll new file mode 100644 index 0000000..845a840 Binary files /dev/null and b/聊天系统课程代码/Tools/ConfigTable/protobuf-net.Core.dll differ diff --git a/聊天系统课程代码/Tools/ConfigTable/protobuf-net.dll b/聊天系统课程代码/Tools/ConfigTable/protobuf-net.dll new file mode 100644 index 0000000..e4b6839 Binary files /dev/null and b/聊天系统课程代码/Tools/ConfigTable/protobuf-net.dll differ diff --git a/聊天系统课程代码/Tools/NetworkProtocol/CommandLine.dll b/聊天系统课程代码/Tools/NetworkProtocol/CommandLine.dll new file mode 100644 index 0000000..3eab2be Binary files /dev/null and b/聊天系统课程代码/Tools/NetworkProtocol/CommandLine.dll differ diff --git a/聊天系统课程代码/Tools/NetworkProtocol/ExporterSettings.json b/聊天系统课程代码/Tools/NetworkProtocol/ExporterSettings.json new file mode 100644 index 0000000..41cb0e4 --- /dev/null +++ b/聊天系统课程代码/Tools/NetworkProtocol/ExporterSettings.json @@ -0,0 +1,29 @@ +{ + "Export": { + "NetworkProtocolDirectory": { + "Value": "../../Config/NetworkProtocol/", + "Comment": "ProtoBuf文件所在的文件夹位置" + }, + "NetworkProtocolServerDirectory": { + "Value": "../../Server/Entity/Generate/NetworkProtocol/", + "Comment": "ProtoBuf生成到服务端的文件夹位置" + }, + "NetworkProtocolClientDirectory": { + "Value": "../../Client/Unity/Assets/Scripts/Hotfix/Generate/NetworkProtocol/", + "Comment": "ProtoBuf生成到客户端的文件夹位置" + }, + "Serializes": { + "Value": [ +// { +// "KeyIndex": 0, +// "NameSpace" : "MemoryPack", +// "SerializeName": "MemoryPack", +// "Attribute": "\t[MemoryPackable]", +// "Ignore": "\t\t[MemoryPackIgnore]", +// "Member": "MemoryPackOrder" +// } + ], + "Comment": "自定义序列化器" + } + } +} \ No newline at end of file diff --git a/聊天系统课程代码/Tools/NetworkProtocol/Fantasy.Tools.NetworkProtocol b/聊天系统课程代码/Tools/NetworkProtocol/Fantasy.Tools.NetworkProtocol new file mode 100644 index 0000000..21bd520 Binary files /dev/null and b/聊天系统课程代码/Tools/NetworkProtocol/Fantasy.Tools.NetworkProtocol differ diff --git a/聊天系统课程代码/Tools/NetworkProtocol/Fantasy.Tools.NetworkProtocol.deps.json b/聊天系统课程代码/Tools/NetworkProtocol/Fantasy.Tools.NetworkProtocol.deps.json new file mode 100644 index 0000000..3c053cb --- /dev/null +++ b/聊天系统课程代码/Tools/NetworkProtocol/Fantasy.Tools.NetworkProtocol.deps.json @@ -0,0 +1,227 @@ +{ + "runtimeTarget": { + "name": ".NETCoreApp,Version=v8.0", + "signature": "" + }, + "compilationOptions": {}, + "targets": { + ".NETCoreApp,Version=v8.0": { + "Fantasy.Tools.NetworkProtocol/1.0.0": { + "dependencies": { + "CommandLineParser": "2.9.1", + "Microsoft.Extensions.Configuration.Json": "8.0.0", + "Newtonsoft.Json": "13.0.3" + }, + "runtime": { + "Fantasy.Tools.NetworkProtocol.dll": {} + } + }, + "CommandLineParser/2.9.1": { + "runtime": { + "lib/netstandard2.0/CommandLine.dll": { + "assemblyVersion": "2.9.1.0", + "fileVersion": "2.9.1.0" + } + } + }, + "Microsoft.Extensions.Configuration/8.0.0": { + "dependencies": { + "Microsoft.Extensions.Configuration.Abstractions": "8.0.0", + "Microsoft.Extensions.Primitives": "8.0.0" + }, + "runtime": { + "lib/net8.0/Microsoft.Extensions.Configuration.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.23.53103" + } + } + }, + "Microsoft.Extensions.Configuration.Abstractions/8.0.0": { + "dependencies": { + "Microsoft.Extensions.Primitives": "8.0.0" + }, + "runtime": { + "lib/net8.0/Microsoft.Extensions.Configuration.Abstractions.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.23.53103" + } + } + }, + "Microsoft.Extensions.Configuration.FileExtensions/8.0.0": { + "dependencies": { + "Microsoft.Extensions.Configuration": "8.0.0", + "Microsoft.Extensions.Configuration.Abstractions": "8.0.0", + "Microsoft.Extensions.FileProviders.Abstractions": "8.0.0", + "Microsoft.Extensions.FileProviders.Physical": "8.0.0", + "Microsoft.Extensions.Primitives": "8.0.0" + }, + "runtime": { + "lib/net8.0/Microsoft.Extensions.Configuration.FileExtensions.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.23.53103" + } + } + }, + "Microsoft.Extensions.Configuration.Json/8.0.0": { + "dependencies": { + "Microsoft.Extensions.Configuration": "8.0.0", + "Microsoft.Extensions.Configuration.Abstractions": "8.0.0", + "Microsoft.Extensions.Configuration.FileExtensions": "8.0.0", + "Microsoft.Extensions.FileProviders.Abstractions": "8.0.0", + "System.Text.Json": "8.0.0" + }, + "runtime": { + "lib/net8.0/Microsoft.Extensions.Configuration.Json.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.23.53103" + } + } + }, + "Microsoft.Extensions.FileProviders.Abstractions/8.0.0": { + "dependencies": { + "Microsoft.Extensions.Primitives": "8.0.0" + }, + "runtime": { + "lib/net8.0/Microsoft.Extensions.FileProviders.Abstractions.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.23.53103" + } + } + }, + "Microsoft.Extensions.FileProviders.Physical/8.0.0": { + "dependencies": { + "Microsoft.Extensions.FileProviders.Abstractions": "8.0.0", + "Microsoft.Extensions.FileSystemGlobbing": "8.0.0", + "Microsoft.Extensions.Primitives": "8.0.0" + }, + "runtime": { + "lib/net8.0/Microsoft.Extensions.FileProviders.Physical.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.23.53103" + } + } + }, + "Microsoft.Extensions.FileSystemGlobbing/8.0.0": { + "runtime": { + "lib/net8.0/Microsoft.Extensions.FileSystemGlobbing.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.23.53103" + } + } + }, + "Microsoft.Extensions.Primitives/8.0.0": { + "runtime": { + "lib/net8.0/Microsoft.Extensions.Primitives.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.23.53103" + } + } + }, + "Newtonsoft.Json/13.0.3": { + "runtime": { + "lib/net6.0/Newtonsoft.Json.dll": { + "assemblyVersion": "13.0.0.0", + "fileVersion": "13.0.3.27908" + } + } + }, + "System.Text.Encodings.Web/8.0.0": {}, + "System.Text.Json/8.0.0": { + "dependencies": { + "System.Text.Encodings.Web": "8.0.0" + } + } + } + }, + "libraries": { + "Fantasy.Tools.NetworkProtocol/1.0.0": { + "type": "project", + "serviceable": false, + "sha512": "" + }, + "CommandLineParser/2.9.1": { + "type": "package", + "serviceable": true, + "sha512": "sha512-OE0sl1/sQ37bjVsPKKtwQlWDgqaxWgtme3xZz7JssWUzg5JpMIyHgCTY9MVMxOg48fJ1AgGT3tgdH5m/kQ5xhA==", + "path": "commandlineparser/2.9.1", + "hashPath": "commandlineparser.2.9.1.nupkg.sha512" + }, + "Microsoft.Extensions.Configuration/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-0J/9YNXTMWSZP2p2+nvl8p71zpSwokZXZuJW+VjdErkegAnFdO1XlqtA62SJtgVYHdKu3uPxJHcMR/r35HwFBA==", + "path": "microsoft.extensions.configuration/8.0.0", + "hashPath": "microsoft.extensions.configuration.8.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.Configuration.Abstractions/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-3lE/iLSutpgX1CC0NOW70FJoGARRHbyKmG7dc0klnUZ9Dd9hS6N/POPWhKhMLCEuNN5nXEY5agmlFtH562vqhQ==", + "path": "microsoft.extensions.configuration.abstractions/8.0.0", + "hashPath": "microsoft.extensions.configuration.abstractions.8.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.Configuration.FileExtensions/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-McP+Lz/EKwvtCv48z0YImw+L1gi1gy5rHhNaNIY2CrjloV+XY8gydT8DjMR6zWeL13AFK+DioVpppwAuO1Gi1w==", + "path": "microsoft.extensions.configuration.fileextensions/8.0.0", + "hashPath": "microsoft.extensions.configuration.fileextensions.8.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.Configuration.Json/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-C2wqUoh9OmRL1akaCcKSTmRU8z0kckfImG7zLNI8uyi47Lp+zd5LWAD17waPQEqCz3ioWOCrFUo+JJuoeZLOBw==", + "path": "microsoft.extensions.configuration.json/8.0.0", + "hashPath": "microsoft.extensions.configuration.json.8.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.FileProviders.Abstractions/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-ZbaMlhJlpisjuWbvXr4LdAst/1XxH3vZ6A0BsgTphZ2L4PGuxRLz7Jr/S7mkAAnOn78Vu0fKhEgNF5JO3zfjqQ==", + "path": "microsoft.extensions.fileproviders.abstractions/8.0.0", + "hashPath": "microsoft.extensions.fileproviders.abstractions.8.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.FileProviders.Physical/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-UboiXxpPUpwulHvIAVE36Knq0VSHaAmfrFkegLyBZeaADuKezJ/AIXYAW8F5GBlGk/VaibN2k/Zn1ca8YAfVdA==", + "path": "microsoft.extensions.fileproviders.physical/8.0.0", + "hashPath": "microsoft.extensions.fileproviders.physical.8.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.FileSystemGlobbing/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-OK+670i7esqlQrPjdIKRbsyMCe9g5kSLpRRQGSr4Q58AOYEe/hCnfLZprh7viNisSUUQZmMrbbuDaIrP+V1ebQ==", + "path": "microsoft.extensions.filesystemglobbing/8.0.0", + "hashPath": "microsoft.extensions.filesystemglobbing.8.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.Primitives/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-bXJEZrW9ny8vjMF1JV253WeLhpEVzFo1lyaZu1vQ4ZxWUlVvknZ/+ftFgVheLubb4eZPSwwxBeqS1JkCOjxd8g==", + "path": "microsoft.extensions.primitives/8.0.0", + "hashPath": "microsoft.extensions.primitives.8.0.0.nupkg.sha512" + }, + "Newtonsoft.Json/13.0.3": { + "type": "package", + "serviceable": true, + "sha512": "sha512-HrC5BXdl00IP9zeV+0Z848QWPAoCr9P3bDEZguI+gkLcBKAOxix/tLEAAHC+UvDNPv4a2d18lOReHMOagPa+zQ==", + "path": "newtonsoft.json/13.0.3", + "hashPath": "newtonsoft.json.13.0.3.nupkg.sha512" + }, + "System.Text.Encodings.Web/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-yev/k9GHAEGx2Rg3/tU6MQh4HGBXJs70y7j1LaM1i/ER9po+6nnQ6RRqTJn1E7Xu0fbIFK80Nh5EoODxrbxwBQ==", + "path": "system.text.encodings.web/8.0.0", + "hashPath": "system.text.encodings.web.8.0.0.nupkg.sha512" + }, + "System.Text.Json/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-OdrZO2WjkiEG6ajEFRABTRCi/wuXQPxeV6g8xvUJqdxMvvuCCEk86zPla8UiIQJz3durtUEbNyY/3lIhS0yZvQ==", + "path": "system.text.json/8.0.0", + "hashPath": "system.text.json.8.0.0.nupkg.sha512" + } + } +} \ No newline at end of file diff --git a/聊天系统课程代码/Tools/NetworkProtocol/Fantasy.Tools.NetworkProtocol.dll b/聊天系统课程代码/Tools/NetworkProtocol/Fantasy.Tools.NetworkProtocol.dll new file mode 100644 index 0000000..014a40f Binary files /dev/null and b/聊天系统课程代码/Tools/NetworkProtocol/Fantasy.Tools.NetworkProtocol.dll differ diff --git a/聊天系统课程代码/Tools/NetworkProtocol/Fantasy.Tools.NetworkProtocol.pdb b/聊天系统课程代码/Tools/NetworkProtocol/Fantasy.Tools.NetworkProtocol.pdb new file mode 100644 index 0000000..a64337f Binary files /dev/null and b/聊天系统课程代码/Tools/NetworkProtocol/Fantasy.Tools.NetworkProtocol.pdb differ diff --git a/聊天系统课程代码/Tools/NetworkProtocol/Fantasy.Tools.NetworkProtocol.runtimeconfig.json b/聊天系统课程代码/Tools/NetworkProtocol/Fantasy.Tools.NetworkProtocol.runtimeconfig.json new file mode 100644 index 0000000..becfaea --- /dev/null +++ b/聊天系统课程代码/Tools/NetworkProtocol/Fantasy.Tools.NetworkProtocol.runtimeconfig.json @@ -0,0 +1,12 @@ +{ + "runtimeOptions": { + "tfm": "net8.0", + "framework": { + "name": "Microsoft.NETCore.App", + "version": "8.0.0" + }, + "configProperties": { + "System.Runtime.Serialization.EnableUnsafeBinaryFormatterSerialization": false + } + } +} \ No newline at end of file diff --git a/聊天系统课程代码/Tools/NetworkProtocol/Microsoft.Extensions.Configuration.Abstractions.dll b/聊天系统课程代码/Tools/NetworkProtocol/Microsoft.Extensions.Configuration.Abstractions.dll new file mode 100644 index 0000000..a5ab313 Binary files /dev/null and b/聊天系统课程代码/Tools/NetworkProtocol/Microsoft.Extensions.Configuration.Abstractions.dll differ diff --git a/聊天系统课程代码/Tools/NetworkProtocol/Microsoft.Extensions.Configuration.FileExtensions.dll b/聊天系统课程代码/Tools/NetworkProtocol/Microsoft.Extensions.Configuration.FileExtensions.dll new file mode 100644 index 0000000..4efc1a5 Binary files /dev/null and b/聊天系统课程代码/Tools/NetworkProtocol/Microsoft.Extensions.Configuration.FileExtensions.dll differ diff --git a/聊天系统课程代码/Tools/NetworkProtocol/Microsoft.Extensions.Configuration.Json.dll b/聊天系统课程代码/Tools/NetworkProtocol/Microsoft.Extensions.Configuration.Json.dll new file mode 100644 index 0000000..296db6a Binary files /dev/null and b/聊天系统课程代码/Tools/NetworkProtocol/Microsoft.Extensions.Configuration.Json.dll differ diff --git a/聊天系统课程代码/Tools/NetworkProtocol/Microsoft.Extensions.Configuration.dll b/聊天系统课程代码/Tools/NetworkProtocol/Microsoft.Extensions.Configuration.dll new file mode 100644 index 0000000..d3e5c22 Binary files /dev/null and b/聊天系统课程代码/Tools/NetworkProtocol/Microsoft.Extensions.Configuration.dll differ diff --git a/聊天系统课程代码/Tools/NetworkProtocol/Microsoft.Extensions.FileProviders.Abstractions.dll b/聊天系统课程代码/Tools/NetworkProtocol/Microsoft.Extensions.FileProviders.Abstractions.dll new file mode 100644 index 0000000..f907206 Binary files /dev/null and b/聊天系统课程代码/Tools/NetworkProtocol/Microsoft.Extensions.FileProviders.Abstractions.dll differ diff --git a/聊天系统课程代码/Tools/NetworkProtocol/Microsoft.Extensions.FileProviders.Physical.dll b/聊天系统课程代码/Tools/NetworkProtocol/Microsoft.Extensions.FileProviders.Physical.dll new file mode 100644 index 0000000..6fb7f47 Binary files /dev/null and b/聊天系统课程代码/Tools/NetworkProtocol/Microsoft.Extensions.FileProviders.Physical.dll differ diff --git a/聊天系统课程代码/Tools/NetworkProtocol/Microsoft.Extensions.FileSystemGlobbing.dll b/聊天系统课程代码/Tools/NetworkProtocol/Microsoft.Extensions.FileSystemGlobbing.dll new file mode 100644 index 0000000..e590735 Binary files /dev/null and b/聊天系统课程代码/Tools/NetworkProtocol/Microsoft.Extensions.FileSystemGlobbing.dll differ diff --git a/聊天系统课程代码/Tools/NetworkProtocol/Microsoft.Extensions.Primitives.dll b/聊天系统课程代码/Tools/NetworkProtocol/Microsoft.Extensions.Primitives.dll new file mode 100644 index 0000000..c24f2a0 Binary files /dev/null and b/聊天系统课程代码/Tools/NetworkProtocol/Microsoft.Extensions.Primitives.dll differ diff --git a/聊天系统课程代码/Tools/NetworkProtocol/Newtonsoft.Json.dll b/聊天系统课程代码/Tools/NetworkProtocol/Newtonsoft.Json.dll new file mode 100644 index 0000000..d035c38 Binary files /dev/null and b/聊天系统课程代码/Tools/NetworkProtocol/Newtonsoft.Json.dll differ diff --git a/聊天系统课程代码/Tools/NetworkProtocol/Run.bat b/聊天系统课程代码/Tools/NetworkProtocol/Run.bat new file mode 100644 index 0000000..8551afc --- /dev/null +++ b/聊天系统课程代码/Tools/NetworkProtocol/Run.bat @@ -0,0 +1,21 @@ +@echo off + +echo Please select an option: +echo 1. Client +echo 2. Server +echo 3. All + +set /p choice=Please select an option: + +if "%choice%"=="1" ( + echo Client + dotnet Fantasy.Tools.NetworkProtocol.dll --ExportPlatform 1 +) else if "%choice%"=="2" ( + echo Server + dotnet Fantasy.Tools.NetworkProtocol.dll --ExportPlatform 2 +) else if "%choice%"=="3" ( + echo All + dotnet Fantasy.Tools.NetworkProtocol.dll --ExportPlatform 3 +) else ( + echo Invalid option +) diff --git a/聊天系统课程代码/Tools/NetworkProtocol/Run.sh b/聊天系统课程代码/Tools/NetworkProtocol/Run.sh new file mode 100644 index 0000000..763ce02 --- /dev/null +++ b/聊天系统课程代码/Tools/NetworkProtocol/Run.sh @@ -0,0 +1,23 @@ +#!/bin/bash + +echo "1. Client" +echo "2. Server" +echo "3. All" + +read -n 1 -p "Please select an option:" choice +echo "" +echo "" +case $choice in + 1) + dotnet Fantasy.Tools.NetworkProtocol.dll --ExportPlatform 1 + ;; + 2) + dotnet Fantasy.Tools.NetworkProtocol.dll --ExportPlatform 2 + ;; + 3) + dotnet Fantasy.Tools.NetworkProtocol.dll --ExportPlatform 3 + ;; + *) + echo "Invalid option" + ;; +esac diff --git a/邮件系统课程完整代码/.idea/.idea.Mail/.idea/.gitignore b/邮件系统课程完整代码/.idea/.idea.Mail/.idea/.gitignore new file mode 100644 index 0000000..a6f8f1b --- /dev/null +++ b/邮件系统课程完整代码/.idea/.idea.Mail/.idea/.gitignore @@ -0,0 +1,13 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Rider ignored files +/modules.xml +/.idea.Mail.iml +/contentModel.xml +/projectSettingsUpdater.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/邮件系统课程完整代码/.idea/.idea.Mail/.idea/.name b/邮件系统课程完整代码/.idea/.idea.Mail/.idea/.name new file mode 100644 index 0000000..d7e8913 --- /dev/null +++ b/邮件系统课程完整代码/.idea/.idea.Mail/.idea/.name @@ -0,0 +1 @@ +Mail \ No newline at end of file diff --git a/邮件系统课程完整代码/.idea/.idea.Mail/.idea/encodings.xml b/邮件系统课程完整代码/.idea/.idea.Mail/.idea/encodings.xml new file mode 100644 index 0000000..df87cf9 --- /dev/null +++ b/邮件系统课程完整代码/.idea/.idea.Mail/.idea/encodings.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/邮件系统课程完整代码/.idea/.idea.Mail/.idea/indexLayout.xml b/邮件系统课程完整代码/.idea/.idea.Mail/.idea/indexLayout.xml new file mode 100644 index 0000000..7b08163 --- /dev/null +++ b/邮件系统课程完整代码/.idea/.idea.Mail/.idea/indexLayout.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/邮件系统课程完整代码/Bin/.DS_Store b/邮件系统课程完整代码/Bin/.DS_Store new file mode 100644 index 0000000..9a8589a Binary files /dev/null and b/邮件系统课程完整代码/Bin/.DS_Store differ diff --git a/邮件系统课程完整代码/Bin/Logs/Server/Server20250302/Server..2025030210.Debug.log b/邮件系统课程完整代码/Bin/Logs/Server/Server20250302/Server..2025030210.Debug.log new file mode 100644 index 0000000..2643f86 --- /dev/null +++ b/邮件系统课程完整代码/Bin/Logs/Server/Server20250302/Server..2025030210.Debug.log @@ -0,0 +1,14 @@ +2025-03-02 10:51:23.2268 (MailUnitManageComponentSystem.cs:38) MailUnitManageComponent Init units:4 +2025-03-02 10:51:53.2391 (C2G_LoginRequestHandler.cs:21) 登陆的用户名为:3 +2025-03-02 10:51:53.2640 (C2G_LoginRequestHandler.cs:40) 当前账号:3 已经存在,直接登陆。 +2025-03-02 10:51:53.2735 (MailUnitManageComponentSystem.cs:55) 用户已经存在行不需要重新创建 Name:3 mailUnit:2589006870177906701 +2025-03-02 10:51:53.3256 (C2G_LoginRequestHandler.cs:53) 登陆成功 Name:3 +2025-03-02 10:52:13.7405 (MailHelper.cs:81) 发送离线邮件成功,用户上线第一时间会领取这个邮件。 +2025-03-02 10:52:13.7648 (MailHelper.cs:102) 保存离线邮件成功 +2025-03-02 10:52:19.4659 (MailUnitManageComponentSystem.cs:122) AccountId:81765354132733953 Name:3 Exit! +2025-03-02 10:52:24.7854 (C2G_LoginRequestHandler.cs:21) 登陆的用户名为:1 +2025-03-02 10:52:24.7954 (C2G_LoginRequestHandler.cs:40) 当前账号:1 已经存在,直接登陆。 +2025-03-02 10:52:24.7989 (MailUnitManageComponentSystem.cs:55) 用户已经存在行不需要重新创建 Name:1 mailUnit:2589006870177906699 +2025-03-02 10:52:24.8191 (MailBoxManageComponentSystem.cs:204) 领取了一个离线邮件 MailId:89237961706831872 +2025-03-02 10:52:24.8283 (C2G_LoginRequestHandler.cs:53) 登陆成功 Name:1 +2025-03-02 10:52:43.4271 (MailUnitManageComponentSystem.cs:122) AccountId:81692975343861761 Name:1 Exit! diff --git a/邮件系统课程完整代码/Bin/Logs/Server/Server20250302/Server..2025030210.Info.log b/邮件系统课程完整代码/Bin/Logs/Server/Server20250302/Server..2025030210.Info.log new file mode 100644 index 0000000..28b0fb1 --- /dev/null +++ b/邮件系统课程完整代码/Bin/Logs/Server/Server20250302/Server..2025030210.Info.log @@ -0,0 +1,9 @@ +2025-03-02 10:51:22.8816 初始化序列化器成功,数量为:2 +2025-03-02 10:51:23.1310 SceneConfigId = 1001 networkTarget = Inner TCPServer Listen 127.0.0.1:11001 +2025-03-02 10:51:23.1447 SceneConfigId = 1002 networkTarget = Inner TCPServer Listen 127.0.0.1:11002 +2025-03-02 10:51:23.1590 SceneConfigId = 1002 networkTarget = Outer KCPServer Listen 127.0.0.1:20000 +2025-03-02 10:51:23.1711 SceneConfigId = 1003 networkTarget = Inner TCPServer Listen 127.0.0.1:11003 +2025-03-02 10:51:23.1875 SceneConfigId = 1004 networkTarget = Inner TCPServer Listen 127.0.0.1:11004 +2025-03-02 10:51:23.1875 Process:1 Startup Complete SceneCount:4 +2025-03-02 10:52:24.8187 (MailComponentSystem.cs:66) MailComponentSystem Add 89237961706831872 Count:1 +2025-03-02 10:52:27.4068 (MailComponentSystem.cs:116) MailComponentSystem CheckTimeOut Count:0 diff --git a/邮件系统课程完整代码/Bin/net8.0/App b/邮件系统课程完整代码/Bin/net8.0/App new file mode 100644 index 0000000..92db307 Binary files /dev/null and b/邮件系统课程完整代码/Bin/net8.0/App differ diff --git a/邮件系统课程完整代码/Bin/net8.0/App.deps.json b/邮件系统课程完整代码/Bin/net8.0/App.deps.json new file mode 100644 index 0000000..4e2d6e0 --- /dev/null +++ b/邮件系统课程完整代码/Bin/net8.0/App.deps.json @@ -0,0 +1,386 @@ +{ + "runtimeTarget": { + "name": ".NETCoreApp,Version=v8.0", + "signature": "" + }, + "compilationOptions": {}, + "targets": { + ".NETCoreApp,Version=v8.0": { + "App/1.0.0": { + "dependencies": { + "Entity": "1.0.0", + "Fantasy-Net.NLog": "2024.1.20", + "Hotfix": "1.0.0" + }, + "runtime": { + "App.dll": {} + } + }, + "CommandLineParser/2.9.1": { + "runtime": { + "lib/netstandard2.0/CommandLine.dll": { + "assemblyVersion": "2.9.1.0", + "fileVersion": "2.9.1.0" + } + } + }, + "DnsClient/1.6.1": { + "dependencies": { + "Microsoft.Win32.Registry": "5.0.0" + }, + "runtime": { + "lib/net5.0/DnsClient.dll": { + "assemblyVersion": "1.6.1.0", + "fileVersion": "1.6.1.0" + } + } + }, + "Fantasy-Net/2024.2.22": { + "dependencies": { + "CommandLineParser": "2.9.1", + "MongoDB.Bson": "3.1.0", + "MongoDB.Driver": "3.1.0", + "Newtonsoft.Json": "13.0.3", + "System.IO.Pipelines": "9.0.0", + "protobuf-net": "3.2.45" + }, + "runtime": { + "lib/net8.0/Fantasy-Net.dll": { + "assemblyVersion": "1.0.0.0", + "fileVersion": "1.0.0.0" + } + } + }, + "Fantasy-Net.NLog/2024.1.20": { + "dependencies": { + "Fantasy-Net": "2024.2.22", + "NLog": "5.3.4" + }, + "runtime": { + "lib/net8.0/Fantasy-Net.NLog.dll": { + "assemblyVersion": "1.0.0.0", + "fileVersion": "1.0.0.0" + } + } + }, + "Microsoft.Extensions.Logging.Abstractions/2.0.0": {}, + "Microsoft.NETCore.Platforms/5.0.0": {}, + "Microsoft.Win32.Registry/5.0.0": { + "dependencies": { + "System.Security.AccessControl": "5.0.0", + "System.Security.Principal.Windows": "5.0.0" + } + }, + "MongoDB.Bson/3.1.0": { + "dependencies": { + "System.Memory": "4.5.5", + "System.Runtime.CompilerServices.Unsafe": "5.0.0" + }, + "runtime": { + "lib/net6.0/MongoDB.Bson.dll": { + "assemblyVersion": "3.1.0.0", + "fileVersion": "3.1.0.0" + } + } + }, + "MongoDB.Driver/3.1.0": { + "dependencies": { + "DnsClient": "1.6.1", + "Microsoft.Extensions.Logging.Abstractions": "2.0.0", + "MongoDB.Bson": "3.1.0", + "SharpCompress": "0.30.1", + "Snappier": "1.0.0", + "System.Buffers": "4.5.1", + "ZstdSharp.Port": "0.7.3" + }, + "runtime": { + "lib/net6.0/MongoDB.Driver.dll": { + "assemblyVersion": "3.1.0.0", + "fileVersion": "3.1.0.0" + } + } + }, + "Newtonsoft.Json/13.0.3": { + "runtime": { + "lib/net6.0/Newtonsoft.Json.dll": { + "assemblyVersion": "13.0.0.0", + "fileVersion": "13.0.3.27908" + } + } + }, + "NLog/5.3.4": { + "runtime": { + "lib/netstandard2.0/NLog.dll": { + "assemblyVersion": "5.0.0.0", + "fileVersion": "5.3.4.2778" + } + } + }, + "protobuf-net/3.2.45": { + "dependencies": { + "protobuf-net.Core": "3.2.45" + }, + "runtime": { + "lib/net6.0/protobuf-net.dll": { + "assemblyVersion": "3.0.0.0", + "fileVersion": "3.2.45.36865" + } + } + }, + "protobuf-net.Core/3.2.45": { + "dependencies": { + "System.Collections.Immutable": "7.0.0" + }, + "runtime": { + "lib/net6.0/protobuf-net.Core.dll": { + "assemblyVersion": "3.0.0.0", + "fileVersion": "3.2.45.36865" + } + } + }, + "SharpCompress/0.30.1": { + "runtime": { + "lib/net5.0/SharpCompress.dll": { + "assemblyVersion": "0.30.1.0", + "fileVersion": "0.30.1.0" + } + } + }, + "Snappier/1.0.0": { + "runtime": { + "lib/net5.0/Snappier.dll": { + "assemblyVersion": "1.0.0.0", + "fileVersion": "1.0.0.0" + } + } + }, + "System.Buffers/4.5.1": {}, + "System.Collections.Immutable/7.0.0": {}, + "System.IO.Pipelines/9.0.0": { + "runtime": { + "lib/net8.0/System.IO.Pipelines.dll": { + "assemblyVersion": "9.0.0.0", + "fileVersion": "9.0.24.52809" + } + } + }, + "System.Memory/4.5.5": {}, + "System.Runtime.CompilerServices.Unsafe/5.0.0": {}, + "System.Security.AccessControl/5.0.0": { + "dependencies": { + "Microsoft.NETCore.Platforms": "5.0.0", + "System.Security.Principal.Windows": "5.0.0" + } + }, + "System.Security.Principal.Windows/5.0.0": {}, + "ZstdSharp.Port/0.7.3": { + "runtime": { + "lib/net7.0/ZstdSharp.dll": { + "assemblyVersion": "0.7.3.0", + "fileVersion": "0.7.3.0" + } + } + }, + "Entity/1.0.0": { + "dependencies": { + "Fantasy-Net": "2024.2.22" + }, + "runtime": { + "Entity.dll": { + "assemblyVersion": "1.0.0", + "fileVersion": "1.0.0.0" + } + } + }, + "Hotfix/1.0.0": { + "dependencies": { + "Entity": "1.0.0" + }, + "runtime": { + "Hotfix.dll": { + "assemblyVersion": "1.0.0", + "fileVersion": "1.0.0.0" + } + } + } + } + }, + "libraries": { + "App/1.0.0": { + "type": "project", + "serviceable": false, + "sha512": "" + }, + "CommandLineParser/2.9.1": { + "type": "package", + "serviceable": true, + "sha512": "sha512-OE0sl1/sQ37bjVsPKKtwQlWDgqaxWgtme3xZz7JssWUzg5JpMIyHgCTY9MVMxOg48fJ1AgGT3tgdH5m/kQ5xhA==", + "path": "commandlineparser/2.9.1", + "hashPath": "commandlineparser.2.9.1.nupkg.sha512" + }, + "DnsClient/1.6.1": { + "type": "package", + "serviceable": true, + "sha512": "sha512-4H/f2uYJOZ+YObZjpY9ABrKZI+JNw3uizp6oMzTXwDw6F+2qIPhpRl/1t68O/6e98+vqNiYGu+lswmwdYUy3gg==", + "path": "dnsclient/1.6.1", + "hashPath": "dnsclient.1.6.1.nupkg.sha512" + }, + "Fantasy-Net/2024.2.22": { + "type": "package", + "serviceable": true, + "sha512": "sha512-cT6B0YJ5JmbPHBLYgLeVgg2WbXYxxa1tudoIase88uMzAuqU9t7EQ7dFZGSWjP41c5JOQ/0f1q9lzGWTh/hskw==", + "path": "fantasy-net/2024.2.22", + "hashPath": "fantasy-net.2024.2.22.nupkg.sha512" + }, + "Fantasy-Net.NLog/2024.1.20": { + "type": "package", + "serviceable": true, + "sha512": "sha512-HJuHfecWrD7tcQYEZezJzgayvG5leAbdWlgvo9ft/CUuwTtAB+tkeKP3e3VtbkCoPaAZO4VAUN0Y30Ute2/vrQ==", + "path": "fantasy-net.nlog/2024.1.20", + "hashPath": "fantasy-net.nlog.2024.1.20.nupkg.sha512" + }, + "Microsoft.Extensions.Logging.Abstractions/2.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-6ZCllUYGFukkymSTx3Yr0G/ajRxoNJp7/FqSxSB4fGISST54ifBhgu4Nc0ItGi3i6DqwuNd8SUyObmiC++AO2Q==", + "path": "microsoft.extensions.logging.abstractions/2.0.0", + "hashPath": "microsoft.extensions.logging.abstractions.2.0.0.nupkg.sha512" + }, + "Microsoft.NETCore.Platforms/5.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-VyPlqzH2wavqquTcYpkIIAQ6WdenuKoFN0BdYBbCWsclXacSOHNQn66Gt4z5NBqEYW0FAPm5rlvki9ZiCij5xQ==", + "path": "microsoft.netcore.platforms/5.0.0", + "hashPath": "microsoft.netcore.platforms.5.0.0.nupkg.sha512" + }, + "Microsoft.Win32.Registry/5.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-dDoKi0PnDz31yAyETfRntsLArTlVAVzUzCIvvEDsDsucrl33Dl8pIJG06ePTJTI3tGpeyHS9Cq7Foc/s4EeKcg==", + "path": "microsoft.win32.registry/5.0.0", + "hashPath": "microsoft.win32.registry.5.0.0.nupkg.sha512" + }, + "MongoDB.Bson/3.1.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-3dhaZhz18B5vUoEP13o2j8A6zQfkHdZhwBvLZEjDJum4BTLLv1/Z8bt25UQEtpqvYwLgde4R6ekWZ7XAYUMxuw==", + "path": "mongodb.bson/3.1.0", + "hashPath": "mongodb.bson.3.1.0.nupkg.sha512" + }, + "MongoDB.Driver/3.1.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-+O7lKaIl7VUHptE0hqTd7UY1G5KDp/o8S4upG7YL4uChMNKD/U6tz9i17nMGHaD/L2AiPLgaJcaDe2XACsegGA==", + "path": "mongodb.driver/3.1.0", + "hashPath": "mongodb.driver.3.1.0.nupkg.sha512" + }, + "Newtonsoft.Json/13.0.3": { + "type": "package", + "serviceable": true, + "sha512": "sha512-HrC5BXdl00IP9zeV+0Z848QWPAoCr9P3bDEZguI+gkLcBKAOxix/tLEAAHC+UvDNPv4a2d18lOReHMOagPa+zQ==", + "path": "newtonsoft.json/13.0.3", + "hashPath": "newtonsoft.json.13.0.3.nupkg.sha512" + }, + "NLog/5.3.4": { + "type": "package", + "serviceable": true, + "sha512": "sha512-gLy7+O1hEYJXIlcTr1/VWjGXrZTQFZzYNO18IWasD64pNwz0BreV+nHLxWKXWZzERRzoKnsk2XYtwLkTVk7J1A==", + "path": "nlog/5.3.4", + "hashPath": "nlog.5.3.4.nupkg.sha512" + }, + "protobuf-net/3.2.45": { + "type": "package", + "serviceable": true, + "sha512": "sha512-5UZ/ukUHcGbFSl7vNMrHsfjqdxusdd9w7w0fCEXzf3UUtsrGNVCzV5SmF+sCHAbnRV2qPcD1ixiDP7Aj8lX/HA==", + "path": "protobuf-net/3.2.45", + "hashPath": "protobuf-net.3.2.45.nupkg.sha512" + }, + "protobuf-net.Core/3.2.45": { + "type": "package", + "serviceable": true, + "sha512": "sha512-PMWatW2NrT1uTXD7etJ4VdQ0wWZLFrIfdRGppD2QX7nzZ0+kIzqhq551u6ZiXJHWJgG4hWFEkSnUnt2aB6posg==", + "path": "protobuf-net.core/3.2.45", + "hashPath": "protobuf-net.core.3.2.45.nupkg.sha512" + }, + "SharpCompress/0.30.1": { + "type": "package", + "serviceable": true, + "sha512": "sha512-XqD4TpfyYGa7QTPzaGlMVbcecKnXy4YmYLDWrU+JIj7IuRNl7DH2END+Ll7ekWIY8o3dAMWLFDE1xdhfIWD1nw==", + "path": "sharpcompress/0.30.1", + "hashPath": "sharpcompress.0.30.1.nupkg.sha512" + }, + "Snappier/1.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-rFtK2KEI9hIe8gtx3a0YDXdHOpedIf9wYCEYtBEmtlyiWVX3XlCNV03JrmmAi/Cdfn7dxK+k0sjjcLv4fpHnqA==", + "path": "snappier/1.0.0", + "hashPath": "snappier.1.0.0.nupkg.sha512" + }, + "System.Buffers/4.5.1": { + "type": "package", + "serviceable": true, + "sha512": "sha512-Rw7ijyl1qqRS0YQD/WycNst8hUUMgrMH4FCn1nNm27M4VxchZ1js3fVjQaANHO5f3sN4isvP4a+Met9Y4YomAg==", + "path": "system.buffers/4.5.1", + "hashPath": "system.buffers.4.5.1.nupkg.sha512" + }, + "System.Collections.Immutable/7.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-dQPcs0U1IKnBdRDBkrCTi1FoajSTBzLcVTpjO4MBCMC7f4pDOIPzgBoX8JjG7X6uZRJ8EBxsi8+DR1JuwjnzOQ==", + "path": "system.collections.immutable/7.0.0", + "hashPath": "system.collections.immutable.7.0.0.nupkg.sha512" + }, + "System.IO.Pipelines/9.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-eA3cinogwaNB4jdjQHOP3Z3EuyiDII7MT35jgtnsA4vkn0LUrrSHsU0nzHTzFzmaFYeKV7MYyMxOocFzsBHpTw==", + "path": "system.io.pipelines/9.0.0", + "hashPath": "system.io.pipelines.9.0.0.nupkg.sha512" + }, + "System.Memory/4.5.5": { + "type": "package", + "serviceable": true, + "sha512": "sha512-XIWiDvKPXaTveaB7HVganDlOCRoj03l+jrwNvcge/t8vhGYKvqV+dMv6G4SAX2NoNmN0wZfVPTAlFwZcZvVOUw==", + "path": "system.memory/4.5.5", + "hashPath": "system.memory.4.5.5.nupkg.sha512" + }, + "System.Runtime.CompilerServices.Unsafe/5.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-ZD9TMpsmYJLrxbbmdvhwt9YEgG5WntEnZ/d1eH8JBX9LBp+Ju8BSBhUGbZMNVHHomWo2KVImJhTDl2hIgw/6MA==", + "path": "system.runtime.compilerservices.unsafe/5.0.0", + "hashPath": "system.runtime.compilerservices.unsafe.5.0.0.nupkg.sha512" + }, + "System.Security.AccessControl/5.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-dagJ1mHZO3Ani8GH0PHpPEe/oYO+rVdbQjvjJkBRNQkX4t0r1iaeGn8+/ybkSLEan3/slM0t59SVdHzuHf2jmw==", + "path": "system.security.accesscontrol/5.0.0", + "hashPath": "system.security.accesscontrol.5.0.0.nupkg.sha512" + }, + "System.Security.Principal.Windows/5.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-t0MGLukB5WAVU9bO3MGzvlGnyJPgUlcwerXn1kzBRjwLKixT96XV0Uza41W49gVd8zEMFu9vQEFlv0IOrytICA==", + "path": "system.security.principal.windows/5.0.0", + "hashPath": "system.security.principal.windows.5.0.0.nupkg.sha512" + }, + "ZstdSharp.Port/0.7.3": { + "type": "package", + "serviceable": true, + "sha512": "sha512-U9Ix4l4cl58Kzz1rJzj5hoVTjmbx1qGMwzAcbv1j/d3NzrFaESIurQyg+ow4mivCgkE3S413y+U9k4WdnEIkRA==", + "path": "zstdsharp.port/0.7.3", + "hashPath": "zstdsharp.port.0.7.3.nupkg.sha512" + }, + "Entity/1.0.0": { + "type": "project", + "serviceable": false, + "sha512": "" + }, + "Hotfix/1.0.0": { + "type": "project", + "serviceable": false, + "sha512": "" + } + } +} \ No newline at end of file diff --git a/邮件系统课程完整代码/Bin/net8.0/App.dll b/邮件系统课程完整代码/Bin/net8.0/App.dll new file mode 100644 index 0000000..6625e40 Binary files /dev/null and b/邮件系统课程完整代码/Bin/net8.0/App.dll differ diff --git a/邮件系统课程完整代码/Bin/net8.0/App.pdb b/邮件系统课程完整代码/Bin/net8.0/App.pdb new file mode 100644 index 0000000..b109dba Binary files /dev/null and b/邮件系统课程完整代码/Bin/net8.0/App.pdb differ diff --git a/邮件系统课程完整代码/Bin/net8.0/App.runtimeconfig.json b/邮件系统课程完整代码/Bin/net8.0/App.runtimeconfig.json new file mode 100644 index 0000000..206362b --- /dev/null +++ b/邮件系统课程完整代码/Bin/net8.0/App.runtimeconfig.json @@ -0,0 +1,18 @@ +{ + "runtimeOptions": { + "tfm": "net8.0", + "frameworks": [ + { + "name": "Microsoft.NETCore.App", + "version": "8.0.0" + }, + { + "name": "Microsoft.AspNetCore.App", + "version": "8.0.0" + } + ], + "configProperties": { + "System.Runtime.Serialization.EnableUnsafeBinaryFormatterSerialization": false + } + } +} \ No newline at end of file diff --git a/邮件系统课程完整代码/Bin/net8.0/CommandLine.dll b/邮件系统课程完整代码/Bin/net8.0/CommandLine.dll new file mode 100644 index 0000000..3eab2be Binary files /dev/null and b/邮件系统课程完整代码/Bin/net8.0/CommandLine.dll differ diff --git a/邮件系统课程完整代码/Bin/net8.0/DnsClient.dll b/邮件系统课程完整代码/Bin/net8.0/DnsClient.dll new file mode 100644 index 0000000..39aa546 Binary files /dev/null and b/邮件系统课程完整代码/Bin/net8.0/DnsClient.dll differ diff --git a/邮件系统课程完整代码/Bin/net8.0/Entity.dll b/邮件系统课程完整代码/Bin/net8.0/Entity.dll new file mode 100644 index 0000000..7a53135 Binary files /dev/null and b/邮件系统课程完整代码/Bin/net8.0/Entity.dll differ diff --git a/邮件系统课程完整代码/Bin/net8.0/Entity.pdb b/邮件系统课程完整代码/Bin/net8.0/Entity.pdb new file mode 100644 index 0000000..46121e0 Binary files /dev/null and b/邮件系统课程完整代码/Bin/net8.0/Entity.pdb differ diff --git a/邮件系统课程完整代码/Bin/net8.0/Fantasy-Net.NLog.dll b/邮件系统课程完整代码/Bin/net8.0/Fantasy-Net.NLog.dll new file mode 100644 index 0000000..7ffbcb5 Binary files /dev/null and b/邮件系统课程完整代码/Bin/net8.0/Fantasy-Net.NLog.dll differ diff --git a/邮件系统课程完整代码/Bin/net8.0/Fantasy-Net.dll b/邮件系统课程完整代码/Bin/net8.0/Fantasy-Net.dll new file mode 100644 index 0000000..31f582f Binary files /dev/null and b/邮件系统课程完整代码/Bin/net8.0/Fantasy-Net.dll differ diff --git a/邮件系统课程完整代码/Bin/net8.0/Hotfix.dll b/邮件系统课程完整代码/Bin/net8.0/Hotfix.dll new file mode 100644 index 0000000..5cc9998 Binary files /dev/null and b/邮件系统课程完整代码/Bin/net8.0/Hotfix.dll differ diff --git a/邮件系统课程完整代码/Bin/net8.0/Hotfix.pdb b/邮件系统课程完整代码/Bin/net8.0/Hotfix.pdb new file mode 100644 index 0000000..0388ba5 Binary files /dev/null and b/邮件系统课程完整代码/Bin/net8.0/Hotfix.pdb differ diff --git a/邮件系统课程完整代码/Bin/net8.0/MongoDB.Bson.dll b/邮件系统课程完整代码/Bin/net8.0/MongoDB.Bson.dll new file mode 100644 index 0000000..c604c81 Binary files /dev/null and b/邮件系统课程完整代码/Bin/net8.0/MongoDB.Bson.dll differ diff --git a/邮件系统课程完整代码/Bin/net8.0/MongoDB.Driver.dll b/邮件系统课程完整代码/Bin/net8.0/MongoDB.Driver.dll new file mode 100644 index 0000000..1308944 Binary files /dev/null and b/邮件系统课程完整代码/Bin/net8.0/MongoDB.Driver.dll differ diff --git a/邮件系统课程完整代码/Bin/net8.0/NLog.config b/邮件系统课程完整代码/Bin/net8.0/NLog.config new file mode 100644 index 0000000..4df5ea1 --- /dev/null +++ b/邮件系统课程完整代码/Bin/net8.0/NLog.config @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/邮件系统课程完整代码/Bin/net8.0/NLog.dll b/邮件系统课程完整代码/Bin/net8.0/NLog.dll new file mode 100644 index 0000000..49604e1 Binary files /dev/null and b/邮件系统课程完整代码/Bin/net8.0/NLog.dll differ diff --git a/邮件系统课程完整代码/Bin/net8.0/NLog.xsd b/邮件系统课程完整代码/Bin/net8.0/NLog.xsd new file mode 100644 index 0000000..63c9a0c --- /dev/null +++ b/邮件系统课程完整代码/Bin/net8.0/NLog.xsd @@ -0,0 +1,3483 @@ + + + + + + + + + + + + + + + Watch config file for changes and reload automatically. + + + + + Print internal NLog messages to the console. Default value is: false + + + + + Print internal NLog messages to the console error output. Default value is: false + + + + + Write internal NLog messages to the specified file. + + + + + Log level threshold for internal log messages. Default value is: Info. + + + + + Global log level threshold for application log messages. Messages below this level won't be logged. + + + + + Throw an exception when there is an internal error. Default value is: false. Not recommend to set to true in production! + + + + + Throw an exception when there is a configuration error. If not set, determined by throwExceptions. + + + + + Gets or sets a value indicating whether Variables should be kept on configuration reload. Default value is: false. + + + + + Write internal NLog messages to the System.Diagnostics.Trace. Default value is: false. + + + + + Write timestamps for internal NLog messages. Default value is: true. + + + + + Use InvariantCulture as default culture instead of CurrentCulture. Default value is: false. + + + + + Perform message template parsing and formatting of LogEvent messages (true = Always, false = Never, empty = Auto Detect). Default value is: empty. + + + + + + + + + + + + + + Make all targets within this section asynchronous (creates additional threads but the calling thread isn't blocked by any target writes). + + + + + + + + + + + + + + + + + Prefix for targets/layout renderers/filters/conditions loaded from this assembly. + + + + + Load NLog extensions from the specified file (*.dll) + + + + + Load NLog extensions from the specified assembly. Assembly name should be fully qualified. + + + + + + + + + + Filter on the name of the logger. May include wildcard characters ('*' or '?'). + + + + + Comma separated list of levels that this rule matches. + + + + + Minimum level that this rule matches. + + + + + Maximum level that this rule matches. + + + + + Level that this rule matches. + + + + + Comma separated list of target names. + + + + + Ignore further rules if this one matches. + + + + + Enable this rule. Note: disabled rules aren't available from the API. + + + + + Rule identifier to allow rule lookup with Configuration.FindRuleByName and Configuration.RemoveRuleByName. + + + + + Loggers matching will be restricted to specified minimum level for following rules. + + + + + + + + + + + + + + + Default action if none of the filters match. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Name of the file to be included. You could use * wildcard. The name is relative to the name of the current config file. + + + + + Ignore any errors in the include file. + + + + + + + + Variable value. Note, the 'value' attribute has precedence over this one. + + + + + + Variable name. + + + + + Variable value. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Action to be taken when the lazy writer thread request queue count exceeds the set limit. + + + + + Limit on the number of requests in the lazy writer thread request queue. + + + + + Number of log events that should be processed in a batch by the lazy writer thread. + + + + + Whether to use the locking queue, instead of a lock-free concurrent queue + + + + + Number of batches of P:NLog.Targets.Wrappers.AsyncTargetWrapper.BatchSize to write before yielding into P:NLog.Targets.Wrappers.AsyncTargetWrapper.TimeToSleepBetweenBatches + + + + + Time in milliseconds to sleep between batches. (1 or less means trigger on new activity) + + + + + + + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Delay the flush until the LogEvent has been confirmed as written + + + + + Condition expression. Log events who meet this condition will cause a flush on the wrapped target. + + + + + Only flush when LogEvent matches condition. Ignore explicit-flush, config-reload-flush and shutdown-flush + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Number of log events to be buffered. + + + + + Action to take if the buffer overflows. + + + + + Timeout (in milliseconds) after which the contents of buffer will be flushed if there's no write in the specified period of time. Use -1 to disable timed flushes. + + + + + Indicates whether to use sliding timeout. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Separator for T:NLog.ScopeContext operation-states-stack. + + + + + Stack separator for log4j:NDC in output from T:NLog.ScopeContext nested context. + + + + + Renderer for log4j:event logger-xml-attribute (Default ${logger}) + + + + + Whether to include the contents of the T:NLog.ScopeContext properties-dictionary. + + + + + Whether to include log4j:NDC in output from T:NLog.ScopeContext nested context. + + + + + Indicates whether to include source info (file name and line number) in the information sent over the network. + + + + + Whether to include log4j:NDC in output from T:NLog.ScopeContext nested context. + + + + + Option to include all properties from the log events + + + + + Indicates whether to include call site (class and method name) in the information sent over the network. + + + + + AppInfo field. By default it's the friendly name of the current AppDomain. + + + + + Instance of T:NLog.Layouts.Log4JXmlEventLayout that is used to format log messages. + + + + + Indicates whether to include NLog-specific extensions to log4j schema. + + + + + Action that should be taken, when more connections than P:NLog.Targets.NetworkTarget.MaxConnections. + + + + + SSL/TLS protocols. Default no SSL/TLS is used. Currently only implemented for TCP. + + + + + Action that should be taken, when more pending messages than P:NLog.Targets.NetworkTarget.MaxQueueSize. + + + + + Action that should be taken if the message is larger than P:NLog.Targets.NetworkTarget.MaxMessageSize + + + + + Maximum queue size for a single connection. Requires P:NLog.Targets.NetworkTarget.KeepConnection = true + + + + + Network address. + + + + + Indicates whether to keep connection open whenever possible. + + + + + The number of seconds a connection will remain idle before the first keep-alive probe is sent + + + + + Size of the connection cache (number of connections which are kept alive). Requires P:NLog.Targets.NetworkTarget.KeepConnection = true + + + + + Maximum simultaneous connections. Requires P:NLog.Targets.NetworkTarget.KeepConnection = false + + + + + Type of compression for protocol payload. Useful for UDP where datagram max-size is 8192 bytes. + + + + + Skip compression when protocol payload is below limit to reduce overhead in cpu-usage and additional headers + + + + + Maximum message size in bytes. On limit breach then P:NLog.Targets.NetworkTarget.OnOverflow action is activated. + + + + + Encoding to be used. + + + + + End of line value if a newline is appended at the end of log message P:NLog.Targets.NetworkTarget.NewLine. + + + + + Indicates whether to append newline at the end of log message. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Viewer parameter name. + + + + + Layout that should be use to calculate the value for the parameter. + + + + + Whether an attribute with empty value should be included in the output + + + + + + + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Text to be rendered. + + + + + Header. + + + + + Footer. + + + + + Indicates whether to auto-check if the console is available. - Disables console writing if Environment.UserInteractive = False (Windows Service) - Disables console writing if Console Standard Input is not available (Non-Console-App) + + + + + Enables output using ANSI Color Codes + + + + + The encoding for writing messages to the T:System.Console. + + + + + Indicates whether to send the log messages to the standard error instead of the standard output. + + + + + Indicates whether to auto-flush after M:System.Console.WriteLine + + + + + Indicates whether to auto-check if the console has been redirected to file - Disables coloring logic when System.Console.IsOutputRedirected = true + + + + + Indicates whether to use default row highlighting rules. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Background color. + + + + + Condition that must be met in order to set the specified foreground and background color. + + + + + Foreground color. + + + + + + + + + + + + + + + + + Background color. + + + + + Compile the P:NLog.Targets.ConsoleWordHighlightingRule.Regex? This can improve the performance, but at the costs of more memory usage. If false, the Regex Cache is used. + + + + + Condition that must be met before scanning the row for highlight of words + + + + + Foreground color. + + + + + Indicates whether to ignore case when comparing texts. + + + + + Regular expression to be matched. You must specify either text or regex. + + + + + Text to be matched. You must specify either text or regex. + + + + + Indicates whether to match whole words only. + + + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Text to be rendered. + + + + + Header. + + + + + Footer. + + + + + Indicates whether to auto-flush after M:System.Console.WriteLine + + + + + Indicates whether to auto-check if the console is available - Disables console writing if Environment.UserInteractive = False (Windows Service) - Disables console writing if Console Standard Input is not available (Non-Console-App) + + + + + The encoding for writing messages to the T:System.Console. + + + + + Indicates whether to send the log messages to the standard error instead of the standard output. + + + + + Whether to activate internal buffering to allow batch writing, instead of using M:System.Console.WriteLine + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Database user name. If the ConnectionString is not provided this value will be used to construct the "User ID=" part of the connection string. + + + + + Database password. If the ConnectionString is not provided this value will be used to construct the "Password=" part of the connection string. + + + + + Database name. If the ConnectionString is not provided this value will be used to construct the "Database=" part of the connection string. + + + + + Name of the connection string (as specified in <connectionStrings> configuration section. + + + + + Database host name. If the ConnectionString is not provided this value will be used to construct the "Server=" part of the connection string. + + + + + Indicates whether to keep the database connection open between the log events. + + + + + Name of the database provider. + + + + + Connection string. When provided, it overrides the values specified in DBHost, DBUserName, DBPassword, DBDatabase. + + + + + Connection string using for installation and uninstallation. If not provided, regular ConnectionString is being used. + + + + + Configures isolated transaction batch writing. If supported by the database, then it will improve insert performance. + + + + + Text of the SQL command to be run on each log level. + + + + + Type of the SQL command to be run on each log level. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Convert format of the property value + + + + + Culture used for parsing property string-value for type-conversion + + + + + Value to assign on the object-property + + + + + Name for the object-property + + + + + Type of the object-property + + + + + + + + + + + + + + Type of the command. + + + + + Connection string to run the command against. If not provided, connection string from the target is used. + + + + + Indicates whether to ignore failures. + + + + + Command text. + + + + + + + + + + + + + + + + + + + + Database parameter name. + + + + + Layout that should be use to calculate the value for the parameter. + + + + + Database parameter DbType. + + + + + Database parameter size. + + + + + Database parameter precision. + + + + + Database parameter scale. + + + + + Type of the parameter. + + + + + Fallback value when result value is not available + + + + + Convert format of the database parameter value. + + + + + Culture used for parsing parameter string-value for type-conversion + + + + + Whether empty value should translate into DbNull. Requires database column to allow NULL values. + + + + + + + + + + + + + + + Name of the target. + + + + + Text to be rendered. + + + + + Header. + + + + + Footer. + + + + + + + + + + + + + + + + + Name of the target. + + + + + Text to be rendered. + + + + + Header. + + + + + Footer. + + + + + + + + + + + + + + + Name of the target. + + + + + Layout used to format log messages. + + + + + + + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Layout used to format log messages. + + + + + Layout that renders event Category. + + + + + Optional entry type. When not set, or when not convertible to T:System.Diagnostics.EventLogEntryType then determined by T:NLog.LogLevel + + + + + Layout that renders event ID. + + + + + Name of the Event Log to write to. This can be System, Application or any user-defined name. + + + + + Name of the machine on which Event Log service is running. + + + + + Maximum Event log size in kilobytes. + + + + + Message length limit to write to the Event Log. + + + + + Value to be used as the event Source. + + + + + Action to take if the message is larger than the P:NLog.Targets.EventLogTarget.MaxMessageLength option. + + + + + + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Indicates whether to return to the first target after any successful write. + + + + + Whether to enable batching, but fallback will be handled individually + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Name of the file to write to. + + + + + Text to be rendered. + + + + + Header. + + + + + Footer. + + + + + Indicates whether the footer should be written only when the file is archived. + + + + + Maximum number of archive files that should be kept. + + + + + Maximum days of archive files that should be kept. + + + + + Value of the file size threshold to archive old log file on startup. + + + + + Indicates whether to archive old log file on startup. + + + + + Indicates whether to compress archive files into the zip archive format. + + + + + Name of the file to be used for an archive. + + + + + Is the P:NLog.Targets.FileTarget.ArchiveFileName an absolute or relative path? + + + + + Indicates whether to automatically archive log files every time the specified time passes. + + + + + Value specifying the date format to use when archiving files. + + + + + Size in bytes above which log files will be automatically archived. + + + + + Way file archives are numbered. + + + + + Indicates whether to create directories if they do not exist. + + + + + Indicates whether file creation calls should be synchronized by a system global mutex. + + + + + Gets or set a value indicating whether a managed file stream is forced, instead of using the native implementation. + + + + + Is the P:NLog.Targets.FileTarget.FileName an absolute or relative path? + + + + + File attributes (Windows only). + + + + + Cleanup invalid values in a filename, e.g. slashes in a filename. If set to true, this can impact the performance of massive writes. If set to false, nothing gets written when the filename is wrong. + + + + + Indicates whether to write BOM (byte order mark) in created files. Defaults to true for UTF-16 and UTF-32 + + + + + Indicates whether to enable log file(s) to be deleted. + + + + + Indicates whether to delete old log file on startup. + + + + + File encoding. + + + + + Indicates whether to replace file contents on each write instead of appending log message at the end. + + + + + Line ending mode. + + + + + Number of times the write is appended on the file before NLog discards the log message. + + + + + Delay in milliseconds to wait before attempting to write to the file again. + + + + + Maximum number of seconds before open files are flushed. Zero or negative means disabled. + + + + + Maximum number of seconds that files are kept open. Zero or negative means disabled. + + + + + Indicates whether concurrent writes to the log file by multiple processes on different network hosts. + + + + + Log file buffer size in bytes. + + + + + Indicates whether to automatically flush the file buffers after each log message. + + + + + Indicates whether to keep log file open instead of opening and closing it on each logging event. + + + + + Indicates whether concurrent writes to the log file by multiple processes on the same host. + + + + + Whether or not this target should just discard all data that its asked to write. Mostly used for when testing NLog Stack except final write + + + + + Number of files to be kept open. Setting this to a higher value may improve performance in a situation where a single File target is writing to many files (such as splitting by level or by logger). + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Condition expression. Log events who meet this condition will be forwarded to the wrapped target. + + + + + + + + + + + + + + + Name of the target. + + + + + Identifier to perform group-by + + + + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Windows domain name to change context to. + + + + + Required impersonation level. + + + + + Type of the logon provider. + + + + + Logon Type. + + + + + User account password. + + + + + Indicates whether to revert to the credentials of the process instead of impersonating another user. + + + + + Username to change context to. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Interval in which messages will be written up to the P:NLog.Targets.Wrappers.LimitingTargetWrapper.MessageLimit number of messages. + + + + + Maximum allowed number of messages written per P:NLog.Targets.Wrappers.LimitingTargetWrapper.Interval. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Text to be rendered. + + + + + Header. + + + + + Footer. + + + + + Indicates whether NewLine characters in the body should be replaced with tags. + + + + + Priority used for sending mails. + + + + + Encoding to be used for sending e-mail. + + + + + BCC email addresses separated by semicolons (e.g. john@domain.com;jane@domain.com). + + + + + CC email addresses separated by semicolons (e.g. john@domain.com;jane@domain.com). + + + + + Indicates whether to add new lines between log entries. + + + + + Indicates whether to send message as HTML instead of plain text. + + + + + Sender's email address (e.g. joe@domain.com). + + + + + Mail message body (repeated for each log message send in one mail). + + + + + Mail subject. + + + + + Recipients' email addresses separated by semicolons (e.g. john@domain.com;jane@domain.com). + + + + + Specifies how outgoing email messages will be handled. + + + + + SMTP Server to be used for sending. + + + + + SMTP Authentication mode. + + + + + Username used to connect to SMTP server (used when SmtpAuthentication is set to "basic"). + + + + + Password used to authenticate against SMTP server (used when SmtpAuthentication is set to "basic"). + + + + + Indicates whether SSL (secure sockets layer) should be used when communicating with SMTP server. + + + + + Port number that SMTP Server is listening on. + + + + + Indicates whether the default Settings from System.Net.MailSettings should be used. + + + + + Folder where applications save mail messages to be processed by the local SMTP server. + + + + + Indicates the SMTP client timeout. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Text to be rendered. + + + + + Header. + + + + + Footer. + + + + + Max number of items to have in memory + + + + + + + + + + + + + + + + + Name of the target. + + + + + Class name. + + + + + Method name. The method must be public and static. Use the AssemblyQualifiedName , https://msdn.microsoft.com/en-us/library/system.type.assemblyqualifiedname(v=vs.110).aspx e.g. + + + + + + + + + + + + + + + Name of the parameter. + + + + + Layout that should be use to calculate the value for the parameter. + + + + + Fallback value when result value is not available + + + + + Type of the parameter. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Layout used to format log messages. + + + + + SSL/TLS protocols. Default no SSL/TLS is used. Currently only implemented for TCP. + + + + + Action that should be taken, when more pending messages than P:NLog.Targets.NetworkTarget.MaxQueueSize. + + + + + Action that should be taken if the message is larger than P:NLog.Targets.NetworkTarget.MaxMessageSize + + + + + Maximum queue size for a single connection. Requires P:NLog.Targets.NetworkTarget.KeepConnection = true + + + + + Action that should be taken, when more connections than P:NLog.Targets.NetworkTarget.MaxConnections. + + + + + Indicates whether to keep connection open whenever possible. + + + + + The number of seconds a connection will remain idle before the first keep-alive probe is sent + + + + + Size of the connection cache (number of connections which are kept alive). Requires P:NLog.Targets.NetworkTarget.KeepConnection = true + + + + + Network address. + + + + + Maximum simultaneous connections. Requires P:NLog.Targets.NetworkTarget.KeepConnection = false + + + + + Type of compression for protocol payload. Useful for UDP where datagram max-size is 8192 bytes. + + + + + Skip compression when protocol payload is below limit to reduce overhead in cpu-usage and additional headers + + + + + Maximum message size in bytes. On limit breach then P:NLog.Targets.NetworkTarget.OnOverflow action is activated. + + + + + Encoding to be used. + + + + + End of line value if a newline is appended at the end of log message P:NLog.Targets.NetworkTarget.NewLine. + + + + + Indicates whether to append newline at the end of log message. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Separator for T:NLog.ScopeContext operation-states-stack. + + + + + Stack separator for log4j:NDC in output from T:NLog.ScopeContext nested context. + + + + + Renderer for log4j:event logger-xml-attribute (Default ${logger}) + + + + + Whether to include the contents of the T:NLog.ScopeContext properties-dictionary. + + + + + Whether to include log4j:NDC in output from T:NLog.ScopeContext nested context. + + + + + Indicates whether to include source info (file name and line number) in the information sent over the network. + + + + + Whether to include log4j:NDC in output from T:NLog.ScopeContext nested context. + + + + + Option to include all properties from the log events + + + + + Indicates whether to include call site (class and method name) in the information sent over the network. + + + + + AppInfo field. By default it's the friendly name of the current AppDomain. + + + + + Instance of T:NLog.Layouts.Log4JXmlEventLayout that is used to format log messages. + + + + + Indicates whether to include NLog-specific extensions to log4j schema. + + + + + Action that should be taken, when more connections than P:NLog.Targets.NetworkTarget.MaxConnections. + + + + + SSL/TLS protocols. Default no SSL/TLS is used. Currently only implemented for TCP. + + + + + Action that should be taken, when more pending messages than P:NLog.Targets.NetworkTarget.MaxQueueSize. + + + + + Action that should be taken if the message is larger than P:NLog.Targets.NetworkTarget.MaxMessageSize + + + + + Maximum queue size for a single connection. Requires P:NLog.Targets.NetworkTarget.KeepConnection = true + + + + + Network address. + + + + + Indicates whether to keep connection open whenever possible. + + + + + The number of seconds a connection will remain idle before the first keep-alive probe is sent + + + + + Size of the connection cache (number of connections which are kept alive). Requires P:NLog.Targets.NetworkTarget.KeepConnection = true + + + + + Maximum simultaneous connections. Requires P:NLog.Targets.NetworkTarget.KeepConnection = false + + + + + Type of compression for protocol payload. Useful for UDP where datagram max-size is 8192 bytes. + + + + + Skip compression when protocol payload is below limit to reduce overhead in cpu-usage and additional headers + + + + + Maximum message size in bytes. On limit breach then P:NLog.Targets.NetworkTarget.OnOverflow action is activated. + + + + + Encoding to be used. + + + + + End of line value if a newline is appended at the end of log message P:NLog.Targets.NetworkTarget.NewLine. + + + + + Indicates whether to append newline at the end of log message. + + + + + + + + + + + + + + + + Name of the target. + + + + + Layout used to format log messages. + + + + + Indicates whether to perform layout calculation. + + + + + + + + + + + + + + + + Name of the target. + + + + + Default filter to be applied when no specific rule matches. + + + + + + + + + + + + + Condition to be tested. + + + + + Resulting filter to be applied when the condition matches. + + + + + + + + + + + + Name of the target. + + + + + + + + + + + + + + + Name of the target. + + + + + Number of times to repeat each log message. + + + + + + + + + + + + + + + + + Name of the target. + + + + + Whether to enable batching, and only apply single delay when a whole batch fails + + + + + Number of retries that should be attempted on the wrapped target in case of a failure. + + + + + Time to wait between retries in milliseconds. + + + + + + + + + + + + + + Name of the target. + + + + + + + + + + + + + + Name of the target. + + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Text to be rendered. + + + + + Header. + + + + + Footer. + + + + + Forward F:NLog.LogLevel.Fatal to M:System.Diagnostics.Trace.Fail(System.String) (Instead of M:System.Diagnostics.Trace.TraceError(System.String)) + + + + + Force use M:System.Diagnostics.Trace.WriteLine(System.String) independent of T:NLog.LogLevel + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Indicates whether to pre-authenticate the HttpWebRequest (Requires 'Authorization' in P:NLog.Targets.WebServiceTarget.Headers parameters) + + + + + Value whether escaping be done according to Rfc3986 (Supports Internationalized Resource Identifiers - IRIs) + + + + + Value whether escaping be done according to the old NLog style (Very non-standard) + + + + + Value of the User-agent HTTP header. + + + + + Web service URL. + + + + + Proxy configuration when calling web service + + + + + Custom proxy address, include port separated by a colon + + + + + Protocol to be used when calling web service. + + + + + Web service namespace. Only used with Soap. + + + + + Web service method name. Only used with Soap. + + + + + Should we include the BOM (Byte-order-mark) for UTF? Influences the P:NLog.Targets.WebServiceTarget.Encoding property. This will only work for UTF-8. + + + + + Encoding. + + + + + Name of the root XML element, if POST of XML document chosen. If so, this property must not be null. (see P:NLog.Targets.WebServiceTarget.Protocol and F:NLog.Targets.WebServiceProtocol.XmlPost). + + + + + (optional) root namespace of the XML document, if POST of XML document chosen. (see P:NLog.Targets.WebServiceTarget.Protocol and F:NLog.Targets.WebServiceProtocol.XmlPost). + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Custom column delimiter value (valid when ColumnDelimiter is set to 'Custom'). + + + + + Column delimiter. + + + + + Footer layout. + + + + + Header layout. + + + + + Body layout (can be repeated multiple times). + + + + + Quote Character. + + + + + Quoting mode. + + + + + Indicates whether CVS should include header. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Name of the column. + + + + + Layout of the column. + + + + + Override of Quoting mode + + + + + + + + + + + + + + Option to render the empty object value {} + + + + + Option to suppress the extra spaces in the output json + + + + + + + + + + + + + + + + + + + + + + + Option to include all properties from the log event (as JSON) + + + + + Indicates whether to include contents of the T:NLog.GlobalDiagnosticsContext dictionary. + + + + + Whether to include the contents of the T:NLog.ScopeContext dictionary. + + + + + Should forward slashes be escaped? If true, / will be converted to \/ + + + + + Option to exclude null/empty properties from the log event (as JSON) + + + + + List of property names to exclude when P:NLog.Layouts.JsonLayout.IncludeAllProperties is true + + + + + How far should the JSON serializer follow object references before backing off + + + + + Option to render the empty object value {} + + + + + Option to suppress the extra spaces in the output json + + + + + + + + + + + + + + + + + + + Name of the attribute. + + + + + Layout that will be rendered as the attribute's value. + + + + + Fallback value when result value is not available + + + + + Determines whether or not this attribute will be Json encoded. + + + + + Should forward slashes be escaped? If true, / will be converted to \/ + + + + + Indicates whether to escape non-ascii characters + + + + + Whether an attribute with empty value should be included in the output + + + + + Result value type, for conversion of layout rendering output + + + + + + + + + + + + + + Footer layout. + + + + + Header layout. + + + + + Body layout (can be repeated multiple times). + + + + + + + + + + + + + + + + + + + + + + + Option to include all properties from the log events + + + + + Whether to include log4j:NDC in output from T:NLog.ScopeContext nested context. + + + + + Whether to include log4j:NDC in output from T:NLog.ScopeContext nested context. + + + + + Whether to include the contents of the T:NLog.ScopeContext properties-dictionary. + + + + + AppInfo field. By default it's the friendly name of the current AppDomain. + + + + + Indicates whether to include call site (class and method name) in the information sent over the network. + + + + + Indicates whether to include source info (file name and line number) in the information sent over the network. + + + + + Log4j:event logger-xml-attribute (Default ${logger}) + + + + + Whether the log4j:throwable xml-element should be written as CDATA + + + + + + + + + + + + + + Layout text. + + + + + + + + + + + + + + + + + + + + + + + + + + + + Name of the root XML element + + + + + Value inside the root XML element + + + + + Whether to include the contents of the T:NLog.ScopeContext dictionary. + + + + + Determines whether or not this attribute will be Xml encoded. + + + + + List of property names to exclude when P:NLog.Layouts.XmlElementBase.IncludeAllProperties is true + + + + + Whether a ElementValue with empty value should be included in the output + + + + + Auto indent and create new lines + + + + + How far should the XML serializer follow object references before backing off + + + + + XML element name to use for rendering IList-collections items + + + + + XML attribute name to use when rendering property-key When null (or empty) then key-attribute is not included + + + + + XML element name to use when rendering properties + + + + + XML attribute name to use when rendering property-value When null (or empty) then value-attribute is not included and value is formatted as XML-element-value + + + + + Option to include all properties from the log event (as XML) + + + + + + + + + + + + + + + + + Name of the attribute. + + + + + Layout that will be rendered as the attribute's value. + + + + + Fallback value when result value is not available + + + + + Determines whether or not this attribute will be Xml encoded. + + + + + Whether an attribute with empty value should be included in the output + + + + + Result value type, for conversion of layout rendering output + + + + + + + + + + + + + + + + + + + + + + + + Name of the element + + + + + Whether to include the contents of the T:NLog.ScopeContext dictionary. + + + + + Value inside the element + + + + + Determines whether or not this attribute will be Xml encoded. + + + + + List of property names to exclude when P:NLog.Layouts.XmlElementBase.IncludeAllProperties is true + + + + + Whether a ElementValue with empty value should be included in the output + + + + + Auto indent and create new lines + + + + + How far should the XML serializer follow object references before backing off + + + + + XML element name to use for rendering IList-collections items + + + + + XML attribute name to use when rendering property-key When null (or empty) then key-attribute is not included + + + + + XML element name to use when rendering properties + + + + + XML attribute name to use when rendering property-value When null (or empty) then value-attribute is not included and value is formatted as XML-element-value + + + + + Option to include all properties from the log event (as XML) + + + + + + + + + + + + + Action to be taken when filter matches. + + + + + Condition expression. + + + + + + + + + + + + + + + + + + + + + + + + + + Action to be taken when filter matches. + + + + + Indicates whether to ignore case when comparing strings. + + + + + Layout to be used to filter log messages. + + + + + Substring to be matched. + + + + + + + + + + + + + + + + + Action to be taken when filter matches. + + + + + String to compare the layout to. + + + + + Indicates whether to ignore case when comparing strings. + + + + + Layout to be used to filter log messages. + + + + + + + + + + + + + + + + + Action to be taken when filter matches. + + + + + Indicates whether to ignore case when comparing strings. + + + + + Layout to be used to filter log messages. + + + + + Substring to be matched. + + + + + + + + + + + + + + + + + Action to be taken when filter matches. + + + + + String to compare the layout to. + + + + + Indicates whether to ignore case when comparing strings. + + + + + Layout to be used to filter log messages. + + + + + + + + + + + + + + + + + + + + + + + Action to be taken when filter matches. + + + + + Append FilterCount to the P:NLog.LogEventInfo.Message when an event is no longer filtered + + + + + Insert FilterCount value into P:NLog.LogEventInfo.Properties when an event is no longer filtered + + + + + Applies the configured action to the initial logevent that starts the timeout period. Used to configure that it should ignore all events until timeout. + + + + + Layout to be used to filter log messages. + + + + + Max length of filter values, will truncate if above limit + + + + + How long before a filter expires, and logging is accepted again + + + + + Default number of unique filter values to expect, will automatically increase if needed + + + + + Max number of unique filter values to expect simultaneously + + + + + Default buffer size for the internal buffers + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/邮件系统课程完整代码/Bin/net8.0/Newtonsoft.Json.dll b/邮件系统课程完整代码/Bin/net8.0/Newtonsoft.Json.dll new file mode 100644 index 0000000..d035c38 Binary files /dev/null and b/邮件系统课程完整代码/Bin/net8.0/Newtonsoft.Json.dll differ diff --git a/邮件系统课程完整代码/Bin/net8.0/SharpCompress.dll b/邮件系统课程完整代码/Bin/net8.0/SharpCompress.dll new file mode 100644 index 0000000..c1a7f07 Binary files /dev/null and b/邮件系统课程完整代码/Bin/net8.0/SharpCompress.dll differ diff --git a/邮件系统课程完整代码/Bin/net8.0/Snappier.dll b/邮件系统课程完整代码/Bin/net8.0/Snappier.dll new file mode 100644 index 0000000..9b68e85 Binary files /dev/null and b/邮件系统课程完整代码/Bin/net8.0/Snappier.dll differ diff --git a/邮件系统课程完整代码/Bin/net8.0/System.IO.Pipelines.dll b/邮件系统课程完整代码/Bin/net8.0/System.IO.Pipelines.dll new file mode 100644 index 0000000..712f47d Binary files /dev/null and b/邮件系统课程完整代码/Bin/net8.0/System.IO.Pipelines.dll differ diff --git a/邮件系统课程完整代码/Bin/net8.0/ZstdSharp.dll b/邮件系统课程完整代码/Bin/net8.0/ZstdSharp.dll new file mode 100644 index 0000000..5d93f7e Binary files /dev/null and b/邮件系统课程完整代码/Bin/net8.0/ZstdSharp.dll differ diff --git a/邮件系统课程完整代码/Bin/net8.0/protobuf-net.Core.dll b/邮件系统课程完整代码/Bin/net8.0/protobuf-net.Core.dll new file mode 100644 index 0000000..b3e554d Binary files /dev/null and b/邮件系统课程完整代码/Bin/net8.0/protobuf-net.Core.dll differ diff --git a/邮件系统课程完整代码/Bin/net8.0/protobuf-net.dll b/邮件系统课程完整代码/Bin/net8.0/protobuf-net.dll new file mode 100644 index 0000000..e75237b Binary files /dev/null and b/邮件系统课程完整代码/Bin/net8.0/protobuf-net.dll differ diff --git a/邮件系统课程完整代码/Client/.DS_Store b/邮件系统课程完整代码/Client/.DS_Store new file mode 100644 index 0000000..1e5182d Binary files /dev/null and b/邮件系统课程完整代码/Client/.DS_Store differ diff --git a/邮件系统课程完整代码/Client/Unity/.DS_Store b/邮件系统课程完整代码/Client/Unity/.DS_Store new file mode 100644 index 0000000..9ba5bb4 Binary files /dev/null and b/邮件系统课程完整代码/Client/Unity/.DS_Store differ diff --git a/邮件系统课程完整代码/Client/Unity/Assembly-CSharp.csproj b/邮件系统课程完整代码/Client/Unity/Assembly-CSharp.csproj new file mode 100644 index 0000000..023b197 --- /dev/null +++ b/邮件系统课程完整代码/Client/Unity/Assembly-CSharp.csproj @@ -0,0 +1,862 @@ + + + + 9.0 + <_TargetFrameworkDirectories>non_empty_path_generated_by_unity.rider.package + <_FullFrameworkReferenceAssemblyPaths>non_empty_path_generated_by_unity.rider.package + true + + + Debug + AnyCPU + 10.0.20506 + 2.0 + + {03938ccd-4b40-8dfb-6b9b-21988d5cac0a} + {E097FAD1-6243-4DAD-9C02-E9B9EFC3FFC1};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + Library + Properties + Assembly-CSharp + v4.7.1 + 512 + . + + + true + full + false + Temp\Bin\Debug\Assembly-CSharp\ + UNITY_2021_3_14;UNITY_2021_3;UNITY_2021;UNITY_5_3_OR_NEWER;UNITY_5_4_OR_NEWER;UNITY_5_5_OR_NEWER;UNITY_5_6_OR_NEWER;UNITY_2017_1_OR_NEWER;UNITY_2017_2_OR_NEWER;UNITY_2017_3_OR_NEWER;UNITY_2017_4_OR_NEWER;UNITY_2018_1_OR_NEWER;UNITY_2018_2_OR_NEWER;UNITY_2018_3_OR_NEWER;UNITY_2018_4_OR_NEWER;UNITY_2019_1_OR_NEWER;UNITY_2019_2_OR_NEWER;UNITY_2019_3_OR_NEWER;UNITY_2019_4_OR_NEWER;UNITY_2020_1_OR_NEWER;UNITY_2020_2_OR_NEWER;UNITY_2020_3_OR_NEWER;UNITY_2021_1_OR_NEWER;UNITY_2021_2_OR_NEWER;UNITY_2021_3_OR_NEWER;PLATFORM_ARCH_64;UNITY_64;UNITY_INCLUDE_TESTS;USE_SEARCH_ENGINE_API;USE_SEARCH_TABLE;USE_SEARCH_MODULE;USE_PROPERTY_DATABASE;USE_SEARCH_EXTENSION_API;ENABLE_AR;ENABLE_AUDIO;ENABLE_CACHING;ENABLE_CLOTH;ENABLE_MICROPHONE;ENABLE_MULTIPLE_DISPLAYS;ENABLE_PHYSICS;ENABLE_TEXTURE_STREAMING;ENABLE_VIRTUALTEXTURING;ENABLE_UNET;ENABLE_LZMA;ENABLE_UNITYEVENTS;ENABLE_VR;ENABLE_WEBCAM;ENABLE_UNITYWEBREQUEST;ENABLE_WWW;ENABLE_CLOUD_SERVICES;ENABLE_CLOUD_SERVICES_COLLAB;ENABLE_CLOUD_SERVICES_COLLAB_SOFTLOCKS;ENABLE_CLOUD_SERVICES_ADS;ENABLE_CLOUD_SERVICES_USE_WEBREQUEST;ENABLE_CLOUD_SERVICES_CRASH_REPORTING;ENABLE_CLOUD_SERVICES_NATIVE_CRASH_REPORTING;ENABLE_CLOUD_SERVICES_PURCHASING;ENABLE_CLOUD_SERVICES_ANALYTICS;ENABLE_CLOUD_SERVICES_UNET;ENABLE_CLOUD_SERVICES_BUILD;ENABLE_CLOUD_LICENSE;ENABLE_EDITOR_HUB_LICENSE;ENABLE_WEBSOCKET_CLIENT;ENABLE_DIRECTOR_AUDIO;ENABLE_DIRECTOR_TEXTURE;ENABLE_MANAGED_JOBS;ENABLE_MANAGED_TRANSFORM_JOBS;ENABLE_MANAGED_ANIMATION_JOBS;ENABLE_MANAGED_AUDIO_JOBS;ENABLE_MANAGED_UNITYTLS;INCLUDE_DYNAMIC_GI;ENABLE_SCRIPTING_GC_WBARRIERS;PLATFORM_SUPPORTS_MONO;RENDER_SOFTWARE_CURSOR;ENABLE_VIDEO;ENABLE_ACCELERATOR_CLIENT_DEBUGGING;PLATFORM_STANDALONE;TEXTCORE_1_0_OR_NEWER;PLATFORM_STANDALONE_OSX;UNITY_STANDALONE_OSX;UNITY_STANDALONE;ENABLE_GAMECENTER;ENABLE_RUNTIME_GI;ENABLE_MOVIES;ENABLE_NETWORK;ENABLE_CRUNCH_TEXTURE_COMPRESSION;ENABLE_UNITY_GAME_SERVICES_ANALYTICS_SUPPORT;ENABLE_CLUSTER_SYNC;ENABLE_CLUSTERINPUT;ENABLE_SPATIALTRACKING;PLATFORM_UPDATES_TIME_OUTSIDE_OF_PLAYER_LOOP;ENABLE_WEBSOCKET_HOST;ENABLE_MONO;NET_STANDARD_2_0;NET_STANDARD;NET_STANDARD_2_1;NETSTANDARD;NETSTANDARD2_1;ENABLE_PROFILER;DEBUG;TRACE;UNITY_ASSERTIONS;UNITY_EDITOR;UNITY_EDITOR_64;UNITY_EDITOR_OSX;ENABLE_UNITY_COLLECTIONS_CHECKS;ENABLE_BURST_AOT;UNITY_TEAM_LICENSE;ENABLE_CUSTOM_RENDER_TEXTURE;ENABLE_DIRECTOR;ENABLE_LOCALIZATION;ENABLE_SPRITES;ENABLE_TERRAIN;ENABLE_TILEMAP;ENABLE_TIMELINE;ENABLE_LEGACY_INPUT_MANAGER;CSHARP_7_OR_LATER;CSHARP_7_3_OR_NEWER + prompt + 4 + 0169,0649 + False + False + + + true + true + false + false + false + + + + + + + + + + + + + + + + + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.AIModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.ARModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.AccessibilityModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.AndroidJNIModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.AnimationModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.AssetBundleModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.AudioModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.ClothModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.ClusterInputModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.ClusterRendererModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.CoreModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.CrashReportingModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.DSPGraphModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.DirectorModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.GIModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.GameCenterModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.GridModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.HotReloadModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.IMGUIModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.ImageConversionModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.InputModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.InputLegacyModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.JSONSerializeModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.LocalizationModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.ParticleSystemModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.PerformanceReportingModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.PhysicsModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.Physics2DModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.ProfilerModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.RuntimeInitializeOnLoadManagerInitializerModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.ScreenCaptureModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.SharedInternalsModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.SpriteMaskModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.SpriteShapeModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.StreamingModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.SubstanceModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.SubsystemsModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.TLSModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.TerrainModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.TerrainPhysicsModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.TextCoreFontEngineModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.TextCoreTextEngineModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.TextRenderingModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.TilemapModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.UIModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.UIElementsModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.UIElementsNativeModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.UNETModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.UmbraModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.UnityAnalyticsModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.UnityAnalyticsCommonModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.UnityConnectModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.UnityCurlModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.UnityTestProtocolModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.UnityWebRequestModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.UnityWebRequestAssetBundleModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.UnityWebRequestAudioModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.UnityWebRequestTextureModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.UnityWebRequestWWWModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.VFXModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.VRModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.VehiclesModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.VideoModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.VirtualTexturingModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.WindModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEngine.XRModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEditor.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEditor.CoreModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEditor.DeviceSimulatorModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEditor.DiagnosticsModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEditor.GraphViewModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEditor.PackageManagerUIModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEditor.QuickSearchModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEditor.SceneTemplateModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEditor.TextCoreFontEngineModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEditor.TextCoreTextEngineModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEditor.UIBuilderModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEditor.UIElementsModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEditor.UIElementsSamplesModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEditor.UIServiceModule.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/Managed/UnityEngine/UnityEditor.UnityConnectModule.dll + + + /Users/fantasy/Movies/邮件系统/Lession/Client/Unity/Library/PackageCache/com.fantasy.unity@2024.2.22/Runtime/Plugins/Other/System.Collections.Immutable.dll + + + /Users/fantasy/Movies/邮件系统/Lession/Client/Unity/Library/PackageCache/com.fantasy.unity@2024.2.22/Runtime/Plugins/Other/System.IO.Pipelines.dll + + + /Users/fantasy/Movies/邮件系统/Lession/Client/Unity/Library/PackageCache/com.unity.burst@1.6.6/Unity.Burst.Unsafe.dll + + + /Users/fantasy/Movies/邮件系统/Lession/Client/Unity/Library/PackageCache/com.unity.burst@1.6.6/Unity.Burst.CodeGen/Unity.Burst.Cecil.Mdb.dll + + + /Users/fantasy/Movies/邮件系统/Lession/Client/Unity/Library/PackageCache/com.unity.burst@1.6.6/Unity.Burst.CodeGen/Unity.Burst.Cecil.Pdb.dll + + + /Users/fantasy/Movies/邮件系统/Lession/Client/Unity/Library/PackageCache/com.unity.burst@1.6.6/Unity.Burst.CodeGen/Unity.Burst.Cecil.dll + + + /Users/fantasy/Movies/邮件系统/Lession/Client/Unity/Library/PackageCache/com.unity.burst@1.6.6/Unity.Burst.CodeGen/Unity.Burst.Cecil.Rocks.dll + + + /Users/fantasy/Movies/邮件系统/Lession/Client/Unity/Library/PackageCache/com.unity.visualscripting@1.7.8/Runtime/VisualScripting.Flow/Dependencies/NCalc/Unity.VisualScripting.Antlr3.Runtime.dll + + + /Users/fantasy/Movies/邮件系统/Lession/Client/Unity/Library/PackageCache/com.fantasy.unity@2024.2.22/Runtime/Plugins/Other/System.Runtime.CompilerServices.Unsafe.dll + + + /Users/fantasy/Movies/邮件系统/Lession/Client/Unity/Library/PackageCache/com.unity.nuget.newtonsoft-json@3.2.1/Runtime/Newtonsoft.Json.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/PlaybackEngines/iOSSupport/UnityEditor.iOS.Extensions.Xcode.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/PlaybackEngines/iOSSupport/UnityEditor.iOS.Extensions.Common.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/PlaybackEngines/AndroidPlayer/Unity.Android.Types.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/PlaybackEngines/AndroidPlayer/Unity.Android.Gradle.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/ref/2.1.0/netstandard.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/Microsoft.Win32.Primitives.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.AppContext.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Buffers.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Collections.Concurrent.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Collections.NonGeneric.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Collections.Specialized.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Collections.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.ComponentModel.EventBasedAsync.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.ComponentModel.Primitives.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.ComponentModel.TypeConverter.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.ComponentModel.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Console.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Data.Common.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Diagnostics.Contracts.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Diagnostics.Debug.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Diagnostics.FileVersionInfo.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Diagnostics.Process.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Diagnostics.StackTrace.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Diagnostics.TextWriterTraceListener.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Diagnostics.Tools.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Diagnostics.TraceSource.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Diagnostics.Tracing.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Drawing.Primitives.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Dynamic.Runtime.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Globalization.Calendars.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Globalization.Extensions.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Globalization.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.IO.Compression.ZipFile.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.IO.Compression.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.IO.FileSystem.DriveInfo.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.IO.FileSystem.Primitives.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.IO.FileSystem.Watcher.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.IO.FileSystem.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.IO.IsolatedStorage.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.IO.MemoryMappedFiles.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.IO.Pipes.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.IO.UnmanagedMemoryStream.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.IO.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Linq.Expressions.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Linq.Parallel.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Linq.Queryable.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Linq.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Memory.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Net.Http.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Net.NameResolution.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Net.NetworkInformation.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Net.Ping.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Net.Primitives.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Net.Requests.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Net.Security.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Net.Sockets.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Net.WebHeaderCollection.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Net.WebSockets.Client.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Net.WebSockets.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Numerics.Vectors.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.ObjectModel.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Reflection.DispatchProxy.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Reflection.Emit.ILGeneration.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Reflection.Emit.Lightweight.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Reflection.Emit.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Reflection.Extensions.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Reflection.Primitives.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Reflection.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Resources.Reader.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Resources.ResourceManager.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Resources.Writer.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Runtime.CompilerServices.VisualC.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Runtime.Extensions.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Runtime.Handles.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Runtime.InteropServices.RuntimeInformation.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Runtime.InteropServices.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Runtime.Numerics.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Runtime.Serialization.Formatters.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Runtime.Serialization.Json.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Runtime.Serialization.Primitives.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Runtime.Serialization.Xml.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Runtime.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Security.Claims.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Security.Cryptography.Algorithms.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Security.Cryptography.Csp.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Security.Cryptography.Encoding.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Security.Cryptography.Primitives.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Security.Cryptography.X509Certificates.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Security.Principal.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Security.SecureString.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Text.Encoding.Extensions.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Text.Encoding.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Text.RegularExpressions.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Threading.Overlapped.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Threading.Tasks.Extensions.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Threading.Tasks.Parallel.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Threading.Tasks.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Threading.Thread.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Threading.ThreadPool.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Threading.Timer.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Threading.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.ValueTuple.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Xml.ReaderWriter.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Xml.XDocument.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Xml.XPath.XDocument.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Xml.XPath.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Xml.XmlDocument.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netstandard/System.Xml.XmlSerializer.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/Extensions/2.0.0/System.Runtime.InteropServices.WindowsRuntime.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netfx/System.ComponentModel.Composition.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netfx/System.Core.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netfx/System.Data.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netfx/System.Drawing.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netfx/System.IO.Compression.FileSystem.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netfx/System.Net.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netfx/System.Numerics.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netfx/System.Runtime.Serialization.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netfx/System.ServiceModel.Web.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netfx/System.Transactions.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netfx/System.Web.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netfx/System.Windows.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netfx/System.Xml.Linq.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netfx/System.Xml.Serialization.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netfx/System.Xml.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netfx/System.dll + + + /Applications/Unity/Hub/Editor/2021.3.14f1/Unity.app/Contents/NetStandard/compat/2.1.0/shims/netfx/mscorlib.dll + + + /Users/fantasy/Movies/邮件系统/Lession/Client/Unity/Library/ScriptAssemblies/Unity.VisualScripting.Flow.Editor.dll + + + /Users/fantasy/Movies/邮件系统/Lession/Client/Unity/Library/ScriptAssemblies/Unity.2D.Tilemap.Extras.dll + + + /Users/fantasy/Movies/邮件系统/Lession/Client/Unity/Library/ScriptAssemblies/Unity.2D.Animation.Editor.dll + + + /Users/fantasy/Movies/邮件系统/Lession/Client/Unity/Library/ScriptAssemblies/Unity.InternalAPIEngineBridge.001.dll + + + /Users/fantasy/Movies/邮件系统/Lession/Client/Unity/Library/ScriptAssemblies/Unity.VSCode.Editor.dll + + + /Users/fantasy/Movies/邮件系统/Lession/Client/Unity/Library/ScriptAssemblies/Unity.2D.PixelPerfect.dll + + + /Users/fantasy/Movies/邮件系统/Lession/Client/Unity/Library/ScriptAssemblies/Unity.2D.Tilemap.Editor.dll + + + /Users/fantasy/Movies/邮件系统/Lession/Client/Unity/Library/ScriptAssemblies/PsdPlugin.dll + + + /Users/fantasy/Movies/邮件系统/Lession/Client/Unity/Library/ScriptAssemblies/Unity.TextMeshPro.Editor.dll + + + /Users/fantasy/Movies/邮件系统/Lession/Client/Unity/Library/ScriptAssemblies/Unity.VisualStudio.Editor.dll + + + /Users/fantasy/Movies/邮件系统/Lession/Client/Unity/Library/ScriptAssemblies/Unity.Timeline.dll + + + /Users/fantasy/Movies/邮件系统/Lession/Client/Unity/Library/ScriptAssemblies/Unity.VisualScripting.Core.Editor.dll + + + /Users/fantasy/Movies/邮件系统/Lession/Client/Unity/Library/ScriptAssemblies/Unity.TextMeshPro.dll + + + /Users/fantasy/Movies/邮件系统/Lession/Client/Unity/Library/ScriptAssemblies/Unity.VisualScripting.State.Editor.dll + + + /Users/fantasy/Movies/邮件系统/Lession/Client/Unity/Library/ScriptAssemblies/Unity.Burst.Editor.dll + + + /Users/fantasy/Movies/邮件系统/Lession/Client/Unity/Library/ScriptAssemblies/Unity.2D.IK.Editor.dll + + + /Users/fantasy/Movies/邮件系统/Lession/Client/Unity/Library/ScriptAssemblies/Unity.2D.Sprite.Editor.dll + + + /Users/fantasy/Movies/邮件系统/Lession/Client/Unity/Library/ScriptAssemblies/Unity.2D.Path.Editor.dll + + + /Users/fantasy/Movies/邮件系统/Lession/Client/Unity/Library/ScriptAssemblies/Unity.VisualScripting.SettingsProvider.Editor.dll + + + /Users/fantasy/Movies/邮件系统/Lession/Client/Unity/Library/ScriptAssemblies/Unity.VisualScripting.Flow.dll + + + /Users/fantasy/Movies/邮件系统/Lession/Client/Unity/Library/ScriptAssemblies/UnityEditor.UI.dll + + + /Users/fantasy/Movies/邮件系统/Lession/Client/Unity/Library/ScriptAssemblies/Unity.PlasticSCM.Editor.dll + + + /Users/fantasy/Movies/邮件系统/Lession/Client/Unity/Library/ScriptAssemblies/Unity.Rider.Editor.dll + + + /Users/fantasy/Movies/邮件系统/Lession/Client/Unity/Library/ScriptAssemblies/Unity.2D.Psdimporter.Editor.dll + + + /Users/fantasy/Movies/邮件系统/Lession/Client/Unity/Library/ScriptAssemblies/UnityEngine.UI.dll + + + /Users/fantasy/Movies/邮件系统/Lession/Client/Unity/Library/ScriptAssemblies/Unity.2D.Tilemap.Extras.Editor.dll + + + /Users/fantasy/Movies/邮件系统/Lession/Client/Unity/Library/ScriptAssemblies/Unity.InternalAPIEditorBridge.001.dll + + + /Users/fantasy/Movies/邮件系统/Lession/Client/Unity/Library/ScriptAssemblies/Unity.Services.Core.dll + + + /Users/fantasy/Movies/邮件系统/Lession/Client/Unity/Library/ScriptAssemblies/Unity.VisualScripting.Core.dll + + + /Users/fantasy/Movies/邮件系统/Lession/Client/Unity/Library/ScriptAssemblies/Unity.Mathematics.dll + + + /Users/fantasy/Movies/邮件系统/Lession/Client/Unity/Library/ScriptAssemblies/Unity.2D.IK.Runtime.dll + + + /Users/fantasy/Movies/邮件系统/Lession/Client/Unity/Library/ScriptAssemblies/Unity.Services.Core.Analytics.dll + + + /Users/fantasy/Movies/邮件系统/Lession/Client/Unity/Library/ScriptAssemblies/Unity.Burst.dll + + + /Users/fantasy/Movies/邮件系统/Lession/Client/Unity/Library/ScriptAssemblies/Unity.VisualScripting.Shared.Editor.dll + + + /Users/fantasy/Movies/邮件系统/Lession/Client/Unity/Library/ScriptAssemblies/Unity.Services.Core.Environments.dll + + + /Users/fantasy/Movies/邮件系统/Lession/Client/Unity/Library/ScriptAssemblies/Unity.2D.Animation.Runtime.dll + + + /Users/fantasy/Movies/邮件系统/Lession/Client/Unity/Library/ScriptAssemblies/Unity.2D.PixelPerfect.Editor.dll + + + /Users/fantasy/Movies/邮件系统/Lession/Client/Unity/Library/ScriptAssemblies/Unity.Timeline.Editor.dll + + + /Users/fantasy/Movies/邮件系统/Lession/Client/Unity/Library/ScriptAssemblies/Unity.Mathematics.Editor.dll + + + /Users/fantasy/Movies/邮件系统/Lession/Client/Unity/Library/ScriptAssemblies/Unity.2D.Common.Runtime.dll + + + /Users/fantasy/Movies/邮件系统/Lession/Client/Unity/Library/ScriptAssemblies/Unity.2D.SpriteShape.Editor.dll + + + /Users/fantasy/Movies/邮件系统/Lession/Client/Unity/Library/ScriptAssemblies/Fantasy.Editor.dll + + + /Users/fantasy/Movies/邮件系统/Lession/Client/Unity/Library/ScriptAssemblies/Unity.2D.Common.Editor.dll + + + /Users/fantasy/Movies/邮件系统/Lession/Client/Unity/Library/ScriptAssemblies/Fantasy.Unity.dll + + + /Users/fantasy/Movies/邮件系统/Lession/Client/Unity/Library/ScriptAssemblies/Unity.2D.SpriteShape.Runtime.dll + + + /Users/fantasy/Movies/邮件系统/Lession/Client/Unity/Library/ScriptAssemblies/Unity.VisualScripting.State.dll + + + + + + + diff --git a/邮件系统课程完整代码/Client/Unity/Assets/.DS_Store b/邮件系统课程完整代码/Client/Unity/Assets/.DS_Store new file mode 100644 index 0000000..aa65aa8 Binary files /dev/null and b/邮件系统课程完整代码/Client/Unity/Assets/.DS_Store differ diff --git a/邮件系统课程完整代码/Client/Unity/Assets/Bundles.meta b/邮件系统课程完整代码/Client/Unity/Assets/Bundles.meta new file mode 100644 index 0000000..457f795 --- /dev/null +++ b/邮件系统课程完整代码/Client/Unity/Assets/Bundles.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: fe27b47c7d76e49439bf5072f41f8a94 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/邮件系统课程完整代码/Client/Unity/Assets/Bundles/.DS_Store b/邮件系统课程完整代码/Client/Unity/Assets/Bundles/.DS_Store new file mode 100644 index 0000000..75e23e5 Binary files /dev/null and b/邮件系统课程完整代码/Client/Unity/Assets/Bundles/.DS_Store differ diff --git a/邮件系统课程完整代码/Client/Unity/Assets/Bundles/Config.meta b/邮件系统课程完整代码/Client/Unity/Assets/Bundles/Config.meta new file mode 100644 index 0000000..4183245 --- /dev/null +++ b/邮件系统课程完整代码/Client/Unity/Assets/Bundles/Config.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d0242937a20ae44ac9d626e19fdf17d4 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/邮件系统课程完整代码/Client/Unity/Assets/Scenes.meta b/邮件系统课程完整代码/Client/Unity/Assets/Scenes.meta new file mode 100644 index 0000000..83c741b --- /dev/null +++ b/邮件系统课程完整代码/Client/Unity/Assets/Scenes.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 6ea315d0fd7389c41b19996891e99ae3 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/邮件系统课程完整代码/Client/Unity/Assets/Scenes/SampleScene.unity b/邮件系统课程完整代码/Client/Unity/Assets/Scenes/SampleScene.unity new file mode 100644 index 0000000..5117f51 --- /dev/null +++ b/邮件系统课程完整代码/Client/Unity/Assets/Scenes/SampleScene.unity @@ -0,0 +1,3775 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!29 &1 +OcclusionCullingSettings: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_OcclusionBakeSettings: + smallestOccluder: 5 + smallestHole: 0.25 + backfaceThreshold: 100 + m_SceneGUID: 00000000000000000000000000000000 + m_OcclusionCullingData: {fileID: 0} +--- !u!104 &2 +RenderSettings: + m_ObjectHideFlags: 0 + serializedVersion: 9 + m_Fog: 0 + m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} + m_FogMode: 3 + m_FogDensity: 0.01 + m_LinearFogStart: 0 + m_LinearFogEnd: 300 + m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1} + m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1} + m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1} + m_AmbientIntensity: 1 + m_AmbientMode: 0 + m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} + m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0} + m_HaloStrength: 0.5 + m_FlareStrength: 1 + m_FlareFadeSpeed: 3 + m_HaloTexture: {fileID: 0} + m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0} + m_DefaultReflectionMode: 0 + m_DefaultReflectionResolution: 128 + m_ReflectionBounces: 1 + m_ReflectionIntensity: 1 + m_CustomReflection: {fileID: 0} + m_Sun: {fileID: 705507994} + m_IndirectSpecularColor: {r: 0.44657844, g: 0.49641258, b: 0.57481694, a: 1} + m_UseRadianceAmbientProbe: 0 +--- !u!157 &3 +LightmapSettings: + m_ObjectHideFlags: 0 + serializedVersion: 12 + m_GIWorkflowMode: 1 + m_GISettings: + serializedVersion: 2 + m_BounceScale: 1 + m_IndirectOutputScale: 1 + m_AlbedoBoost: 1 + m_EnvironmentLightingMode: 0 + m_EnableBakedLightmaps: 1 + m_EnableRealtimeLightmaps: 0 + m_LightmapEditorSettings: + serializedVersion: 12 + m_Resolution: 2 + m_BakeResolution: 40 + m_AtlasSize: 1024 + m_AO: 0 + m_AOMaxDistance: 1 + m_CompAOExponent: 1 + m_CompAOExponentDirect: 0 + m_ExtractAmbientOcclusion: 0 + m_Padding: 2 + m_LightmapParameters: {fileID: 0} + m_LightmapsBakeMode: 1 + m_TextureCompression: 1 + m_FinalGather: 0 + m_FinalGatherFiltering: 1 + m_FinalGatherRayCount: 256 + m_ReflectionCompression: 2 + m_MixedBakeMode: 2 + m_BakeBackend: 1 + m_PVRSampling: 1 + m_PVRDirectSampleCount: 32 + m_PVRSampleCount: 500 + m_PVRBounces: 2 + m_PVREnvironmentSampleCount: 500 + m_PVREnvironmentReferencePointCount: 2048 + m_PVRFilteringMode: 2 + m_PVRDenoiserTypeDirect: 0 + m_PVRDenoiserTypeIndirect: 0 + m_PVRDenoiserTypeAO: 0 + m_PVRFilterTypeDirect: 0 + m_PVRFilterTypeIndirect: 0 + m_PVRFilterTypeAO: 0 + m_PVREnvironmentMIS: 0 + m_PVRCulling: 1 + m_PVRFilteringGaussRadiusDirect: 1 + m_PVRFilteringGaussRadiusIndirect: 5 + m_PVRFilteringGaussRadiusAO: 2 + m_PVRFilteringAtrousPositionSigmaDirect: 0.5 + m_PVRFilteringAtrousPositionSigmaIndirect: 2 + m_PVRFilteringAtrousPositionSigmaAO: 1 + m_ExportTrainingData: 0 + m_TrainingDataDestination: TrainingData + m_LightProbeSampleCountMultiplier: 4 + m_LightingDataAsset: {fileID: 0} + m_LightingSettings: {fileID: 0} +--- !u!196 &4 +NavMeshSettings: + serializedVersion: 2 + m_ObjectHideFlags: 0 + m_BuildSettings: + serializedVersion: 2 + agentTypeID: 0 + agentRadius: 0.5 + agentHeight: 2 + agentSlope: 45 + agentClimb: 0.4 + ledgeDropHeight: 0 + maxJumpAcrossDistance: 0 + minRegionArea: 2 + manualCellSize: 0 + cellSize: 0.16666667 + manualTileSize: 0 + tileSize: 256 + accuratePlacement: 0 + maxJobWorkers: 0 + preserveTilesOutsideBounds: 0 + debug: + m_Flags: 0 + m_NavMeshData: {fileID: 0} +--- !u!1 &40703328 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 40703329} + - component: {fileID: 40703331} + - component: {fileID: 40703330} + m_Layer: 5 + m_Name: Text (Legacy) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &40703329 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 40703328} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 554487406} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: -3.5} + m_SizeDelta: {x: -20, y: -17} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &40703330 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 40703328} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 24 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 2 + m_MaxSize: 40 + m_Alignment: 0 + m_AlignByGeometry: 0 + m_RichText: 0 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: +--- !u!222 &40703331 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 40703328} + m_CullTransparentMesh: 1 +--- !u!1 &43230594 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 43230597} + - component: {fileID: 43230596} + - component: {fileID: 43230595} + m_Layer: 0 + m_Name: EventSystem + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &43230595 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 43230594} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4f231c4fb786f3946a6b90b886c48677, type: 3} + m_Name: + m_EditorClassIdentifier: + m_SendPointerHoverToParent: 1 + m_HorizontalAxis: Horizontal + m_VerticalAxis: Vertical + m_SubmitButton: Submit + m_CancelButton: Cancel + m_InputActionsPerSecond: 10 + m_RepeatDelay: 0.5 + m_ForceModuleActive: 0 +--- !u!114 &43230596 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 43230594} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 76c392e42b5098c458856cdf6ecaaaa1, type: 3} + m_Name: + m_EditorClassIdentifier: + m_FirstSelected: {fileID: 0} + m_sendNavigationEvents: 1 + m_DragThreshold: 10 +--- !u!4 &43230597 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 43230594} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 3 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &173184502 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 173184503} + - component: {fileID: 173184505} + - component: {fileID: 173184504} + m_Layer: 5 + m_Name: Text (Legacy) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &173184503 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 173184502} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 417907159} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &173184504 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 173184502} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 24 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 2 + m_MaxSize: 40 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: "\u9000\u51FA\u670D\u52A1\u5668" +--- !u!222 &173184505 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 173184502} + m_CullTransparentMesh: 1 +--- !u!1 &316110486 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 316110487} + - component: {fileID: 316110490} + - component: {fileID: 316110489} + - component: {fileID: 316110488} + m_Layer: 5 + m_Name: MailUserName + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &316110487 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 316110486} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 1506082736} + - {fileID: 862468792} + m_Father: {fileID: 1634917323} + m_RootOrder: 7 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 563.39, y: 164.99997} + m_SizeDelta: {x: 656.99, y: 47.7093} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &316110488 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 316110486} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d199490a83bb2b844b9695cbf13b01ef, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_WrapAround: 0 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Selected + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 316110489} + m_TextComponent: {fileID: 862468793} + m_Placeholder: {fileID: 1506082737} + m_ContentType: 0 + m_InputType: 0 + m_AsteriskChar: 42 + m_KeyboardType: 0 + m_LineType: 0 + m_HideMobileInput: 0 + m_CharacterValidation: 0 + m_CharacterLimit: 0 + m_OnSubmit: + m_PersistentCalls: + m_Calls: [] + m_OnDidEndEdit: + m_PersistentCalls: + m_Calls: [] + m_OnValueChanged: + m_PersistentCalls: + m_Calls: [] + m_CaretColor: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} + m_CustomCaretColor: 0 + m_SelectionColor: {r: 0.65882355, g: 0.80784315, b: 1, a: 0.7529412} + m_Text: + m_CaretBlinkRate: 0.85 + m_CaretWidth: 1 + m_ReadOnly: 0 + m_ShouldActivateOnSelect: 1 +--- !u!114 &316110489 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 316110486} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10911, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &316110490 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 316110486} + m_CullTransparentMesh: 1 +--- !u!1 &417907158 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 417907159} + - component: {fileID: 417907162} + - component: {fileID: 417907161} + - component: {fileID: 417907160} + m_Layer: 5 + m_Name: ExitButton + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &417907159 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 417907158} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 173184503} + m_Father: {fileID: 1124882447} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 1364, y: 10} + m_SizeDelta: {x: 185.0241, y: 45.2925} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &417907160 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 417907158} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_WrapAround: 0 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Selected + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 417907161} + m_OnClick: + m_PersistentCalls: + m_Calls: [] +--- !u!114 &417907161 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 417907158} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &417907162 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 417907158} + m_CullTransparentMesh: 1 +--- !u!1 &456832071 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 456832072} + - component: {fileID: 456832074} + - component: {fileID: 456832073} + m_Layer: 5 + m_Name: Text (Legacy) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &456832072 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 456832071} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 1673164677} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: -3.5} + m_SizeDelta: {x: -20, y: -17} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &456832073 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 456832071} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 24 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 2 + m_MaxSize: 40 + m_Alignment: 0 + m_AlignByGeometry: 0 + m_RichText: 0 + m_HorizontalOverflow: 1 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: +--- !u!222 &456832074 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 456832071} + m_CullTransparentMesh: 1 +--- !u!1 &457709385 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 457709386} + - component: {fileID: 457709388} + - component: {fileID: 457709387} + m_Layer: 5 + m_Name: Text (Legacy) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &457709386 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 457709385} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 1246657865} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &457709387 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 457709385} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 24 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 2 + m_MaxSize: 40 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: "\u83B7\u53D6\u6211\u5F53\u524D\u62E5\u6709\u7684\u90AE\u4EF6" +--- !u!222 &457709388 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 457709385} + m_CullTransparentMesh: 1 +--- !u!1 &457839179 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 457839180} + - component: {fileID: 457839182} + - component: {fileID: 457839181} + m_Layer: 5 + m_Name: Placeholder + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &457839180 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 457839179} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 554487406} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: -3.5} + m_SizeDelta: {x: -20, y: -17} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &457839181 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 457839179} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 0.5} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 24 + m_FontStyle: 2 + m_BestFit: 0 + m_MinSize: 2 + m_MaxSize: 40 + m_Alignment: 0 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: "\u90AE\u4EF6\u5185\u5BB9" +--- !u!222 &457839182 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 457839179} + m_CullTransparentMesh: 1 +--- !u!1 &549834352 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 549834353} + - component: {fileID: 549834355} + - component: {fileID: 549834354} + m_Layer: 5 + m_Name: Text (Legacy) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &549834353 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 549834352} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 1306186265} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &549834354 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 549834352} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 24 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 2 + m_MaxSize: 40 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: "\u5220\u9664\u4E00\u4E2A\u62E5\u6709\u7684\u90AE\u4EF6" +--- !u!222 &549834355 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 549834352} + m_CullTransparentMesh: 1 +--- !u!1 &554487405 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 554487406} + - component: {fileID: 554487409} + - component: {fileID: 554487408} + - component: {fileID: 554487407} + m_Layer: 5 + m_Name: MailContent + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &554487406 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 554487405} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 457839180} + - {fileID: 40703329} + m_Father: {fileID: 1634917323} + m_RootOrder: 8 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: -6.8296, y: -65.00003} + m_SizeDelta: {x: 1797.4257, y: 347.5158} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &554487407 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 554487405} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d199490a83bb2b844b9695cbf13b01ef, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_WrapAround: 0 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Selected + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 554487408} + m_TextComponent: {fileID: 40703330} + m_Placeholder: {fileID: 457839181} + m_ContentType: 0 + m_InputType: 0 + m_AsteriskChar: 42 + m_KeyboardType: 0 + m_LineType: 2 + m_HideMobileInput: 0 + m_CharacterValidation: 0 + m_CharacterLimit: 0 + m_OnSubmit: + m_PersistentCalls: + m_Calls: [] + m_OnDidEndEdit: + m_PersistentCalls: + m_Calls: [] + m_OnValueChanged: + m_PersistentCalls: + m_Calls: [] + m_CaretColor: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} + m_CustomCaretColor: 0 + m_SelectionColor: {r: 0.65882355, g: 0.80784315, b: 1, a: 0.7529412} + m_Text: + m_CaretBlinkRate: 0.85 + m_CaretWidth: 1 + m_ReadOnly: 0 + m_ShouldActivateOnSelect: 1 +--- !u!114 &554487408 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 554487405} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10911, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &554487409 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 554487405} + m_CullTransparentMesh: 1 +--- !u!1 &611927700 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 611927701} + - component: {fileID: 611927703} + - component: {fileID: 611927702} + m_Layer: 5 + m_Name: Text (Legacy) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &611927701 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 611927700} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 1856661521} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &611927702 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 611927700} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 24 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 2 + m_MaxSize: 40 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: "\u7ED9\u6307\u5B9A\u73A9\u5BB6\u53D1\u9001\u4E00\u4E2A\u90AE\u4EF6" +--- !u!222 &611927703 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 611927700} + m_CullTransparentMesh: 1 +--- !u!1 &656443551 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 656443552} + - component: {fileID: 656443554} + - component: {fileID: 656443553} + m_Layer: 5 + m_Name: Placeholder + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &656443552 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 656443551} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 1508323924} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: -3.5} + m_SizeDelta: {x: -20, y: -17} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &656443553 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 656443551} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 0.5} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 24 + m_FontStyle: 2 + m_BestFit: 0 + m_MinSize: 2 + m_MaxSize: 40 + m_Alignment: 3 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: "\u90AE\u4EF6\u6807\u9898" +--- !u!222 &656443554 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 656443551} + m_CullTransparentMesh: 1 +--- !u!1 &705507993 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 705507995} + - component: {fileID: 705507994} + m_Layer: 0 + m_Name: Directional Light + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!108 &705507994 +Light: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 705507993} + m_Enabled: 1 + serializedVersion: 10 + m_Type: 1 + m_Shape: 0 + m_Color: {r: 1, g: 0.95686275, b: 0.8392157, a: 1} + m_Intensity: 1 + m_Range: 10 + m_SpotAngle: 30 + m_InnerSpotAngle: 21.802082 + m_CookieSize: 10 + m_Shadows: + m_Type: 2 + m_Resolution: -1 + m_CustomResolution: -1 + m_Strength: 1 + m_Bias: 0.05 + m_NormalBias: 0.4 + m_NearPlane: 0.2 + m_CullingMatrixOverride: + e00: 1 + e01: 0 + e02: 0 + e03: 0 + e10: 0 + e11: 1 + e12: 0 + e13: 0 + e20: 0 + e21: 0 + e22: 1 + e23: 0 + e30: 0 + e31: 0 + e32: 0 + e33: 1 + m_UseCullingMatrixOverride: 0 + m_Cookie: {fileID: 0} + m_DrawHalo: 0 + m_Flare: {fileID: 0} + m_RenderMode: 0 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingLayerMask: 1 + m_Lightmapping: 1 + m_LightShadowCasterMode: 0 + m_AreaSize: {x: 1, y: 1} + m_BounceIntensity: 1 + m_ColorTemperature: 6570 + m_UseColorTemperature: 0 + m_BoundingSphereOverride: {x: 0, y: 0, z: 0, w: 0} + m_UseBoundingSphereOverride: 0 + m_UseViewFrustumForShadowCasterCull: 1 + m_ShadowRadius: 0 + m_ShadowAngle: 0 +--- !u!4 &705507995 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 705507993} + m_LocalRotation: {x: 0.40821788, y: -0.23456968, z: 0.10938163, w: 0.8754261} + m_LocalPosition: {x: 0, y: 3, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0} +--- !u!1 &742379559 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 742379560} + - component: {fileID: 742379562} + - component: {fileID: 742379561} + m_Layer: 5 + m_Name: Text (Legacy) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &742379560 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 742379559} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 965668904} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &742379561 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 742379559} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 24 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 2 + m_MaxSize: 40 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: "\u767B\u9646\u5230\u670D\u52A1\u5668" +--- !u!222 &742379562 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 742379559} + m_CullTransparentMesh: 1 +--- !u!1 &862468791 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 862468792} + - component: {fileID: 862468794} + - component: {fileID: 862468793} + m_Layer: 5 + m_Name: Text (Legacy) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &862468792 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 862468791} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 316110487} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: -3.5} + m_SizeDelta: {x: -20, y: -17} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &862468793 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 862468791} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 24 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 2 + m_MaxSize: 40 + m_Alignment: 3 + m_AlignByGeometry: 0 + m_RichText: 0 + m_HorizontalOverflow: 1 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: +--- !u!222 &862468794 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 862468791} + m_CullTransparentMesh: 1 +--- !u!1 &963194225 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 963194228} + - component: {fileID: 963194227} + - component: {fileID: 963194226} + - component: {fileID: 963194229} + m_Layer: 0 + m_Name: Main Camera + m_TagString: MainCamera + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!81 &963194226 +AudioListener: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 963194225} + m_Enabled: 1 +--- !u!20 &963194227 +Camera: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 963194225} + m_Enabled: 1 + serializedVersion: 2 + m_ClearFlags: 1 + m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0} + m_projectionMatrixMode: 1 + m_GateFitMode: 2 + m_FOVAxisMode: 0 + m_SensorSize: {x: 36, y: 24} + m_LensShift: {x: 0, y: 0} + m_FocalLength: 50 + m_NormalizedViewPortRect: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 + near clip plane: 0.3 + far clip plane: 1000 + field of view: 60 + orthographic: 0 + orthographic size: 5 + m_Depth: -1 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingPath: -1 + m_TargetTexture: {fileID: 0} + m_TargetDisplay: 0 + m_TargetEye: 3 + m_HDR: 1 + m_AllowMSAA: 1 + m_AllowDynamicResolution: 0 + m_ForceIntoRT: 0 + m_OcclusionCulling: 1 + m_StereoConvergence: 10 + m_StereoSeparation: 0.022 +--- !u!4 &963194228 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 963194225} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 1, z: -10} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &963194229 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 963194225} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 9bd17d680f8ff4bee82ecdd82ba4b804, type: 3} + m_Name: + m_EditorClassIdentifier: + LoginButton: {fileID: 965668905} + ExitButton: {fileID: 417907160} + SendTestButton: {fileID: 1755739494} + GetHaveMailButton: {fileID: 1246657866} + OpenMailButton: {fileID: 1433264944} + ReceiveMailButton: {fileID: 1402508500} + RemoveMailButton: {fileID: 1306186266} + SendMailButton: {fileID: 1856661522} + LoginUserName: {fileID: 1673164678} + MailId: {fileID: 1383089662} + MailTitle: {fileID: 1508323925} + MailUserName: {fileID: 316110488} + MailContent: {fileID: 554487407} +--- !u!1 &965668903 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 965668904} + - component: {fileID: 965668907} + - component: {fileID: 965668906} + - component: {fileID: 965668905} + m_Layer: 5 + m_Name: LoginButton + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &965668904 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 965668903} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 742379560} + m_Father: {fileID: 1124882447} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 215, y: 10} + m_SizeDelta: {x: 185.0241, y: 45.2925} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &965668905 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 965668903} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_WrapAround: 0 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Selected + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 965668906} + m_OnClick: + m_PersistentCalls: + m_Calls: [] +--- !u!114 &965668906 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 965668903} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &965668907 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 965668903} + m_CullTransparentMesh: 1 +--- !u!1 &1016206935 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1016206936} + - component: {fileID: 1016206938} + - component: {fileID: 1016206937} + m_Layer: 5 + m_Name: Placeholder + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1016206936 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1016206935} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 1383089661} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: -3.5} + m_SizeDelta: {x: -20, y: -17} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1016206937 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1016206935} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 0.5} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 24 + m_FontStyle: 2 + m_BestFit: 0 + m_MinSize: 2 + m_MaxSize: 40 + m_Alignment: 1 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: "\u90AE\u4EF6ID" +--- !u!222 &1016206938 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1016206935} + m_CullTransparentMesh: 1 +--- !u!1 &1028105310 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1028105311} + - component: {fileID: 1028105313} + - component: {fileID: 1028105312} + m_Layer: 5 + m_Name: Text (Legacy) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1028105311 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1028105310} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 1755739493} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1028105312 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1028105310} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 24 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 2 + m_MaxSize: 40 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: "\u53D1\u9001\u4E00\u4E2A\u6D4B\u8BD5\u90AE\u4EF6" +--- !u!222 &1028105313 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1028105310} + m_CullTransparentMesh: 1 +--- !u!1 &1124882446 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1124882447} + m_Layer: 5 + m_Name: Login + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1124882447 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1124882446} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 1673164677} + - {fileID: 965668904} + - {fileID: 417907159} + m_Father: {fileID: 1634917323} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: -818, y: 450} + m_SizeDelta: {x: 100, y: 100} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!1 &1246657864 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1246657865} + - component: {fileID: 1246657868} + - component: {fileID: 1246657867} + - component: {fileID: 1246657866} + m_Layer: 5 + m_Name: GetHaveMailButton + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1246657865 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1246657864} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 457709386} + m_Father: {fileID: 1634917323} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: -220.99994, y: 316.99997} + m_SizeDelta: {x: 395.6798, y: 134.3838} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1246657866 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1246657864} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_WrapAround: 0 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Selected + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 1246657867} + m_OnClick: + m_PersistentCalls: + m_Calls: [] +--- !u!114 &1246657867 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1246657864} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &1246657868 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1246657864} + m_CullTransparentMesh: 1 +--- !u!1 &1299180661 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1299180662} + - component: {fileID: 1299180664} + - component: {fileID: 1299180663} + m_Layer: 5 + m_Name: Text (Legacy) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1299180662 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1299180661} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 1383089661} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: -3.5} + m_SizeDelta: {x: -20, y: -17} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1299180663 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1299180661} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 24 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 2 + m_MaxSize: 40 + m_Alignment: 0 + m_AlignByGeometry: 0 + m_RichText: 0 + m_HorizontalOverflow: 1 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: +--- !u!222 &1299180664 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1299180661} + m_CullTransparentMesh: 1 +--- !u!1 &1306186264 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1306186265} + - component: {fileID: 1306186268} + - component: {fileID: 1306186267} + - component: {fileID: 1306186266} + m_Layer: 5 + m_Name: RemoveMailButton + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1306186265 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1306186264} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 549834353} + m_Father: {fileID: 1634917323} + m_RootOrder: 5 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 651.00006, y: 316.99997} + m_SizeDelta: {x: 395.6798, y: 134.3838} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1306186266 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1306186264} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_WrapAround: 0 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Selected + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 1306186267} + m_OnClick: + m_PersistentCalls: + m_Calls: [] +--- !u!114 &1306186267 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1306186264} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &1306186268 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1306186264} + m_CullTransparentMesh: 1 +--- !u!1 &1383089660 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1383089661} + - component: {fileID: 1383089664} + - component: {fileID: 1383089663} + - component: {fileID: 1383089662} + m_Layer: 5 + m_Name: MailId + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1383089661 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1383089660} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 1016206936} + - {fileID: 1299180662} + m_Father: {fileID: 1634917323} + m_RootOrder: 3 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: -36.337097, y: 460} + m_SizeDelta: {x: 829.0846, y: 47.7093} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1383089662 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1383089660} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d199490a83bb2b844b9695cbf13b01ef, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_WrapAround: 0 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Selected + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 1383089663} + m_TextComponent: {fileID: 1299180663} + m_Placeholder: {fileID: 1016206937} + m_ContentType: 0 + m_InputType: 0 + m_AsteriskChar: 42 + m_KeyboardType: 0 + m_LineType: 0 + m_HideMobileInput: 0 + m_CharacterValidation: 0 + m_CharacterLimit: 0 + m_OnSubmit: + m_PersistentCalls: + m_Calls: [] + m_OnDidEndEdit: + m_PersistentCalls: + m_Calls: [] + m_OnValueChanged: + m_PersistentCalls: + m_Calls: [] + m_CaretColor: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} + m_CustomCaretColor: 0 + m_SelectionColor: {r: 0.65882355, g: 0.80784315, b: 1, a: 0.7529412} + m_Text: + m_CaretBlinkRate: 0.85 + m_CaretWidth: 1 + m_ReadOnly: 0 + m_ShouldActivateOnSelect: 1 +--- !u!114 &1383089663 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1383089660} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10911, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &1383089664 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1383089660} + m_CullTransparentMesh: 1 +--- !u!1 &1402508498 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1402508499} + - component: {fileID: 1402508502} + - component: {fileID: 1402508501} + - component: {fileID: 1402508500} + m_Layer: 5 + m_Name: ReceiveMailButton + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1402508499 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1402508498} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 1579164480} + m_Father: {fileID: 1634917323} + m_RootOrder: 10 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 264, y: -338} + m_SizeDelta: {x: 395.6798, y: 134.3838} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1402508500 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1402508498} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_WrapAround: 0 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Selected + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 1402508501} + m_OnClick: + m_PersistentCalls: + m_Calls: [] +--- !u!114 &1402508501 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1402508498} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &1402508502 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1402508498} + m_CullTransparentMesh: 1 +--- !u!1 &1433264942 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1433264943} + - component: {fileID: 1433264946} + - component: {fileID: 1433264945} + - component: {fileID: 1433264944} + m_Layer: 5 + m_Name: OpenMailButton + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1433264943 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1433264942} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 1670286768} + m_Father: {fileID: 1634917323} + m_RootOrder: 4 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 215, y: 316.99997} + m_SizeDelta: {x: 395.6798, y: 134.3838} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1433264944 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1433264942} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_WrapAround: 0 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Selected + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 1433264945} + m_OnClick: + m_PersistentCalls: + m_Calls: [] +--- !u!114 &1433264945 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1433264942} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &1433264946 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1433264942} + m_CullTransparentMesh: 1 +--- !u!1 &1433382151 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1433382152} + - component: {fileID: 1433382154} + - component: {fileID: 1433382153} + m_Layer: 5 + m_Name: Text (Legacy) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1433382152 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1433382151} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 1508323924} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: -3.5} + m_SizeDelta: {x: -20, y: -17} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1433382153 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1433382151} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 24 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 2 + m_MaxSize: 40 + m_Alignment: 3 + m_AlignByGeometry: 0 + m_RichText: 0 + m_HorizontalOverflow: 1 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: +--- !u!222 &1433382154 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1433382151} + m_CullTransparentMesh: 1 +--- !u!1 &1506082735 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1506082736} + - component: {fileID: 1506082738} + - component: {fileID: 1506082737} + m_Layer: 5 + m_Name: Placeholder + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1506082736 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1506082735} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 316110487} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: -3.5} + m_SizeDelta: {x: -20, y: -17} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1506082737 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1506082735} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 0.5} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 24 + m_FontStyle: 2 + m_BestFit: 0 + m_MinSize: 2 + m_MaxSize: 40 + m_Alignment: 3 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: "\u63A5\u6536\u4EBA\u540D\u5B57" +--- !u!222 &1506082738 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1506082735} + m_CullTransparentMesh: 1 +--- !u!1 &1508323923 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1508323924} + - component: {fileID: 1508323927} + - component: {fileID: 1508323926} + - component: {fileID: 1508323925} + m_Layer: 5 + m_Name: MailTitle + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1508323924 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1508323923} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 656443552} + - {fileID: 1433382152} + m_Father: {fileID: 1634917323} + m_RootOrder: 6 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: -348.43494, y: 164.99997} + m_SizeDelta: {x: 1108.2147, y: 47.7093} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1508323925 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1508323923} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d199490a83bb2b844b9695cbf13b01ef, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_WrapAround: 0 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Selected + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 1508323926} + m_TextComponent: {fileID: 1433382153} + m_Placeholder: {fileID: 656443553} + m_ContentType: 0 + m_InputType: 0 + m_AsteriskChar: 42 + m_KeyboardType: 0 + m_LineType: 0 + m_HideMobileInput: 0 + m_CharacterValidation: 0 + m_CharacterLimit: 0 + m_OnSubmit: + m_PersistentCalls: + m_Calls: [] + m_OnDidEndEdit: + m_PersistentCalls: + m_Calls: [] + m_OnValueChanged: + m_PersistentCalls: + m_Calls: [] + m_CaretColor: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} + m_CustomCaretColor: 0 + m_SelectionColor: {r: 0.65882355, g: 0.80784315, b: 1, a: 0.7529412} + m_Text: + m_CaretBlinkRate: 0.85 + m_CaretWidth: 1 + m_ReadOnly: 0 + m_ShouldActivateOnSelect: 1 +--- !u!114 &1508323926 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1508323923} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10911, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &1508323927 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1508323923} + m_CullTransparentMesh: 1 +--- !u!1 &1579164479 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1579164480} + - component: {fileID: 1579164482} + - component: {fileID: 1579164481} + m_Layer: 5 + m_Name: Text (Legacy) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1579164480 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1579164479} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 1402508499} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1579164481 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1579164479} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 24 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 2 + m_MaxSize: 40 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: "\u9886\u53D6\u4E00\u4E2A\u90AE\u4EF6\u7684\u6240\u6709\u9644\u4EF6" +--- !u!222 &1579164482 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1579164479} + m_CullTransparentMesh: 1 +--- !u!1 &1634917322 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1634917323} + - component: {fileID: 1634917325} + - component: {fileID: 1634917324} + m_Layer: 5 + m_Name: MailPanel + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1634917323 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1634917322} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 1124882447} + - {fileID: 1755739493} + - {fileID: 1246657865} + - {fileID: 1383089661} + - {fileID: 1433264943} + - {fileID: 1306186265} + - {fileID: 1508323924} + - {fileID: 316110487} + - {fileID: 554487406} + - {fileID: 1856661521} + - {fileID: 1402508499} + m_Father: {fileID: 1700586183} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1634917324 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1634917322} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 0.392} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10907, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &1634917325 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1634917322} + m_CullTransparentMesh: 1 +--- !u!1 &1670286767 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1670286768} + - component: {fileID: 1670286770} + - component: {fileID: 1670286769} + m_Layer: 5 + m_Name: Text (Legacy) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1670286768 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1670286767} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 1433264943} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1670286769 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1670286767} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 24 + m_FontStyle: 0 + m_BestFit: 0 + m_MinSize: 2 + m_MaxSize: 40 + m_Alignment: 4 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: "\u6253\u5F00\u4E00\u4E2A\u62E5\u6709\u7684\u90AE\u4EF6" +--- !u!222 &1670286770 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1670286767} + m_CullTransparentMesh: 1 +--- !u!1 &1673164676 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1673164677} + - component: {fileID: 1673164680} + - component: {fileID: 1673164679} + - component: {fileID: 1673164678} + m_Layer: 5 + m_Name: UserName + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1673164677 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1673164676} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 2090496545} + - {fileID: 456832072} + m_Father: {fileID: 1124882447} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 12.8795, y: 11} + m_SizeDelta: {x: 185.759, y: 47.7093} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1673164678 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1673164676} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d199490a83bb2b844b9695cbf13b01ef, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_WrapAround: 0 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Selected + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 1673164679} + m_TextComponent: {fileID: 456832073} + m_Placeholder: {fileID: 2090496546} + m_ContentType: 0 + m_InputType: 0 + m_AsteriskChar: 42 + m_KeyboardType: 0 + m_LineType: 0 + m_HideMobileInput: 0 + m_CharacterValidation: 0 + m_CharacterLimit: 0 + m_OnSubmit: + m_PersistentCalls: + m_Calls: [] + m_OnDidEndEdit: + m_PersistentCalls: + m_Calls: [] + m_OnValueChanged: + m_PersistentCalls: + m_Calls: [] + m_CaretColor: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} + m_CustomCaretColor: 0 + m_SelectionColor: {r: 0.65882355, g: 0.80784315, b: 1, a: 0.7529412} + m_Text: + m_CaretBlinkRate: 0.85 + m_CaretWidth: 1 + m_ReadOnly: 0 + m_ShouldActivateOnSelect: 1 +--- !u!114 &1673164679 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1673164676} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10911, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &1673164680 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1673164676} + m_CullTransparentMesh: 1 +--- !u!1 &1700586179 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1700586183} + - component: {fileID: 1700586182} + - component: {fileID: 1700586181} + - component: {fileID: 1700586180} + m_Layer: 5 + m_Name: Canvas + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1700586180 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1700586179} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: dc42784cf147c0c48a680349fa168899, type: 3} + m_Name: + m_EditorClassIdentifier: + m_IgnoreReversedGraphics: 1 + m_BlockingObjects: 0 + m_BlockingMask: + serializedVersion: 2 + m_Bits: 4294967295 +--- !u!114 &1700586181 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1700586179} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 0cd44c1031e13a943bb63640046fad76, type: 3} + m_Name: + m_EditorClassIdentifier: + m_UiScaleMode: 1 + m_ReferencePixelsPerUnit: 100 + m_ScaleFactor: 1 + m_ReferenceResolution: {x: 1920, y: 1080} + m_ScreenMatchMode: 0 + m_MatchWidthOrHeight: 0.5 + m_PhysicalUnit: 3 + m_FallbackScreenDPI: 96 + m_DefaultSpriteDPI: 96 + m_DynamicPixelsPerUnit: 1 + m_PresetInfoIsWorld: 0 +--- !u!223 &1700586182 +Canvas: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1700586179} + m_Enabled: 1 + serializedVersion: 3 + m_RenderMode: 0 + m_Camera: {fileID: 0} + m_PlaneDistance: 100 + m_PixelPerfect: 0 + m_ReceivesEvents: 1 + m_OverrideSorting: 0 + m_OverridePixelPerfect: 0 + m_SortingBucketNormalizedSize: 0 + m_AdditionalShaderChannelsFlag: 0 + m_SortingLayerID: 0 + m_SortingOrder: 0 + m_TargetDisplay: 0 +--- !u!224 &1700586183 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1700586179} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 0, y: 0, z: 0} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 1634917323} + m_Father: {fileID: 0} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 0} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0, y: 0} +--- !u!1 &1755739492 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1755739493} + - component: {fileID: 1755739496} + - component: {fileID: 1755739495} + - component: {fileID: 1755739494} + m_Layer: 5 + m_Name: SendTestButton + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1755739493 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1755739492} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 1028105311} + m_Father: {fileID: 1634917323} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: -658.99994, y: 316.99997} + m_SizeDelta: {x: 395.6798, y: 134.3838} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1755739494 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1755739492} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_WrapAround: 0 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Selected + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 1755739495} + m_OnClick: + m_PersistentCalls: + m_Calls: [] +--- !u!114 &1755739495 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1755739492} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &1755739496 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1755739492} + m_CullTransparentMesh: 1 +--- !u!1 &1856661520 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1856661521} + - component: {fileID: 1856661524} + - component: {fileID: 1856661523} + - component: {fileID: 1856661522} + m_Layer: 5 + m_Name: SendMailButton + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1856661521 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1856661520} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 611927701} + m_Father: {fileID: 1634917323} + m_RootOrder: 9 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 689, y: -341} + m_SizeDelta: {x: 395.6798, y: 134.3838} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1856661522 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1856661520} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_WrapAround: 0 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Selected + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 1856661523} + m_OnClick: + m_PersistentCalls: + m_Calls: [] +--- !u!114 &1856661523 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1856661520} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &1856661524 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1856661520} + m_CullTransparentMesh: 1 +--- !u!1 &2090496544 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2090496545} + - component: {fileID: 2090496547} + - component: {fileID: 2090496546} + m_Layer: 5 + m_Name: Placeholder + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &2090496545 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2090496544} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 1673164677} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: -3.5} + m_SizeDelta: {x: -20, y: -17} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &2090496546 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2090496544} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 5f7201a12d95ffc409449d95f23cf332, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 0.5} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_FontData: + m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} + m_FontSize: 24 + m_FontStyle: 2 + m_BestFit: 0 + m_MinSize: 2 + m_MaxSize: 40 + m_Alignment: 1 + m_AlignByGeometry: 0 + m_RichText: 1 + m_HorizontalOverflow: 0 + m_VerticalOverflow: 0 + m_LineSpacing: 1 + m_Text: "\u767B\u9646\u7684\u7528\u6237\u540D" +--- !u!222 &2090496547 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2090496544} + m_CullTransparentMesh: 1 diff --git a/邮件系统课程完整代码/Client/Unity/Assets/Scenes/SampleScene.unity.meta b/邮件系统课程完整代码/Client/Unity/Assets/Scenes/SampleScene.unity.meta new file mode 100644 index 0000000..952bd1e --- /dev/null +++ b/邮件系统课程完整代码/Client/Unity/Assets/Scenes/SampleScene.unity.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 9fc0d4010bbf28b4594072e72b8655ab +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/邮件系统课程完整代码/Client/Unity/Assets/Scripts.meta b/邮件系统课程完整代码/Client/Unity/Assets/Scripts.meta new file mode 100644 index 0000000..5d8b8eb --- /dev/null +++ b/邮件系统课程完整代码/Client/Unity/Assets/Scripts.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 0ff18268873c34d1898f648db43ca8ed +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/邮件系统课程完整代码/Client/Unity/Assets/Scripts/.DS_Store b/邮件系统课程完整代码/Client/Unity/Assets/Scripts/.DS_Store new file mode 100644 index 0000000..5243526 Binary files /dev/null and b/邮件系统课程完整代码/Client/Unity/Assets/Scripts/.DS_Store differ diff --git a/邮件系统课程完整代码/Client/Unity/Assets/Scripts/Entry.cs b/邮件系统课程完整代码/Client/Unity/Assets/Scripts/Entry.cs new file mode 100644 index 0000000..0a089d8 --- /dev/null +++ b/邮件系统课程完整代码/Client/Unity/Assets/Scripts/Entry.cs @@ -0,0 +1,229 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using Fantasy; +using Fantasy.Async; +using Fantasy.Network; +using UnityEngine; +using UnityEngine.UI; + +public class Entry : MonoBehaviour +{ + private Scene _scene; + private Session _session; + + public Button LoginButton; + public Button ExitButton; + public Button SendTestButton; + public Button GetHaveMailButton; + public Button OpenMailButton; + public Button ReceiveMailButton; + public Button RemoveMailButton; + public Button SendMailButton; + public InputField LoginUserName; + public InputField MailId; + public InputField MailTitle; + public InputField MailUserName; + public InputField MailContent; + void Start() + { + LoginButton.onClick.RemoveAllListeners(); + LoginButton.onClick.AddListener(OnLoginButtonClick); + ExitButton.onClick.RemoveAllListeners(); + ExitButton.onClick.AddListener(OnExitButtonClick); + SendTestButton.onClick.RemoveAllListeners(); + SendTestButton.onClick.AddListener(() => + { + OnSendTestButtonClick().Coroutine(); + }); + GetHaveMailButton.onClick.RemoveAllListeners(); + GetHaveMailButton.onClick.AddListener(() => + { + OnGetHaveMailButtonClick().Coroutine(); + }); + OpenMailButton.onClick.RemoveAllListeners(); + OpenMailButton.onClick.AddListener(() => + { + OnOpenMailButtonClick().Coroutine(); + }); + ReceiveMailButton.onClick.RemoveAllListeners(); + ReceiveMailButton.onClick.AddListener(() => + { + OnReceiveMailButtonClick().Coroutine(); + }); + RemoveMailButton.onClick.RemoveAllListeners(); + RemoveMailButton.onClick.AddListener(() => + { + OnRemoveMailButtonClick().Coroutine(); + }); + SendMailButton.onClick.RemoveAllListeners(); + SendMailButton.onClick.AddListener(() => + { + OnSendMailButtonClick().Coroutine(); + }); + StartAsync().Coroutine(); + } + + private async FTask StartAsync() + { + Fantasy.Platform.Unity.Entry.Initialize(GetType().Assembly); + _scene = await Scene.Create(SceneRuntimeType.MainThread); + } + + private void OnLoginButtonClick() + { + // 1、判定用户输入的用户名是否为空,如果是空,则提示用户输入用户名。 + + if (string.IsNullOrEmpty(LoginUserName.text)) + { + Log.Error("用户名不可以为空!"); + return; + } + + // 2、首先创建一个连接,并且设置连接成功和失败的回调。 + _session = _scene.Connect("127.0.0.1:20000", NetworkProtocolType.KCP, () => + { + Log.Debug("连接成功"); + // 首先要判定一下。当前的Session是否被断开或销毁了 + if (_session.IsDisposed) + { + return; + } + // 添加一个心跳组件,用来跟服务器保持心跳 + _session.AddComponent().Start(2000); + // 执行登陆请求 + LoginRequest().Coroutine(); + }, () => + { + Log.Debug("连接失败"); + }, () => + { + // 能触发到连接断开的委托的时候只有如下两种情况: + // 1、服务器主动跟客户端断开连接。 + // 2、客户端主动跟服务器断开连接。 + Log.Debug("断开连接"); + }, false, 3000); + } + + private void OnApplicationQuit() + { + _scene.Dispose(); + } + + private async FTask LoginRequest() + { + var userName = LoginUserName.text; + var response = (G2C_LoginResponse)await _session.Call(new C2G_LoginRequest() + { + Name = userName + }); + if (response.ErrorCode != 0) + { + Log.Error($"登陆时发生错误。ErrorCode:{response.ErrorCode}"); + return; + } + Log.Debug($"登陆成功,UserName:{userName}"); + } + + private void OnExitButtonClick() + { + if (_session == null || _session.IsDisposed) + { + return; + } + + _session.Send(new C2G_Exit()); + Log.Debug("已经跟服务器发送了断开的协议!"); + } + + private async FTask OnSendTestButtonClick() + { + var userName = LoginUserName.text; + var response = (Mail2C_TestResponse)await _session.Call(new C2Mail_TestRequest() + { + Tag = userName + }); + if (response.ErrorCode != 0) + { + Log.Error($"测试时发生错误。ErrorCode:{response.ErrorCode}"); + return; + } + Log.Debug($"接收到服务器发送来的自定义Route协议,Tag:{response.Tag}"); + } + + private async FTask OnGetHaveMailButtonClick() + { + var response = (Mail2C_GetHaveMailResposne)await _session.Call(new C2Mail_GetHaveMailRequest()); + if (response.ErrorCode != 0) + { + Log.Error($"获取邮件时发生错误。ErrorCode:{response.ErrorCode}"); + return; + } + foreach (var mailSimplifyInfo in response.Mails) + { + MailId.text = mailSimplifyInfo.MailId.ToString(); + Log.Debug($"获取到邮件,MailId:{mailSimplifyInfo.MailId},MailType:{mailSimplifyInfo.MailType} 标题:{mailSimplifyInfo.Title}"); + } + + Log.Debug($"获取到邮件数量:{response.Mails.Count}"); + } + + private async FTask OnOpenMailButtonClick() + { + var response = (Mail2C_OpenMailResposne)await _session.Call(new C2Mail_OpenMailRequest() + { + MailId = long.Parse(MailId.text), ReturnMailInfo = true + }); + if (response.ErrorCode != 0) + { + Log.Error($"打开邮件时发生错误。ErrorCode:{response.ErrorCode}"); + return; + } + Log.Debug($"打开邮件成功,邮件Id:{response.MailInfo.MailId} 标题:{response.MailInfo.Title} 内容:{response.MailInfo.Content}"); + } + + private async FTask OnReceiveMailButtonClick() + { + var response = (Mail2C_ReceiveMailResponse)await _session.Call(new C2Mail_ReceiveMailRequest() + { + MailId = long.Parse(MailId.text) + }); + if (response.ErrorCode != 0) + { + Log.Error($"领取邮件时发生错误。ErrorCode:{response.ErrorCode}"); + return; + } + Log.Debug($"领取邮件附件成功"); + } + + private async FTask OnRemoveMailButtonClick() + { + var response = (Mail2C_RemoveMailResponse)await _session.Call(new C2Mail_RemoveMailRequest() + { + MailId = long.Parse(MailId.text) + }); + if (response.ErrorCode != 0) + { + Log.Error($"删除邮件时发生错误。ErrorCode:{response.ErrorCode}"); + return; + } + Log.Debug($"删除邮件成功"); + } + + private async FTask OnSendMailButtonClick() + { + var response = (Mail2C_SendMailResponse)await _session.Call(new C2Mail_SendMailRequest() + { + UserName = MailUserName.text, + Title = MailTitle.text, + Content = MailContent.text, + Money = 100 + }); + if (response.ErrorCode != 0) + { + Log.Error($"发送邮件时发生错误。ErrorCode:{response.ErrorCode}"); + return; + } + Log.Debug($"发送邮件成功"); + } +} diff --git a/邮件系统课程完整代码/Client/Unity/Assets/Scripts/Entry.cs.meta b/邮件系统课程完整代码/Client/Unity/Assets/Scripts/Entry.cs.meta new file mode 100644 index 0000000..6cab796 --- /dev/null +++ b/邮件系统课程完整代码/Client/Unity/Assets/Scripts/Entry.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9bd17d680f8ff4bee82ecdd82ba4b804 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/邮件系统课程完整代码/Client/Unity/Assets/Scripts/Handler.meta b/邮件系统课程完整代码/Client/Unity/Assets/Scripts/Handler.meta new file mode 100644 index 0000000..2d276ce --- /dev/null +++ b/邮件系统课程完整代码/Client/Unity/Assets/Scripts/Handler.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: a9d17c41edd114162bb7a75c4b500bee +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/邮件系统课程完整代码/Client/Unity/Assets/Scripts/Handler/Mail2C_HaveMailHandler.cs b/邮件系统课程完整代码/Client/Unity/Assets/Scripts/Handler/Mail2C_HaveMailHandler.cs new file mode 100644 index 0000000..963f71d --- /dev/null +++ b/邮件系统课程完整代码/Client/Unity/Assets/Scripts/Handler/Mail2C_HaveMailHandler.cs @@ -0,0 +1,15 @@ +using Fantasy.Async; +using Fantasy.Network; +using Fantasy.Network.Interface; + +namespace Fantasy +{ + public class Mail2C_HaveMailHandler : Message + { + protected override async FTask Run(Session session, Mail2C_HaveMail message) + { + Log.Debug($"Mail2C_HaveMailHandler MailId:{message.Mail.MailId} MailTitle:{message.Mail.Title}"); + await FTask.CompletedTask; + } + } +} \ No newline at end of file diff --git a/邮件系统课程完整代码/Client/Unity/Assets/Scripts/Handler/Mail2C_HaveMailHandler.cs.meta b/邮件系统课程完整代码/Client/Unity/Assets/Scripts/Handler/Mail2C_HaveMailHandler.cs.meta new file mode 100644 index 0000000..5c316c4 --- /dev/null +++ b/邮件系统课程完整代码/Client/Unity/Assets/Scripts/Handler/Mail2C_HaveMailHandler.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: dfc2d0255b4844d1ab6a1e67af759c68 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/邮件系统课程完整代码/Client/Unity/Assets/Scripts/Handler/Mail2C_MailStateHandler.cs b/邮件系统课程完整代码/Client/Unity/Assets/Scripts/Handler/Mail2C_MailStateHandler.cs new file mode 100644 index 0000000..14b32b0 --- /dev/null +++ b/邮件系统课程完整代码/Client/Unity/Assets/Scripts/Handler/Mail2C_MailStateHandler.cs @@ -0,0 +1,15 @@ +using Fantasy.Async; +using Fantasy.Network; +using Fantasy.Network.Interface; + +namespace Fantasy +{ + public class Mail2C_MailStateHandler : Message + { + protected override async FTask Run(Session session, Mail2C_MailState message) + { + Log.Debug($"MailId:{message.MailId} MailState:{message.MailState}"); + await FTask.CompletedTask; + } + } +} \ No newline at end of file diff --git a/邮件系统课程完整代码/Client/Unity/Assets/Scripts/Handler/Mail2C_MailStateHandler.cs.meta b/邮件系统课程完整代码/Client/Unity/Assets/Scripts/Handler/Mail2C_MailStateHandler.cs.meta new file mode 100644 index 0000000..92b85e9 --- /dev/null +++ b/邮件系统课程完整代码/Client/Unity/Assets/Scripts/Handler/Mail2C_MailStateHandler.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0e1475a1860bd42f2b62e0fadfbdf21f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/邮件系统课程完整代码/Client/Unity/Assets/Scripts/Hotfix.meta b/邮件系统课程完整代码/Client/Unity/Assets/Scripts/Hotfix.meta new file mode 100644 index 0000000..7b3149f --- /dev/null +++ b/邮件系统课程完整代码/Client/Unity/Assets/Scripts/Hotfix.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 8dc09a63f0cb84af3a196d9b71ec47ea +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/邮件系统课程完整代码/Client/Unity/Assets/Scripts/Hotfix/.DS_Store b/邮件系统课程完整代码/Client/Unity/Assets/Scripts/Hotfix/.DS_Store new file mode 100644 index 0000000..264338d Binary files /dev/null and b/邮件系统课程完整代码/Client/Unity/Assets/Scripts/Hotfix/.DS_Store differ diff --git a/邮件系统课程完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate.meta b/邮件系统课程完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate.meta new file mode 100644 index 0000000..150aa09 --- /dev/null +++ b/邮件系统课程完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e44210ffde5a14530b15db967824df55 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/邮件系统课程完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/.DS_Store b/邮件系统课程完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/.DS_Store new file mode 100644 index 0000000..83e3d6d Binary files /dev/null and b/邮件系统课程完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/.DS_Store differ diff --git a/邮件系统课程完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/NetworkProtocol.meta b/邮件系统课程完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/NetworkProtocol.meta new file mode 100644 index 0000000..a78a3f3 --- /dev/null +++ b/邮件系统课程完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/NetworkProtocol.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b0d035a3f5e8345ac9577f2089cd91f2 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/邮件系统课程完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/NetworkProtocol/OuterMessage.cs b/邮件系统课程完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/NetworkProtocol/OuterMessage.cs new file mode 100644 index 0000000..9b65a0d --- /dev/null +++ b/邮件系统课程完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/NetworkProtocol/OuterMessage.cs @@ -0,0 +1,515 @@ +using ProtoBuf; + +using System.Collections.Generic; +using Fantasy; +using Fantasy.Network.Interface; +using Fantasy.Serialize; +#pragma warning disable CS8618 + +namespace Fantasy +{ + /// + /// 登陆到Gate服务器 + /// + [ProtoContract] + public partial class C2G_LoginRequest : AMessage, IRequest, IProto + { + public static C2G_LoginRequest Create(Scene scene) + { + return scene.MessagePoolComponent.Rent(); + } + public override void Dispose() + { + Name = default; +#if FANTASY_NET || FANTASY_UNITY + GetScene().MessagePoolComponent.Return(this); +#endif + } + [ProtoIgnore] + public G2C_LoginResponse ResponseType { get; set; } + public uint OpCode() { return OuterOpcode.C2G_LoginRequest; } + [ProtoMember(1)] + public string Name { get; set; } + } + [ProtoContract] + public partial class G2C_LoginResponse : AMessage, IResponse, IProto + { + public static G2C_LoginResponse Create(Scene scene) + { + return scene.MessagePoolComponent.Rent(); + } + public override void Dispose() + { + ErrorCode = default; +#if FANTASY_NET || FANTASY_UNITY + GetScene().MessagePoolComponent.Return(this); +#endif + } + public uint OpCode() { return OuterOpcode.G2C_LoginResponse; } + [ProtoMember(1)] + public uint ErrorCode { get; set; } + } + /// + /// 客户端通知服务器退出游戏 + /// + [ProtoContract] + public partial class C2G_Exit : AMessage, IMessage, IProto + { + public static C2G_Exit Create(Scene scene) + { + return scene.MessagePoolComponent.Rent(); + } + public override void Dispose() + { +#if FANTASY_NET || FANTASY_UNITY + GetScene().MessagePoolComponent.Return(this); +#endif + } + public uint OpCode() { return OuterOpcode.C2G_Exit; } + } + /// + /// 测试Mail自定义Route协议 + /// + [ProtoContract] + public partial class C2Mail_TestRequest : AMessage, ICustomRouteRequest, IProto + { + public static C2Mail_TestRequest Create(Scene scene) + { + return scene.MessagePoolComponent.Rent(); + } + public override void Dispose() + { + Tag = default; +#if FANTASY_NET || FANTASY_UNITY + GetScene().MessagePoolComponent.Return(this); +#endif + } + [ProtoIgnore] + public Mail2C_TestResponse ResponseType { get; set; } + public uint OpCode() { return OuterOpcode.C2Mail_TestRequest; } + [ProtoIgnore] + public int RouteType => Fantasy.RouteType.MailRoute; + [ProtoMember(1)] + public string Tag { get; set; } + } + [ProtoContract] + public partial class Mail2C_TestResponse : AMessage, ICustomRouteResponse, IProto + { + public static Mail2C_TestResponse Create(Scene scene) + { + return scene.MessagePoolComponent.Rent(); + } + public override void Dispose() + { + ErrorCode = default; + Tag = default; +#if FANTASY_NET || FANTASY_UNITY + GetScene().MessagePoolComponent.Return(this); +#endif + } + public uint OpCode() { return OuterOpcode.Mail2C_TestResponse; } + [ProtoMember(1)] + public string Tag { get; set; } + [ProtoMember(2)] + public uint ErrorCode { get; set; } + } + /// + /// 一个邮件的完整信息 + /// + [ProtoContract] + public partial class MailInfo : AMessage, IProto + { + public static MailInfo Create(Scene scene) + { + return scene.MessagePoolComponent.Rent(); + } + public override void Dispose() + { + MailId = default; + OwnerId = default; + Title = default; + Content = default; + CreateTime = default; + ExpireTime = default; + Money = default; + MailState = default; + MailType = default; + Items.Clear(); +#if FANTASY_NET || FANTASY_UNITY + GetScene().MessagePoolComponent.Return(this); +#endif + } + [ProtoMember(1)] + public long MailId { get; set; } + [ProtoMember(2)] + public long OwnerId { get; set; } + [ProtoMember(3)] + public string Title { get; set; } + [ProtoMember(4)] + public string Content { get; set; } + [ProtoMember(5)] + public long CreateTime { get; set; } + [ProtoMember(6)] + public long ExpireTime { get; set; } + [ProtoMember(7)] + public int Money { get; set; } + [ProtoMember(8)] + public int MailState { get; set; } + [ProtoMember(9)] + public int MailType { get; set; } + [ProtoMember(10)] + public List Items = new List(); + } + /// + /// 一个邮件的简单版消息 + /// + [ProtoContract] + public partial class MailSimplifyInfo : AMessage, IProto + { + public static MailSimplifyInfo Create(Scene scene) + { + return scene.MessagePoolComponent.Rent(); + } + public override void Dispose() + { + MailId = default; + OwnerId = default; + Title = default; + Content = default; + CreateTime = default; + ExpireTime = default; + MailState = default; + MailType = default; +#if FANTASY_NET || FANTASY_UNITY + GetScene().MessagePoolComponent.Return(this); +#endif + } + [ProtoMember(1)] + public long MailId { get; set; } + [ProtoMember(2)] + public long OwnerId { get; set; } + [ProtoMember(3)] + public string Title { get; set; } + [ProtoMember(4)] + public string Content { get; set; } + [ProtoMember(5)] + public long CreateTime { get; set; } + [ProtoMember(6)] + public long ExpireTime { get; set; } + [ProtoMember(7)] + public int MailState { get; set; } + [ProtoMember(8)] + public int MailType { get; set; } + } + /// + /// 一个简单的物品信息 + /// + [ProtoContract] + public partial class ItemInfo : AMessage, IProto + { + public static ItemInfo Create(Scene scene) + { + return scene.MessagePoolComponent.Rent(); + } + public override void Dispose() + { + ItemId = default; + Name = default; +#if FANTASY_NET || FANTASY_UNITY + GetScene().MessagePoolComponent.Return(this); +#endif + } + [ProtoMember(1)] + public long ItemId { get; set; } + [ProtoMember(2)] + public string Name { get; set; } + } + /// + /// Mail通知客户端有新的邮件 + /// + [ProtoContract] + public partial class Mail2C_HaveMail : AMessage, ICustomRouteMessage, IProto + { + public static Mail2C_HaveMail Create(Scene scene) + { + return scene.MessagePoolComponent.Rent(); + } + public override void Dispose() + { + Mail = default; +#if FANTASY_NET || FANTASY_UNITY + GetScene().MessagePoolComponent.Return(this); +#endif + } + public uint OpCode() { return OuterOpcode.Mail2C_HaveMail; } + [ProtoIgnore] + public int RouteType => Fantasy.RouteType.MailRoute; + [ProtoMember(1)] + public MailSimplifyInfo Mail { get; set; } + } + /// + /// Mail通知客户端邮件状态变化 + /// + [ProtoContract] + public partial class Mail2C_MailState : AMessage, ICustomRouteMessage, IProto + { + public static Mail2C_MailState Create(Scene scene) + { + return scene.MessagePoolComponent.Rent(); + } + public override void Dispose() + { + MailState = default; + MailId = default; +#if FANTASY_NET || FANTASY_UNITY + GetScene().MessagePoolComponent.Return(this); +#endif + } + public uint OpCode() { return OuterOpcode.Mail2C_MailState; } + [ProtoIgnore] + public int RouteType => Fantasy.RouteType.MailRoute; + [ProtoMember(1)] + public int MailState { get; set; } + [ProtoMember(2)] + public long MailId { get; set; } + } + /// + /// 客户端获取档期所有邮件的信息 + /// + [ProtoContract] + public partial class C2Mail_GetHaveMailRequest : AMessage, ICustomRouteRequest, IProto + { + public static C2Mail_GetHaveMailRequest Create(Scene scene) + { + return scene.MessagePoolComponent.Rent(); + } + public override void Dispose() + { +#if FANTASY_NET || FANTASY_UNITY + GetScene().MessagePoolComponent.Return(this); +#endif + } + [ProtoIgnore] + public Mail2C_GetHaveMailResposne ResponseType { get; set; } + public uint OpCode() { return OuterOpcode.C2Mail_GetHaveMailRequest; } + [ProtoIgnore] + public int RouteType => Fantasy.RouteType.MailRoute; + } + [ProtoContract] + public partial class Mail2C_GetHaveMailResposne : AMessage, ICustomRouteResponse, IProto + { + public static Mail2C_GetHaveMailResposne Create(Scene scene) + { + return scene.MessagePoolComponent.Rent(); + } + public override void Dispose() + { + ErrorCode = default; + Mails.Clear(); +#if FANTASY_NET || FANTASY_UNITY + GetScene().MessagePoolComponent.Return(this); +#endif + } + public uint OpCode() { return OuterOpcode.Mail2C_GetHaveMailResposne; } + [ProtoMember(1)] + public List Mails = new List(); + [ProtoMember(2)] + public uint ErrorCode { get; set; } + } + /// + /// 客户端发开一个邮件 + /// + [ProtoContract] + public partial class C2Mail_OpenMailRequest : AMessage, ICustomRouteRequest, IProto + { + public static C2Mail_OpenMailRequest Create(Scene scene) + { + return scene.MessagePoolComponent.Rent(); + } + public override void Dispose() + { + MailId = default; + ReturnMailInfo = default; +#if FANTASY_NET || FANTASY_UNITY + GetScene().MessagePoolComponent.Return(this); +#endif + } + [ProtoIgnore] + public Mail2C_OpenMailResposne ResponseType { get; set; } + public uint OpCode() { return OuterOpcode.C2Mail_OpenMailRequest; } + [ProtoIgnore] + public int RouteType => Fantasy.RouteType.MailRoute; + [ProtoMember(1)] + public long MailId { get; set; } + [ProtoMember(2)] + public bool ReturnMailInfo { get; set; } + } + [ProtoContract] + public partial class Mail2C_OpenMailResposne : AMessage, ICustomRouteResponse, IProto + { + public static Mail2C_OpenMailResposne Create(Scene scene) + { + return scene.MessagePoolComponent.Rent(); + } + public override void Dispose() + { + ErrorCode = default; + MailInfo = default; +#if FANTASY_NET || FANTASY_UNITY + GetScene().MessagePoolComponent.Return(this); +#endif + } + public uint OpCode() { return OuterOpcode.Mail2C_OpenMailResposne; } + [ProtoMember(1)] + public MailInfo MailInfo { get; set; } + [ProtoMember(2)] + public uint ErrorCode { get; set; } + } + /// + /// 客户端领取邮件的附件 + /// + [ProtoContract] + public partial class C2Mail_ReceiveMailRequest : AMessage, ICustomRouteRequest, IProto + { + public static C2Mail_ReceiveMailRequest Create(Scene scene) + { + return scene.MessagePoolComponent.Rent(); + } + public override void Dispose() + { + MailId = default; + Money = default; + ItemId.Clear(); +#if FANTASY_NET || FANTASY_UNITY + GetScene().MessagePoolComponent.Return(this); +#endif + } + [ProtoIgnore] + public Mail2C_ReceiveMailResponse ResponseType { get; set; } + public uint OpCode() { return OuterOpcode.C2Mail_ReceiveMailRequest; } + [ProtoIgnore] + public int RouteType => Fantasy.RouteType.MailRoute; + [ProtoMember(1)] + public long MailId { get; set; } + [ProtoMember(2)] + public bool Money { get; set; } + [ProtoMember(3)] + public List ItemId = new List(); + } + [ProtoContract] + public partial class Mail2C_ReceiveMailResponse : AMessage, ICustomRouteResponse, IProto + { + public static Mail2C_ReceiveMailResponse Create(Scene scene) + { + return scene.MessagePoolComponent.Rent(); + } + public override void Dispose() + { + ErrorCode = default; +#if FANTASY_NET || FANTASY_UNITY + GetScene().MessagePoolComponent.Return(this); +#endif + } + public uint OpCode() { return OuterOpcode.Mail2C_ReceiveMailResponse; } + [ProtoMember(1)] + public uint ErrorCode { get; set; } + } + /// + /// 客户端通知服务器删除一个邮件 + /// + [ProtoContract] + public partial class C2Mail_RemoveMailRequest : AMessage, ICustomRouteRequest, IProto + { + public static C2Mail_RemoveMailRequest Create(Scene scene) + { + return scene.MessagePoolComponent.Rent(); + } + public override void Dispose() + { + MailId = default; +#if FANTASY_NET || FANTASY_UNITY + GetScene().MessagePoolComponent.Return(this); +#endif + } + [ProtoIgnore] + public Mail2C_RemoveMailResponse ResponseType { get; set; } + public uint OpCode() { return OuterOpcode.C2Mail_RemoveMailRequest; } + [ProtoIgnore] + public int RouteType => Fantasy.RouteType.MailRoute; + [ProtoMember(1)] + public long MailId { get; set; } + } + [ProtoContract] + public partial class Mail2C_RemoveMailResponse : AMessage, ICustomRouteResponse, IProto + { + public static Mail2C_RemoveMailResponse Create(Scene scene) + { + return scene.MessagePoolComponent.Rent(); + } + public override void Dispose() + { + ErrorCode = default; +#if FANTASY_NET || FANTASY_UNITY + GetScene().MessagePoolComponent.Return(this); +#endif + } + public uint OpCode() { return OuterOpcode.Mail2C_RemoveMailResponse; } + [ProtoMember(1)] + public uint ErrorCode { get; set; } + } + /// + /// 客户端玩家发送邮件到另外一个玩家 + /// + [ProtoContract] + public partial class C2Mail_SendMailRequest : AMessage, ICustomRouteRequest, IProto + { + public static C2Mail_SendMailRequest Create(Scene scene) + { + return scene.MessagePoolComponent.Rent(); + } + public override void Dispose() + { + UserName = default; + Title = default; + Content = default; + Money = default; + ItemId.Clear(); +#if FANTASY_NET || FANTASY_UNITY + GetScene().MessagePoolComponent.Return(this); +#endif + } + [ProtoIgnore] + public Mail2C_SendMailResponse ResponseType { get; set; } + public uint OpCode() { return OuterOpcode.C2Mail_SendMailRequest; } + [ProtoIgnore] + public int RouteType => Fantasy.RouteType.MailRoute; + [ProtoMember(1)] + public string UserName { get; set; } + [ProtoMember(2)] + public string Title { get; set; } + [ProtoMember(3)] + public string Content { get; set; } + [ProtoMember(4)] + public int Money { get; set; } + [ProtoMember(5)] + public List ItemId = new List(); + } + [ProtoContract] + public partial class Mail2C_SendMailResponse : AMessage, ICustomRouteResponse, IProto + { + public static Mail2C_SendMailResponse Create(Scene scene) + { + return scene.MessagePoolComponent.Rent(); + } + public override void Dispose() + { + ErrorCode = default; +#if FANTASY_NET || FANTASY_UNITY + GetScene().MessagePoolComponent.Return(this); +#endif + } + public uint OpCode() { return OuterOpcode.Mail2C_SendMailResponse; } + [ProtoMember(1)] + public uint ErrorCode { get; set; } + } +} diff --git a/邮件系统课程完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/NetworkProtocol/OuterMessage.cs.meta b/邮件系统课程完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/NetworkProtocol/OuterMessage.cs.meta new file mode 100644 index 0000000..8bff1b9 --- /dev/null +++ b/邮件系统课程完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/NetworkProtocol/OuterMessage.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: acc26a269baf9426b801a737dc694325 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/邮件系统课程完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/NetworkProtocol/OuterOpcode.cs b/邮件系统课程完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/NetworkProtocol/OuterOpcode.cs new file mode 100644 index 0000000..43b59e1 --- /dev/null +++ b/邮件系统课程完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/NetworkProtocol/OuterOpcode.cs @@ -0,0 +1,23 @@ +namespace Fantasy +{ + public static partial class OuterOpcode + { + public const uint C2G_LoginRequest = 268445457; + public const uint G2C_LoginResponse = 402663185; + public const uint C2G_Exit = 134227729; + public const uint C2Mail_TestRequest = 2281711377; + public const uint Mail2C_TestResponse = 2415929105; + public const uint Mail2C_HaveMail = 2147493649; + public const uint Mail2C_MailState = 2147493650; + public const uint C2Mail_GetHaveMailRequest = 2281711378; + public const uint Mail2C_GetHaveMailResposne = 2415929106; + public const uint C2Mail_OpenMailRequest = 2281711379; + public const uint Mail2C_OpenMailResposne = 2415929107; + public const uint C2Mail_ReceiveMailRequest = 2281711380; + public const uint Mail2C_ReceiveMailResponse = 2415929108; + public const uint C2Mail_RemoveMailRequest = 2281711381; + public const uint Mail2C_RemoveMailResponse = 2415929109; + public const uint C2Mail_SendMailRequest = 2281711382; + public const uint Mail2C_SendMailResponse = 2415929110; + } +} diff --git a/邮件系统课程完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/NetworkProtocol/OuterOpcode.cs.meta b/邮件系统课程完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/NetworkProtocol/OuterOpcode.cs.meta new file mode 100644 index 0000000..05f8a94 --- /dev/null +++ b/邮件系统课程完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/NetworkProtocol/OuterOpcode.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2b692d81b97f74cbab5848e775363a45 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/邮件系统课程完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/NetworkProtocol/RouteType.cs b/邮件系统课程完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/NetworkProtocol/RouteType.cs new file mode 100644 index 0000000..84968b2 --- /dev/null +++ b/邮件系统课程完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/NetworkProtocol/RouteType.cs @@ -0,0 +1,8 @@ +namespace Fantasy +{ + // Route协议定义(需要定义1000以上、因为1000以内的框架预留) + public static class RouteType + { + public const int MailRoute = 1001; // Mail + } +} diff --git a/邮件系统课程完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/NetworkProtocol/RouteType.cs.meta b/邮件系统课程完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/NetworkProtocol/RouteType.cs.meta new file mode 100644 index 0000000..2f92680 --- /dev/null +++ b/邮件系统课程完整代码/Client/Unity/Assets/Scripts/Hotfix/Generate/NetworkProtocol/RouteType.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: aac3ea5a9123c4d6998c0dcb3a8981e9 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/邮件系统课程完整代码/Client/Unity/Packages/manifest.json b/邮件系统课程完整代码/Client/Unity/Packages/manifest.json new file mode 100644 index 0000000..f5e9491 --- /dev/null +++ b/邮件系统课程完整代码/Client/Unity/Packages/manifest.json @@ -0,0 +1,55 @@ +{ + "dependencies": { + "com.fantasy.unity": "2024.2.22", + "com.unity.collab-proxy": "1.17.6", + "com.unity.feature.2d": "1.0.0", + "com.unity.ide.rider": "3.0.16", + "com.unity.ide.visualstudio": "2.0.16", + "com.unity.ide.vscode": "1.2.5", + "com.unity.test-framework": "1.1.31", + "com.unity.textmeshpro": "3.0.6", + "com.unity.timeline": "1.6.4", + "com.unity.ugui": "1.0.0", + "com.unity.visualscripting": "1.7.8", + "com.unity.modules.ai": "1.0.0", + "com.unity.modules.androidjni": "1.0.0", + "com.unity.modules.animation": "1.0.0", + "com.unity.modules.assetbundle": "1.0.0", + "com.unity.modules.audio": "1.0.0", + "com.unity.modules.cloth": "1.0.0", + "com.unity.modules.director": "1.0.0", + "com.unity.modules.imageconversion": "1.0.0", + "com.unity.modules.imgui": "1.0.0", + "com.unity.modules.jsonserialize": "1.0.0", + "com.unity.modules.particlesystem": "1.0.0", + "com.unity.modules.physics": "1.0.0", + "com.unity.modules.physics2d": "1.0.0", + "com.unity.modules.screencapture": "1.0.0", + "com.unity.modules.terrain": "1.0.0", + "com.unity.modules.terrainphysics": "1.0.0", + "com.unity.modules.tilemap": "1.0.0", + "com.unity.modules.ui": "1.0.0", + "com.unity.modules.uielements": "1.0.0", + "com.unity.modules.umbra": "1.0.0", + "com.unity.modules.unityanalytics": "1.0.0", + "com.unity.modules.unitywebrequest": "1.0.0", + "com.unity.modules.unitywebrequestassetbundle": "1.0.0", + "com.unity.modules.unitywebrequestaudio": "1.0.0", + "com.unity.modules.unitywebrequesttexture": "1.0.0", + "com.unity.modules.unitywebrequestwww": "1.0.0", + "com.unity.modules.vehicles": "1.0.0", + "com.unity.modules.video": "1.0.0", + "com.unity.modules.vr": "1.0.0", + "com.unity.modules.wind": "1.0.0", + "com.unity.modules.xr": "1.0.0" + }, + "scopedRegistries": [ + { + "name": "package.openupm.com", + "url": "https://package.openupm.com", + "scopes": [ + "com.fantasy.unity" + ] + } + ] +} diff --git a/邮件系统课程完整代码/Client/Unity/Packages/packages-lock.json b/邮件系统课程完整代码/Client/Unity/Packages/packages-lock.json new file mode 100644 index 0000000..02a5863 --- /dev/null +++ b/邮件系统课程完整代码/Client/Unity/Packages/packages-lock.json @@ -0,0 +1,492 @@ +{ + "dependencies": { + "com.fantasy.unity": { + "version": "2024.2.22", + "depth": 0, + "source": "registry", + "dependencies": { + "com.unity.nuget.newtonsoft-json": "3.2.1" + }, + "url": "https://package.openupm.com" + }, + "com.unity.2d.animation": { + "version": "7.0.8", + "depth": 1, + "source": "registry", + "dependencies": { + "com.unity.2d.common": "6.0.5", + "com.unity.2d.sprite": "1.0.0", + "com.unity.modules.animation": "1.0.0", + "com.unity.modules.uielements": "1.0.0" + }, + "url": "https://packages.unity.com" + }, + "com.unity.2d.common": { + "version": "6.0.5", + "depth": 2, + "source": "registry", + "dependencies": { + "com.unity.burst": "1.5.1", + "com.unity.2d.sprite": "1.0.0", + "com.unity.mathematics": "1.1.0", + "com.unity.modules.uielements": "1.0.0" + }, + "url": "https://packages.unity.com" + }, + "com.unity.2d.path": { + "version": "5.0.2", + "depth": 2, + "source": "registry", + "dependencies": {}, + "url": "https://packages.unity.com" + }, + "com.unity.2d.pixel-perfect": { + "version": "5.0.1", + "depth": 1, + "source": "registry", + "dependencies": {}, + "url": "https://packages.unity.com" + }, + "com.unity.2d.psdimporter": { + "version": "6.0.6", + "depth": 1, + "source": "registry", + "dependencies": { + "com.unity.2d.common": "6.0.5", + "com.unity.2d.sprite": "1.0.0", + "com.unity.2d.animation": "7.0.8" + }, + "url": "https://packages.unity.com" + }, + "com.unity.2d.sprite": { + "version": "1.0.0", + "depth": 1, + "source": "builtin", + "dependencies": {} + }, + "com.unity.2d.spriteshape": { + "version": "7.0.6", + "depth": 1, + "source": "registry", + "dependencies": { + "com.unity.2d.path": "5.0.2", + "com.unity.2d.common": "6.0.4", + "com.unity.mathematics": "1.1.0", + "com.unity.modules.physics2d": "1.0.0" + }, + "url": "https://packages.unity.com" + }, + "com.unity.2d.tilemap": { + "version": "1.0.0", + "depth": 1, + "source": "builtin", + "dependencies": {} + }, + "com.unity.2d.tilemap.extras": { + "version": "2.2.3", + "depth": 1, + "source": "registry", + "dependencies": { + "com.unity.ugui": "1.0.0", + "com.unity.2d.tilemap": "1.0.0", + "com.unity.modules.tilemap": "1.0.0", + "com.unity.modules.jsonserialize": "1.0.0" + }, + "url": "https://packages.unity.com" + }, + "com.unity.burst": { + "version": "1.6.6", + "depth": 3, + "source": "registry", + "dependencies": { + "com.unity.mathematics": "1.2.1" + }, + "url": "https://packages.unity.com" + }, + "com.unity.collab-proxy": { + "version": "1.17.6", + "depth": 0, + "source": "registry", + "dependencies": { + "com.unity.services.core": "1.0.1" + }, + "url": "https://packages.unity.com" + }, + "com.unity.ext.nunit": { + "version": "1.0.6", + "depth": 1, + "source": "registry", + "dependencies": {}, + "url": "https://packages.unity.com" + }, + "com.unity.feature.2d": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.2d.animation": "7.0.8", + "com.unity.2d.pixel-perfect": "5.0.1", + "com.unity.2d.psdimporter": "6.0.6", + "com.unity.2d.sprite": "1.0.0", + "com.unity.2d.spriteshape": "7.0.6", + "com.unity.2d.tilemap": "1.0.0", + "com.unity.2d.tilemap.extras": "2.2.3" + } + }, + "com.unity.ide.rider": { + "version": "3.0.16", + "depth": 0, + "source": "registry", + "dependencies": { + "com.unity.ext.nunit": "1.0.6" + }, + "url": "https://packages.unity.com" + }, + "com.unity.ide.visualstudio": { + "version": "2.0.16", + "depth": 0, + "source": "registry", + "dependencies": { + "com.unity.test-framework": "1.1.9" + }, + "url": "https://packages.unity.com" + }, + "com.unity.ide.vscode": { + "version": "1.2.5", + "depth": 0, + "source": "registry", + "dependencies": {}, + "url": "https://packages.unity.com" + }, + "com.unity.mathematics": { + "version": "1.2.6", + "depth": 2, + "source": "registry", + "dependencies": {}, + "url": "https://packages.unity.com" + }, + "com.unity.nuget.newtonsoft-json": { + "version": "3.2.1", + "depth": 1, + "source": "registry", + "dependencies": {}, + "url": "https://packages.unity.com" + }, + "com.unity.services.core": { + "version": "1.6.0", + "depth": 1, + "source": "registry", + "dependencies": { + "com.unity.modules.androidjni": "1.0.0", + "com.unity.nuget.newtonsoft-json": "3.0.2", + "com.unity.modules.unitywebrequest": "1.0.0" + }, + "url": "https://packages.unity.com" + }, + "com.unity.test-framework": { + "version": "1.1.31", + "depth": 0, + "source": "registry", + "dependencies": { + "com.unity.ext.nunit": "1.0.6", + "com.unity.modules.imgui": "1.0.0", + "com.unity.modules.jsonserialize": "1.0.0" + }, + "url": "https://packages.unity.com" + }, + "com.unity.textmeshpro": { + "version": "3.0.6", + "depth": 0, + "source": "registry", + "dependencies": { + "com.unity.ugui": "1.0.0" + }, + "url": "https://packages.unity.com" + }, + "com.unity.timeline": { + "version": "1.6.4", + "depth": 0, + "source": "registry", + "dependencies": { + "com.unity.modules.audio": "1.0.0", + "com.unity.modules.director": "1.0.0", + "com.unity.modules.animation": "1.0.0", + "com.unity.modules.particlesystem": "1.0.0" + }, + "url": "https://packages.unity.com" + }, + "com.unity.ugui": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.ui": "1.0.0", + "com.unity.modules.imgui": "1.0.0" + } + }, + "com.unity.visualscripting": { + "version": "1.7.8", + "depth": 0, + "source": "registry", + "dependencies": { + "com.unity.ugui": "1.0.0", + "com.unity.modules.jsonserialize": "1.0.0" + }, + "url": "https://packages.unity.com" + }, + "com.unity.modules.ai": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.androidjni": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.animation": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.assetbundle": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.audio": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.cloth": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.physics": "1.0.0" + } + }, + "com.unity.modules.director": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.audio": "1.0.0", + "com.unity.modules.animation": "1.0.0" + } + }, + "com.unity.modules.imageconversion": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.imgui": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.jsonserialize": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.particlesystem": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.physics": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.physics2d": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.screencapture": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.imageconversion": "1.0.0" + } + }, + "com.unity.modules.subsystems": { + "version": "1.0.0", + "depth": 1, + "source": "builtin", + "dependencies": { + "com.unity.modules.jsonserialize": "1.0.0" + } + }, + "com.unity.modules.terrain": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.terrainphysics": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.physics": "1.0.0", + "com.unity.modules.terrain": "1.0.0" + } + }, + "com.unity.modules.tilemap": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.physics2d": "1.0.0" + } + }, + "com.unity.modules.ui": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.uielements": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.ui": "1.0.0", + "com.unity.modules.imgui": "1.0.0", + "com.unity.modules.jsonserialize": "1.0.0", + "com.unity.modules.uielementsnative": "1.0.0" + } + }, + "com.unity.modules.uielementsnative": { + "version": "1.0.0", + "depth": 1, + "source": "builtin", + "dependencies": { + "com.unity.modules.ui": "1.0.0", + "com.unity.modules.imgui": "1.0.0", + "com.unity.modules.jsonserialize": "1.0.0" + } + }, + "com.unity.modules.umbra": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.unityanalytics": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.unitywebrequest": "1.0.0", + "com.unity.modules.jsonserialize": "1.0.0" + } + }, + "com.unity.modules.unitywebrequest": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.unitywebrequestassetbundle": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.assetbundle": "1.0.0", + "com.unity.modules.unitywebrequest": "1.0.0" + } + }, + "com.unity.modules.unitywebrequestaudio": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.unitywebrequest": "1.0.0", + "com.unity.modules.audio": "1.0.0" + } + }, + "com.unity.modules.unitywebrequesttexture": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.unitywebrequest": "1.0.0", + "com.unity.modules.imageconversion": "1.0.0" + } + }, + "com.unity.modules.unitywebrequestwww": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.unitywebrequest": "1.0.0", + "com.unity.modules.unitywebrequestassetbundle": "1.0.0", + "com.unity.modules.unitywebrequestaudio": "1.0.0", + "com.unity.modules.audio": "1.0.0", + "com.unity.modules.assetbundle": "1.0.0", + "com.unity.modules.imageconversion": "1.0.0" + } + }, + "com.unity.modules.vehicles": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.physics": "1.0.0" + } + }, + "com.unity.modules.video": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.audio": "1.0.0", + "com.unity.modules.ui": "1.0.0", + "com.unity.modules.unitywebrequest": "1.0.0" + } + }, + "com.unity.modules.vr": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.jsonserialize": "1.0.0", + "com.unity.modules.physics": "1.0.0", + "com.unity.modules.xr": "1.0.0" + } + }, + "com.unity.modules.wind": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.xr": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.physics": "1.0.0", + "com.unity.modules.jsonserialize": "1.0.0", + "com.unity.modules.subsystems": "1.0.0" + } + } + } +} diff --git a/邮件系统课程完整代码/Client/Unity/ProjectSettings/AudioManager.asset b/邮件系统课程完整代码/Client/Unity/ProjectSettings/AudioManager.asset new file mode 100644 index 0000000..27287fe --- /dev/null +++ b/邮件系统课程完整代码/Client/Unity/ProjectSettings/AudioManager.asset @@ -0,0 +1,19 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!11 &1 +AudioManager: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Volume: 1 + Rolloff Scale: 1 + Doppler Factor: 1 + Default Speaker Mode: 2 + m_SampleRate: 0 + m_DSPBufferSize: 1024 + m_VirtualVoiceCount: 512 + m_RealVoiceCount: 32 + m_SpatializerPlugin: + m_AmbisonicDecoderPlugin: + m_DisableAudio: 0 + m_VirtualizeEffects: 1 + m_RequestedDSPBufferSize: 0 diff --git a/邮件系统课程完整代码/Client/Unity/ProjectSettings/ClusterInputManager.asset b/邮件系统课程完整代码/Client/Unity/ProjectSettings/ClusterInputManager.asset new file mode 100644 index 0000000..e7886b2 --- /dev/null +++ b/邮件系统课程完整代码/Client/Unity/ProjectSettings/ClusterInputManager.asset @@ -0,0 +1,6 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!236 &1 +ClusterInputManager: + m_ObjectHideFlags: 0 + m_Inputs: [] diff --git a/邮件系统课程完整代码/Client/Unity/ProjectSettings/DynamicsManager.asset b/邮件系统课程完整代码/Client/Unity/ProjectSettings/DynamicsManager.asset new file mode 100644 index 0000000..72d1430 --- /dev/null +++ b/邮件系统课程完整代码/Client/Unity/ProjectSettings/DynamicsManager.asset @@ -0,0 +1,37 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!55 &1 +PhysicsManager: + m_ObjectHideFlags: 0 + serializedVersion: 13 + m_Gravity: {x: 0, y: -9.81, z: 0} + m_DefaultMaterial: {fileID: 0} + m_BounceThreshold: 2 + m_DefaultMaxDepenetrationVelocity: 10 + m_SleepThreshold: 0.005 + m_DefaultContactOffset: 0.01 + m_DefaultSolverIterations: 6 + m_DefaultSolverVelocityIterations: 1 + m_QueriesHitBackfaces: 0 + m_QueriesHitTriggers: 1 + m_EnableAdaptiveForce: 0 + m_ClothInterCollisionDistance: 0.1 + m_ClothInterCollisionStiffness: 0.2 + m_ContactsGeneration: 1 + m_LayerCollisionMatrix: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff + m_AutoSimulation: 1 + m_AutoSyncTransforms: 0 + m_ReuseCollisionCallbacks: 1 + m_ClothInterCollisionSettingsToggle: 0 + m_ClothGravity: {x: 0, y: -9.81, z: 0} + m_ContactPairsMode: 0 + m_BroadphaseType: 0 + m_WorldBounds: + m_Center: {x: 0, y: 0, z: 0} + m_Extent: {x: 250, y: 250, z: 250} + m_WorldSubdivisions: 8 + m_FrictionType: 0 + m_EnableEnhancedDeterminism: 0 + m_EnableUnifiedHeightmaps: 1 + m_SolverType: 0 + m_DefaultMaxAngularSpeed: 50 diff --git a/邮件系统课程完整代码/Client/Unity/ProjectSettings/EditorBuildSettings.asset b/邮件系统课程完整代码/Client/Unity/ProjectSettings/EditorBuildSettings.asset new file mode 100644 index 0000000..9bd6d10 --- /dev/null +++ b/邮件系统课程完整代码/Client/Unity/ProjectSettings/EditorBuildSettings.asset @@ -0,0 +1,11 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1045 &1 +EditorBuildSettings: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Scenes: + - enabled: 0 + path: + guid: 00000000000000000000000000000000 + m_configObjects: {} diff --git a/邮件系统课程完整代码/Client/Unity/ProjectSettings/EditorSettings.asset b/邮件系统课程完整代码/Client/Unity/ProjectSettings/EditorSettings.asset new file mode 100644 index 0000000..fa3ed49 --- /dev/null +++ b/邮件系统课程完整代码/Client/Unity/ProjectSettings/EditorSettings.asset @@ -0,0 +1,40 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!159 &1 +EditorSettings: + m_ObjectHideFlags: 0 + serializedVersion: 11 + m_SerializationMode: 2 + m_LineEndingsForNewScripts: 0 + m_DefaultBehaviorMode: 1 + m_PrefabRegularEnvironment: {fileID: 0} + m_PrefabUIEnvironment: {fileID: 0} + m_SpritePackerMode: 4 + m_SpritePackerPaddingPower: 1 + m_EtcTextureCompressorBehavior: 1 + m_EtcTextureFastCompressor: 1 + m_EtcTextureNormalCompressor: 2 + m_EtcTextureBestCompressor: 4 + m_ProjectGenerationIncludedExtensions: txt;xml;fnt;cd;asmdef;asmref;rsp + m_ProjectGenerationRootNamespace: + m_EnableTextureStreamingInEditMode: 1 + m_EnableTextureStreamingInPlayMode: 1 + m_AsyncShaderCompilation: 1 + m_CachingShaderPreprocessor: 1 + m_PrefabModeAllowAutoSave: 1 + m_EnterPlayModeOptionsEnabled: 0 + m_EnterPlayModeOptions: 3 + m_GameObjectNamingDigits: 1 + m_GameObjectNamingScheme: 0 + m_AssetNamingUsesSpace: 1 + m_UseLegacyProbeSampleCount: 0 + m_SerializeInlineMappingsOnOneLine: 1 + m_DisableCookiesInLightmapper: 1 + m_AssetPipelineMode: 1 + m_CacheServerMode: 0 + m_CacheServerEndpoint: + m_CacheServerNamespacePrefix: default + m_CacheServerEnableDownload: 1 + m_CacheServerEnableUpload: 1 + m_CacheServerEnableAuth: 0 + m_CacheServerEnableTls: 0 diff --git a/邮件系统课程完整代码/Client/Unity/ProjectSettings/GraphicsSettings.asset b/邮件系统课程完整代码/Client/Unity/ProjectSettings/GraphicsSettings.asset new file mode 100644 index 0000000..c165afb --- /dev/null +++ b/邮件系统课程完整代码/Client/Unity/ProjectSettings/GraphicsSettings.asset @@ -0,0 +1,64 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!30 &1 +GraphicsSettings: + m_ObjectHideFlags: 0 + serializedVersion: 13 + m_Deferred: + m_Mode: 1 + m_Shader: {fileID: 69, guid: 0000000000000000f000000000000000, type: 0} + m_DeferredReflections: + m_Mode: 1 + m_Shader: {fileID: 74, guid: 0000000000000000f000000000000000, type: 0} + m_ScreenSpaceShadows: + m_Mode: 1 + m_Shader: {fileID: 64, guid: 0000000000000000f000000000000000, type: 0} + m_LegacyDeferred: + m_Mode: 1 + m_Shader: {fileID: 63, guid: 0000000000000000f000000000000000, type: 0} + m_DepthNormals: + m_Mode: 1 + m_Shader: {fileID: 62, guid: 0000000000000000f000000000000000, type: 0} + m_MotionVectors: + m_Mode: 1 + m_Shader: {fileID: 75, guid: 0000000000000000f000000000000000, type: 0} + m_LightHalo: + m_Mode: 1 + m_Shader: {fileID: 105, guid: 0000000000000000f000000000000000, type: 0} + m_LensFlare: + m_Mode: 1 + m_Shader: {fileID: 102, guid: 0000000000000000f000000000000000, type: 0} + m_VideoShadersIncludeMode: 2 + m_AlwaysIncludedShaders: + - {fileID: 7, guid: 0000000000000000f000000000000000, type: 0} + - {fileID: 15104, guid: 0000000000000000f000000000000000, type: 0} + - {fileID: 15105, guid: 0000000000000000f000000000000000, type: 0} + - {fileID: 15106, guid: 0000000000000000f000000000000000, type: 0} + - {fileID: 10753, guid: 0000000000000000f000000000000000, type: 0} + - {fileID: 10770, guid: 0000000000000000f000000000000000, type: 0} + - {fileID: 10783, guid: 0000000000000000f000000000000000, type: 0} + m_PreloadedShaders: [] + m_SpritesDefaultMaterial: {fileID: 10754, guid: 0000000000000000f000000000000000, type: 0} + m_CustomRenderPipeline: {fileID: 0} + m_TransparencySortMode: 0 + m_TransparencySortAxis: {x: 0, y: 0, z: 1} + m_DefaultRenderingPath: 1 + m_DefaultMobileRenderingPath: 1 + m_TierSettings: [] + m_LightmapStripping: 0 + m_FogStripping: 0 + m_InstancingStripping: 0 + m_LightmapKeepPlain: 1 + m_LightmapKeepDirCombined: 1 + m_LightmapKeepDynamicPlain: 1 + m_LightmapKeepDynamicDirCombined: 1 + m_LightmapKeepShadowMask: 1 + m_LightmapKeepSubtractive: 1 + m_FogKeepLinear: 1 + m_FogKeepExp: 1 + m_FogKeepExp2: 1 + m_AlbedoSwatchInfos: [] + m_LightsUseLinearIntensity: 0 + m_LightsUseColorTemperature: 0 + m_DefaultRenderingLayerMask: 1 + m_LogWhenShaderIsCompiled: 0 diff --git a/邮件系统课程完整代码/Client/Unity/ProjectSettings/InputManager.asset b/邮件系统课程完整代码/Client/Unity/ProjectSettings/InputManager.asset new file mode 100644 index 0000000..b16147e --- /dev/null +++ b/邮件系统课程完整代码/Client/Unity/ProjectSettings/InputManager.asset @@ -0,0 +1,487 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!13 &1 +InputManager: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Axes: + - serializedVersion: 3 + m_Name: Horizontal + descriptiveName: + descriptiveNegativeName: + negativeButton: left + positiveButton: right + altNegativeButton: a + altPositiveButton: d + gravity: 3 + dead: 0.001 + sensitivity: 3 + snap: 1 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Vertical + descriptiveName: + descriptiveNegativeName: + negativeButton: down + positiveButton: up + altNegativeButton: s + altPositiveButton: w + gravity: 3 + dead: 0.001 + sensitivity: 3 + snap: 1 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Fire1 + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: left ctrl + altNegativeButton: + altPositiveButton: mouse 0 + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Fire2 + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: left alt + altNegativeButton: + altPositiveButton: mouse 1 + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Fire3 + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: left shift + altNegativeButton: + altPositiveButton: mouse 2 + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Jump + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: space + altNegativeButton: + altPositiveButton: + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Mouse X + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: + altNegativeButton: + altPositiveButton: + gravity: 0 + dead: 0 + sensitivity: 0.1 + snap: 0 + invert: 0 + type: 1 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Mouse Y + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: + altNegativeButton: + altPositiveButton: + gravity: 0 + dead: 0 + sensitivity: 0.1 + snap: 0 + invert: 0 + type: 1 + axis: 1 + joyNum: 0 + - serializedVersion: 3 + m_Name: Mouse ScrollWheel + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: + altNegativeButton: + altPositiveButton: + gravity: 0 + dead: 0 + sensitivity: 0.1 + snap: 0 + invert: 0 + type: 1 + axis: 2 + joyNum: 0 + - serializedVersion: 3 + m_Name: Horizontal + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: + altNegativeButton: + altPositiveButton: + gravity: 0 + dead: 0.19 + sensitivity: 1 + snap: 0 + invert: 0 + type: 2 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Vertical + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: + altNegativeButton: + altPositiveButton: + gravity: 0 + dead: 0.19 + sensitivity: 1 + snap: 0 + invert: 1 + type: 2 + axis: 1 + joyNum: 0 + - serializedVersion: 3 + m_Name: Fire1 + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: joystick button 0 + altNegativeButton: + altPositiveButton: + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Fire2 + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: joystick button 1 + altNegativeButton: + altPositiveButton: + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Fire3 + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: joystick button 2 + altNegativeButton: + altPositiveButton: + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Jump + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: joystick button 3 + altNegativeButton: + altPositiveButton: + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Submit + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: return + altNegativeButton: + altPositiveButton: joystick button 0 + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Submit + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: enter + altNegativeButton: + altPositiveButton: space + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Cancel + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: escape + altNegativeButton: + altPositiveButton: joystick button 1 + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Enable Debug Button 1 + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: left ctrl + altNegativeButton: + altPositiveButton: joystick button 8 + gravity: 0 + dead: 0 + sensitivity: 0 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Enable Debug Button 2 + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: backspace + altNegativeButton: + altPositiveButton: joystick button 9 + gravity: 0 + dead: 0 + sensitivity: 0 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Debug Reset + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: left alt + altNegativeButton: + altPositiveButton: joystick button 1 + gravity: 0 + dead: 0 + sensitivity: 0 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Debug Next + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: page down + altNegativeButton: + altPositiveButton: joystick button 5 + gravity: 0 + dead: 0 + sensitivity: 0 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Debug Previous + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: page up + altNegativeButton: + altPositiveButton: joystick button 4 + gravity: 0 + dead: 0 + sensitivity: 0 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Debug Validate + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: return + altNegativeButton: + altPositiveButton: joystick button 0 + gravity: 0 + dead: 0 + sensitivity: 0 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Debug Persistent + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: right shift + altNegativeButton: + altPositiveButton: joystick button 2 + gravity: 0 + dead: 0 + sensitivity: 0 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Debug Multiplier + descriptiveName: + descriptiveNegativeName: + negativeButton: + positiveButton: left shift + altNegativeButton: + altPositiveButton: joystick button 3 + gravity: 0 + dead: 0 + sensitivity: 0 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Debug Horizontal + descriptiveName: + descriptiveNegativeName: + negativeButton: left + positiveButton: right + altNegativeButton: + altPositiveButton: + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Debug Vertical + descriptiveName: + descriptiveNegativeName: + negativeButton: down + positiveButton: up + altNegativeButton: + altPositiveButton: + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 0 + axis: 0 + joyNum: 0 + - serializedVersion: 3 + m_Name: Debug Vertical + descriptiveName: + descriptiveNegativeName: + negativeButton: down + positiveButton: up + altNegativeButton: + altPositiveButton: + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 2 + axis: 6 + joyNum: 0 + - serializedVersion: 3 + m_Name: Debug Horizontal + descriptiveName: + descriptiveNegativeName: + negativeButton: left + positiveButton: right + altNegativeButton: + altPositiveButton: + gravity: 1000 + dead: 0.001 + sensitivity: 1000 + snap: 0 + invert: 0 + type: 2 + axis: 5 + joyNum: 0 diff --git a/邮件系统课程完整代码/Client/Unity/ProjectSettings/MemorySettings.asset b/邮件系统课程完整代码/Client/Unity/ProjectSettings/MemorySettings.asset new file mode 100644 index 0000000..5b5face --- /dev/null +++ b/邮件系统课程完整代码/Client/Unity/ProjectSettings/MemorySettings.asset @@ -0,0 +1,35 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!387306366 &1 +MemorySettings: + m_ObjectHideFlags: 0 + m_EditorMemorySettings: + m_MainAllocatorBlockSize: -1 + m_ThreadAllocatorBlockSize: -1 + m_MainGfxBlockSize: -1 + m_ThreadGfxBlockSize: -1 + m_CacheBlockSize: -1 + m_TypetreeBlockSize: -1 + m_ProfilerBlockSize: -1 + m_ProfilerEditorBlockSize: -1 + m_BucketAllocatorGranularity: -1 + m_BucketAllocatorBucketsCount: -1 + m_BucketAllocatorBlockSize: -1 + m_BucketAllocatorBlockCount: -1 + m_ProfilerBucketAllocatorGranularity: -1 + m_ProfilerBucketAllocatorBucketsCount: -1 + m_ProfilerBucketAllocatorBlockSize: -1 + m_ProfilerBucketAllocatorBlockCount: -1 + m_TempAllocatorSizeMain: -1 + m_JobTempAllocatorBlockSize: -1 + m_BackgroundJobTempAllocatorBlockSize: -1 + m_JobTempAllocatorReducedBlockSize: -1 + m_TempAllocatorSizeGIBakingWorker: -1 + m_TempAllocatorSizeNavMeshWorker: -1 + m_TempAllocatorSizeAudioWorker: -1 + m_TempAllocatorSizeCloudWorker: -1 + m_TempAllocatorSizeGfx: -1 + m_TempAllocatorSizeJobWorker: -1 + m_TempAllocatorSizeBackgroundWorker: -1 + m_TempAllocatorSizePreloadManager: -1 + m_PlatformMemorySettings: {} diff --git a/邮件系统课程完整代码/Client/Unity/ProjectSettings/NavMeshAreas.asset b/邮件系统课程完整代码/Client/Unity/ProjectSettings/NavMeshAreas.asset new file mode 100644 index 0000000..ad2654e --- /dev/null +++ b/邮件系统课程完整代码/Client/Unity/ProjectSettings/NavMeshAreas.asset @@ -0,0 +1,93 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!126 &1 +NavMeshProjectSettings: + m_ObjectHideFlags: 0 + serializedVersion: 2 + areas: + - name: Walkable + cost: 1 + - name: Not Walkable + cost: 1 + - name: Jump + cost: 2 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + - name: + cost: 1 + m_LastAgentTypeID: -887442657 + m_Settings: + - serializedVersion: 2 + agentTypeID: 0 + agentRadius: 0.5 + agentHeight: 2 + agentSlope: 45 + agentClimb: 0.75 + ledgeDropHeight: 0 + maxJumpAcrossDistance: 0 + minRegionArea: 2 + manualCellSize: 0 + cellSize: 0.16666667 + manualTileSize: 0 + tileSize: 256 + accuratePlacement: 0 + maxJobWorkers: 0 + preserveTilesOutsideBounds: 0 + debug: + m_Flags: 0 + m_SettingNames: + - Humanoid diff --git a/邮件系统课程完整代码/Client/Unity/ProjectSettings/NetworkManager.asset b/邮件系统课程完整代码/Client/Unity/ProjectSettings/NetworkManager.asset new file mode 100644 index 0000000..5dc6a83 --- /dev/null +++ b/邮件系统课程完整代码/Client/Unity/ProjectSettings/NetworkManager.asset @@ -0,0 +1,8 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!149 &1 +NetworkManager: + m_ObjectHideFlags: 0 + m_DebugLevel: 0 + m_Sendrate: 15 + m_AssetToPrefab: {} diff --git a/邮件系统课程完整代码/Client/Unity/ProjectSettings/PackageManagerSettings.asset b/邮件系统课程完整代码/Client/Unity/ProjectSettings/PackageManagerSettings.asset new file mode 100644 index 0000000..513fb79 --- /dev/null +++ b/邮件系统课程完整代码/Client/Unity/ProjectSettings/PackageManagerSettings.asset @@ -0,0 +1,44 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &1 +MonoBehaviour: + m_ObjectHideFlags: 61 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 13964, guid: 0000000000000000e000000000000000, type: 0} + m_Name: + m_EditorClassIdentifier: + m_EnablePreReleasePackages: 0 + m_EnablePackageDependencies: 0 + m_AdvancedSettingsExpanded: 1 + m_ScopedRegistriesSettingsExpanded: 1 + m_SeeAllPackageVersions: 0 + oneTimeWarningShown: 0 + m_Registries: + - m_Id: main + m_Name: + m_Url: https://packages.unity.com + m_Scopes: [] + m_IsDefault: 1 + m_Capabilities: 7 + m_ConfigSource: 0 + - m_Id: scoped:project:package.openupm.com + m_Name: package.openupm.com + m_Url: https://package.openupm.com + m_Scopes: + - com.fantasy.unity + m_IsDefault: 0 + m_Capabilities: 0 + m_ConfigSource: 4 + m_UserSelectedRegistryName: package.openupm.com + m_UserAddingNewScopedRegistry: 0 + m_RegistryInfoDraft: + m_Modified: 0 + m_ErrorMessage: + m_UserModificationsInstanceId: -828 + m_OriginalInstanceId: -830 + m_LoadAssets: 0 diff --git a/邮件系统课程完整代码/Client/Unity/ProjectSettings/Physics2DSettings.asset b/邮件系统课程完整代码/Client/Unity/ProjectSettings/Physics2DSettings.asset new file mode 100644 index 0000000..6cfcdda --- /dev/null +++ b/邮件系统课程完整代码/Client/Unity/ProjectSettings/Physics2DSettings.asset @@ -0,0 +1,56 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!19 &1 +Physics2DSettings: + m_ObjectHideFlags: 0 + serializedVersion: 5 + m_Gravity: {x: 0, y: -9.81} + m_DefaultMaterial: {fileID: 0} + m_VelocityIterations: 8 + m_PositionIterations: 3 + m_VelocityThreshold: 1 + m_MaxLinearCorrection: 0.2 + m_MaxAngularCorrection: 8 + m_MaxTranslationSpeed: 100 + m_MaxRotationSpeed: 360 + m_BaumgarteScale: 0.2 + m_BaumgarteTimeOfImpactScale: 0.75 + m_TimeToSleep: 0.5 + m_LinearSleepTolerance: 0.01 + m_AngularSleepTolerance: 2 + m_DefaultContactOffset: 0.01 + m_JobOptions: + serializedVersion: 2 + useMultithreading: 0 + useConsistencySorting: 0 + m_InterpolationPosesPerJob: 100 + m_NewContactsPerJob: 30 + m_CollideContactsPerJob: 100 + m_ClearFlagsPerJob: 200 + m_ClearBodyForcesPerJob: 200 + m_SyncDiscreteFixturesPerJob: 50 + m_SyncContinuousFixturesPerJob: 50 + m_FindNearestContactsPerJob: 100 + m_UpdateTriggerContactsPerJob: 100 + m_IslandSolverCostThreshold: 100 + m_IslandSolverBodyCostScale: 1 + m_IslandSolverContactCostScale: 10 + m_IslandSolverJointCostScale: 10 + m_IslandSolverBodiesPerJob: 50 + m_IslandSolverContactsPerJob: 50 + m_SimulationMode: 0 + m_QueriesHitTriggers: 1 + m_QueriesStartInColliders: 1 + m_CallbacksOnDisable: 1 + m_ReuseCollisionCallbacks: 1 + m_AutoSyncTransforms: 0 + m_AlwaysShowColliders: 0 + m_ShowColliderSleep: 1 + m_ShowColliderContacts: 0 + m_ShowColliderAABB: 0 + m_ContactArrowScale: 0.2 + m_ColliderAwakeColor: {r: 0.5686275, g: 0.95686275, b: 0.54509807, a: 0.7529412} + m_ColliderAsleepColor: {r: 0.5686275, g: 0.95686275, b: 0.54509807, a: 0.36078432} + m_ColliderContactColor: {r: 1, g: 0, b: 1, a: 0.6862745} + m_ColliderAABBColor: {r: 1, g: 1, b: 0, a: 0.2509804} + m_LayerCollisionMatrix: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff diff --git a/邮件系统课程完整代码/Client/Unity/ProjectSettings/PresetManager.asset b/邮件系统课程完整代码/Client/Unity/ProjectSettings/PresetManager.asset new file mode 100644 index 0000000..67a94da --- /dev/null +++ b/邮件系统课程完整代码/Client/Unity/ProjectSettings/PresetManager.asset @@ -0,0 +1,7 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1386491679 &1 +PresetManager: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_DefaultPresets: {} diff --git a/邮件系统课程完整代码/Client/Unity/ProjectSettings/ProjectSettings.asset b/邮件系统课程完整代码/Client/Unity/ProjectSettings/ProjectSettings.asset new file mode 100644 index 0000000..504c0d6 --- /dev/null +++ b/邮件系统课程完整代码/Client/Unity/ProjectSettings/ProjectSettings.asset @@ -0,0 +1,865 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!129 &1 +PlayerSettings: + m_ObjectHideFlags: 0 + serializedVersion: 23 + productGUID: d144098b071e24e7bb2d8336d1631979 + AndroidProfiler: 0 + AndroidFilterTouchesWhenObscured: 0 + AndroidEnableSustainedPerformanceMode: 0 + defaultScreenOrientation: 4 + targetDevice: 2 + useOnDemandResources: 0 + accelerometerFrequency: 60 + companyName: DefaultCompany + productName: Unity + defaultCursor: {fileID: 0} + cursorHotspot: {x: 0, y: 0} + m_SplashScreenBackgroundColor: {r: 0.13725491, g: 0.12156863, b: 0.1254902, a: 1} + m_ShowUnitySplashScreen: 1 + m_ShowUnitySplashLogo: 1 + m_SplashScreenOverlayOpacity: 1 + m_SplashScreenAnimation: 1 + m_SplashScreenLogoStyle: 1 + m_SplashScreenDrawMode: 0 + m_SplashScreenBackgroundAnimationZoom: 1 + m_SplashScreenLogoAnimationZoom: 1 + m_SplashScreenBackgroundLandscapeAspect: 1 + m_SplashScreenBackgroundPortraitAspect: 1 + m_SplashScreenBackgroundLandscapeUvs: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 + m_SplashScreenBackgroundPortraitUvs: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 + m_SplashScreenLogos: [] + m_VirtualRealitySplashScreen: {fileID: 0} + m_HolographicTrackingLossScreen: {fileID: 0} + defaultScreenWidth: 1920 + defaultScreenHeight: 1080 + defaultScreenWidthWeb: 960 + defaultScreenHeightWeb: 600 + m_StereoRenderingPath: 0 + m_ActiveColorSpace: 0 + m_MTRendering: 1 + mipStripping: 0 + numberOfMipsStripped: 0 + m_StackTraceTypes: 010000000100000001000000010000000100000001000000 + iosShowActivityIndicatorOnLoading: -1 + androidShowActivityIndicatorOnLoading: -1 + iosUseCustomAppBackgroundBehavior: 0 + iosAllowHTTPDownload: 1 + allowedAutorotateToPortrait: 1 + allowedAutorotateToPortraitUpsideDown: 1 + allowedAutorotateToLandscapeRight: 1 + allowedAutorotateToLandscapeLeft: 1 + useOSAutorotation: 1 + use32BitDisplayBuffer: 1 + preserveFramebufferAlpha: 0 + disableDepthAndStencilBuffers: 0 + androidStartInFullscreen: 1 + androidRenderOutsideSafeArea: 1 + androidUseSwappy: 1 + androidBlitType: 0 + androidResizableWindow: 0 + androidDefaultWindowWidth: 1920 + androidDefaultWindowHeight: 1080 + androidMinimumWindowWidth: 400 + androidMinimumWindowHeight: 300 + androidFullscreenMode: 1 + defaultIsNativeResolution: 1 + macRetinaSupport: 1 + runInBackground: 1 + captureSingleScreen: 0 + muteOtherAudioSources: 0 + Prepare IOS For Recording: 0 + Force IOS Speakers When Recording: 0 + deferSystemGesturesMode: 0 + hideHomeButton: 0 + submitAnalytics: 1 + usePlayerLog: 1 + bakeCollisionMeshes: 0 + forceSingleInstance: 0 + useFlipModelSwapchain: 1 + resizableWindow: 0 + useMacAppStoreValidation: 0 + macAppStoreCategory: public.app-category.games + gpuSkinning: 0 + xboxPIXTextureCapture: 0 + xboxEnableAvatar: 0 + xboxEnableKinect: 0 + xboxEnableKinectAutoTracking: 0 + xboxEnableFitness: 0 + visibleInBackground: 1 + allowFullscreenSwitch: 1 + fullscreenMode: 1 + xboxSpeechDB: 0 + xboxEnableHeadOrientation: 0 + xboxEnableGuest: 0 + xboxEnablePIXSampling: 0 + metalFramebufferOnly: 0 + xboxOneResolution: 0 + xboxOneSResolution: 0 + xboxOneXResolution: 3 + xboxOneMonoLoggingLevel: 0 + xboxOneLoggingLevel: 1 + xboxOneDisableEsram: 0 + xboxOneEnableTypeOptimization: 0 + xboxOnePresentImmediateThreshold: 0 + switchQueueCommandMemory: 1048576 + switchQueueControlMemory: 16384 + switchQueueComputeMemory: 262144 + switchNVNShaderPoolsGranularity: 33554432 + switchNVNDefaultPoolsGranularity: 16777216 + switchNVNOtherPoolsGranularity: 16777216 + switchNVNMaxPublicTextureIDCount: 0 + switchNVNMaxPublicSamplerIDCount: 0 + stadiaPresentMode: 0 + stadiaTargetFramerate: 0 + vulkanNumSwapchainBuffers: 3 + vulkanEnableSetSRGBWrite: 0 + vulkanEnablePreTransform: 0 + vulkanEnableLateAcquireNextImage: 0 + vulkanEnableCommandBufferRecycling: 1 + m_SupportedAspectRatios: + 4:3: 1 + 5:4: 1 + 16:10: 1 + 16:9: 1 + Others: 1 + bundleVersion: 1.0 + preloadedAssets: [] + metroInputSource: 0 + wsaTransparentSwapchain: 0 + m_HolographicPauseOnTrackingLoss: 1 + xboxOneDisableKinectGpuReservation: 1 + xboxOneEnable7thCore: 1 + vrSettings: + enable360StereoCapture: 0 + isWsaHolographicRemotingEnabled: 0 + enableFrameTimingStats: 0 + enableOpenGLProfilerGPURecorders: 1 + useHDRDisplay: 0 + D3DHDRBitDepth: 0 + m_ColorGamuts: 00000000 + targetPixelDensity: 30 + resolutionScalingMode: 0 + resetResolutionOnWindowResize: 0 + androidSupportedAspectRatio: 1 + androidMaxAspectRatio: 2.1 + applicationIdentifier: + Standalone: com.DefaultCompany.2DProject + buildNumber: + Standalone: 0 + iPhone: 0 + tvOS: 0 + overrideDefaultApplicationIdentifier: 1 + AndroidBundleVersionCode: 1 + AndroidMinSdkVersion: 22 + AndroidTargetSdkVersion: 0 + AndroidPreferredInstallLocation: 1 + aotOptions: + stripEngineCode: 1 + iPhoneStrippingLevel: 0 + iPhoneScriptCallOptimization: 0 + ForceInternetPermission: 0 + ForceSDCardPermission: 0 + CreateWallpaper: 0 + APKExpansionFiles: 0 + keepLoadedShadersAlive: 0 + StripUnusedMeshComponents: 0 + VertexChannelCompressionMask: 4054 + iPhoneSdkVersion: 988 + iOSTargetOSVersionString: 11.0 + tvOSSdkVersion: 0 + tvOSRequireExtendedGameController: 0 + tvOSTargetOSVersionString: 11.0 + uIPrerenderedIcon: 0 + uIRequiresPersistentWiFi: 0 + uIRequiresFullScreen: 1 + uIStatusBarHidden: 1 + uIExitOnSuspend: 0 + uIStatusBarStyle: 0 + appleTVSplashScreen: {fileID: 0} + appleTVSplashScreen2x: {fileID: 0} + tvOSSmallIconLayers: [] + tvOSSmallIconLayers2x: [] + tvOSLargeIconLayers: [] + tvOSLargeIconLayers2x: [] + tvOSTopShelfImageLayers: [] + tvOSTopShelfImageLayers2x: [] + tvOSTopShelfImageWideLayers: [] + tvOSTopShelfImageWideLayers2x: [] + iOSLaunchScreenType: 0 + iOSLaunchScreenPortrait: {fileID: 0} + iOSLaunchScreenLandscape: {fileID: 0} + iOSLaunchScreenBackgroundColor: + serializedVersion: 2 + rgba: 0 + iOSLaunchScreenFillPct: 100 + iOSLaunchScreenSize: 100 + iOSLaunchScreenCustomXibPath: + iOSLaunchScreeniPadType: 0 + iOSLaunchScreeniPadImage: {fileID: 0} + iOSLaunchScreeniPadBackgroundColor: + serializedVersion: 2 + rgba: 0 + iOSLaunchScreeniPadFillPct: 100 + iOSLaunchScreeniPadSize: 100 + iOSLaunchScreeniPadCustomXibPath: + iOSLaunchScreenCustomStoryboardPath: + iOSLaunchScreeniPadCustomStoryboardPath: + iOSDeviceRequirements: [] + iOSURLSchemes: [] + macOSURLSchemes: [] + iOSBackgroundModes: 0 + iOSMetalForceHardShadows: 0 + metalEditorSupport: 1 + metalAPIValidation: 1 + iOSRenderExtraFrameOnPause: 0 + iosCopyPluginsCodeInsteadOfSymlink: 0 + appleDeveloperTeamID: + iOSManualSigningProvisioningProfileID: + tvOSManualSigningProvisioningProfileID: + iOSManualSigningProvisioningProfileType: 0 + tvOSManualSigningProvisioningProfileType: 0 + appleEnableAutomaticSigning: 0 + iOSRequireARKit: 0 + iOSAutomaticallyDetectAndAddCapabilities: 1 + appleEnableProMotion: 0 + shaderPrecisionModel: 0 + clonedFromGUID: 10ad67313f4034357812315f3c407484 + templatePackageId: com.unity.template.2d@6.1.1 + templateDefaultScene: Assets/Scenes/SampleScene.unity + useCustomMainManifest: 0 + useCustomLauncherManifest: 0 + useCustomMainGradleTemplate: 0 + useCustomLauncherGradleManifest: 0 + useCustomBaseGradleTemplate: 0 + useCustomGradlePropertiesTemplate: 0 + useCustomProguardFile: 0 + AndroidTargetArchitectures: 1 + AndroidTargetDevices: 0 + AndroidSplashScreenScale: 0 + androidSplashScreen: {fileID: 0} + AndroidKeystoreName: + AndroidKeyaliasName: + AndroidBuildApkPerCpuArchitecture: 0 + AndroidTVCompatibility: 0 + AndroidIsGame: 1 + AndroidEnableTango: 0 + androidEnableBanner: 1 + androidUseLowAccuracyLocation: 0 + androidUseCustomKeystore: 0 + m_AndroidBanners: + - width: 320 + height: 180 + banner: {fileID: 0} + androidGamepadSupportLevel: 0 + chromeosInputEmulation: 1 + AndroidMinifyWithR8: 0 + AndroidMinifyRelease: 0 + AndroidMinifyDebug: 0 + AndroidValidateAppBundleSize: 1 + AndroidAppBundleSizeToValidate: 150 + m_BuildTargetIcons: [] + m_BuildTargetPlatformIcons: + - m_BuildTarget: iPhone + m_Icons: + - m_Textures: [] + m_Width: 180 + m_Height: 180 + m_Kind: 0 + m_SubKind: iPhone + - m_Textures: [] + m_Width: 120 + m_Height: 120 + m_Kind: 0 + m_SubKind: iPhone + - m_Textures: [] + m_Width: 167 + m_Height: 167 + m_Kind: 0 + m_SubKind: iPad + - m_Textures: [] + m_Width: 152 + m_Height: 152 + m_Kind: 0 + m_SubKind: iPad + - m_Textures: [] + m_Width: 76 + m_Height: 76 + m_Kind: 0 + m_SubKind: iPad + - m_Textures: [] + m_Width: 120 + m_Height: 120 + m_Kind: 3 + m_SubKind: iPhone + - m_Textures: [] + m_Width: 80 + m_Height: 80 + m_Kind: 3 + m_SubKind: iPhone + - m_Textures: [] + m_Width: 80 + m_Height: 80 + m_Kind: 3 + m_SubKind: iPad + - m_Textures: [] + m_Width: 40 + m_Height: 40 + m_Kind: 3 + m_SubKind: iPad + - m_Textures: [] + m_Width: 87 + m_Height: 87 + m_Kind: 1 + m_SubKind: iPhone + - m_Textures: [] + m_Width: 58 + m_Height: 58 + m_Kind: 1 + m_SubKind: iPhone + - m_Textures: [] + m_Width: 29 + m_Height: 29 + m_Kind: 1 + m_SubKind: iPhone + - m_Textures: [] + m_Width: 58 + m_Height: 58 + m_Kind: 1 + m_SubKind: iPad + - m_Textures: [] + m_Width: 29 + m_Height: 29 + m_Kind: 1 + m_SubKind: iPad + - m_Textures: [] + m_Width: 60 + m_Height: 60 + m_Kind: 2 + m_SubKind: iPhone + - m_Textures: [] + m_Width: 40 + m_Height: 40 + m_Kind: 2 + m_SubKind: iPhone + - m_Textures: [] + m_Width: 40 + m_Height: 40 + m_Kind: 2 + m_SubKind: iPad + - m_Textures: [] + m_Width: 20 + m_Height: 20 + m_Kind: 2 + m_SubKind: iPad + - m_Textures: [] + m_Width: 1024 + m_Height: 1024 + m_Kind: 4 + m_SubKind: App Store + - m_BuildTarget: Android + m_Icons: + - m_Textures: [] + m_Width: 432 + m_Height: 432 + m_Kind: 2 + m_SubKind: + - m_Textures: [] + m_Width: 324 + m_Height: 324 + m_Kind: 2 + m_SubKind: + - m_Textures: [] + m_Width: 216 + m_Height: 216 + m_Kind: 2 + m_SubKind: + - m_Textures: [] + m_Width: 162 + m_Height: 162 + m_Kind: 2 + m_SubKind: + - m_Textures: [] + m_Width: 108 + m_Height: 108 + m_Kind: 2 + m_SubKind: + - m_Textures: [] + m_Width: 81 + m_Height: 81 + m_Kind: 2 + m_SubKind: + - m_Textures: [] + m_Width: 192 + m_Height: 192 + m_Kind: 1 + m_SubKind: + - m_Textures: [] + m_Width: 144 + m_Height: 144 + m_Kind: 1 + m_SubKind: + - m_Textures: [] + m_Width: 96 + m_Height: 96 + m_Kind: 1 + m_SubKind: + - m_Textures: [] + m_Width: 72 + m_Height: 72 + m_Kind: 1 + m_SubKind: + - m_Textures: [] + m_Width: 48 + m_Height: 48 + m_Kind: 1 + m_SubKind: + - m_Textures: [] + m_Width: 36 + m_Height: 36 + m_Kind: 1 + m_SubKind: + - m_Textures: [] + m_Width: 192 + m_Height: 192 + m_Kind: 0 + m_SubKind: + - m_Textures: [] + m_Width: 144 + m_Height: 144 + m_Kind: 0 + m_SubKind: + - m_Textures: [] + m_Width: 96 + m_Height: 96 + m_Kind: 0 + m_SubKind: + - m_Textures: [] + m_Width: 72 + m_Height: 72 + m_Kind: 0 + m_SubKind: + - m_Textures: [] + m_Width: 48 + m_Height: 48 + m_Kind: 0 + m_SubKind: + - m_Textures: [] + m_Width: 36 + m_Height: 36 + m_Kind: 0 + m_SubKind: + m_BuildTargetBatching: [] + m_BuildTargetShaderSettings: [] + m_BuildTargetGraphicsJobs: + - m_BuildTarget: MacStandaloneSupport + m_GraphicsJobs: 0 + - m_BuildTarget: Switch + m_GraphicsJobs: 0 + - m_BuildTarget: MetroSupport + m_GraphicsJobs: 0 + - m_BuildTarget: AppleTVSupport + m_GraphicsJobs: 0 + - m_BuildTarget: BJMSupport + m_GraphicsJobs: 0 + - m_BuildTarget: LinuxStandaloneSupport + m_GraphicsJobs: 0 + - m_BuildTarget: PS4Player + m_GraphicsJobs: 0 + - m_BuildTarget: iOSSupport + m_GraphicsJobs: 0 + - m_BuildTarget: WindowsStandaloneSupport + m_GraphicsJobs: 0 + - m_BuildTarget: XboxOnePlayer + m_GraphicsJobs: 0 + - m_BuildTarget: LuminSupport + m_GraphicsJobs: 0 + - m_BuildTarget: AndroidPlayer + m_GraphicsJobs: 0 + - m_BuildTarget: WebGLSupport + m_GraphicsJobs: 0 + m_BuildTargetGraphicsJobMode: [] + m_BuildTargetGraphicsAPIs: + - m_BuildTarget: AndroidPlayer + m_APIs: 150000000b000000 + m_Automatic: 1 + - m_BuildTarget: iOSSupport + m_APIs: 10000000 + m_Automatic: 1 + m_BuildTargetVRSettings: [] + m_DefaultShaderChunkSizeInMB: 16 + m_DefaultShaderChunkCount: 0 + openGLRequireES31: 0 + openGLRequireES31AEP: 0 + openGLRequireES32: 0 + m_TemplateCustomTags: {} + mobileMTRendering: + Android: 1 + iPhone: 1 + tvOS: 1 + m_BuildTargetGroupLightmapEncodingQuality: [] + m_BuildTargetGroupLightmapSettings: [] + m_BuildTargetNormalMapEncoding: [] + m_BuildTargetDefaultTextureCompressionFormat: + - m_BuildTarget: Android + m_Format: 3 + playModeTestRunnerEnabled: 0 + runPlayModeTestAsEditModeTest: 0 + actionOnDotNetUnhandledException: 1 + enableInternalProfiler: 0 + logObjCUncaughtExceptions: 1 + enableCrashReportAPI: 0 + cameraUsageDescription: + locationUsageDescription: + microphoneUsageDescription: + bluetoothUsageDescription: + switchNMETAOverride: + switchNetLibKey: + switchSocketMemoryPoolSize: 6144 + switchSocketAllocatorPoolSize: 128 + switchSocketConcurrencyLimit: 14 + switchScreenResolutionBehavior: 2 + switchUseCPUProfiler: 0 + switchUseGOLDLinker: 0 + switchLTOSetting: 0 + switchApplicationID: 0x01004b9000490000 + switchNSODependencies: + switchTitleNames_0: + switchTitleNames_1: + switchTitleNames_2: + switchTitleNames_3: + switchTitleNames_4: + switchTitleNames_5: + switchTitleNames_6: + switchTitleNames_7: + switchTitleNames_8: + switchTitleNames_9: + switchTitleNames_10: + switchTitleNames_11: + switchTitleNames_12: + switchTitleNames_13: + switchTitleNames_14: + switchTitleNames_15: + switchPublisherNames_0: + switchPublisherNames_1: + switchPublisherNames_2: + switchPublisherNames_3: + switchPublisherNames_4: + switchPublisherNames_5: + switchPublisherNames_6: + switchPublisherNames_7: + switchPublisherNames_8: + switchPublisherNames_9: + switchPublisherNames_10: + switchPublisherNames_11: + switchPublisherNames_12: + switchPublisherNames_13: + switchPublisherNames_14: + switchPublisherNames_15: + switchIcons_0: {fileID: 0} + switchIcons_1: {fileID: 0} + switchIcons_2: {fileID: 0} + switchIcons_3: {fileID: 0} + switchIcons_4: {fileID: 0} + switchIcons_5: {fileID: 0} + switchIcons_6: {fileID: 0} + switchIcons_7: {fileID: 0} + switchIcons_8: {fileID: 0} + switchIcons_9: {fileID: 0} + switchIcons_10: {fileID: 0} + switchIcons_11: {fileID: 0} + switchIcons_12: {fileID: 0} + switchIcons_13: {fileID: 0} + switchIcons_14: {fileID: 0} + switchIcons_15: {fileID: 0} + switchSmallIcons_0: {fileID: 0} + switchSmallIcons_1: {fileID: 0} + switchSmallIcons_2: {fileID: 0} + switchSmallIcons_3: {fileID: 0} + switchSmallIcons_4: {fileID: 0} + switchSmallIcons_5: {fileID: 0} + switchSmallIcons_6: {fileID: 0} + switchSmallIcons_7: {fileID: 0} + switchSmallIcons_8: {fileID: 0} + switchSmallIcons_9: {fileID: 0} + switchSmallIcons_10: {fileID: 0} + switchSmallIcons_11: {fileID: 0} + switchSmallIcons_12: {fileID: 0} + switchSmallIcons_13: {fileID: 0} + switchSmallIcons_14: {fileID: 0} + switchSmallIcons_15: {fileID: 0} + switchManualHTML: + switchAccessibleURLs: + switchLegalInformation: + switchMainThreadStackSize: 1048576 + switchPresenceGroupId: + switchLogoHandling: 0 + switchReleaseVersion: 0 + switchDisplayVersion: 1.0.0 + switchStartupUserAccount: 0 + switchTouchScreenUsage: 0 + switchSupportedLanguagesMask: 0 + switchLogoType: 0 + switchApplicationErrorCodeCategory: + switchUserAccountSaveDataSize: 0 + switchUserAccountSaveDataJournalSize: 0 + switchApplicationAttribute: 0 + switchCardSpecSize: -1 + switchCardSpecClock: -1 + switchRatingsMask: 0 + switchRatingsInt_0: 0 + switchRatingsInt_1: 0 + switchRatingsInt_2: 0 + switchRatingsInt_3: 0 + switchRatingsInt_4: 0 + switchRatingsInt_5: 0 + switchRatingsInt_6: 0 + switchRatingsInt_7: 0 + switchRatingsInt_8: 0 + switchRatingsInt_9: 0 + switchRatingsInt_10: 0 + switchRatingsInt_11: 0 + switchRatingsInt_12: 0 + switchLocalCommunicationIds_0: + switchLocalCommunicationIds_1: + switchLocalCommunicationIds_2: + switchLocalCommunicationIds_3: + switchLocalCommunicationIds_4: + switchLocalCommunicationIds_5: + switchLocalCommunicationIds_6: + switchLocalCommunicationIds_7: + switchParentalControl: 0 + switchAllowsScreenshot: 1 + switchAllowsVideoCapturing: 1 + switchAllowsRuntimeAddOnContentInstall: 0 + switchDataLossConfirmation: 0 + switchUserAccountLockEnabled: 0 + switchSystemResourceMemory: 16777216 + switchSupportedNpadStyles: 22 + switchNativeFsCacheSize: 32 + switchIsHoldTypeHorizontal: 0 + switchSupportedNpadCount: 8 + switchSocketConfigEnabled: 0 + switchTcpInitialSendBufferSize: 32 + switchTcpInitialReceiveBufferSize: 64 + switchTcpAutoSendBufferSizeMax: 256 + switchTcpAutoReceiveBufferSizeMax: 256 + switchUdpSendBufferSize: 9 + switchUdpReceiveBufferSize: 42 + switchSocketBufferEfficiency: 4 + switchSocketInitializeEnabled: 1 + switchNetworkInterfaceManagerInitializeEnabled: 1 + switchPlayerConnectionEnabled: 1 + switchUseNewStyleFilepaths: 0 + switchUseMicroSleepForYield: 1 + switchEnableRamDiskSupport: 0 + switchMicroSleepForYieldTime: 25 + switchRamDiskSpaceSize: 12 + ps4NPAgeRating: 12 + ps4NPTitleSecret: + ps4NPTrophyPackPath: + ps4ParentalLevel: 11 + ps4ContentID: ED1633-NPXX51362_00-0000000000000000 + ps4Category: 0 + ps4MasterVersion: 01.00 + ps4AppVersion: 01.00 + ps4AppType: 0 + ps4ParamSfxPath: + ps4VideoOutPixelFormat: 0 + ps4VideoOutInitialWidth: 1920 + ps4VideoOutBaseModeInitialWidth: 1920 + ps4VideoOutReprojectionRate: 60 + ps4PronunciationXMLPath: + ps4PronunciationSIGPath: + ps4BackgroundImagePath: + ps4StartupImagePath: + ps4StartupImagesFolder: + ps4IconImagesFolder: + ps4SaveDataImagePath: + ps4SdkOverride: + ps4BGMPath: + ps4ShareFilePath: + ps4ShareOverlayImagePath: + ps4PrivacyGuardImagePath: + ps4ExtraSceSysFile: + ps4NPtitleDatPath: + ps4RemotePlayKeyAssignment: -1 + ps4RemotePlayKeyMappingDir: + ps4PlayTogetherPlayerCount: 0 + ps4EnterButtonAssignment: 2 + ps4ApplicationParam1: 0 + ps4ApplicationParam2: 0 + ps4ApplicationParam3: 0 + ps4ApplicationParam4: 0 + ps4DownloadDataSize: 0 + ps4GarlicHeapSize: 2048 + ps4ProGarlicHeapSize: 2560 + playerPrefsMaxSize: 32768 + ps4Passcode: bi9UOuSpM2Tlh01vOzwvSikHFswuzleh + ps4pnSessions: 1 + ps4pnPresence: 1 + ps4pnFriends: 1 + ps4pnGameCustomData: 1 + playerPrefsSupport: 0 + enableApplicationExit: 0 + resetTempFolder: 1 + restrictedAudioUsageRights: 0 + ps4UseResolutionFallback: 0 + ps4ReprojectionSupport: 0 + ps4UseAudio3dBackend: 0 + ps4UseLowGarlicFragmentationMode: 1 + ps4SocialScreenEnabled: 0 + ps4ScriptOptimizationLevel: 2 + ps4Audio3dVirtualSpeakerCount: 14 + ps4attribCpuUsage: 0 + ps4PatchPkgPath: + ps4PatchLatestPkgPath: + ps4PatchChangeinfoPath: + ps4PatchDayOne: 0 + ps4attribUserManagement: 0 + ps4attribMoveSupport: 0 + ps4attrib3DSupport: 0 + ps4attribShareSupport: 0 + ps4attribExclusiveVR: 0 + ps4disableAutoHideSplash: 0 + ps4videoRecordingFeaturesUsed: 0 + ps4contentSearchFeaturesUsed: 0 + ps4CompatibilityPS5: 0 + ps4AllowPS5Detection: 0 + ps4GPU800MHz: 1 + ps4attribEyeToEyeDistanceSettingVR: 0 + ps4IncludedModules: [] + ps4attribVROutputEnabled: 0 + monoEnv: + splashScreenBackgroundSourceLandscape: {fileID: 0} + splashScreenBackgroundSourcePortrait: {fileID: 0} + blurSplashScreenBackground: 1 + spritePackerPolicy: + webGLMemorySize: 32 + webGLExceptionSupport: 1 + webGLNameFilesAsHashes: 0 + webGLDataCaching: 1 + webGLDebugSymbols: 0 + webGLEmscriptenArgs: + webGLModulesDirectory: + webGLTemplate: APPLICATION:Default + webGLAnalyzeBuildSize: 0 + webGLUseEmbeddedResources: 0 + webGLCompressionFormat: 0 + webGLWasmArithmeticExceptions: 0 + webGLLinkerTarget: 1 + webGLThreadsSupport: 0 + webGLDecompressionFallback: 0 + webGLPowerPreference: 2 + scriptingDefineSymbols: {} + additionalCompilerArguments: {} + platformArchitecture: {} + scriptingBackend: {} + il2cppCompilerConfiguration: {} + managedStrippingLevel: {} + incrementalIl2cppBuild: {} + suppressCommonWarnings: 1 + allowUnsafeCode: 0 + useDeterministicCompilation: 1 + enableRoslynAnalyzers: 1 + selectedPlatform: 0 + additionalIl2CppArgs: + scriptingRuntimeVersion: 1 + gcIncremental: 1 + assemblyVersionValidation: 1 + gcWBarrierValidation: 0 + apiCompatibilityLevelPerPlatform: {} + m_RenderingPath: 1 + m_MobileRenderingPath: 1 + metroPackageName: 2D_BuiltInRenderer + metroPackageVersion: + metroCertificatePath: + metroCertificatePassword: + metroCertificateSubject: + metroCertificateIssuer: + metroCertificateNotAfter: 0000000000000000 + metroApplicationDescription: 2D_BuiltInRenderer + wsaImages: {} + metroTileShortName: + metroTileShowName: 0 + metroMediumTileShowName: 0 + metroLargeTileShowName: 0 + metroWideTileShowName: 0 + metroSupportStreamingInstall: 0 + metroLastRequiredScene: 0 + metroDefaultTileSize: 1 + metroTileForegroundText: 2 + metroTileBackgroundColor: {r: 0.13333334, g: 0.17254902, b: 0.21568628, a: 0} + metroSplashScreenBackgroundColor: {r: 0.12941177, g: 0.17254902, b: 0.21568628, a: 1} + metroSplashScreenUseBackgroundColor: 0 + platformCapabilities: {} + metroTargetDeviceFamilies: {} + metroFTAName: + metroFTAFileTypes: [] + metroProtocolName: + vcxProjDefaultLanguage: + XboxOneProductId: + XboxOneUpdateKey: + XboxOneSandboxId: + XboxOneContentId: + XboxOneTitleId: + XboxOneSCId: + XboxOneGameOsOverridePath: + XboxOnePackagingOverridePath: + XboxOneAppManifestOverridePath: + XboxOneVersion: 1.0.0.0 + XboxOnePackageEncryption: 0 + XboxOnePackageUpdateGranularity: 2 + XboxOneDescription: + XboxOneLanguage: + - enus + XboxOneCapability: [] + XboxOneGameRating: {} + XboxOneIsContentPackage: 0 + XboxOneEnhancedXboxCompatibilityMode: 0 + XboxOneEnableGPUVariability: 1 + XboxOneSockets: {} + XboxOneSplashScreen: {fileID: 0} + XboxOneAllowedProductIds: [] + XboxOnePersistentLocalStorageSize: 0 + XboxOneXTitleMemory: 8 + XboxOneOverrideIdentityName: + XboxOneOverrideIdentityPublisher: + vrEditorSettings: {} + cloudServicesEnabled: + Collab: 1 + luminIcon: + m_Name: + m_ModelFolderPath: + m_PortalFolderPath: + luminCert: + m_CertPath: + m_SignPackage: 1 + luminIsChannelApp: 0 + luminVersion: + m_VersionCode: 1 + m_VersionName: + apiCompatibilityLevel: 6 + activeInputHandler: 0 + windowsGamepadBackendHint: 0 + cloudProjectId: + framebufferDepthMemorylessMode: 0 + qualitySettingsNames: [] + projectName: + organizationId: + cloudEnabled: 0 + legacyClampBlendShapeWeights: 0 + playerDataPath: + forceSRGBBlit: 1 + virtualTexturingSupportEnabled: 0 diff --git a/邮件系统课程完整代码/Client/Unity/ProjectSettings/ProjectVersion.txt b/邮件系统课程完整代码/Client/Unity/ProjectSettings/ProjectVersion.txt new file mode 100644 index 0000000..6a95707 --- /dev/null +++ b/邮件系统课程完整代码/Client/Unity/ProjectSettings/ProjectVersion.txt @@ -0,0 +1,2 @@ +m_EditorVersion: 2021.3.14f1 +m_EditorVersionWithRevision: 2021.3.14f1 (eee1884e7226) diff --git a/邮件系统课程完整代码/Client/Unity/ProjectSettings/QualitySettings.asset b/邮件系统课程完整代码/Client/Unity/ProjectSettings/QualitySettings.asset new file mode 100644 index 0000000..bcd6706 --- /dev/null +++ b/邮件系统课程完整代码/Client/Unity/ProjectSettings/QualitySettings.asset @@ -0,0 +1,239 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!47 &1 +QualitySettings: + m_ObjectHideFlags: 0 + serializedVersion: 5 + m_CurrentQuality: 5 + m_QualitySettings: + - serializedVersion: 2 + name: Very Low + pixelLightCount: 0 + shadows: 0 + shadowResolution: 0 + shadowProjection: 1 + shadowCascades: 1 + shadowDistance: 15 + shadowNearPlaneOffset: 3 + shadowCascade2Split: 0.33333334 + shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} + shadowmaskMode: 0 + skinWeights: 1 + textureQuality: 1 + anisotropicTextures: 0 + antiAliasing: 0 + softParticles: 0 + softVegetation: 0 + realtimeReflectionProbes: 0 + billboardsFaceCameraPosition: 0 + vSyncCount: 0 + lodBias: 0.3 + maximumLODLevel: 0 + streamingMipmapsActive: 0 + streamingMipmapsAddAllCameras: 1 + streamingMipmapsMemoryBudget: 512 + streamingMipmapsRenderersPerFrame: 512 + streamingMipmapsMaxLevelReduction: 2 + streamingMipmapsMaxFileIORequests: 1024 + particleRaycastBudget: 4 + asyncUploadTimeSlice: 2 + asyncUploadBufferSize: 16 + asyncUploadPersistentBuffer: 1 + resolutionScalingFixedDPIFactor: 1 + customRenderPipeline: {fileID: 0} + excludedTargetPlatforms: [] + - serializedVersion: 2 + name: Low + pixelLightCount: 0 + shadows: 0 + shadowResolution: 0 + shadowProjection: 1 + shadowCascades: 1 + shadowDistance: 20 + shadowNearPlaneOffset: 3 + shadowCascade2Split: 0.33333334 + shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} + shadowmaskMode: 0 + skinWeights: 2 + textureQuality: 0 + anisotropicTextures: 0 + antiAliasing: 0 + softParticles: 0 + softVegetation: 0 + realtimeReflectionProbes: 0 + billboardsFaceCameraPosition: 0 + vSyncCount: 0 + lodBias: 0.4 + maximumLODLevel: 0 + streamingMipmapsActive: 0 + streamingMipmapsAddAllCameras: 1 + streamingMipmapsMemoryBudget: 512 + streamingMipmapsRenderersPerFrame: 512 + streamingMipmapsMaxLevelReduction: 2 + streamingMipmapsMaxFileIORequests: 1024 + particleRaycastBudget: 16 + asyncUploadTimeSlice: 2 + asyncUploadBufferSize: 16 + asyncUploadPersistentBuffer: 1 + resolutionScalingFixedDPIFactor: 1 + customRenderPipeline: {fileID: 0} + excludedTargetPlatforms: [] + - serializedVersion: 2 + name: Medium + pixelLightCount: 1 + shadows: 1 + shadowResolution: 0 + shadowProjection: 1 + shadowCascades: 1 + shadowDistance: 20 + shadowNearPlaneOffset: 3 + shadowCascade2Split: 0.33333334 + shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} + shadowmaskMode: 0 + skinWeights: 2 + textureQuality: 0 + anisotropicTextures: 1 + antiAliasing: 0 + softParticles: 0 + softVegetation: 0 + realtimeReflectionProbes: 0 + billboardsFaceCameraPosition: 0 + vSyncCount: 1 + lodBias: 0.7 + maximumLODLevel: 0 + streamingMipmapsActive: 0 + streamingMipmapsAddAllCameras: 1 + streamingMipmapsMemoryBudget: 512 + streamingMipmapsRenderersPerFrame: 512 + streamingMipmapsMaxLevelReduction: 2 + streamingMipmapsMaxFileIORequests: 1024 + particleRaycastBudget: 64 + asyncUploadTimeSlice: 2 + asyncUploadBufferSize: 16 + asyncUploadPersistentBuffer: 1 + resolutionScalingFixedDPIFactor: 1 + customRenderPipeline: {fileID: 0} + excludedTargetPlatforms: [] + - serializedVersion: 2 + name: High + pixelLightCount: 2 + shadows: 2 + shadowResolution: 1 + shadowProjection: 1 + shadowCascades: 2 + shadowDistance: 40 + shadowNearPlaneOffset: 3 + shadowCascade2Split: 0.33333334 + shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} + shadowmaskMode: 1 + skinWeights: 2 + textureQuality: 0 + anisotropicTextures: 1 + antiAliasing: 0 + softParticles: 0 + softVegetation: 1 + realtimeReflectionProbes: 1 + billboardsFaceCameraPosition: 1 + vSyncCount: 1 + lodBias: 1 + maximumLODLevel: 0 + streamingMipmapsActive: 0 + streamingMipmapsAddAllCameras: 1 + streamingMipmapsMemoryBudget: 512 + streamingMipmapsRenderersPerFrame: 512 + streamingMipmapsMaxLevelReduction: 2 + streamingMipmapsMaxFileIORequests: 1024 + particleRaycastBudget: 256 + asyncUploadTimeSlice: 2 + asyncUploadBufferSize: 16 + asyncUploadPersistentBuffer: 1 + resolutionScalingFixedDPIFactor: 1 + customRenderPipeline: {fileID: 0} + excludedTargetPlatforms: [] + - serializedVersion: 2 + name: Very High + pixelLightCount: 3 + shadows: 2 + shadowResolution: 2 + shadowProjection: 1 + shadowCascades: 2 + shadowDistance: 70 + shadowNearPlaneOffset: 3 + shadowCascade2Split: 0.33333334 + shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} + shadowmaskMode: 1 + skinWeights: 4 + textureQuality: 0 + anisotropicTextures: 2 + antiAliasing: 2 + softParticles: 1 + softVegetation: 1 + realtimeReflectionProbes: 1 + billboardsFaceCameraPosition: 1 + vSyncCount: 1 + lodBias: 1.5 + maximumLODLevel: 0 + streamingMipmapsActive: 0 + streamingMipmapsAddAllCameras: 1 + streamingMipmapsMemoryBudget: 512 + streamingMipmapsRenderersPerFrame: 512 + streamingMipmapsMaxLevelReduction: 2 + streamingMipmapsMaxFileIORequests: 1024 + particleRaycastBudget: 1024 + asyncUploadTimeSlice: 2 + asyncUploadBufferSize: 16 + asyncUploadPersistentBuffer: 1 + resolutionScalingFixedDPIFactor: 1 + customRenderPipeline: {fileID: 0} + excludedTargetPlatforms: [] + - serializedVersion: 2 + name: Ultra + pixelLightCount: 4 + shadows: 2 + shadowResolution: 2 + shadowProjection: 1 + shadowCascades: 4 + shadowDistance: 150 + shadowNearPlaneOffset: 3 + shadowCascade2Split: 0.33333334 + shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667} + shadowmaskMode: 1 + skinWeights: 255 + textureQuality: 0 + anisotropicTextures: 2 + antiAliasing: 2 + softParticles: 1 + softVegetation: 1 + realtimeReflectionProbes: 1 + billboardsFaceCameraPosition: 1 + vSyncCount: 1 + lodBias: 2 + maximumLODLevel: 0 + streamingMipmapsActive: 0 + streamingMipmapsAddAllCameras: 1 + streamingMipmapsMemoryBudget: 512 + streamingMipmapsRenderersPerFrame: 512 + streamingMipmapsMaxLevelReduction: 2 + streamingMipmapsMaxFileIORequests: 1024 + particleRaycastBudget: 4096 + asyncUploadTimeSlice: 2 + asyncUploadBufferSize: 16 + asyncUploadPersistentBuffer: 1 + resolutionScalingFixedDPIFactor: 1 + customRenderPipeline: {fileID: 0} + excludedTargetPlatforms: [] + m_PerPlatformDefaultQuality: + Android: 2 + Lumin: 5 + GameCoreScarlett: 5 + GameCoreXboxOne: 5 + Nintendo Switch: 5 + PS4: 5 + PS5: 5 + Stadia: 5 + Standalone: 5 + WebGL: 3 + Windows Store Apps: 5 + XboxOne: 5 + iPhone: 2 + tvOS: 2 diff --git a/邮件系统课程完整代码/Client/Unity/ProjectSettings/SceneTemplateSettings.json b/邮件系统课程完整代码/Client/Unity/ProjectSettings/SceneTemplateSettings.json new file mode 100644 index 0000000..6f3e60f --- /dev/null +++ b/邮件系统课程完整代码/Client/Unity/ProjectSettings/SceneTemplateSettings.json @@ -0,0 +1,167 @@ +{ + "templatePinStates": [], + "dependencyTypeInfos": [ + { + "userAdded": false, + "type": "UnityEngine.AnimationClip", + "ignore": false, + "defaultInstantiationMode": 0, + "supportsModification": true + }, + { + "userAdded": false, + "type": "UnityEditor.Animations.AnimatorController", + "ignore": false, + "defaultInstantiationMode": 0, + "supportsModification": true + }, + { + "userAdded": false, + "type": "UnityEngine.AnimatorOverrideController", + "ignore": false, + "defaultInstantiationMode": 0, + "supportsModification": true + }, + { + "userAdded": false, + "type": "UnityEditor.Audio.AudioMixerController", + "ignore": false, + "defaultInstantiationMode": 0, + "supportsModification": true + }, + { + "userAdded": false, + "type": "UnityEngine.ComputeShader", + "ignore": true, + "defaultInstantiationMode": 1, + "supportsModification": true + }, + { + "userAdded": false, + "type": "UnityEngine.Cubemap", + "ignore": false, + "defaultInstantiationMode": 0, + "supportsModification": true + }, + { + "userAdded": false, + "type": "UnityEngine.GameObject", + "ignore": false, + "defaultInstantiationMode": 0, + "supportsModification": true + }, + { + "userAdded": false, + "type": "UnityEditor.LightingDataAsset", + "ignore": false, + "defaultInstantiationMode": 0, + "supportsModification": false + }, + { + "userAdded": false, + "type": "UnityEngine.LightingSettings", + "ignore": false, + "defaultInstantiationMode": 0, + "supportsModification": true + }, + { + "userAdded": false, + "type": "UnityEngine.Material", + "ignore": false, + "defaultInstantiationMode": 0, + "supportsModification": true + }, + { + "userAdded": false, + "type": "UnityEditor.MonoScript", + "ignore": true, + "defaultInstantiationMode": 1, + "supportsModification": true + }, + { + "userAdded": false, + "type": "UnityEngine.PhysicMaterial", + "ignore": false, + "defaultInstantiationMode": 0, + "supportsModification": true + }, + { + "userAdded": false, + "type": "UnityEngine.PhysicsMaterial2D", + "ignore": false, + "defaultInstantiationMode": 0, + "supportsModification": true + }, + { + "userAdded": false, + "type": "UnityEngine.Rendering.PostProcessing.PostProcessProfile", + "ignore": false, + "defaultInstantiationMode": 0, + "supportsModification": true + }, + { + "userAdded": false, + "type": "UnityEngine.Rendering.PostProcessing.PostProcessResources", + "ignore": false, + "defaultInstantiationMode": 0, + "supportsModification": true + }, + { + "userAdded": false, + "type": "UnityEngine.Rendering.VolumeProfile", + "ignore": false, + "defaultInstantiationMode": 0, + "supportsModification": true + }, + { + "userAdded": false, + "type": "UnityEditor.SceneAsset", + "ignore": false, + "defaultInstantiationMode": 0, + "supportsModification": false + }, + { + "userAdded": false, + "type": "UnityEngine.Shader", + "ignore": true, + "defaultInstantiationMode": 1, + "supportsModification": true + }, + { + "userAdded": false, + "type": "UnityEngine.ShaderVariantCollection", + "ignore": true, + "defaultInstantiationMode": 1, + "supportsModification": true + }, + { + "userAdded": false, + "type": "UnityEngine.Texture", + "ignore": false, + "defaultInstantiationMode": 0, + "supportsModification": true + }, + { + "userAdded": false, + "type": "UnityEngine.Texture2D", + "ignore": false, + "defaultInstantiationMode": 0, + "supportsModification": true + }, + { + "userAdded": false, + "type": "UnityEngine.Timeline.TimelineAsset", + "ignore": false, + "defaultInstantiationMode": 0, + "supportsModification": true + } + ], + "defaultDependencyTypeInfo": { + "userAdded": false, + "type": "", + "ignore": false, + "defaultInstantiationMode": 1, + "supportsModification": true + }, + "newSceneOverride": 0 +} \ No newline at end of file diff --git a/邮件系统课程完整代码/Client/Unity/ProjectSettings/TagManager.asset b/邮件系统课程完整代码/Client/Unity/ProjectSettings/TagManager.asset new file mode 100644 index 0000000..1c92a78 --- /dev/null +++ b/邮件系统课程完整代码/Client/Unity/ProjectSettings/TagManager.asset @@ -0,0 +1,43 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!78 &1 +TagManager: + serializedVersion: 2 + tags: [] + layers: + - Default + - TransparentFX + - Ignore Raycast + - + - Water + - UI + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + m_SortingLayers: + - name: Default + uniqueID: 0 + locked: 0 diff --git a/邮件系统课程完整代码/Client/Unity/ProjectSettings/TimeManager.asset b/邮件系统课程完整代码/Client/Unity/ProjectSettings/TimeManager.asset new file mode 100644 index 0000000..558a017 --- /dev/null +++ b/邮件系统课程完整代码/Client/Unity/ProjectSettings/TimeManager.asset @@ -0,0 +1,9 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!5 &1 +TimeManager: + m_ObjectHideFlags: 0 + Fixed Timestep: 0.02 + Maximum Allowed Timestep: 0.33333334 + m_TimeScale: 1 + Maximum Particle Timestep: 0.03 diff --git a/邮件系统课程完整代码/Client/Unity/ProjectSettings/UnityConnectSettings.asset b/邮件系统课程完整代码/Client/Unity/ProjectSettings/UnityConnectSettings.asset new file mode 100644 index 0000000..a88bee0 --- /dev/null +++ b/邮件系统课程完整代码/Client/Unity/ProjectSettings/UnityConnectSettings.asset @@ -0,0 +1,36 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!310 &1 +UnityConnectSettings: + m_ObjectHideFlags: 0 + serializedVersion: 1 + m_Enabled: 0 + m_TestMode: 0 + m_EventOldUrl: https://api.uca.cloud.unity3d.com/v1/events + m_EventUrl: https://cdp.cloud.unity3d.com/v1/events + m_ConfigUrl: https://config.uca.cloud.unity3d.com + m_DashboardUrl: https://dashboard.unity3d.com + m_TestInitMode: 0 + CrashReportingSettings: + m_EventUrl: https://perf-events.cloud.unity3d.com + m_Enabled: 0 + m_LogBufferSize: 10 + m_CaptureEditorExceptions: 1 + UnityPurchasingSettings: + m_Enabled: 0 + m_TestMode: 0 + UnityAnalyticsSettings: + m_Enabled: 0 + m_TestMode: 0 + m_InitializeOnStartup: 1 + m_PackageRequiringCoreStatsPresent: 0 + UnityAdsSettings: + m_Enabled: 0 + m_InitializeOnStartup: 1 + m_TestMode: 0 + m_IosGameId: + m_AndroidGameId: + m_GameIds: {} + m_GameId: + PerformanceReportingSettings: + m_Enabled: 0 diff --git a/邮件系统课程完整代码/Client/Unity/ProjectSettings/VFXManager.asset b/邮件系统课程完整代码/Client/Unity/ProjectSettings/VFXManager.asset new file mode 100644 index 0000000..46f38e1 --- /dev/null +++ b/邮件系统课程完整代码/Client/Unity/ProjectSettings/VFXManager.asset @@ -0,0 +1,14 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!937362698 &1 +VFXManager: + m_ObjectHideFlags: 0 + m_IndirectShader: {fileID: 0} + m_CopyBufferShader: {fileID: 0} + m_SortShader: {fileID: 0} + m_StripUpdateShader: {fileID: 0} + m_RenderPipeSettingsPath: + m_FixedTimeStep: 0.016666668 + m_MaxDeltaTime: 0.05 + m_CompiledVersion: 0 + m_RuntimeVersion: 0 diff --git a/邮件系统课程完整代码/Client/Unity/ProjectSettings/VersionControlSettings.asset b/邮件系统课程完整代码/Client/Unity/ProjectSettings/VersionControlSettings.asset new file mode 100644 index 0000000..dca2881 --- /dev/null +++ b/邮件系统课程完整代码/Client/Unity/ProjectSettings/VersionControlSettings.asset @@ -0,0 +1,8 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!890905787 &1 +VersionControlSettings: + m_ObjectHideFlags: 0 + m_Mode: Visible Meta Files + m_CollabEditorSettings: + inProgressEnabled: 1 diff --git a/邮件系统课程完整代码/Client/Unity/ProjectSettings/XRSettings.asset b/邮件系统课程完整代码/Client/Unity/ProjectSettings/XRSettings.asset new file mode 100644 index 0000000..482590c --- /dev/null +++ b/邮件系统课程完整代码/Client/Unity/ProjectSettings/XRSettings.asset @@ -0,0 +1,10 @@ +{ + "m_SettingKeys": [ + "VR Device Disabled", + "VR Device User Alert" + ], + "m_SettingValues": [ + "False", + "False" + ] +} \ No newline at end of file diff --git a/邮件系统课程完整代码/Client/Unity/ProjectSettings/boot.config b/邮件系统课程完整代码/Client/Unity/ProjectSettings/boot.config new file mode 100644 index 0000000..e69de29 diff --git a/邮件系统课程完整代码/Client/Unity/Unity.sln b/邮件系统课程完整代码/Client/Unity/Unity.sln new file mode 100644 index 0000000..3cd23d4 --- /dev/null +++ b/邮件系统课程完整代码/Client/Unity/Unity.sln @@ -0,0 +1,17 @@ + +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Assembly-CSharp", "Assembly-CSharp.csproj", "{03938ccd-4b40-8dfb-6b9b-21988d5cac0a}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {03938ccd-4b40-8dfb-6b9b-21988d5cac0a}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {03938ccd-4b40-8dfb-6b9b-21988d5cac0a}.Debug|Any CPU.Build.0 = Debug|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/邮件系统课程完整代码/Client/Unity/UserSettings/.DS_Store b/邮件系统课程完整代码/Client/Unity/UserSettings/.DS_Store new file mode 100644 index 0000000..ba3edf2 Binary files /dev/null and b/邮件系统课程完整代码/Client/Unity/UserSettings/.DS_Store differ diff --git a/邮件系统课程完整代码/Client/Unity/UserSettings/EditorUserSettings.asset b/邮件系统课程完整代码/Client/Unity/UserSettings/EditorUserSettings.asset new file mode 100644 index 0000000..d3de59e --- /dev/null +++ b/邮件系统课程完整代码/Client/Unity/UserSettings/EditorUserSettings.asset @@ -0,0 +1,31 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!162 &1 +EditorUserSettings: + m_ObjectHideFlags: 0 + serializedVersion: 4 + m_ConfigSettings: + RecentlyUsedSceneGuid-0: + value: 515250075c0c595e5f5a5e71122159444e4e4a2f7a7d7f602f284d66b4b76661 + flags: 0 + RecentlyUsedSceneGuid-1: + value: 5a5757560101590a5d0c0e24427b5d44434e4c7a7b7a23677f2b4565b7b5353a + flags: 0 + vcSharedLogLevel: + value: 0d5e400f0650 + flags: 0 + m_VCAutomaticAdd: 1 + m_VCDebugCom: 0 + m_VCDebugCmd: 0 + m_VCDebugOut: 0 + m_SemanticMergeMode: 2 + m_DesiredImportWorkerCount: 4 + m_StandbyImportWorkerCount: 2 + m_IdleImportWorkerShutdownDelay: 60000 + m_VCShowFailedCheckout: 1 + m_VCOverwriteFailedCheckoutAssets: 1 + m_VCProjectOverlayIcons: 1 + m_VCHierarchyOverlayIcons: 1 + m_VCOtherOverlayIcons: 1 + m_VCAllowAsyncUpdate: 1 + m_ArtifactGarbageCollection: 1 diff --git a/邮件系统课程完整代码/Client/Unity/UserSettings/Layouts/CurrentMaximizeLayout.dwlt b/邮件系统课程完整代码/Client/Unity/UserSettings/Layouts/CurrentMaximizeLayout.dwlt new file mode 100644 index 0000000..9d08626 --- /dev/null +++ b/邮件系统课程完整代码/Client/Unity/UserSettings/Layouts/CurrentMaximizeLayout.dwlt @@ -0,0 +1,927 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &1 +MonoBehaviour: + m_ObjectHideFlags: 52 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 1 + m_Script: {fileID: 12010, guid: 0000000000000000e000000000000000, type: 0} + m_Name: + m_EditorClassIdentifier: + m_Children: + - {fileID: 3} + - {fileID: 7} + - {fileID: 13} + m_Position: + serializedVersion: 2 + x: 0 + y: 30 + width: 1920 + height: 977 + m_MinSize: {x: 300, y: 200} + m_MaxSize: {x: 24288, y: 16192} + vertical: 0 + controlID: 3835 +--- !u!114 &2 +MonoBehaviour: + m_ObjectHideFlags: 52 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 1 + m_Script: {fileID: 12015, guid: 0000000000000000e000000000000000, type: 0} + m_Name: + m_EditorClassIdentifier: + m_MinSize: {x: 200, y: 200} + m_MaxSize: {x: 4000, y: 4000} + m_TitleContent: + m_Text: Game + m_Image: {fileID: 4621777727084837110, guid: 0000000000000000d000000000000000, type: 0} + m_Tooltip: + m_Pos: + serializedVersion: 2 + x: -1920 + y: 733 + width: 1254.5 + height: 306 + m_ViewDataDictionary: {fileID: 0} + m_OverlayCanvas: + m_LastAppliedPresetName: Default + m_SaveData: [] + m_SerializedViewNames: [] + m_SerializedViewValues: [] + m_PlayModeViewName: GameView + m_ShowGizmos: 0 + m_TargetDisplay: 0 + m_ClearColor: {r: 0, g: 0, b: 0, a: 0} + m_TargetSize: {x: 1013, y: 570} + m_TextureFilterMode: 0 + m_TextureHideFlags: 61 + m_RenderIMGUI: 1 + m_EnterPlayModeBehavior: 1 + m_UseMipMap: 0 + m_VSyncEnabled: 0 + m_Gizmos: 0 + m_Stats: 0 + m_SelectedSizes: 01000000000000000000000000000000000000000000000000000000000000000000000000000000 + m_ZoomArea: + m_HRangeLocked: 0 + m_VRangeLocked: 0 + hZoomLockedByDefault: 0 + vZoomLockedByDefault: 0 + m_HBaseRangeMin: -253.25 + m_HBaseRangeMax: 253.25 + m_VBaseRangeMin: -142.5 + m_VBaseRangeMax: 142.5 + m_HAllowExceedBaseRangeMin: 1 + m_HAllowExceedBaseRangeMax: 1 + m_VAllowExceedBaseRangeMin: 1 + m_VAllowExceedBaseRangeMax: 1 + m_ScaleWithWindow: 0 + m_HSlider: 0 + m_VSlider: 0 + m_IgnoreScrollWheelUntilClicked: 0 + m_EnableMouseInput: 1 + m_EnableSliderZoomHorizontal: 0 + m_EnableSliderZoomVertical: 0 + m_UniformScale: 1 + m_UpDirection: 1 + m_DrawArea: + serializedVersion: 2 + x: 0 + y: 21 + width: 1254.5 + height: 285 + m_Scale: {x: 1, y: 1} + m_Translation: {x: 627.25, y: 142.5} + m_MarginLeft: 0 + m_MarginRight: 0 + m_MarginTop: 0 + m_MarginBottom: 0 + m_LastShownAreaInsideMargins: + serializedVersion: 2 + x: -627.25 + y: -142.5 + width: 1254.5 + height: 285 + m_MinimalGUI: 1 + m_defaultScale: 1 + m_LastWindowPixelSize: {x: 2509, y: 612} + m_ClearInEditMode: 1 + m_NoCameraWarning: 1 + m_LowResolutionForAspectRatios: 00000000000000000000 + m_XRRenderMode: 0 + m_RenderTexture: {fileID: 0} +--- !u!114 &3 +MonoBehaviour: + m_ObjectHideFlags: 52 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 12010, guid: 0000000000000000e000000000000000, type: 0} + m_Name: + m_EditorClassIdentifier: + m_Children: + - {fileID: 4} + - {fileID: 6} + m_Position: + serializedVersion: 2 + x: 0 + y: 0 + width: 1255.5 + height: 977 + m_MinSize: {x: 100, y: 200} + m_MaxSize: {x: 8096, y: 16192} + vertical: 1 + controlID: 3836 +--- !u!114 &4 +MonoBehaviour: + m_ObjectHideFlags: 52 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 1 + m_Script: {fileID: 12006, guid: 0000000000000000e000000000000000, type: 0} + m_Name: SceneView + m_EditorClassIdentifier: + m_Children: [] + m_Position: + serializedVersion: 2 + x: 0 + y: 0 + width: 1255.5 + height: 650 + m_MinSize: {x: 200, y: 200} + m_MaxSize: {x: 4000, y: 4000} + m_ActualView: {fileID: 5} + m_Panes: + - {fileID: 5} + m_Selected: 0 + m_LastSelected: 0 +--- !u!114 &5 +MonoBehaviour: + m_ObjectHideFlags: 52 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 1 + m_Script: {fileID: 12013, guid: 0000000000000000e000000000000000, type: 0} + m_Name: + m_EditorClassIdentifier: + m_MinSize: {x: 200, y: 200} + m_MaxSize: {x: 4000, y: 4000} + m_TitleContent: + m_Text: Scene + m_Image: {fileID: 8634526014445323508, guid: 0000000000000000d000000000000000, type: 0} + m_Tooltip: + m_Pos: + serializedVersion: 2 + x: -1920 + y: 83 + width: 1254.5 + height: 629 + m_ViewDataDictionary: {fileID: 0} + m_OverlayCanvas: + m_LastAppliedPresetName: Default + m_SaveData: + - dockPosition: 0 + containerId: overlay-toolbar__top + floating: 0 + collapsed: 0 + displayed: 1 + snapOffset: {x: -101, y: -26} + snapOffsetDelta: {x: 0, y: 0} + snapCorner: 3 + id: Tool Settings + index: 0 + layout: 1 + - dockPosition: 0 + containerId: overlay-toolbar__top + floating: 0 + collapsed: 0 + displayed: 1 + snapOffset: {x: -141, y: 149} + snapOffsetDelta: {x: 0, y: 0} + snapCorner: 1 + id: unity-grid-and-snap-toolbar + index: 1 + layout: 1 + - dockPosition: 1 + containerId: overlay-toolbar__top + floating: 0 + collapsed: 0 + displayed: 1 + snapOffset: {x: 0, y: 0} + snapOffsetDelta: {x: 0, y: 0} + snapCorner: 0 + id: unity-scene-view-toolbar + index: 0 + layout: 1 + - dockPosition: 1 + containerId: overlay-toolbar__top + floating: 0 + collapsed: 0 + displayed: 0 + snapOffset: {x: 0, y: 0} + snapOffsetDelta: {x: 0, y: 0} + snapCorner: 1 + id: unity-search-toolbar + index: 1 + layout: 1 + - dockPosition: 0 + containerId: overlay-container--left + floating: 0 + collapsed: 0 + displayed: 1 + snapOffset: {x: 0, y: 0} + snapOffsetDelta: {x: 0, y: 0} + snapCorner: 0 + id: unity-transform-toolbar + index: 0 + layout: 2 + - dockPosition: 0 + containerId: overlay-container--left + floating: 0 + collapsed: 0 + displayed: 1 + snapOffset: {x: 0, y: 197} + snapOffsetDelta: {x: 0, y: 0} + snapCorner: 0 + id: unity-component-tools + index: 1 + layout: 2 + - dockPosition: 0 + containerId: overlay-container--right + floating: 0 + collapsed: 0 + displayed: 1 + snapOffset: {x: 67.5, y: 86} + snapOffsetDelta: {x: 0, y: 0} + snapCorner: 0 + id: Orientation + index: 0 + layout: 4 + - dockPosition: 1 + containerId: overlay-container--right + floating: 0 + collapsed: 0 + displayed: 0 + snapOffset: {x: 0, y: 0} + snapOffsetDelta: {x: 0, y: 0} + snapCorner: 0 + id: Scene View/Light Settings + index: 0 + layout: 4 + - dockPosition: 1 + containerId: overlay-container--right + floating: 0 + collapsed: 0 + displayed: 1 + snapOffset: {x: 0, y: 0} + snapOffsetDelta: {x: 0, y: 0} + snapCorner: 0 + id: Scene View/Camera + index: 1 + layout: 4 + - dockPosition: 1 + containerId: overlay-container--right + floating: 0 + collapsed: 0 + displayed: 0 + snapOffset: {x: 0, y: 0} + snapOffsetDelta: {x: 0, y: 0} + snapCorner: 0 + id: Scene View/Cloth Constraints + index: 2 + layout: 4 + - dockPosition: 1 + containerId: overlay-container--right + floating: 0 + collapsed: 0 + displayed: 0 + snapOffset: {x: 0, y: 0} + snapOffsetDelta: {x: 0, y: 0} + snapCorner: 0 + id: Scene View/Cloth Collisions + index: 3 + layout: 4 + - dockPosition: 1 + containerId: overlay-container--right + floating: 0 + collapsed: 0 + displayed: 0 + snapOffset: {x: 0, y: 0} + snapOffsetDelta: {x: 0, y: 0} + snapCorner: 0 + id: Scene View/Navmesh Display + index: 4 + layout: 4 + - dockPosition: 1 + containerId: overlay-container--right + floating: 0 + collapsed: 0 + displayed: 0 + snapOffset: {x: 0, y: 0} + snapOffsetDelta: {x: 0, y: 0} + snapCorner: 0 + id: Scene View/Agent Display + index: 5 + layout: 4 + - dockPosition: 1 + containerId: overlay-container--right + floating: 0 + collapsed: 0 + displayed: 0 + snapOffset: {x: 0, y: 0} + snapOffsetDelta: {x: 0, y: 0} + snapCorner: 0 + id: Scene View/Obstacle Display + index: 6 + layout: 4 + - dockPosition: 1 + containerId: overlay-container--right + floating: 0 + collapsed: 0 + displayed: 0 + snapOffset: {x: 0, y: 0} + snapOffsetDelta: {x: 0, y: 0} + snapCorner: 0 + id: Scene View/Occlusion Culling + index: 7 + layout: 4 + - dockPosition: 1 + containerId: overlay-container--right + floating: 0 + collapsed: 0 + displayed: 0 + snapOffset: {x: 0, y: 0} + snapOffsetDelta: {x: 0, y: 0} + snapCorner: 0 + id: Scene View/Physics Debugger + index: 8 + layout: 4 + - dockPosition: 1 + containerId: overlay-container--right + floating: 0 + collapsed: 0 + displayed: 0 + snapOffset: {x: 0, y: 0} + snapOffsetDelta: {x: 0, y: 0} + snapCorner: 0 + id: Scene View/Scene Visibility + index: 9 + layout: 4 + - dockPosition: 1 + containerId: overlay-container--right + floating: 0 + collapsed: 0 + displayed: 0 + snapOffset: {x: 0, y: 0} + snapOffsetDelta: {x: 0, y: 0} + snapCorner: 0 + id: Scene View/Particles + index: 10 + layout: 4 + - dockPosition: 1 + containerId: overlay-container--right + floating: 0 + collapsed: 0 + displayed: 0 + snapOffset: {x: 0, y: 0} + snapOffsetDelta: {x: 0, y: 0} + snapCorner: 0 + id: Scene View/Tilemap + index: 11 + layout: 4 + - dockPosition: 1 + containerId: overlay-container--right + floating: 0 + collapsed: 0 + displayed: 0 + snapOffset: {x: 0, y: 0} + snapOffsetDelta: {x: 0, y: 0} + snapCorner: 0 + id: Scene View/Tilemap Palette Helper + index: 12 + layout: 4 + - dockPosition: 1 + containerId: overlay-toolbar__top + floating: 0 + collapsed: 0 + displayed: 0 + snapOffset: {x: 0, y: 0} + snapOffsetDelta: {x: 0, y: 0} + snapCorner: 0 + id: Scene View/Open Tile Palette + index: 2 + layout: 4 + - dockPosition: 1 + containerId: overlay-toolbar__top + floating: 0 + collapsed: 0 + displayed: 0 + snapOffset: {x: 0, y: 0} + snapOffsetDelta: {x: 0, y: 0} + snapCorner: 0 + id: Scene View/Tilemap Focus + index: 3 + layout: 4 + m_WindowGUID: a9b755b8a23b944249716e5248d146c0 + m_Gizmos: 1 + m_OverrideSceneCullingMask: 6917529027641081856 + m_SceneIsLit: 1 + m_SceneLighting: 1 + m_2DMode: 1 + m_isRotationLocked: 0 + m_PlayAudio: 0 + m_AudioPlay: 0 + m_Position: + m_Target: {x: 489.70132, y: 249.58237, z: -7.293578} + speed: 2 + m_Value: {x: 489.70132, y: 249.58237, z: -7.293578} + m_RenderMode: 0 + m_CameraMode: + drawMode: 0 + name: Shaded + section: Shading Mode + m_ValidateTrueMetals: 0 + m_DoValidateTrueMetals: 0 + m_ExposureSliderValue: 0 + m_SceneViewState: + m_AlwaysRefresh: 0 + showFog: 1 + showSkybox: 1 + showFlares: 1 + showImageEffects: 1 + showParticleSystems: 1 + showVisualEffectGraphs: 1 + m_FxEnabled: 1 + m_Grid: + xGrid: + m_Fade: + m_Target: 0 + speed: 2 + m_Value: 0 + m_Color: {r: 0.5, g: 0.5, b: 0.5, a: 0.4} + m_Pivot: {x: 0, y: 0, z: 0} + m_Size: {x: 0, y: 0} + yGrid: + m_Fade: + m_Target: 0 + speed: 2 + m_Value: 0 + m_Color: {r: 0.5, g: 0.5, b: 0.5, a: 0.4} + m_Pivot: {x: 0, y: 0, z: 0} + m_Size: {x: 0, y: 0} + zGrid: + m_Fade: + m_Target: 1 + speed: 2 + m_Value: 1 + m_Color: {r: 0.5, g: 0.5, b: 0.5, a: 0.4} + m_Pivot: {x: 0, y: 0, z: 0} + m_Size: {x: 1, y: 1} + m_ShowGrid: 1 + m_GridAxis: 1 + m_gridOpacity: 0.5 + m_Rotation: + m_Target: {x: 0, y: 0, z: 0, w: 1} + speed: 2 + m_Value: {x: 0, y: 0, z: 0, w: 1} + m_Size: + m_Target: 316.5856 + speed: 2 + m_Value: 316.5856 + m_Ortho: + m_Target: 1 + speed: 2 + m_Value: 1 + m_CameraSettings: + m_Speed: 1 + m_SpeedNormalized: 0.5 + m_SpeedMin: 0.01 + m_SpeedMax: 2 + m_EasingEnabled: 1 + m_EasingDuration: 0.4 + m_AccelerationEnabled: 1 + m_FieldOfViewHorizontalOrVertical: 60 + m_NearClip: 0.03 + m_FarClip: 10000 + m_DynamicClip: 1 + m_OcclusionCulling: 0 + m_LastSceneViewRotation: {x: -0.08717229, y: 0.89959055, z: -0.21045254, w: -0.3726226} + m_LastSceneViewOrtho: 0 + m_ReplacementShader: {fileID: 0} + m_ReplacementString: + m_SceneVisActive: 1 + m_LastLockedObject: {fileID: 0} + m_ViewIsLockedToObject: 0 +--- !u!114 &6 +MonoBehaviour: + m_ObjectHideFlags: 52 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 12006, guid: 0000000000000000e000000000000000, type: 0} + m_Name: GameView + m_EditorClassIdentifier: + m_Children: [] + m_Position: + serializedVersion: 2 + x: 0 + y: 650 + width: 1255.5 + height: 327 + m_MinSize: {x: 200, y: 200} + m_MaxSize: {x: 4000, y: 4000} + m_ActualView: {fileID: 2} + m_Panes: + - {fileID: 2} + m_Selected: 0 + m_LastSelected: 0 +--- !u!114 &7 +MonoBehaviour: + m_ObjectHideFlags: 52 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 1 + m_Script: {fileID: 12010, guid: 0000000000000000e000000000000000, type: 0} + m_Name: + m_EditorClassIdentifier: + m_Children: + - {fileID: 8} + - {fileID: 10} + m_Position: + serializedVersion: 2 + x: 1255.5 + y: 0 + width: 346.5 + height: 977 + m_MinSize: {x: 100, y: 200} + m_MaxSize: {x: 8096, y: 16192} + vertical: 1 + controlID: 3776 +--- !u!114 &8 +MonoBehaviour: + m_ObjectHideFlags: 52 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 1 + m_Script: {fileID: 12006, guid: 0000000000000000e000000000000000, type: 0} + m_Name: + m_EditorClassIdentifier: + m_Children: [] + m_Position: + serializedVersion: 2 + x: 0 + y: 0 + width: 346.5 + height: 430.5 + m_MinSize: {x: 202, y: 221} + m_MaxSize: {x: 4002, y: 4021} + m_ActualView: {fileID: 9} + m_Panes: + - {fileID: 9} + m_Selected: 0 + m_LastSelected: 0 +--- !u!114 &9 +MonoBehaviour: + m_ObjectHideFlags: 52 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 1 + m_Script: {fileID: 12061, guid: 0000000000000000e000000000000000, type: 0} + m_Name: + m_EditorClassIdentifier: + m_MinSize: {x: 200, y: 200} + m_MaxSize: {x: 4000, y: 4000} + m_TitleContent: + m_Text: Hierarchy + m_Image: {fileID: -3734745235275155857, guid: 0000000000000000d000000000000000, type: 0} + m_Tooltip: + m_Pos: + serializedVersion: 2 + x: -664.5 + y: 83 + width: 344.5 + height: 409.5 + m_ViewDataDictionary: {fileID: 0} + m_OverlayCanvas: + m_LastAppliedPresetName: Default + m_SaveData: [] + m_SceneHierarchy: + m_TreeViewState: + scrollPos: {x: 0, y: 0} + m_SelectedIDs: + m_LastClickedID: 0 + m_ExpandedIDs: aac0ffffbcc1ffffde990000f8990000 + m_RenameOverlay: + m_UserAcceptedRename: 0 + m_Name: + m_OriginalName: + m_EditFieldRect: + serializedVersion: 2 + x: 0 + y: 0 + width: 0 + height: 0 + m_UserData: 0 + m_IsWaitingForDelay: 0 + m_IsRenaming: 0 + m_OriginalEventType: 11 + m_IsRenamingFilename: 0 + m_ClientGUIView: {fileID: 8} + m_SearchString: + m_ExpandedScenes: [] + m_CurrenRootInstanceID: 0 + m_LockTracker: + m_IsLocked: 0 + m_CurrentSortingName: TransformSorting + m_WindowGUID: e1c71fe86c3f5471f87d740604c2690c +--- !u!114 &10 +MonoBehaviour: + m_ObjectHideFlags: 52 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 1 + m_Script: {fileID: 12006, guid: 0000000000000000e000000000000000, type: 0} + m_Name: ProjectBrowser + m_EditorClassIdentifier: + m_Children: [] + m_Position: + serializedVersion: 2 + x: 0 + y: 430.5 + width: 346.5 + height: 546.5 + m_MinSize: {x: 232, y: 271} + m_MaxSize: {x: 10002, y: 10021} + m_ActualView: {fileID: 11} + m_Panes: + - {fileID: 11} + - {fileID: 12} + m_Selected: 0 + m_LastSelected: 1 +--- !u!114 &11 +MonoBehaviour: + m_ObjectHideFlags: 52 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 1 + m_Script: {fileID: 12014, guid: 0000000000000000e000000000000000, type: 0} + m_Name: + m_EditorClassIdentifier: + m_MinSize: {x: 230, y: 250} + m_MaxSize: {x: 10000, y: 10000} + m_TitleContent: + m_Text: Project + m_Image: {fileID: -5179483145760003458, guid: 0000000000000000d000000000000000, type: 0} + m_Tooltip: + m_Pos: + serializedVersion: 2 + x: -664.5 + y: 513.5 + width: 344.5 + height: 525.5 + m_ViewDataDictionary: {fileID: 0} + m_OverlayCanvas: + m_LastAppliedPresetName: Default + m_SaveData: [] + m_SearchFilter: + m_NameFilter: + m_ClassNames: [] + m_AssetLabels: [] + m_AssetBundleNames: [] + m_VersionControlStates: [] + m_SoftLockControlStates: [] + m_ReferencingInstanceIDs: + m_SceneHandles: + m_ShowAllHits: 0 + m_SkipHidden: 0 + m_SearchArea: 1 + m_Folders: + - Assets/Scenes + m_Globs: [] + m_OriginalText: + m_ViewMode: 0 + m_StartGridSize: 64 + m_LastFolders: + - Assets + m_LastFoldersGridSize: -1 + m_LastProjectPath: "/Users/fantasy/Movies/\u90AE\u4EF6\u7CFB\u7EDF/Lession/Client/Unity" + m_LockTracker: + m_IsLocked: 0 + m_FolderTreeState: + scrollPos: {x: 0, y: 0} + m_SelectedIDs: 8c980000 + m_LastClickedID: 39052 + m_ExpandedIDs: ffffffff9a980000ce980000 + m_RenameOverlay: + m_UserAcceptedRename: 0 + m_Name: + m_OriginalName: + m_EditFieldRect: + serializedVersion: 2 + x: 0 + y: 0 + width: 0 + height: 0 + m_UserData: 0 + m_IsWaitingForDelay: 0 + m_IsRenaming: 0 + m_OriginalEventType: 11 + m_IsRenamingFilename: 1 + m_ClientGUIView: {fileID: 0} + m_SearchString: + m_CreateAssetUtility: + m_EndAction: {fileID: 0} + m_InstanceID: 0 + m_Path: + m_Icon: {fileID: 0} + m_ResourceFile: + m_AssetTreeState: + scrollPos: {x: 0, y: 0} + m_SelectedIDs: 5a990000 + m_LastClickedID: 0 + m_ExpandedIDs: ffffffff9a980000ce980000 + m_RenameOverlay: + m_UserAcceptedRename: 0 + m_Name: + m_OriginalName: + m_EditFieldRect: + serializedVersion: 2 + x: 0 + y: 0 + width: 0 + height: 0 + m_UserData: 0 + m_IsWaitingForDelay: 0 + m_IsRenaming: 0 + m_OriginalEventType: 11 + m_IsRenamingFilename: 1 + m_ClientGUIView: {fileID: 0} + m_SearchString: + m_CreateAssetUtility: + m_EndAction: {fileID: 0} + m_InstanceID: 0 + m_Path: + m_Icon: {fileID: 0} + m_ResourceFile: + m_ListAreaState: + m_SelectedInstanceIDs: 5a990000 + m_LastClickedInstanceID: 39258 + m_HadKeyboardFocusLastEvent: 0 + m_ExpandedInstanceIDs: c6230000 + m_RenameOverlay: + m_UserAcceptedRename: 0 + m_Name: + m_OriginalName: + m_EditFieldRect: + serializedVersion: 2 + x: 0 + y: 0 + width: 0 + height: 0 + m_UserData: 0 + m_IsWaitingForDelay: 0 + m_IsRenaming: 0 + m_OriginalEventType: 11 + m_IsRenamingFilename: 1 + m_ClientGUIView: {fileID: 0} + m_CreateAssetUtility: + m_EndAction: {fileID: 0} + m_InstanceID: 0 + m_Path: + m_Icon: {fileID: 0} + m_ResourceFile: + m_NewAssetIndexInList: -1 + m_ScrollPosition: {x: 0, y: 0} + m_GridSize: 64 + m_SkipHiddenPackages: 0 + m_DirectoriesAreaWidth: 115 +--- !u!114 &12 +MonoBehaviour: + m_ObjectHideFlags: 52 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 12003, guid: 0000000000000000e000000000000000, type: 0} + m_Name: + m_EditorClassIdentifier: + m_MinSize: {x: 100, y: 100} + m_MaxSize: {x: 4000, y: 4000} + m_TitleContent: + m_Text: Console + m_Image: {fileID: -4950941429401207979, guid: 0000000000000000d000000000000000, type: 0} + m_Tooltip: + m_Pos: + serializedVersion: 2 + x: -664.5 + y: 513.5 + width: 344.5 + height: 525.5 + m_ViewDataDictionary: {fileID: 0} + m_OverlayCanvas: + m_LastAppliedPresetName: Default + m_SaveData: [] +--- !u!114 &13 +MonoBehaviour: + m_ObjectHideFlags: 52 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 1 + m_Script: {fileID: 12006, guid: 0000000000000000e000000000000000, type: 0} + m_Name: + m_EditorClassIdentifier: + m_Children: [] + m_Position: + serializedVersion: 2 + x: 1602 + y: 0 + width: 318 + height: 977 + m_MinSize: {x: 275, y: 50} + m_MaxSize: {x: 4000, y: 4000} + m_ActualView: {fileID: 14} + m_Panes: + - {fileID: 14} + m_Selected: 0 + m_LastSelected: 0 +--- !u!114 &14 +MonoBehaviour: + m_ObjectHideFlags: 52 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 1 + m_Script: {fileID: 12019, guid: 0000000000000000e000000000000000, type: 0} + m_Name: + m_EditorClassIdentifier: + m_MinSize: {x: 275, y: 50} + m_MaxSize: {x: 4000, y: 4000} + m_TitleContent: + m_Text: Inspector + m_Image: {fileID: -440750813802333266, guid: 0000000000000000d000000000000000, type: 0} + m_Tooltip: + m_Pos: + serializedVersion: 2 + x: -318 + y: 83 + width: 317 + height: 956 + m_ViewDataDictionary: {fileID: 0} + m_OverlayCanvas: + m_LastAppliedPresetName: Default + m_SaveData: [] + m_ObjectsLockedBeforeSerialization: [] + m_InstanceIDsLockedBeforeSerialization: + m_PreviewResizer: + m_CachedPref: -160 + m_ControlHash: -371814159 + m_PrefName: Preview_InspectorPreview + m_LastInspectedObjectInstanceID: 39258 + m_LastVerticalScrollValue: 0 + m_GlobalObjectId: + m_InspectorMode: 0 + m_LockTracker: + m_IsLocked: 0 + m_PreviewWindow: {fileID: 0} diff --git a/邮件系统课程完整代码/Client/Unity/UserSettings/Layouts/default-2021.dwlt b/邮件系统课程完整代码/Client/Unity/UserSettings/Layouts/default-2021.dwlt new file mode 100644 index 0000000..c96e297 --- /dev/null +++ b/邮件系统课程完整代码/Client/Unity/UserSettings/Layouts/default-2021.dwlt @@ -0,0 +1,1022 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &1 +MonoBehaviour: + m_ObjectHideFlags: 52 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 1 + m_Script: {fileID: 12004, guid: 0000000000000000e000000000000000, type: 0} + m_Name: + m_EditorClassIdentifier: + m_PixelRect: + serializedVersion: 2 + x: -1921 + y: 53 + width: 1920 + height: 1027 + m_ShowMode: 4 + m_Title: Scene + m_RootView: {fileID: 2} + m_MinSize: {x: 875, y: 300} + m_MaxSize: {x: 10000, y: 10000} + m_Maximized: 1 +--- !u!114 &2 +MonoBehaviour: + m_ObjectHideFlags: 52 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 1 + m_Script: {fileID: 12008, guid: 0000000000000000e000000000000000, type: 0} + m_Name: + m_EditorClassIdentifier: + m_Children: + - {fileID: 3} + - {fileID: 5} + - {fileID: 4} + m_Position: + serializedVersion: 2 + x: 0 + y: 0 + width: 1920 + height: 1027 + m_MinSize: {x: 875, y: 300} + m_MaxSize: {x: 10000, y: 10000} + m_UseTopView: 1 + m_TopViewHeight: 30 + m_UseBottomView: 1 + m_BottomViewHeight: 20 +--- !u!114 &3 +MonoBehaviour: + m_ObjectHideFlags: 52 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 1 + m_Script: {fileID: 12011, guid: 0000000000000000e000000000000000, type: 0} + m_Name: + m_EditorClassIdentifier: + m_Children: [] + m_Position: + serializedVersion: 2 + x: 0 + y: 0 + width: 1920 + height: 30 + m_MinSize: {x: 0, y: 0} + m_MaxSize: {x: 0, y: 0} + m_LastLoadedLayoutName: +--- !u!114 &4 +MonoBehaviour: + m_ObjectHideFlags: 52 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 1 + m_Script: {fileID: 12042, guid: 0000000000000000e000000000000000, type: 0} + m_Name: + m_EditorClassIdentifier: + m_Children: [] + m_Position: + serializedVersion: 2 + x: 0 + y: 1007 + width: 1920 + height: 20 + m_MinSize: {x: 0, y: 0} + m_MaxSize: {x: 0, y: 0} +--- !u!114 &5 +MonoBehaviour: + m_ObjectHideFlags: 52 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 1 + m_Script: {fileID: 12010, guid: 0000000000000000e000000000000000, type: 0} + m_Name: + m_EditorClassIdentifier: + m_Children: + - {fileID: 6} + - {fileID: 9} + - {fileID: 12} + m_Position: + serializedVersion: 2 + x: 0 + y: 30 + width: 1920 + height: 977 + m_MinSize: {x: 300, y: 200} + m_MaxSize: {x: 24288, y: 16192} + vertical: 0 + controlID: 4099 +--- !u!114 &6 +MonoBehaviour: + m_ObjectHideFlags: 52 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 12010, guid: 0000000000000000e000000000000000, type: 0} + m_Name: + m_EditorClassIdentifier: + m_Children: + - {fileID: 7} + - {fileID: 8} + m_Position: + serializedVersion: 2 + x: 0 + y: 0 + width: 1255.5 + height: 977 + m_MinSize: {x: 100, y: 200} + m_MaxSize: {x: 8096, y: 16192} + vertical: 1 + controlID: 4077 +--- !u!114 &7 +MonoBehaviour: + m_ObjectHideFlags: 52 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 1 + m_Script: {fileID: 12006, guid: 0000000000000000e000000000000000, type: 0} + m_Name: SceneView + m_EditorClassIdentifier: + m_Children: [] + m_Position: + serializedVersion: 2 + x: 0 + y: 0 + width: 1255.5 + height: 650 + m_MinSize: {x: 201, y: 221} + m_MaxSize: {x: 4001, y: 4021} + m_ActualView: {fileID: 14} + m_Panes: + - {fileID: 14} + m_Selected: 0 + m_LastSelected: 0 +--- !u!114 &8 +MonoBehaviour: + m_ObjectHideFlags: 52 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 12006, guid: 0000000000000000e000000000000000, type: 0} + m_Name: GameView + m_EditorClassIdentifier: + m_Children: [] + m_Position: + serializedVersion: 2 + x: 0 + y: 650 + width: 1255.5 + height: 327 + m_MinSize: {x: 201, y: 221} + m_MaxSize: {x: 4001, y: 4021} + m_ActualView: {fileID: 13} + m_Panes: + - {fileID: 13} + m_Selected: 0 + m_LastSelected: 0 +--- !u!114 &9 +MonoBehaviour: + m_ObjectHideFlags: 52 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 1 + m_Script: {fileID: 12010, guid: 0000000000000000e000000000000000, type: 0} + m_Name: + m_EditorClassIdentifier: + m_Children: + - {fileID: 10} + - {fileID: 11} + m_Position: + serializedVersion: 2 + x: 1255.5 + y: 0 + width: 346.5 + height: 977 + m_MinSize: {x: 100, y: 200} + m_MaxSize: {x: 8096, y: 16192} + vertical: 1 + controlID: 4100 +--- !u!114 &10 +MonoBehaviour: + m_ObjectHideFlags: 52 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 1 + m_Script: {fileID: 12006, guid: 0000000000000000e000000000000000, type: 0} + m_Name: + m_EditorClassIdentifier: + m_Children: [] + m_Position: + serializedVersion: 2 + x: 0 + y: 0 + width: 346.5 + height: 430.5 + m_MinSize: {x: 201, y: 221} + m_MaxSize: {x: 4001, y: 4021} + m_ActualView: {fileID: 15} + m_Panes: + - {fileID: 15} + m_Selected: 0 + m_LastSelected: 0 +--- !u!114 &11 +MonoBehaviour: + m_ObjectHideFlags: 52 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 1 + m_Script: {fileID: 12006, guid: 0000000000000000e000000000000000, type: 0} + m_Name: ConsoleWindow + m_EditorClassIdentifier: + m_Children: [] + m_Position: + serializedVersion: 2 + x: 0 + y: 430.5 + width: 346.5 + height: 546.5 + m_MinSize: {x: 102, y: 121} + m_MaxSize: {x: 4002, y: 4021} + m_ActualView: {fileID: 17} + m_Panes: + - {fileID: 16} + - {fileID: 17} + m_Selected: 1 + m_LastSelected: 0 +--- !u!114 &12 +MonoBehaviour: + m_ObjectHideFlags: 52 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 1 + m_Script: {fileID: 12006, guid: 0000000000000000e000000000000000, type: 0} + m_Name: + m_EditorClassIdentifier: + m_Children: [] + m_Position: + serializedVersion: 2 + x: 1602 + y: 0 + width: 318 + height: 977 + m_MinSize: {x: 276, y: 71} + m_MaxSize: {x: 4001, y: 4021} + m_ActualView: {fileID: 18} + m_Panes: + - {fileID: 18} + m_Selected: 0 + m_LastSelected: 0 +--- !u!114 &13 +MonoBehaviour: + m_ObjectHideFlags: 52 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 1 + m_Script: {fileID: 12015, guid: 0000000000000000e000000000000000, type: 0} + m_Name: + m_EditorClassIdentifier: + m_MinSize: {x: 200, y: 200} + m_MaxSize: {x: 4000, y: 4000} + m_TitleContent: + m_Text: Game + m_Image: {fileID: 4621777727084837110, guid: 0000000000000000d000000000000000, type: 0} + m_Tooltip: + m_Pos: + serializedVersion: 2 + x: -1921 + y: 733 + width: 1254.5 + height: 306 + m_ViewDataDictionary: {fileID: 0} + m_OverlayCanvas: + m_LastAppliedPresetName: Default + m_SaveData: [] + m_SerializedViewNames: [] + m_SerializedViewValues: [] + m_PlayModeViewName: GameView + m_ShowGizmos: 0 + m_TargetDisplay: 0 + m_ClearColor: {r: 0, g: 0, b: 0, a: 0} + m_TargetSize: {x: 1013, y: 570} + m_TextureFilterMode: 0 + m_TextureHideFlags: 61 + m_RenderIMGUI: 1 + m_EnterPlayModeBehavior: 1 + m_UseMipMap: 0 + m_VSyncEnabled: 0 + m_Gizmos: 0 + m_Stats: 0 + m_SelectedSizes: 01000000000000000000000000000000000000000000000000000000000000000000000000000000 + m_ZoomArea: + m_HRangeLocked: 0 + m_VRangeLocked: 0 + hZoomLockedByDefault: 0 + vZoomLockedByDefault: 0 + m_HBaseRangeMin: -253.25 + m_HBaseRangeMax: 253.25 + m_VBaseRangeMin: -142.5 + m_VBaseRangeMax: 142.5 + m_HAllowExceedBaseRangeMin: 1 + m_HAllowExceedBaseRangeMax: 1 + m_VAllowExceedBaseRangeMin: 1 + m_VAllowExceedBaseRangeMax: 1 + m_ScaleWithWindow: 0 + m_HSlider: 0 + m_VSlider: 0 + m_IgnoreScrollWheelUntilClicked: 0 + m_EnableMouseInput: 1 + m_EnableSliderZoomHorizontal: 0 + m_EnableSliderZoomVertical: 0 + m_UniformScale: 1 + m_UpDirection: 1 + m_DrawArea: + serializedVersion: 2 + x: 0 + y: 21 + width: 1254.5 + height: 285 + m_Scale: {x: 1, y: 1} + m_Translation: {x: 627.25, y: 142.5} + m_MarginLeft: 0 + m_MarginRight: 0 + m_MarginTop: 0 + m_MarginBottom: 0 + m_LastShownAreaInsideMargins: + serializedVersion: 2 + x: -627.25 + y: -142.5 + width: 1254.5 + height: 285 + m_MinimalGUI: 1 + m_defaultScale: 1 + m_LastWindowPixelSize: {x: 2509, y: 612} + m_ClearInEditMode: 1 + m_NoCameraWarning: 1 + m_LowResolutionForAspectRatios: 00000000000000000000 + m_XRRenderMode: 0 + m_RenderTexture: {fileID: 0} +--- !u!114 &14 +MonoBehaviour: + m_ObjectHideFlags: 52 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 1 + m_Script: {fileID: 12013, guid: 0000000000000000e000000000000000, type: 0} + m_Name: + m_EditorClassIdentifier: + m_MinSize: {x: 200, y: 200} + m_MaxSize: {x: 4000, y: 4000} + m_TitleContent: + m_Text: Scene + m_Image: {fileID: 8634526014445323508, guid: 0000000000000000d000000000000000, type: 0} + m_Tooltip: + m_Pos: + serializedVersion: 2 + x: -1921 + y: 83 + width: 1254.5 + height: 629 + m_ViewDataDictionary: {fileID: 0} + m_OverlayCanvas: + m_LastAppliedPresetName: Default + m_SaveData: + - dockPosition: 0 + containerId: overlay-toolbar__top + floating: 0 + collapsed: 0 + displayed: 1 + snapOffset: {x: -101, y: -26} + snapOffsetDelta: {x: 0, y: 0} + snapCorner: 3 + id: Tool Settings + index: 0 + layout: 1 + - dockPosition: 0 + containerId: overlay-toolbar__top + floating: 0 + collapsed: 0 + displayed: 1 + snapOffset: {x: -141, y: 149} + snapOffsetDelta: {x: 0, y: 0} + snapCorner: 1 + id: unity-grid-and-snap-toolbar + index: 1 + layout: 1 + - dockPosition: 1 + containerId: overlay-toolbar__top + floating: 0 + collapsed: 0 + displayed: 1 + snapOffset: {x: 0, y: 0} + snapOffsetDelta: {x: 0, y: 0} + snapCorner: 0 + id: unity-scene-view-toolbar + index: 0 + layout: 1 + - dockPosition: 1 + containerId: overlay-toolbar__top + floating: 0 + collapsed: 0 + displayed: 0 + snapOffset: {x: 0, y: 0} + snapOffsetDelta: {x: 0, y: 0} + snapCorner: 1 + id: unity-search-toolbar + index: 1 + layout: 1 + - dockPosition: 0 + containerId: overlay-container--left + floating: 0 + collapsed: 0 + displayed: 1 + snapOffset: {x: 0, y: 0} + snapOffsetDelta: {x: 0, y: 0} + snapCorner: 0 + id: unity-transform-toolbar + index: 0 + layout: 2 + - dockPosition: 0 + containerId: overlay-container--left + floating: 0 + collapsed: 0 + displayed: 1 + snapOffset: {x: 0, y: 197} + snapOffsetDelta: {x: 0, y: 0} + snapCorner: 0 + id: unity-component-tools + index: 1 + layout: 2 + - dockPosition: 0 + containerId: overlay-container--right + floating: 0 + collapsed: 0 + displayed: 1 + snapOffset: {x: 67.5, y: 86} + snapOffsetDelta: {x: 0, y: 0} + snapCorner: 0 + id: Orientation + index: 0 + layout: 4 + - dockPosition: 1 + containerId: overlay-container--right + floating: 0 + collapsed: 0 + displayed: 0 + snapOffset: {x: 0, y: 0} + snapOffsetDelta: {x: 0, y: 0} + snapCorner: 0 + id: Scene View/Light Settings + index: 0 + layout: 4 + - dockPosition: 1 + containerId: overlay-container--right + floating: 0 + collapsed: 0 + displayed: 0 + snapOffset: {x: 0, y: 0} + snapOffsetDelta: {x: 0, y: 0} + snapCorner: 0 + id: Scene View/Camera + index: 1 + layout: 4 + - dockPosition: 1 + containerId: overlay-container--right + floating: 0 + collapsed: 0 + displayed: 0 + snapOffset: {x: 0, y: 0} + snapOffsetDelta: {x: 0, y: 0} + snapCorner: 0 + id: Scene View/Cloth Constraints + index: 2 + layout: 4 + - dockPosition: 1 + containerId: overlay-container--right + floating: 0 + collapsed: 0 + displayed: 0 + snapOffset: {x: 0, y: 0} + snapOffsetDelta: {x: 0, y: 0} + snapCorner: 0 + id: Scene View/Cloth Collisions + index: 3 + layout: 4 + - dockPosition: 1 + containerId: overlay-container--right + floating: 0 + collapsed: 0 + displayed: 0 + snapOffset: {x: 0, y: 0} + snapOffsetDelta: {x: 0, y: 0} + snapCorner: 0 + id: Scene View/Navmesh Display + index: 4 + layout: 4 + - dockPosition: 1 + containerId: overlay-container--right + floating: 0 + collapsed: 0 + displayed: 0 + snapOffset: {x: 0, y: 0} + snapOffsetDelta: {x: 0, y: 0} + snapCorner: 0 + id: Scene View/Agent Display + index: 5 + layout: 4 + - dockPosition: 1 + containerId: overlay-container--right + floating: 0 + collapsed: 0 + displayed: 0 + snapOffset: {x: 0, y: 0} + snapOffsetDelta: {x: 0, y: 0} + snapCorner: 0 + id: Scene View/Obstacle Display + index: 6 + layout: 4 + - dockPosition: 1 + containerId: overlay-container--right + floating: 0 + collapsed: 0 + displayed: 0 + snapOffset: {x: 0, y: 0} + snapOffsetDelta: {x: 0, y: 0} + snapCorner: 0 + id: Scene View/Occlusion Culling + index: 7 + layout: 4 + - dockPosition: 1 + containerId: overlay-container--right + floating: 0 + collapsed: 0 + displayed: 0 + snapOffset: {x: 0, y: 0} + snapOffsetDelta: {x: 0, y: 0} + snapCorner: 0 + id: Scene View/Physics Debugger + index: 8 + layout: 4 + - dockPosition: 1 + containerId: overlay-container--right + floating: 0 + collapsed: 0 + displayed: 0 + snapOffset: {x: 0, y: 0} + snapOffsetDelta: {x: 0, y: 0} + snapCorner: 0 + id: Scene View/Scene Visibility + index: 9 + layout: 4 + - dockPosition: 1 + containerId: overlay-container--right + floating: 0 + collapsed: 0 + displayed: 0 + snapOffset: {x: 0, y: 0} + snapOffsetDelta: {x: 0, y: 0} + snapCorner: 0 + id: Scene View/Particles + index: 10 + layout: 4 + - dockPosition: 1 + containerId: overlay-container--right + floating: 0 + collapsed: 0 + displayed: 0 + snapOffset: {x: 0, y: 0} + snapOffsetDelta: {x: 0, y: 0} + snapCorner: 0 + id: Scene View/Tilemap + index: 11 + layout: 4 + - dockPosition: 1 + containerId: overlay-container--right + floating: 0 + collapsed: 0 + displayed: 0 + snapOffset: {x: 0, y: 0} + snapOffsetDelta: {x: 0, y: 0} + snapCorner: 0 + id: Scene View/Tilemap Palette Helper + index: 12 + layout: 4 + - dockPosition: 1 + containerId: overlay-toolbar__top + floating: 0 + collapsed: 0 + displayed: 0 + snapOffset: {x: 0, y: 0} + snapOffsetDelta: {x: 0, y: 0} + snapCorner: 0 + id: Scene View/Open Tile Palette + index: 2 + layout: 4 + - dockPosition: 1 + containerId: overlay-toolbar__top + floating: 0 + collapsed: 0 + displayed: 0 + snapOffset: {x: 0, y: 0} + snapOffsetDelta: {x: 0, y: 0} + snapCorner: 0 + id: Scene View/Tilemap Focus + index: 3 + layout: 4 + m_WindowGUID: a9b755b8a23b944249716e5248d146c0 + m_Gizmos: 1 + m_OverrideSceneCullingMask: 6917529027641081856 + m_SceneIsLit: 1 + m_SceneLighting: 1 + m_2DMode: 1 + m_isRotationLocked: 0 + m_PlayAudio: 0 + m_AudioPlay: 0 + m_Position: + m_Target: {x: 489.70132, y: 249.58237, z: -7.293578} + speed: 2 + m_Value: {x: 489.70132, y: 249.58237, z: -7.293578} + m_RenderMode: 0 + m_CameraMode: + drawMode: 0 + name: Shaded + section: Shading Mode + m_ValidateTrueMetals: 0 + m_DoValidateTrueMetals: 0 + m_ExposureSliderValue: 0 + m_SceneViewState: + m_AlwaysRefresh: 0 + showFog: 1 + showSkybox: 1 + showFlares: 1 + showImageEffects: 1 + showParticleSystems: 1 + showVisualEffectGraphs: 1 + m_FxEnabled: 1 + m_Grid: + xGrid: + m_Fade: + m_Target: 0 + speed: 2 + m_Value: 0 + m_Color: {r: 0.5, g: 0.5, b: 0.5, a: 0.4} + m_Pivot: {x: 0, y: 0, z: 0} + m_Size: {x: 0, y: 0} + yGrid: + m_Fade: + m_Target: 0 + speed: 2 + m_Value: 0 + m_Color: {r: 0.5, g: 0.5, b: 0.5, a: 0.4} + m_Pivot: {x: 0, y: 0, z: 0} + m_Size: {x: 0, y: 0} + zGrid: + m_Fade: + m_Target: 1 + speed: 2 + m_Value: 1 + m_Color: {r: 0.5, g: 0.5, b: 0.5, a: 0.4} + m_Pivot: {x: 0, y: 0, z: 0} + m_Size: {x: 1, y: 1} + m_ShowGrid: 1 + m_GridAxis: 1 + m_gridOpacity: 0.5 + m_Rotation: + m_Target: {x: 0, y: 0, z: 0, w: 1} + speed: 2 + m_Value: {x: 0, y: 0, z: 0, w: 1} + m_Size: + m_Target: 316.5856 + speed: 2 + m_Value: 316.5856 + m_Ortho: + m_Target: 1 + speed: 2 + m_Value: 1 + m_CameraSettings: + m_Speed: 1 + m_SpeedNormalized: 0.5 + m_SpeedMin: 0.01 + m_SpeedMax: 2 + m_EasingEnabled: 1 + m_EasingDuration: 0.4 + m_AccelerationEnabled: 1 + m_FieldOfViewHorizontalOrVertical: 60 + m_NearClip: 0.03 + m_FarClip: 10000 + m_DynamicClip: 1 + m_OcclusionCulling: 0 + m_LastSceneViewRotation: {x: -0.08717229, y: 0.89959055, z: -0.21045254, w: -0.3726226} + m_LastSceneViewOrtho: 0 + m_ReplacementShader: {fileID: 0} + m_ReplacementString: + m_SceneVisActive: 1 + m_LastLockedObject: {fileID: 0} + m_ViewIsLockedToObject: 0 +--- !u!114 &15 +MonoBehaviour: + m_ObjectHideFlags: 52 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 1 + m_Script: {fileID: 12061, guid: 0000000000000000e000000000000000, type: 0} + m_Name: + m_EditorClassIdentifier: + m_MinSize: {x: 200, y: 200} + m_MaxSize: {x: 4000, y: 4000} + m_TitleContent: + m_Text: Hierarchy + m_Image: {fileID: -3734745235275155857, guid: 0000000000000000d000000000000000, type: 0} + m_Tooltip: + m_Pos: + serializedVersion: 2 + x: -665.5 + y: 83 + width: 344.5 + height: 409.5 + m_ViewDataDictionary: {fileID: 0} + m_OverlayCanvas: + m_LastAppliedPresetName: Default + m_SaveData: [] + m_SceneHierarchy: + m_TreeViewState: + scrollPos: {x: 0, y: 0} + m_SelectedIDs: f8990000 + m_LastClickedID: 39416 + m_ExpandedIDs: aac0ffffbcc1ffffa8990000b2990000de990000f8990000 + m_RenameOverlay: + m_UserAcceptedRename: 0 + m_Name: + m_OriginalName: + m_EditFieldRect: + serializedVersion: 2 + x: 0 + y: 0 + width: 0 + height: 0 + m_UserData: 0 + m_IsWaitingForDelay: 0 + m_IsRenaming: 0 + m_OriginalEventType: 11 + m_IsRenamingFilename: 0 + m_ClientGUIView: {fileID: 10} + m_SearchString: + m_ExpandedScenes: [] + m_CurrenRootInstanceID: 0 + m_LockTracker: + m_IsLocked: 0 + m_CurrentSortingName: TransformSorting + m_WindowGUID: e1c71fe86c3f5471f87d740604c2690c +--- !u!114 &16 +MonoBehaviour: + m_ObjectHideFlags: 52 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 1 + m_Script: {fileID: 12014, guid: 0000000000000000e000000000000000, type: 0} + m_Name: + m_EditorClassIdentifier: + m_MinSize: {x: 230, y: 250} + m_MaxSize: {x: 10000, y: 10000} + m_TitleContent: + m_Text: Project + m_Image: {fileID: -5179483145760003458, guid: 0000000000000000d000000000000000, type: 0} + m_Tooltip: + m_Pos: + serializedVersion: 2 + x: -664.5 + y: 513.5 + width: 344.5 + height: 525.5 + m_ViewDataDictionary: {fileID: 0} + m_OverlayCanvas: + m_LastAppliedPresetName: Default + m_SaveData: [] + m_SearchFilter: + m_NameFilter: + m_ClassNames: [] + m_AssetLabels: [] + m_AssetBundleNames: [] + m_VersionControlStates: [] + m_SoftLockControlStates: [] + m_ReferencingInstanceIDs: + m_SceneHandles: + m_ShowAllHits: 0 + m_SkipHidden: 0 + m_SearchArea: 1 + m_Folders: + - Assets/Scenes + m_Globs: [] + m_OriginalText: + m_ViewMode: 0 + m_StartGridSize: 64 + m_LastFolders: + - Assets + m_LastFoldersGridSize: -1 + m_LastProjectPath: "/Users/fantasy/Movies/\u90AE\u4EF6\u7CFB\u7EDF/Lession/Client/Unity" + m_LockTracker: + m_IsLocked: 0 + m_FolderTreeState: + scrollPos: {x: 0, y: 0} + m_SelectedIDs: 8c980000 + m_LastClickedID: 39052 + m_ExpandedIDs: ffffffff9a980000ce980000 + m_RenameOverlay: + m_UserAcceptedRename: 0 + m_Name: + m_OriginalName: + m_EditFieldRect: + serializedVersion: 2 + x: 0 + y: 0 + width: 0 + height: 0 + m_UserData: 0 + m_IsWaitingForDelay: 0 + m_IsRenaming: 0 + m_OriginalEventType: 11 + m_IsRenamingFilename: 1 + m_ClientGUIView: {fileID: 0} + m_SearchString: + m_CreateAssetUtility: + m_EndAction: {fileID: 0} + m_InstanceID: 0 + m_Path: + m_Icon: {fileID: 0} + m_ResourceFile: + m_AssetTreeState: + scrollPos: {x: 0, y: 0} + m_SelectedIDs: 5a990000 + m_LastClickedID: 0 + m_ExpandedIDs: ffffffff9a980000ce980000 + m_RenameOverlay: + m_UserAcceptedRename: 0 + m_Name: + m_OriginalName: + m_EditFieldRect: + serializedVersion: 2 + x: 0 + y: 0 + width: 0 + height: 0 + m_UserData: 0 + m_IsWaitingForDelay: 0 + m_IsRenaming: 0 + m_OriginalEventType: 11 + m_IsRenamingFilename: 1 + m_ClientGUIView: {fileID: 0} + m_SearchString: + m_CreateAssetUtility: + m_EndAction: {fileID: 0} + m_InstanceID: 0 + m_Path: + m_Icon: {fileID: 0} + m_ResourceFile: + m_ListAreaState: + m_SelectedInstanceIDs: 5a990000 + m_LastClickedInstanceID: 39258 + m_HadKeyboardFocusLastEvent: 0 + m_ExpandedInstanceIDs: c6230000 + m_RenameOverlay: + m_UserAcceptedRename: 0 + m_Name: + m_OriginalName: + m_EditFieldRect: + serializedVersion: 2 + x: 0 + y: 0 + width: 0 + height: 0 + m_UserData: 0 + m_IsWaitingForDelay: 0 + m_IsRenaming: 0 + m_OriginalEventType: 11 + m_IsRenamingFilename: 1 + m_ClientGUIView: {fileID: 0} + m_CreateAssetUtility: + m_EndAction: {fileID: 0} + m_InstanceID: 0 + m_Path: + m_Icon: {fileID: 0} + m_ResourceFile: + m_NewAssetIndexInList: -1 + m_ScrollPosition: {x: 0, y: 0} + m_GridSize: 64 + m_SkipHiddenPackages: 0 + m_DirectoriesAreaWidth: 115 +--- !u!114 &17 +MonoBehaviour: + m_ObjectHideFlags: 52 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 12003, guid: 0000000000000000e000000000000000, type: 0} + m_Name: + m_EditorClassIdentifier: + m_MinSize: {x: 100, y: 100} + m_MaxSize: {x: 4000, y: 4000} + m_TitleContent: + m_Text: Console + m_Image: {fileID: -4950941429401207979, guid: 0000000000000000d000000000000000, type: 0} + m_Tooltip: + m_Pos: + serializedVersion: 2 + x: -665.5 + y: 513.5 + width: 344.5 + height: 525.5 + m_ViewDataDictionary: {fileID: 0} + m_OverlayCanvas: + m_LastAppliedPresetName: Default + m_SaveData: [] +--- !u!114 &18 +MonoBehaviour: + m_ObjectHideFlags: 52 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 1 + m_Script: {fileID: 12019, guid: 0000000000000000e000000000000000, type: 0} + m_Name: + m_EditorClassIdentifier: + m_MinSize: {x: 275, y: 50} + m_MaxSize: {x: 4000, y: 4000} + m_TitleContent: + m_Text: Inspector + m_Image: {fileID: -440750813802333266, guid: 0000000000000000d000000000000000, type: 0} + m_Tooltip: + m_Pos: + serializedVersion: 2 + x: -319 + y: 83 + width: 317 + height: 956 + m_ViewDataDictionary: {fileID: 0} + m_OverlayCanvas: + m_LastAppliedPresetName: Default + m_SaveData: [] + m_ObjectsLockedBeforeSerialization: [] + m_InstanceIDsLockedBeforeSerialization: + m_PreviewResizer: + m_CachedPref: -160 + m_ControlHash: -371814159 + m_PrefName: Preview_InspectorPreview + m_LastInspectedObjectInstanceID: -1 + m_LastVerticalScrollValue: 0 + m_GlobalObjectId: + m_InspectorMode: 0 + m_LockTracker: + m_IsLocked: 0 + m_PreviewWindow: {fileID: 0} diff --git a/邮件系统课程完整代码/Client/Unity/UserSettings/Search.settings b/邮件系统课程完整代码/Client/Unity/UserSettings/Search.settings new file mode 100644 index 0000000..9e26dfe --- /dev/null +++ b/邮件系统课程完整代码/Client/Unity/UserSettings/Search.settings @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/邮件系统课程完整代码/Config/.DS_Store b/邮件系统课程完整代码/Config/.DS_Store new file mode 100644 index 0000000..f2c55b4 Binary files /dev/null and b/邮件系统课程完整代码/Config/.DS_Store differ diff --git a/邮件系统课程完整代码/Config/Binary/MachineConfigData.bytes b/邮件系统课程完整代码/Config/Binary/MachineConfigData.bytes new file mode 100644 index 0000000..d4ebe57 --- /dev/null +++ b/邮件系统课程完整代码/Config/Binary/MachineConfigData.bytes @@ -0,0 +1,2 @@ + +# 127.0.0.1 127.0.0.1" 127.0.0.1 \ No newline at end of file diff --git a/邮件系统课程完整代码/Config/Binary/ProcessConfigData.bytes b/邮件系统课程完整代码/Config/Binary/ProcessConfigData.bytes new file mode 100644 index 0000000..b9c2dfd --- /dev/null +++ b/邮件系统课程完整代码/Config/Binary/ProcessConfigData.bytes @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/邮件系统课程完整代码/Config/Binary/SceneConfigData.bytes b/邮件系统课程完整代码/Config/Binary/SceneConfigData.bytes new file mode 100644 index 0000000..27bfc6c --- /dev/null +++ b/邮件系统课程完整代码/Config/Binary/SceneConfigData.bytes @@ -0,0 +1,5 @@ + +&" MultiThread* Addressable@UH +(" MultiThread*Gate2KCP8@UH +" MultiThread*Map@UH +" MultiThread*Mail@UH \ No newline at end of file diff --git a/邮件系统课程完整代码/Config/Binary/WorldConfigData.bytes b/邮件系统课程完整代码/Config/Binary/WorldConfigData.bytes new file mode 100644 index 0000000..0ad1979 --- /dev/null +++ b/邮件系统课程完整代码/Config/Binary/WorldConfigData.bytes @@ -0,0 +1,2 @@ + +9 测试服mongodb://127.0.0.1" fantasy_mail*MongoDB \ No newline at end of file diff --git a/邮件系统课程完整代码/Config/Excel/.DS_Store b/邮件系统课程完整代码/Config/Excel/.DS_Store new file mode 100644 index 0000000..bdc181f Binary files /dev/null and b/邮件系统课程完整代码/Config/Excel/.DS_Store differ diff --git a/邮件系统课程完整代码/Config/Excel/Custom.txt b/邮件系统课程完整代码/Config/Excel/Custom.txt new file mode 100644 index 0000000..fd90a9b --- /dev/null +++ b/邮件系统课程完整代码/Config/Excel/Custom.txt @@ -0,0 +1 @@ +// 自定义导出配置文件,用于配置自定义导出自定义程序的路径 diff --git a/邮件系统课程完整代码/Config/Excel/Server/MachineConfig.xlsx b/邮件系统课程完整代码/Config/Excel/Server/MachineConfig.xlsx new file mode 100644 index 0000000..a2e8902 Binary files /dev/null and b/邮件系统课程完整代码/Config/Excel/Server/MachineConfig.xlsx differ diff --git a/邮件系统课程完整代码/Config/Excel/Server/ProcessConfig.xlsx b/邮件系统课程完整代码/Config/Excel/Server/ProcessConfig.xlsx new file mode 100644 index 0000000..001235a Binary files /dev/null and b/邮件系统课程完整代码/Config/Excel/Server/ProcessConfig.xlsx differ diff --git a/邮件系统课程完整代码/Config/Excel/Server/SceneConfig.xlsx b/邮件系统课程完整代码/Config/Excel/Server/SceneConfig.xlsx new file mode 100644 index 0000000..a1a1afc Binary files /dev/null and b/邮件系统课程完整代码/Config/Excel/Server/SceneConfig.xlsx differ diff --git a/邮件系统课程完整代码/Config/Excel/Server/WorldConfig.xlsx b/邮件系统课程完整代码/Config/Excel/Server/WorldConfig.xlsx new file mode 100644 index 0000000..ff84ce0 Binary files /dev/null and b/邮件系统课程完整代码/Config/Excel/Server/WorldConfig.xlsx differ diff --git a/邮件系统课程完整代码/Config/Excel/Version.txt b/邮件系统课程完整代码/Config/Excel/Version.txt new file mode 100644 index 0000000..ec7cf50 --- /dev/null +++ b/邮件系统课程完整代码/Config/Excel/Version.txt @@ -0,0 +1 @@ +{"WorksheetNames":["ProcessConfig","MachineConfig","WorldConfig","SceneConfig","SceneTypeConfig"],"Tables":{"MachineConfig":1739296621442,"SceneConfig":1739530293874,"WorldConfig":1739530344968,"ProcessConfig":1727164776000}} \ No newline at end of file diff --git a/邮件系统课程完整代码/Config/Json/.DS_Store b/邮件系统课程完整代码/Config/Json/.DS_Store new file mode 100644 index 0000000..935c14d Binary files /dev/null and b/邮件系统课程完整代码/Config/Json/.DS_Store differ diff --git a/邮件系统课程完整代码/Config/Json/Server/MachineConfigData.Json b/邮件系统课程完整代码/Config/Json/Server/MachineConfigData.Json new file mode 100644 index 0000000..f56f98e --- /dev/null +++ b/邮件系统课程完整代码/Config/Json/Server/MachineConfigData.Json @@ -0,0 +1,3 @@ +{"List":[ +{"Id":1,"OuterIP":"127.0.0.1","OuterBindIP":"127.0.0.1","InnerBindIP":"127.0.0.1"} +]} diff --git a/邮件系统课程完整代码/Config/Json/Server/ProcessConfigData.Json b/邮件系统课程完整代码/Config/Json/Server/ProcessConfigData.Json new file mode 100644 index 0000000..a05a13c --- /dev/null +++ b/邮件系统课程完整代码/Config/Json/Server/ProcessConfigData.Json @@ -0,0 +1,3 @@ +{"List":[ +{"Id":1,"MachineId":1,"StartupGroup":0} +]} diff --git a/邮件系统课程完整代码/Config/Json/Server/SceneConfigData.Json b/邮件系统课程完整代码/Config/Json/Server/SceneConfigData.Json new file mode 100644 index 0000000..40862e7 --- /dev/null +++ b/邮件系统课程完整代码/Config/Json/Server/SceneConfigData.Json @@ -0,0 +1,6 @@ +{"List":[ +{"Id":1001,"ProcessConfigId":1,"WorldConfigId":1,"SceneRuntimeType":"MultiThread","SceneTypeString":"Addressable","NetworkProtocol":null,"OuterPort":0,"InnerPort":11001,"SceneType":2}, +{"Id":1002,"ProcessConfigId":1,"WorldConfigId":1,"SceneRuntimeType":"MultiThread","SceneTypeString":"Gate","NetworkProtocol":"KCP","OuterPort":20000,"InnerPort":11002,"SceneType":3}, +{"Id":1003,"ProcessConfigId":1,"WorldConfigId":1,"SceneRuntimeType":"MultiThread","SceneTypeString":"Map","NetworkProtocol":null,"OuterPort":0,"InnerPort":11003,"SceneType":4}, +{"Id":1004,"ProcessConfigId":1,"WorldConfigId":1,"SceneRuntimeType":"MultiThread","SceneTypeString":"Mail","NetworkProtocol":null,"OuterPort":0,"InnerPort":11004,"SceneType":9} +]} diff --git a/邮件系统课程完整代码/Config/Json/Server/WorldConfigData.Json b/邮件系统课程完整代码/Config/Json/Server/WorldConfigData.Json new file mode 100644 index 0000000..7f28f8c --- /dev/null +++ b/邮件系统课程完整代码/Config/Json/Server/WorldConfigData.Json @@ -0,0 +1,3 @@ +{"List":[ +{"Id":1,"WorldName":"测试服","DbConnection":"mongodb://127.0.0.1","DbName":"fantasy_mail","DbType":"MongoDB"} +]} diff --git a/邮件系统课程完整代码/Config/NetworkProtocol/.DS_Store b/邮件系统课程完整代码/Config/NetworkProtocol/.DS_Store new file mode 100644 index 0000000..dcfac20 Binary files /dev/null and b/邮件系统课程完整代码/Config/NetworkProtocol/.DS_Store differ diff --git a/邮件系统课程完整代码/Config/NetworkProtocol/Inner/InnerMessage.proto b/邮件系统课程完整代码/Config/NetworkProtocol/Inner/InnerMessage.proto new file mode 100644 index 0000000..bc83976 --- /dev/null +++ b/邮件系统课程完整代码/Config/NetworkProtocol/Inner/InnerMessage.proto @@ -0,0 +1,38 @@ +syntax = "proto3"; +package Sining.Message; +/// Gate服务器登陆到Mail服务器 +message G2Mail_LoginRequest // IRouteRequest,Mail2G_LoginResponse +{ + string Name = 1; + int64 AccountId = 2; + int64 CreateTime = 3; + int64 GateRouteId = 4; +} +message Mail2G_LoginResponse // IRouteResponse +{ + int64 MailUnitRouteId = 1; +} +/// 发送一个Gate服务器发送给Mail之间的测试协议 +message G2Mail_TestMessage // IRouteMessage +{ + string Tag = 1; +} +/// 发送给Mail服务器进行下线 +message G2Mail_ExitRequest // IRouteRequest,Mail2G_ExitResponse +{ + +} +message Mail2G_ExitResponse // IRouteResponse +{ + +} +/// 其他服务器发送邮件 +// Protocol Bson +message Other2Mail_SendMailRequest // IRouteRequest,Mail2Other_SendMailResponse +{ + MailBox MailBox = 1; +} +message Mail2Other_SendMailResponse // IRouteResponse +{ + +} \ No newline at end of file diff --git a/邮件系统课程完整代码/Config/NetworkProtocol/OpCode.Cache b/邮件系统课程完整代码/Config/NetworkProtocol/OpCode.Cache new file mode 100644 index 0000000..9e26dfe --- /dev/null +++ b/邮件系统课程完整代码/Config/NetworkProtocol/OpCode.Cache @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/邮件系统课程完整代码/Config/NetworkProtocol/Outer/OuterMessage.proto b/邮件系统课程完整代码/Config/NetworkProtocol/Outer/OuterMessage.proto new file mode 100644 index 0000000..72b73bd --- /dev/null +++ b/邮件系统课程完整代码/Config/NetworkProtocol/Outer/OuterMessage.proto @@ -0,0 +1,165 @@ +syntax = "proto3"; +package Fantasy.Network.Message; +// 协议分为: +// ProtoBuf:可以在Outer和Inner文件里使用。 +// MemoryPack:可以在Outer和Inner文件里使用。 +// Bson:仅支持在Inner文件里使用。 +// 使用方式: +// 在message协议上方添加// Protocol+空格+协议名字 +// 例如:// Protocol ProtoBuf 或 // Protocol MemoryPack +/// 登陆到Gate服务器 +message C2G_LoginRequest // IRequest,G2C_LoginResponse +{ + string Name = 1; // 登陆的用户名,现在情况下是如果不存在服务器会自动创建一个新的账号。 +} +message G2C_LoginResponse // IResponse +{ + +} +/// 客户端通知服务器退出游戏 +message C2G_Exit // IMessage +{ + +} +/// 测试Mail自定义Route协议 +message C2Mail_TestRequest // ICustomRouteRequest,Mail2C_TestResponse,MailRoute +{ + string Tag = 1; +} +message Mail2C_TestResponse // ICustomRouteResponse +{ + string Tag = 1; +} +/// 一个邮件的完整信息 +message MailInfo +{ + int64 MailId = 1; + int64 OwnerId = 2; + string Title = 3; + string Content = 4; + int64 CreateTime = 5; + int64 ExpireTime = 6; + int32 Money = 7; + int32 MailState = 8; + int32 MailType = 9; + repeated ItemInfo Items = 10; +} +/// 一个邮件的简单版消息 +message MailSimplifyInfo +{ + int64 MailId = 1; + int64 OwnerId = 2; + string Title = 3; + string Content = 4; + int64 CreateTime = 5; + int64 ExpireTime = 6; + int32 MailState = 7; + int32 MailType = 8; + +} +/// 一个简单的物品信息 +message ItemInfo +{ + int64 ItemId = 1; + string Name = 2; +} +/// Mail通知客户端有新的邮件 +message Mail2C_HaveMail // ICustomRouteMessage,MailRoute +{ + MailSimplifyInfo Mail = 1; +} +/// Mail通知客户端邮件状态变化 +message Mail2C_MailState // ICustomRouteMessage,MailRoute +{ + int32 MailState = 1; + int64 MailId = 2; +} +/// 客户端获取档期所有邮件的信息 +message C2Mail_GetHaveMailRequest // ICustomRouteRequest,Mail2C_GetHaveMailResposne,MailRoute +{ + +} +message Mail2C_GetHaveMailResposne // ICustomRouteResponse +{ + repeated MailSimplifyInfo Mails = 1; +} +/// 客户端发开一个邮件 +message C2Mail_OpenMailRequest // ICustomRouteRequest,Mail2C_OpenMailResposne,MailRoute +{ + int64 MailId = 1; + bool ReturnMailInfo = 2; +} +message Mail2C_OpenMailResposne // ICustomRouteResponse +{ + MailInfo MailInfo = 1; +} +/// 客户端领取邮件的附件 +message C2Mail_ReceiveMailRequest // ICustomRouteRequest,Mail2C_ReceiveMailResponse,MailRoute +{ + int64 MailId = 1; + bool Money = 2; + repeated int64 ItemId = 3; +} +message Mail2C_ReceiveMailResponse // ICustomRouteResponse +{ + +} +/// 客户端通知服务器删除一个邮件 +message C2Mail_RemoveMailRequest // ICustomRouteRequest,Mail2C_RemoveMailResponse,MailRoute +{ + int64 MailId = 1; +} +message Mail2C_RemoveMailResponse // ICustomRouteResponse +{ + +} +/// 客户端玩家发送邮件到另外一个玩家 +message C2Mail_SendMailRequest // ICustomRouteRequest,Mail2C_SendMailResponse,MailRoute +{ + string UserName = 1; + string Title = 2; + string Content = 3; + int32 Money = 4; + repeated int64 ItemId = 5; +} +message Mail2C_SendMailResponse // ICustomRouteResponse +{ + +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/邮件系统课程完整代码/Config/NetworkProtocol/RouteType.Config b/邮件系统课程完整代码/Config/NetworkProtocol/RouteType.Config new file mode 100644 index 0000000..8b02acc --- /dev/null +++ b/邮件系统课程完整代码/Config/NetworkProtocol/RouteType.Config @@ -0,0 +1,2 @@ +// Route协议定义(需要定义1000以上、因为1000以内的框架预留) +MailRoute = 1001 // Mail \ No newline at end of file diff --git a/邮件系统课程完整代码/Config/README.md b/邮件系统课程完整代码/Config/README.md new file mode 100644 index 0000000..697ec05 --- /dev/null +++ b/邮件系统课程完整代码/Config/README.md @@ -0,0 +1,16 @@ +# Fantasy-Net.Config +在Config文件夹中,存放着Fantasy所需的各种配置文件。这些文件涵盖了多个方面。每个配置文件都有其特定的格式和功能,通过精心设计的这些配置文件,开发团队能够快速调整框架参数,以实现更好的游戏体验,从而提升Fantasy的整体质量。 +## Excel文件夹 +里面存放了Fantasy.Net所需的四个Excel配置文件。用户可以利用Fantasy-Net.Exporter工具,依据这四个Excel文件生成相应的JSON文件,以供框架使用。这一过程不仅简化了数据处理,还确保了不同组件之间的无缝对接,使得工作流程更加高效。请确保在导出之前,Excel文件的格式和内容符合要求,以避免产生错误。 +## Json文件夹 +在该目录中存放了Fantasy.Net所需的四个JSON配置文件。用户可以根据这四个文件的模板进行添加或修改配置,以满足具体需求。每个项目的功能说明在相应的Excel文件中有详细描述,方便用户理解和使用这些配置文件。我们建议用户仔细阅读Excel文件中的说明,以确保配置的正确性和有效性。 +## NetworkProtocol文件夹 +存放框架所需定义网络协议的模版和文件夹 +### Inner文件夹 +定义服务器之间的网络协议 +### Outer文件夹 +定义客户端和服务器之间的网络协议 +### RouteType.Config +定义自定义Route协议的配置文件 +## 交流与讨论: +__讨论QQ群 : Fantasy服务器开发交流群 569888673 __ \ No newline at end of file diff --git a/邮件系统课程完整代码/Mail.sln b/邮件系统课程完整代码/Mail.sln new file mode 100644 index 0000000..8c34602 --- /dev/null +++ b/邮件系统课程完整代码/Mail.sln @@ -0,0 +1,67 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "NuGet", "NuGet", "{1221594F-E9BA-4567-9E5B-A12011ABF2C7}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Client", "Client", "{A3F59C11-8619-42AF-90A0-88CFB8FA784F}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Server", "Server", "{6FA2590F-A0D4-4DD5-8D14-88C11F8914DA}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "App", "Server\App\App.csproj", "{D31887AB-26E0-46EB-AFCA-C7BB2B76071D}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Hotfix", "Server\Hotfix\Hotfix.csproj", "{392ADC21-14BA-49EB-A364-ADFCF818CE5F}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Entity", "Server\Entity\Entity.csproj", "{15EB00C4-79C4-422D-AFD5-6CEB13517276}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Assembly-CSharp", "Client\Unity\Assembly-CSharp.csproj", "{03938CCD-4B40-8DFB-6B9B-21988D5CAC0A}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Fantasy.Config", "NuGet\Fantasy.Config\Fantasy.Config.csproj", "{F7AA93F5-E26A-429B-AC1C-C39575DD5893}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Fanatsy.NetworkProtocol", "NuGet\Fanatsy.NetworkProtocol\Fanatsy.NetworkProtocol.csproj", "{9C66D277-09DE-4FC9-B160-D547BF068E8E}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Fantasy.ConfigTableProtocol", "NuGet\Fantasy.ConfigTableProtocol\Fantasy.ConfigTableProtocol.csproj", "{C585AF27-CBC7-4F37-921A-21429864CD05}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {D31887AB-26E0-46EB-AFCA-C7BB2B76071D} = {6FA2590F-A0D4-4DD5-8D14-88C11F8914DA} + {392ADC21-14BA-49EB-A364-ADFCF818CE5F} = {6FA2590F-A0D4-4DD5-8D14-88C11F8914DA} + {15EB00C4-79C4-422D-AFD5-6CEB13517276} = {6FA2590F-A0D4-4DD5-8D14-88C11F8914DA} + {03938CCD-4B40-8DFB-6B9B-21988D5CAC0A} = {A3F59C11-8619-42AF-90A0-88CFB8FA784F} + {F7AA93F5-E26A-429B-AC1C-C39575DD5893} = {1221594F-E9BA-4567-9E5B-A12011ABF2C7} + {9C66D277-09DE-4FC9-B160-D547BF068E8E} = {1221594F-E9BA-4567-9E5B-A12011ABF2C7} + {C585AF27-CBC7-4F37-921A-21429864CD05} = {1221594F-E9BA-4567-9E5B-A12011ABF2C7} + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {D31887AB-26E0-46EB-AFCA-C7BB2B76071D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D31887AB-26E0-46EB-AFCA-C7BB2B76071D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D31887AB-26E0-46EB-AFCA-C7BB2B76071D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D31887AB-26E0-46EB-AFCA-C7BB2B76071D}.Release|Any CPU.Build.0 = Release|Any CPU + {392ADC21-14BA-49EB-A364-ADFCF818CE5F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {392ADC21-14BA-49EB-A364-ADFCF818CE5F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {392ADC21-14BA-49EB-A364-ADFCF818CE5F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {392ADC21-14BA-49EB-A364-ADFCF818CE5F}.Release|Any CPU.Build.0 = Release|Any CPU + {15EB00C4-79C4-422D-AFD5-6CEB13517276}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {15EB00C4-79C4-422D-AFD5-6CEB13517276}.Debug|Any CPU.Build.0 = Debug|Any CPU + {15EB00C4-79C4-422D-AFD5-6CEB13517276}.Release|Any CPU.ActiveCfg = Release|Any CPU + {15EB00C4-79C4-422D-AFD5-6CEB13517276}.Release|Any CPU.Build.0 = Release|Any CPU + {03938CCD-4B40-8DFB-6B9B-21988D5CAC0A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {03938CCD-4B40-8DFB-6B9B-21988D5CAC0A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {03938CCD-4B40-8DFB-6B9B-21988D5CAC0A}.Release|Any CPU.ActiveCfg = Debug|Any CPU + {03938CCD-4B40-8DFB-6B9B-21988D5CAC0A}.Release|Any CPU.Build.0 = Debug|Any CPU + {F7AA93F5-E26A-429B-AC1C-C39575DD5893}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F7AA93F5-E26A-429B-AC1C-C39575DD5893}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F7AA93F5-E26A-429B-AC1C-C39575DD5893}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F7AA93F5-E26A-429B-AC1C-C39575DD5893}.Release|Any CPU.Build.0 = Release|Any CPU + {9C66D277-09DE-4FC9-B160-D547BF068E8E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9C66D277-09DE-4FC9-B160-D547BF068E8E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9C66D277-09DE-4FC9-B160-D547BF068E8E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9C66D277-09DE-4FC9-B160-D547BF068E8E}.Release|Any CPU.Build.0 = Release|Any CPU + {C585AF27-CBC7-4F37-921A-21429864CD05}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C585AF27-CBC7-4F37-921A-21429864CD05}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C585AF27-CBC7-4F37-921A-21429864CD05}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C585AF27-CBC7-4F37-921A-21429864CD05}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection +EndGlobal diff --git a/邮件系统课程完整代码/Mail.sln.DotSettings.user b/邮件系统课程完整代码/Mail.sln.DotSettings.user new file mode 100644 index 0000000..4500b51 --- /dev/null +++ b/邮件系统课程完整代码/Mail.sln.DotSettings.user @@ -0,0 +1,12 @@ + + ForceIncluded + ForceIncluded + ForceIncluded + ForceIncluded + ForceIncluded + ForceIncluded + ForceIncluded + ForceIncluded + ForceIncluded + ForceIncluded + ForceIncluded \ No newline at end of file diff --git a/邮件系统课程完整代码/NuGet/.DS_Store b/邮件系统课程完整代码/NuGet/.DS_Store new file mode 100644 index 0000000..15fec97 Binary files /dev/null and b/邮件系统课程完整代码/NuGet/.DS_Store differ diff --git a/邮件系统课程完整代码/NuGet/Fanatsy.NetworkProtocol/.DS_Store b/邮件系统课程完整代码/NuGet/Fanatsy.NetworkProtocol/.DS_Store new file mode 100644 index 0000000..50e5868 Binary files /dev/null and b/邮件系统课程完整代码/NuGet/Fanatsy.NetworkProtocol/.DS_Store differ diff --git a/邮件系统课程完整代码/NuGet/Fanatsy.NetworkProtocol/Fanatsy.NetworkProtocol.csproj b/邮件系统课程完整代码/NuGet/Fanatsy.NetworkProtocol/Fanatsy.NetworkProtocol.csproj new file mode 100644 index 0000000..7e37a23 --- /dev/null +++ b/邮件系统课程完整代码/NuGet/Fanatsy.NetworkProtocol/Fanatsy.NetworkProtocol.csproj @@ -0,0 +1,13 @@ + + + + net8.0 + enable + enable + + + + + + + diff --git a/邮件系统课程完整代码/NuGet/Fanatsy.NetworkProtocol/Tools/.DS_Store b/邮件系统课程完整代码/NuGet/Fanatsy.NetworkProtocol/Tools/.DS_Store new file mode 100644 index 0000000..53fde77 Binary files /dev/null and b/邮件系统课程完整代码/NuGet/Fanatsy.NetworkProtocol/Tools/.DS_Store differ diff --git a/邮件系统课程完整代码/NuGet/Fanatsy.NetworkProtocol/Tools/Exporter/.DS_Store b/邮件系统课程完整代码/NuGet/Fanatsy.NetworkProtocol/Tools/Exporter/.DS_Store new file mode 100644 index 0000000..f6a0eb3 Binary files /dev/null and b/邮件系统课程完整代码/NuGet/Fanatsy.NetworkProtocol/Tools/Exporter/.DS_Store differ diff --git a/邮件系统课程完整代码/NuGet/Fanatsy.NetworkProtocol/Tools/Exporter/NetworkProtocol/CommandLine.dll b/邮件系统课程完整代码/NuGet/Fanatsy.NetworkProtocol/Tools/Exporter/NetworkProtocol/CommandLine.dll new file mode 100644 index 0000000..3eab2be Binary files /dev/null and b/邮件系统课程完整代码/NuGet/Fanatsy.NetworkProtocol/Tools/Exporter/NetworkProtocol/CommandLine.dll differ diff --git a/邮件系统课程完整代码/NuGet/Fanatsy.NetworkProtocol/Tools/Exporter/NetworkProtocol/ExporterSettings.json b/邮件系统课程完整代码/NuGet/Fanatsy.NetworkProtocol/Tools/Exporter/NetworkProtocol/ExporterSettings.json new file mode 100644 index 0000000..f093812 --- /dev/null +++ b/邮件系统课程完整代码/NuGet/Fanatsy.NetworkProtocol/Tools/Exporter/NetworkProtocol/ExporterSettings.json @@ -0,0 +1,29 @@ +{ + "Export": { + "NetworkProtocolDirectory": { + "Value": "../../../Examples/Config/NetworkProtocol/", + "Comment": "ProtoBuf文件所在的文件夹位置" + }, + "NetworkProtocolServerDirectory": { + "Value": "../../../Examples/Server/Entity/Generate/NetworkProtocol/", + "Comment": "ProtoBuf生成到服务端的文件夹位置" + }, + "NetworkProtocolClientDirectory": { + "Value": "../../../Examples/Client/Unity/Assets/Scripts/Hotfix/Generate/NetworkProtocol/", + "Comment": "ProtoBuf生成到客户端的文件夹位置" + }, + "Serializes": { + "Value": [ +// { +// "KeyIndex": 0, +// "NameSpace" : "MemoryPack", +// "SerializeName": "MemoryPack", +// "Attribute": "\t[MemoryPackable]", +// "Ignore": "\t\t[MemoryPackIgnore]", +// "Member": "MemoryPackOrder" +// } + ], + "Comment": "自定义序列化器" + } + } +} \ No newline at end of file diff --git a/邮件系统课程完整代码/NuGet/Fanatsy.NetworkProtocol/Tools/Exporter/NetworkProtocol/Fantasy.Tools.NetworkProtocol b/邮件系统课程完整代码/NuGet/Fanatsy.NetworkProtocol/Tools/Exporter/NetworkProtocol/Fantasy.Tools.NetworkProtocol new file mode 100644 index 0000000..25ceaf1 Binary files /dev/null and b/邮件系统课程完整代码/NuGet/Fanatsy.NetworkProtocol/Tools/Exporter/NetworkProtocol/Fantasy.Tools.NetworkProtocol differ diff --git a/邮件系统课程完整代码/NuGet/Fanatsy.NetworkProtocol/Tools/Exporter/NetworkProtocol/Fantasy.Tools.NetworkProtocol.deps.json b/邮件系统课程完整代码/NuGet/Fanatsy.NetworkProtocol/Tools/Exporter/NetworkProtocol/Fantasy.Tools.NetworkProtocol.deps.json new file mode 100644 index 0000000..3c053cb --- /dev/null +++ b/邮件系统课程完整代码/NuGet/Fanatsy.NetworkProtocol/Tools/Exporter/NetworkProtocol/Fantasy.Tools.NetworkProtocol.deps.json @@ -0,0 +1,227 @@ +{ + "runtimeTarget": { + "name": ".NETCoreApp,Version=v8.0", + "signature": "" + }, + "compilationOptions": {}, + "targets": { + ".NETCoreApp,Version=v8.0": { + "Fantasy.Tools.NetworkProtocol/1.0.0": { + "dependencies": { + "CommandLineParser": "2.9.1", + "Microsoft.Extensions.Configuration.Json": "8.0.0", + "Newtonsoft.Json": "13.0.3" + }, + "runtime": { + "Fantasy.Tools.NetworkProtocol.dll": {} + } + }, + "CommandLineParser/2.9.1": { + "runtime": { + "lib/netstandard2.0/CommandLine.dll": { + "assemblyVersion": "2.9.1.0", + "fileVersion": "2.9.1.0" + } + } + }, + "Microsoft.Extensions.Configuration/8.0.0": { + "dependencies": { + "Microsoft.Extensions.Configuration.Abstractions": "8.0.0", + "Microsoft.Extensions.Primitives": "8.0.0" + }, + "runtime": { + "lib/net8.0/Microsoft.Extensions.Configuration.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.23.53103" + } + } + }, + "Microsoft.Extensions.Configuration.Abstractions/8.0.0": { + "dependencies": { + "Microsoft.Extensions.Primitives": "8.0.0" + }, + "runtime": { + "lib/net8.0/Microsoft.Extensions.Configuration.Abstractions.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.23.53103" + } + } + }, + "Microsoft.Extensions.Configuration.FileExtensions/8.0.0": { + "dependencies": { + "Microsoft.Extensions.Configuration": "8.0.0", + "Microsoft.Extensions.Configuration.Abstractions": "8.0.0", + "Microsoft.Extensions.FileProviders.Abstractions": "8.0.0", + "Microsoft.Extensions.FileProviders.Physical": "8.0.0", + "Microsoft.Extensions.Primitives": "8.0.0" + }, + "runtime": { + "lib/net8.0/Microsoft.Extensions.Configuration.FileExtensions.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.23.53103" + } + } + }, + "Microsoft.Extensions.Configuration.Json/8.0.0": { + "dependencies": { + "Microsoft.Extensions.Configuration": "8.0.0", + "Microsoft.Extensions.Configuration.Abstractions": "8.0.0", + "Microsoft.Extensions.Configuration.FileExtensions": "8.0.0", + "Microsoft.Extensions.FileProviders.Abstractions": "8.0.0", + "System.Text.Json": "8.0.0" + }, + "runtime": { + "lib/net8.0/Microsoft.Extensions.Configuration.Json.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.23.53103" + } + } + }, + "Microsoft.Extensions.FileProviders.Abstractions/8.0.0": { + "dependencies": { + "Microsoft.Extensions.Primitives": "8.0.0" + }, + "runtime": { + "lib/net8.0/Microsoft.Extensions.FileProviders.Abstractions.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.23.53103" + } + } + }, + "Microsoft.Extensions.FileProviders.Physical/8.0.0": { + "dependencies": { + "Microsoft.Extensions.FileProviders.Abstractions": "8.0.0", + "Microsoft.Extensions.FileSystemGlobbing": "8.0.0", + "Microsoft.Extensions.Primitives": "8.0.0" + }, + "runtime": { + "lib/net8.0/Microsoft.Extensions.FileProviders.Physical.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.23.53103" + } + } + }, + "Microsoft.Extensions.FileSystemGlobbing/8.0.0": { + "runtime": { + "lib/net8.0/Microsoft.Extensions.FileSystemGlobbing.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.23.53103" + } + } + }, + "Microsoft.Extensions.Primitives/8.0.0": { + "runtime": { + "lib/net8.0/Microsoft.Extensions.Primitives.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.23.53103" + } + } + }, + "Newtonsoft.Json/13.0.3": { + "runtime": { + "lib/net6.0/Newtonsoft.Json.dll": { + "assemblyVersion": "13.0.0.0", + "fileVersion": "13.0.3.27908" + } + } + }, + "System.Text.Encodings.Web/8.0.0": {}, + "System.Text.Json/8.0.0": { + "dependencies": { + "System.Text.Encodings.Web": "8.0.0" + } + } + } + }, + "libraries": { + "Fantasy.Tools.NetworkProtocol/1.0.0": { + "type": "project", + "serviceable": false, + "sha512": "" + }, + "CommandLineParser/2.9.1": { + "type": "package", + "serviceable": true, + "sha512": "sha512-OE0sl1/sQ37bjVsPKKtwQlWDgqaxWgtme3xZz7JssWUzg5JpMIyHgCTY9MVMxOg48fJ1AgGT3tgdH5m/kQ5xhA==", + "path": "commandlineparser/2.9.1", + "hashPath": "commandlineparser.2.9.1.nupkg.sha512" + }, + "Microsoft.Extensions.Configuration/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-0J/9YNXTMWSZP2p2+nvl8p71zpSwokZXZuJW+VjdErkegAnFdO1XlqtA62SJtgVYHdKu3uPxJHcMR/r35HwFBA==", + "path": "microsoft.extensions.configuration/8.0.0", + "hashPath": "microsoft.extensions.configuration.8.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.Configuration.Abstractions/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-3lE/iLSutpgX1CC0NOW70FJoGARRHbyKmG7dc0klnUZ9Dd9hS6N/POPWhKhMLCEuNN5nXEY5agmlFtH562vqhQ==", + "path": "microsoft.extensions.configuration.abstractions/8.0.0", + "hashPath": "microsoft.extensions.configuration.abstractions.8.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.Configuration.FileExtensions/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-McP+Lz/EKwvtCv48z0YImw+L1gi1gy5rHhNaNIY2CrjloV+XY8gydT8DjMR6zWeL13AFK+DioVpppwAuO1Gi1w==", + "path": "microsoft.extensions.configuration.fileextensions/8.0.0", + "hashPath": "microsoft.extensions.configuration.fileextensions.8.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.Configuration.Json/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-C2wqUoh9OmRL1akaCcKSTmRU8z0kckfImG7zLNI8uyi47Lp+zd5LWAD17waPQEqCz3ioWOCrFUo+JJuoeZLOBw==", + "path": "microsoft.extensions.configuration.json/8.0.0", + "hashPath": "microsoft.extensions.configuration.json.8.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.FileProviders.Abstractions/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-ZbaMlhJlpisjuWbvXr4LdAst/1XxH3vZ6A0BsgTphZ2L4PGuxRLz7Jr/S7mkAAnOn78Vu0fKhEgNF5JO3zfjqQ==", + "path": "microsoft.extensions.fileproviders.abstractions/8.0.0", + "hashPath": "microsoft.extensions.fileproviders.abstractions.8.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.FileProviders.Physical/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-UboiXxpPUpwulHvIAVE36Knq0VSHaAmfrFkegLyBZeaADuKezJ/AIXYAW8F5GBlGk/VaibN2k/Zn1ca8YAfVdA==", + "path": "microsoft.extensions.fileproviders.physical/8.0.0", + "hashPath": "microsoft.extensions.fileproviders.physical.8.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.FileSystemGlobbing/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-OK+670i7esqlQrPjdIKRbsyMCe9g5kSLpRRQGSr4Q58AOYEe/hCnfLZprh7viNisSUUQZmMrbbuDaIrP+V1ebQ==", + "path": "microsoft.extensions.filesystemglobbing/8.0.0", + "hashPath": "microsoft.extensions.filesystemglobbing.8.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.Primitives/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-bXJEZrW9ny8vjMF1JV253WeLhpEVzFo1lyaZu1vQ4ZxWUlVvknZ/+ftFgVheLubb4eZPSwwxBeqS1JkCOjxd8g==", + "path": "microsoft.extensions.primitives/8.0.0", + "hashPath": "microsoft.extensions.primitives.8.0.0.nupkg.sha512" + }, + "Newtonsoft.Json/13.0.3": { + "type": "package", + "serviceable": true, + "sha512": "sha512-HrC5BXdl00IP9zeV+0Z848QWPAoCr9P3bDEZguI+gkLcBKAOxix/tLEAAHC+UvDNPv4a2d18lOReHMOagPa+zQ==", + "path": "newtonsoft.json/13.0.3", + "hashPath": "newtonsoft.json.13.0.3.nupkg.sha512" + }, + "System.Text.Encodings.Web/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-yev/k9GHAEGx2Rg3/tU6MQh4HGBXJs70y7j1LaM1i/ER9po+6nnQ6RRqTJn1E7Xu0fbIFK80Nh5EoODxrbxwBQ==", + "path": "system.text.encodings.web/8.0.0", + "hashPath": "system.text.encodings.web.8.0.0.nupkg.sha512" + }, + "System.Text.Json/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-OdrZO2WjkiEG6ajEFRABTRCi/wuXQPxeV6g8xvUJqdxMvvuCCEk86zPla8UiIQJz3durtUEbNyY/3lIhS0yZvQ==", + "path": "system.text.json/8.0.0", + "hashPath": "system.text.json.8.0.0.nupkg.sha512" + } + } +} \ No newline at end of file diff --git a/邮件系统课程完整代码/NuGet/Fanatsy.NetworkProtocol/Tools/Exporter/NetworkProtocol/Fantasy.Tools.NetworkProtocol.dll b/邮件系统课程完整代码/NuGet/Fanatsy.NetworkProtocol/Tools/Exporter/NetworkProtocol/Fantasy.Tools.NetworkProtocol.dll new file mode 100644 index 0000000..f9219d9 Binary files /dev/null and b/邮件系统课程完整代码/NuGet/Fanatsy.NetworkProtocol/Tools/Exporter/NetworkProtocol/Fantasy.Tools.NetworkProtocol.dll differ diff --git a/邮件系统课程完整代码/NuGet/Fanatsy.NetworkProtocol/Tools/Exporter/NetworkProtocol/Fantasy.Tools.NetworkProtocol.pdb b/邮件系统课程完整代码/NuGet/Fanatsy.NetworkProtocol/Tools/Exporter/NetworkProtocol/Fantasy.Tools.NetworkProtocol.pdb new file mode 100644 index 0000000..91a7531 Binary files /dev/null and b/邮件系统课程完整代码/NuGet/Fanatsy.NetworkProtocol/Tools/Exporter/NetworkProtocol/Fantasy.Tools.NetworkProtocol.pdb differ diff --git a/邮件系统课程完整代码/NuGet/Fanatsy.NetworkProtocol/Tools/Exporter/NetworkProtocol/Fantasy.Tools.NetworkProtocol.runtimeconfig.json b/邮件系统课程完整代码/NuGet/Fanatsy.NetworkProtocol/Tools/Exporter/NetworkProtocol/Fantasy.Tools.NetworkProtocol.runtimeconfig.json new file mode 100644 index 0000000..becfaea --- /dev/null +++ b/邮件系统课程完整代码/NuGet/Fanatsy.NetworkProtocol/Tools/Exporter/NetworkProtocol/Fantasy.Tools.NetworkProtocol.runtimeconfig.json @@ -0,0 +1,12 @@ +{ + "runtimeOptions": { + "tfm": "net8.0", + "framework": { + "name": "Microsoft.NETCore.App", + "version": "8.0.0" + }, + "configProperties": { + "System.Runtime.Serialization.EnableUnsafeBinaryFormatterSerialization": false + } + } +} \ No newline at end of file diff --git a/邮件系统课程完整代码/NuGet/Fanatsy.NetworkProtocol/Tools/Exporter/NetworkProtocol/Microsoft.Extensions.Configuration.Abstractions.dll b/邮件系统课程完整代码/NuGet/Fanatsy.NetworkProtocol/Tools/Exporter/NetworkProtocol/Microsoft.Extensions.Configuration.Abstractions.dll new file mode 100644 index 0000000..a5ab313 Binary files /dev/null and b/邮件系统课程完整代码/NuGet/Fanatsy.NetworkProtocol/Tools/Exporter/NetworkProtocol/Microsoft.Extensions.Configuration.Abstractions.dll differ diff --git a/邮件系统课程完整代码/NuGet/Fanatsy.NetworkProtocol/Tools/Exporter/NetworkProtocol/Microsoft.Extensions.Configuration.FileExtensions.dll b/邮件系统课程完整代码/NuGet/Fanatsy.NetworkProtocol/Tools/Exporter/NetworkProtocol/Microsoft.Extensions.Configuration.FileExtensions.dll new file mode 100644 index 0000000..4efc1a5 Binary files /dev/null and b/邮件系统课程完整代码/NuGet/Fanatsy.NetworkProtocol/Tools/Exporter/NetworkProtocol/Microsoft.Extensions.Configuration.FileExtensions.dll differ diff --git a/邮件系统课程完整代码/NuGet/Fanatsy.NetworkProtocol/Tools/Exporter/NetworkProtocol/Microsoft.Extensions.Configuration.Json.dll b/邮件系统课程完整代码/NuGet/Fanatsy.NetworkProtocol/Tools/Exporter/NetworkProtocol/Microsoft.Extensions.Configuration.Json.dll new file mode 100644 index 0000000..296db6a Binary files /dev/null and b/邮件系统课程完整代码/NuGet/Fanatsy.NetworkProtocol/Tools/Exporter/NetworkProtocol/Microsoft.Extensions.Configuration.Json.dll differ diff --git a/邮件系统课程完整代码/NuGet/Fanatsy.NetworkProtocol/Tools/Exporter/NetworkProtocol/Microsoft.Extensions.Configuration.dll b/邮件系统课程完整代码/NuGet/Fanatsy.NetworkProtocol/Tools/Exporter/NetworkProtocol/Microsoft.Extensions.Configuration.dll new file mode 100644 index 0000000..d3e5c22 Binary files /dev/null and b/邮件系统课程完整代码/NuGet/Fanatsy.NetworkProtocol/Tools/Exporter/NetworkProtocol/Microsoft.Extensions.Configuration.dll differ diff --git a/邮件系统课程完整代码/NuGet/Fanatsy.NetworkProtocol/Tools/Exporter/NetworkProtocol/Microsoft.Extensions.FileProviders.Abstractions.dll b/邮件系统课程完整代码/NuGet/Fanatsy.NetworkProtocol/Tools/Exporter/NetworkProtocol/Microsoft.Extensions.FileProviders.Abstractions.dll new file mode 100644 index 0000000..f907206 Binary files /dev/null and b/邮件系统课程完整代码/NuGet/Fanatsy.NetworkProtocol/Tools/Exporter/NetworkProtocol/Microsoft.Extensions.FileProviders.Abstractions.dll differ diff --git a/邮件系统课程完整代码/NuGet/Fanatsy.NetworkProtocol/Tools/Exporter/NetworkProtocol/Microsoft.Extensions.FileProviders.Physical.dll b/邮件系统课程完整代码/NuGet/Fanatsy.NetworkProtocol/Tools/Exporter/NetworkProtocol/Microsoft.Extensions.FileProviders.Physical.dll new file mode 100644 index 0000000..6fb7f47 Binary files /dev/null and b/邮件系统课程完整代码/NuGet/Fanatsy.NetworkProtocol/Tools/Exporter/NetworkProtocol/Microsoft.Extensions.FileProviders.Physical.dll differ diff --git a/邮件系统课程完整代码/NuGet/Fanatsy.NetworkProtocol/Tools/Exporter/NetworkProtocol/Microsoft.Extensions.FileSystemGlobbing.dll b/邮件系统课程完整代码/NuGet/Fanatsy.NetworkProtocol/Tools/Exporter/NetworkProtocol/Microsoft.Extensions.FileSystemGlobbing.dll new file mode 100644 index 0000000..e590735 Binary files /dev/null and b/邮件系统课程完整代码/NuGet/Fanatsy.NetworkProtocol/Tools/Exporter/NetworkProtocol/Microsoft.Extensions.FileSystemGlobbing.dll differ diff --git a/邮件系统课程完整代码/NuGet/Fanatsy.NetworkProtocol/Tools/Exporter/NetworkProtocol/Microsoft.Extensions.Primitives.dll b/邮件系统课程完整代码/NuGet/Fanatsy.NetworkProtocol/Tools/Exporter/NetworkProtocol/Microsoft.Extensions.Primitives.dll new file mode 100644 index 0000000..c24f2a0 Binary files /dev/null and b/邮件系统课程完整代码/NuGet/Fanatsy.NetworkProtocol/Tools/Exporter/NetworkProtocol/Microsoft.Extensions.Primitives.dll differ diff --git a/邮件系统课程完整代码/NuGet/Fanatsy.NetworkProtocol/Tools/Exporter/NetworkProtocol/Newtonsoft.Json.dll b/邮件系统课程完整代码/NuGet/Fanatsy.NetworkProtocol/Tools/Exporter/NetworkProtocol/Newtonsoft.Json.dll new file mode 100644 index 0000000..d035c38 Binary files /dev/null and b/邮件系统课程完整代码/NuGet/Fanatsy.NetworkProtocol/Tools/Exporter/NetworkProtocol/Newtonsoft.Json.dll differ diff --git a/邮件系统课程完整代码/NuGet/Fanatsy.NetworkProtocol/Tools/Exporter/NetworkProtocol/Run.bat b/邮件系统课程完整代码/NuGet/Fanatsy.NetworkProtocol/Tools/Exporter/NetworkProtocol/Run.bat new file mode 100644 index 0000000..8551afc --- /dev/null +++ b/邮件系统课程完整代码/NuGet/Fanatsy.NetworkProtocol/Tools/Exporter/NetworkProtocol/Run.bat @@ -0,0 +1,21 @@ +@echo off + +echo Please select an option: +echo 1. Client +echo 2. Server +echo 3. All + +set /p choice=Please select an option: + +if "%choice%"=="1" ( + echo Client + dotnet Fantasy.Tools.NetworkProtocol.dll --ExportPlatform 1 +) else if "%choice%"=="2" ( + echo Server + dotnet Fantasy.Tools.NetworkProtocol.dll --ExportPlatform 2 +) else if "%choice%"=="3" ( + echo All + dotnet Fantasy.Tools.NetworkProtocol.dll --ExportPlatform 3 +) else ( + echo Invalid option +) diff --git a/邮件系统课程完整代码/NuGet/Fanatsy.NetworkProtocol/Tools/Exporter/NetworkProtocol/Run.sh b/邮件系统课程完整代码/NuGet/Fanatsy.NetworkProtocol/Tools/Exporter/NetworkProtocol/Run.sh new file mode 100644 index 0000000..763ce02 --- /dev/null +++ b/邮件系统课程完整代码/NuGet/Fanatsy.NetworkProtocol/Tools/Exporter/NetworkProtocol/Run.sh @@ -0,0 +1,23 @@ +#!/bin/bash + +echo "1. Client" +echo "2. Server" +echo "3. All" + +read -n 1 -p "Please select an option:" choice +echo "" +echo "" +case $choice in + 1) + dotnet Fantasy.Tools.NetworkProtocol.dll --ExportPlatform 1 + ;; + 2) + dotnet Fantasy.Tools.NetworkProtocol.dll --ExportPlatform 2 + ;; + 3) + dotnet Fantasy.Tools.NetworkProtocol.dll --ExportPlatform 3 + ;; + *) + echo "Invalid option" + ;; +esac diff --git a/邮件系统课程完整代码/NuGet/Fanatsy.NetworkProtocol/obj/Debug/net8.0/.NETCoreApp,Version=v8.0.AssemblyAttributes.cs b/邮件系统课程完整代码/NuGet/Fanatsy.NetworkProtocol/obj/Debug/net8.0/.NETCoreApp,Version=v8.0.AssemblyAttributes.cs new file mode 100644 index 0000000..2217181 --- /dev/null +++ b/邮件系统课程完整代码/NuGet/Fanatsy.NetworkProtocol/obj/Debug/net8.0/.NETCoreApp,Version=v8.0.AssemblyAttributes.cs @@ -0,0 +1,4 @@ +// +using System; +using System.Reflection; +[assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute(".NETCoreApp,Version=v8.0", FrameworkDisplayName = ".NET 8.0")] diff --git a/邮件系统课程完整代码/NuGet/Fanatsy.NetworkProtocol/obj/Debug/net8.0/Fanatsy.NetworkProtocol.AssemblyInfo.cs b/邮件系统课程完整代码/NuGet/Fanatsy.NetworkProtocol/obj/Debug/net8.0/Fanatsy.NetworkProtocol.AssemblyInfo.cs new file mode 100644 index 0000000..b7d698c --- /dev/null +++ b/邮件系统课程完整代码/NuGet/Fanatsy.NetworkProtocol/obj/Debug/net8.0/Fanatsy.NetworkProtocol.AssemblyInfo.cs @@ -0,0 +1,22 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +using System; +using System.Reflection; + +[assembly: System.Reflection.AssemblyCompanyAttribute("Fanatsy.NetworkProtocol")] +[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")] +[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")] +[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0")] +[assembly: System.Reflection.AssemblyProductAttribute("Fanatsy.NetworkProtocol")] +[assembly: System.Reflection.AssemblyTitleAttribute("Fanatsy.NetworkProtocol")] +[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")] + +// 由 MSBuild WriteCodeFragment 类生成。 + diff --git a/邮件系统课程完整代码/NuGet/Fanatsy.NetworkProtocol/obj/Debug/net8.0/Fanatsy.NetworkProtocol.AssemblyInfoInputs.cache b/邮件系统课程完整代码/NuGet/Fanatsy.NetworkProtocol/obj/Debug/net8.0/Fanatsy.NetworkProtocol.AssemblyInfoInputs.cache new file mode 100644 index 0000000..a3ddc65 --- /dev/null +++ b/邮件系统课程完整代码/NuGet/Fanatsy.NetworkProtocol/obj/Debug/net8.0/Fanatsy.NetworkProtocol.AssemblyInfoInputs.cache @@ -0,0 +1 @@ +93eef8847d6d6537543f02c8a5c6dd1f85e6db156d39602e7f1b17bc3560c937 diff --git a/邮件系统课程完整代码/NuGet/Fanatsy.NetworkProtocol/obj/Debug/net8.0/Fanatsy.NetworkProtocol.GeneratedMSBuildEditorConfig.editorconfig b/邮件系统课程完整代码/NuGet/Fanatsy.NetworkProtocol/obj/Debug/net8.0/Fanatsy.NetworkProtocol.GeneratedMSBuildEditorConfig.editorconfig new file mode 100644 index 0000000..e7a3075 --- /dev/null +++ b/邮件系统课程完整代码/NuGet/Fanatsy.NetworkProtocol/obj/Debug/net8.0/Fanatsy.NetworkProtocol.GeneratedMSBuildEditorConfig.editorconfig @@ -0,0 +1,15 @@ +is_global = true +build_property.TargetFramework = net8.0 +build_property.TargetPlatformMinVersion = +build_property.UsingMicrosoftNETSdkWeb = +build_property.ProjectTypeGuids = +build_property.InvariantGlobalization = +build_property.PlatformNeutralAssembly = +build_property.EnforceExtendedAnalyzerRules = +build_property._SupportedPlatformList = Linux,macOS,Windows +build_property.RootNamespace = Fanatsy.NetworkProtocol +build_property.ProjectDir = /Users/fantasy/Movies/邮件系统/Lession/NuGet/Fanatsy.NetworkProtocol/ +build_property.EnableComHosting = +build_property.EnableGeneratedComInterfaceComImportInterop = +build_property.EffectiveAnalysisLevelStyle = 8.0 +build_property.EnableCodeStyleSeverity = diff --git a/邮件系统课程完整代码/NuGet/Fanatsy.NetworkProtocol/obj/Debug/net8.0/Fanatsy.NetworkProtocol.GlobalUsings.g.cs b/邮件系统课程完整代码/NuGet/Fanatsy.NetworkProtocol/obj/Debug/net8.0/Fanatsy.NetworkProtocol.GlobalUsings.g.cs new file mode 100644 index 0000000..8578f3d --- /dev/null +++ b/邮件系统课程完整代码/NuGet/Fanatsy.NetworkProtocol/obj/Debug/net8.0/Fanatsy.NetworkProtocol.GlobalUsings.g.cs @@ -0,0 +1,8 @@ +// +global using global::System; +global using global::System.Collections.Generic; +global using global::System.IO; +global using global::System.Linq; +global using global::System.Net.Http; +global using global::System.Threading; +global using global::System.Threading.Tasks; diff --git a/邮件系统课程完整代码/NuGet/Fanatsy.NetworkProtocol/obj/Debug/net8.0/Fanatsy.NetworkProtocol.assets.cache b/邮件系统课程完整代码/NuGet/Fanatsy.NetworkProtocol/obj/Debug/net8.0/Fanatsy.NetworkProtocol.assets.cache new file mode 100644 index 0000000..0440c81 Binary files /dev/null and b/邮件系统课程完整代码/NuGet/Fanatsy.NetworkProtocol/obj/Debug/net8.0/Fanatsy.NetworkProtocol.assets.cache differ diff --git a/邮件系统课程完整代码/NuGet/Fanatsy.NetworkProtocol/obj/Debug/net8.0/Fanatsy.NetworkProtocol.csproj.AssemblyReference.cache b/邮件系统课程完整代码/NuGet/Fanatsy.NetworkProtocol/obj/Debug/net8.0/Fanatsy.NetworkProtocol.csproj.AssemblyReference.cache new file mode 100644 index 0000000..5559bdc Binary files /dev/null and b/邮件系统课程完整代码/NuGet/Fanatsy.NetworkProtocol/obj/Debug/net8.0/Fanatsy.NetworkProtocol.csproj.AssemblyReference.cache differ diff --git a/邮件系统课程完整代码/NuGet/Fanatsy.NetworkProtocol/obj/Fanatsy.NetworkProtocol.csproj.nuget.dgspec.json b/邮件系统课程完整代码/NuGet/Fanatsy.NetworkProtocol/obj/Fanatsy.NetworkProtocol.csproj.nuget.dgspec.json new file mode 100644 index 0000000..07bc56a --- /dev/null +++ b/邮件系统课程完整代码/NuGet/Fanatsy.NetworkProtocol/obj/Fanatsy.NetworkProtocol.csproj.nuget.dgspec.json @@ -0,0 +1,74 @@ +{ + "format": 1, + "restore": { + "/Users/fantasy/Movies/邮件系统/Lession/NuGet/Fanatsy.NetworkProtocol/Fanatsy.NetworkProtocol.csproj": {} + }, + "projects": { + "/Users/fantasy/Movies/邮件系统/Lession/NuGet/Fanatsy.NetworkProtocol/Fanatsy.NetworkProtocol.csproj": { + "version": "1.0.0", + "restore": { + "projectUniqueName": "/Users/fantasy/Movies/邮件系统/Lession/NuGet/Fanatsy.NetworkProtocol/Fanatsy.NetworkProtocol.csproj", + "projectName": "Fanatsy.NetworkProtocol", + "projectPath": "/Users/fantasy/Movies/邮件系统/Lession/NuGet/Fanatsy.NetworkProtocol/Fanatsy.NetworkProtocol.csproj", + "packagesPath": "/Users/fantasy/.nuget/packages/", + "outputPath": "/Users/fantasy/Movies/邮件系统/Lession/NuGet/Fanatsy.NetworkProtocol/obj/", + "projectStyle": "PackageReference", + "configFilePaths": [ + "/Users/fantasy/.nuget/NuGet/NuGet.Config" + ], + "originalTargetFrameworks": [ + "net8.0" + ], + "sources": { + "/usr/local/share/dotnet/library-packs": {}, + "https://api.nuget.org/v3/index.json": {} + }, + "frameworks": { + "net8.0": { + "targetAlias": "net8.0", + "projectReferences": {} + } + }, + "warningProperties": { + "warnAsError": [ + "NU1605" + ] + }, + "restoreAuditProperties": { + "enableAudit": "true", + "auditLevel": "low", + "auditMode": "all" + }, + "SdkAnalysisLevel": "9.0.100" + }, + "frameworks": { + "net8.0": { + "targetAlias": "net8.0", + "dependencies": { + "Fantasy-Net.Tools.ExporterNetworkProtocol": { + "target": "Package", + "version": "[2024.2.20, )" + } + }, + "imports": [ + "net461", + "net462", + "net47", + "net471", + "net472", + "net48", + "net481" + ], + "assetTargetFallback": true, + "warn": true, + "frameworkReferences": { + "Microsoft.NETCore.App": { + "privateAssets": "all" + } + }, + "runtimeIdentifierGraphPath": "/usr/local/share/dotnet/sdk/9.0.100/PortableRuntimeIdentifierGraph.json" + } + } + } + } +} \ No newline at end of file diff --git a/邮件系统课程完整代码/NuGet/Fanatsy.NetworkProtocol/obj/Fanatsy.NetworkProtocol.csproj.nuget.g.props b/邮件系统课程完整代码/NuGet/Fanatsy.NetworkProtocol/obj/Fanatsy.NetworkProtocol.csproj.nuget.g.props new file mode 100644 index 0000000..e5942c5 --- /dev/null +++ b/邮件系统课程完整代码/NuGet/Fanatsy.NetworkProtocol/obj/Fanatsy.NetworkProtocol.csproj.nuget.g.props @@ -0,0 +1,18 @@ + + + + True + NuGet + $(MSBuildThisFileDirectory)project.assets.json + /Users/fantasy/.nuget/packages/ + /Users/fantasy/.nuget/packages/ + PackageReference + 6.12.2 + + + + + + /Users/fantasy/.nuget/packages/fantasy-net.tools.exporternetworkprotocol/2024.2.20 + + \ No newline at end of file diff --git a/邮件系统课程完整代码/NuGet/Fanatsy.NetworkProtocol/obj/Fanatsy.NetworkProtocol.csproj.nuget.g.targets b/邮件系统课程完整代码/NuGet/Fanatsy.NetworkProtocol/obj/Fanatsy.NetworkProtocol.csproj.nuget.g.targets new file mode 100644 index 0000000..4273679 --- /dev/null +++ b/邮件系统课程完整代码/NuGet/Fanatsy.NetworkProtocol/obj/Fanatsy.NetworkProtocol.csproj.nuget.g.targets @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/邮件系统课程完整代码/NuGet/Fanatsy.NetworkProtocol/obj/project.assets.json b/邮件系统课程完整代码/NuGet/Fanatsy.NetworkProtocol/obj/project.assets.json new file mode 100644 index 0000000..54604fe --- /dev/null +++ b/邮件系统课程完整代码/NuGet/Fanatsy.NetworkProtocol/obj/project.assets.json @@ -0,0 +1,128 @@ +{ + "version": 3, + "targets": { + "net8.0": { + "Fantasy-Net.Tools.ExporterNetworkProtocol/2024.2.20": { + "type": "package", + "compile": { + "lib/net8.0/Fantasy.Tools.ExporterNetworkProtocol.dll": {} + }, + "runtime": { + "lib/net8.0/Fantasy.Tools.ExporterNetworkProtocol.dll": {} + }, + "build": { + "buildTransitive/Fantasy-Net.Tools.ExporterNetworkProtocol.targets": {} + } + } + } + }, + "libraries": { + "Fantasy-Net.Tools.ExporterNetworkProtocol/2024.2.20": { + "sha512": "wpZ1AjXBWLWOHsEAz2X6pSFVox4olqAz5eeDJlDXJZeRfJ1iAkszS9BLLqRmJet3Q46GCyCOheDaPImqEla0Vw==", + "type": "package", + "path": "fantasy-net.tools.exporternetworkprotocol/2024.2.20", + "hasTools": true, + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "buildTransitive/Fantasy-Net.Tools.ExporterNetworkProtocol.targets", + "fantasy-net.tools.exporternetworkprotocol.2024.2.20.nupkg.sha512", + "fantasy-net.tools.exporternetworkprotocol.nuspec", + "icon.png", + "lib/net8.0/Fantasy.Tools.ExporterNetworkProtocol.dll", + "tools/output/CommandLine.dll", + "tools/output/ExporterSettings.json", + "tools/output/Fantasy.Tools.NetworkProtocol", + "tools/output/Fantasy.Tools.NetworkProtocol.deps.json", + "tools/output/Fantasy.Tools.NetworkProtocol.dll", + "tools/output/Fantasy.Tools.NetworkProtocol.pdb", + "tools/output/Fantasy.Tools.NetworkProtocol.runtimeconfig.json", + "tools/output/Microsoft.Extensions.Configuration.Abstractions.dll", + "tools/output/Microsoft.Extensions.Configuration.FileExtensions.dll", + "tools/output/Microsoft.Extensions.Configuration.Json.dll", + "tools/output/Microsoft.Extensions.Configuration.dll", + "tools/output/Microsoft.Extensions.FileProviders.Abstractions.dll", + "tools/output/Microsoft.Extensions.FileProviders.Physical.dll", + "tools/output/Microsoft.Extensions.FileSystemGlobbing.dll", + "tools/output/Microsoft.Extensions.Primitives.dll", + "tools/output/Newtonsoft.Json.dll", + "tools/output/Run.bat", + "tools/output/Run.sh" + ] + } + }, + "projectFileDependencyGroups": { + "net8.0": [ + "Fantasy-Net.Tools.ExporterNetworkProtocol >= 2024.2.20" + ] + }, + "packageFolders": { + "/Users/fantasy/.nuget/packages/": {} + }, + "project": { + "version": "1.0.0", + "restore": { + "projectUniqueName": "/Users/fantasy/Movies/邮件系统/Lession/NuGet/Fanatsy.NetworkProtocol/Fanatsy.NetworkProtocol.csproj", + "projectName": "Fanatsy.NetworkProtocol", + "projectPath": "/Users/fantasy/Movies/邮件系统/Lession/NuGet/Fanatsy.NetworkProtocol/Fanatsy.NetworkProtocol.csproj", + "packagesPath": "/Users/fantasy/.nuget/packages/", + "outputPath": "/Users/fantasy/Movies/邮件系统/Lession/NuGet/Fanatsy.NetworkProtocol/obj/", + "projectStyle": "PackageReference", + "configFilePaths": [ + "/Users/fantasy/.nuget/NuGet/NuGet.Config" + ], + "originalTargetFrameworks": [ + "net8.0" + ], + "sources": { + "/usr/local/share/dotnet/library-packs": {}, + "https://api.nuget.org/v3/index.json": {} + }, + "frameworks": { + "net8.0": { + "targetAlias": "net8.0", + "projectReferences": {} + } + }, + "warningProperties": { + "warnAsError": [ + "NU1605" + ] + }, + "restoreAuditProperties": { + "enableAudit": "true", + "auditLevel": "low", + "auditMode": "all" + }, + "SdkAnalysisLevel": "9.0.100" + }, + "frameworks": { + "net8.0": { + "targetAlias": "net8.0", + "dependencies": { + "Fantasy-Net.Tools.ExporterNetworkProtocol": { + "target": "Package", + "version": "[2024.2.20, )" + } + }, + "imports": [ + "net461", + "net462", + "net47", + "net471", + "net472", + "net48", + "net481" + ], + "assetTargetFallback": true, + "warn": true, + "frameworkReferences": { + "Microsoft.NETCore.App": { + "privateAssets": "all" + } + }, + "runtimeIdentifierGraphPath": "/usr/local/share/dotnet/sdk/9.0.100/PortableRuntimeIdentifierGraph.json" + } + } + } +} \ No newline at end of file diff --git a/邮件系统课程完整代码/NuGet/Fanatsy.NetworkProtocol/obj/project.nuget.cache b/邮件系统课程完整代码/NuGet/Fanatsy.NetworkProtocol/obj/project.nuget.cache new file mode 100644 index 0000000..8c0523c --- /dev/null +++ b/邮件系统课程完整代码/NuGet/Fanatsy.NetworkProtocol/obj/project.nuget.cache @@ -0,0 +1,10 @@ +{ + "version": 2, + "dgSpecHash": "Eqzy+t7CiXE=", + "success": true, + "projectFilePath": "/Users/fantasy/Movies/邮件系统/Lession/NuGet/Fanatsy.NetworkProtocol/Fanatsy.NetworkProtocol.csproj", + "expectedPackageFiles": [ + "/Users/fantasy/.nuget/packages/fantasy-net.tools.exporternetworkprotocol/2024.2.20/fantasy-net.tools.exporternetworkprotocol.2024.2.20.nupkg.sha512" + ], + "logs": [] +} \ No newline at end of file diff --git a/邮件系统课程完整代码/NuGet/Fanatsy.NetworkProtocol/obj/project.packagespec.json b/邮件系统课程完整代码/NuGet/Fanatsy.NetworkProtocol/obj/project.packagespec.json new file mode 100644 index 0000000..faaabef --- /dev/null +++ b/邮件系统课程完整代码/NuGet/Fanatsy.NetworkProtocol/obj/project.packagespec.json @@ -0,0 +1 @@ +"restore":{"projectUniqueName":"/Users/fantasy/Movies/邮件系统/Lession/NuGet/Fanatsy.NetworkProtocol/Fanatsy.NetworkProtocol.csproj","projectName":"Fanatsy.NetworkProtocol","projectPath":"/Users/fantasy/Movies/邮件系统/Lession/NuGet/Fanatsy.NetworkProtocol/Fanatsy.NetworkProtocol.csproj","outputPath":"/Users/fantasy/Movies/邮件系统/Lession/NuGet/Fanatsy.NetworkProtocol/obj/","projectStyle":"PackageReference","originalTargetFrameworks":["net8.0"],"sources":{"/usr/local/share/dotnet/library-packs":{},"https://api.nuget.org/v3/index.json":{}},"frameworks":{"net8.0":{"targetAlias":"net8.0","projectReferences":{}}},"warningProperties":{"warnAsError":["NU1605"]},"restoreAuditProperties":{"enableAudit":"true","auditLevel":"low","auditMode":"all"},"SdkAnalysisLevel":"9.0.100"}"frameworks":{"net8.0":{"targetAlias":"net8.0","dependencies":{"Fantasy-Net.Tools.ExporterNetworkProtocol":{"target":"Package","version":"[2024.2.20, )"}},"imports":["net461","net462","net47","net471","net472","net48","net481"],"assetTargetFallback":true,"warn":true,"frameworkReferences":{"Microsoft.NETCore.App":{"privateAssets":"all"}},"runtimeIdentifierGraphPath":"/usr/local/share/dotnet/sdk/9.0.100/PortableRuntimeIdentifierGraph.json"}} \ No newline at end of file diff --git a/邮件系统课程完整代码/NuGet/Fanatsy.NetworkProtocol/obj/rider.project.model.nuget.info b/邮件系统课程完整代码/NuGet/Fanatsy.NetworkProtocol/obj/rider.project.model.nuget.info new file mode 100644 index 0000000..57cb53c --- /dev/null +++ b/邮件系统课程完整代码/NuGet/Fanatsy.NetworkProtocol/obj/rider.project.model.nuget.info @@ -0,0 +1 @@ +17392438089760459 \ No newline at end of file diff --git a/邮件系统课程完整代码/NuGet/Fanatsy.NetworkProtocol/obj/rider.project.restore.info b/邮件系统课程完整代码/NuGet/Fanatsy.NetworkProtocol/obj/rider.project.restore.info new file mode 100644 index 0000000..57cb53c --- /dev/null +++ b/邮件系统课程完整代码/NuGet/Fanatsy.NetworkProtocol/obj/rider.project.restore.info @@ -0,0 +1 @@ +17392438089760459 \ No newline at end of file diff --git a/邮件系统课程完整代码/NuGet/Fantasy.Config/.DS_Store b/邮件系统课程完整代码/NuGet/Fantasy.Config/.DS_Store new file mode 100644 index 0000000..7012a81 Binary files /dev/null and b/邮件系统课程完整代码/NuGet/Fantasy.Config/.DS_Store differ diff --git a/邮件系统课程完整代码/NuGet/Fantasy.Config/Fantasy.Config.csproj b/邮件系统课程完整代码/NuGet/Fantasy.Config/Fantasy.Config.csproj new file mode 100644 index 0000000..42e8eb9 --- /dev/null +++ b/邮件系统课程完整代码/NuGet/Fantasy.Config/Fantasy.Config.csproj @@ -0,0 +1,13 @@ + + + + net8.0 + enable + enable + + + + + + + diff --git a/邮件系统课程完整代码/NuGet/Fantasy.Config/Tools/.DS_Store b/邮件系统课程完整代码/NuGet/Fantasy.Config/Tools/.DS_Store new file mode 100644 index 0000000..ef2d6b1 Binary files /dev/null and b/邮件系统课程完整代码/NuGet/Fantasy.Config/Tools/.DS_Store differ diff --git a/邮件系统课程完整代码/NuGet/Fantasy.Config/Tools/Exporter/.DS_Store b/邮件系统课程完整代码/NuGet/Fantasy.Config/Tools/Exporter/.DS_Store new file mode 100644 index 0000000..a94417f Binary files /dev/null and b/邮件系统课程完整代码/NuGet/Fantasy.Config/Tools/Exporter/.DS_Store differ diff --git a/邮件系统课程完整代码/NuGet/Fantasy.Config/Tools/Exporter/ConfigTable/.DS_Store b/邮件系统课程完整代码/NuGet/Fantasy.Config/Tools/Exporter/ConfigTable/.DS_Store new file mode 100644 index 0000000..ba1d698 Binary files /dev/null and b/邮件系统课程完整代码/NuGet/Fantasy.Config/Tools/Exporter/ConfigTable/.DS_Store differ diff --git a/邮件系统课程完整代码/NuGet/Fantasy.Config/Tools/Exporter/ConfigTable/Excel/.DS_Store b/邮件系统课程完整代码/NuGet/Fantasy.Config/Tools/Exporter/ConfigTable/Excel/.DS_Store new file mode 100644 index 0000000..fdc1b76 Binary files /dev/null and b/邮件系统课程完整代码/NuGet/Fantasy.Config/Tools/Exporter/ConfigTable/Excel/.DS_Store differ diff --git a/邮件系统课程完整代码/NuGet/Fantasy.Config/Tools/Exporter/ConfigTable/Excel/Custom.txt b/邮件系统课程完整代码/NuGet/Fantasy.Config/Tools/Exporter/ConfigTable/Excel/Custom.txt new file mode 100644 index 0000000..fd90a9b --- /dev/null +++ b/邮件系统课程完整代码/NuGet/Fantasy.Config/Tools/Exporter/ConfigTable/Excel/Custom.txt @@ -0,0 +1 @@ +// 自定义导出配置文件,用于配置自定义导出自定义程序的路径 diff --git a/邮件系统课程完整代码/NuGet/Fantasy.Config/Tools/Exporter/ConfigTable/Excel/Server/MachineConfig.xlsx b/邮件系统课程完整代码/NuGet/Fantasy.Config/Tools/Exporter/ConfigTable/Excel/Server/MachineConfig.xlsx new file mode 100644 index 0000000..999e939 Binary files /dev/null and b/邮件系统课程完整代码/NuGet/Fantasy.Config/Tools/Exporter/ConfigTable/Excel/Server/MachineConfig.xlsx differ diff --git a/邮件系统课程完整代码/NuGet/Fantasy.Config/Tools/Exporter/ConfigTable/Excel/Server/ProcessConfig.xlsx b/邮件系统课程完整代码/NuGet/Fantasy.Config/Tools/Exporter/ConfigTable/Excel/Server/ProcessConfig.xlsx new file mode 100644 index 0000000..001235a Binary files /dev/null and b/邮件系统课程完整代码/NuGet/Fantasy.Config/Tools/Exporter/ConfigTable/Excel/Server/ProcessConfig.xlsx differ diff --git a/邮件系统课程完整代码/NuGet/Fantasy.Config/Tools/Exporter/ConfigTable/Excel/Server/SceneConfig.xlsx b/邮件系统课程完整代码/NuGet/Fantasy.Config/Tools/Exporter/ConfigTable/Excel/Server/SceneConfig.xlsx new file mode 100644 index 0000000..a4ca05e Binary files /dev/null and b/邮件系统课程完整代码/NuGet/Fantasy.Config/Tools/Exporter/ConfigTable/Excel/Server/SceneConfig.xlsx differ diff --git a/邮件系统课程完整代码/NuGet/Fantasy.Config/Tools/Exporter/ConfigTable/Excel/Server/WorldConfig.xlsx b/邮件系统课程完整代码/NuGet/Fantasy.Config/Tools/Exporter/ConfigTable/Excel/Server/WorldConfig.xlsx new file mode 100644 index 0000000..8194c9a Binary files /dev/null and b/邮件系统课程完整代码/NuGet/Fantasy.Config/Tools/Exporter/ConfigTable/Excel/Server/WorldConfig.xlsx differ diff --git a/邮件系统课程完整代码/NuGet/Fantasy.Config/Tools/Exporter/ConfigTable/Excel/Version.txt b/邮件系统课程完整代码/NuGet/Fantasy.Config/Tools/Exporter/ConfigTable/Excel/Version.txt new file mode 100644 index 0000000..1877ad8 --- /dev/null +++ b/邮件系统课程完整代码/NuGet/Fantasy.Config/Tools/Exporter/ConfigTable/Excel/Version.txt @@ -0,0 +1 @@ +{"WorksheetNames":["MachineConfig","ProcessConfig","WorldConfig","SceneConfig","SceneTypeConfig"],"Tables":{"MachineConfig":1725984682557,"SceneConfig":1726083372000,"WorldConfig":1724007858627,"ProcessConfig":1725195494442}} \ No newline at end of file diff --git a/邮件系统课程完整代码/NuGet/Fantasy.Config/Tools/Exporter/ConfigTable/Json/Server/MachineConfigData.Json b/邮件系统课程完整代码/NuGet/Fantasy.Config/Tools/Exporter/ConfigTable/Json/Server/MachineConfigData.Json new file mode 100644 index 0000000..f56f98e --- /dev/null +++ b/邮件系统课程完整代码/NuGet/Fantasy.Config/Tools/Exporter/ConfigTable/Json/Server/MachineConfigData.Json @@ -0,0 +1,3 @@ +{"List":[ +{"Id":1,"OuterIP":"127.0.0.1","OuterBindIP":"127.0.0.1","InnerBindIP":"127.0.0.1"} +]} diff --git a/邮件系统课程完整代码/NuGet/Fantasy.Config/Tools/Exporter/ConfigTable/Json/Server/ProcessConfigData.Json b/邮件系统课程完整代码/NuGet/Fantasy.Config/Tools/Exporter/ConfigTable/Json/Server/ProcessConfigData.Json new file mode 100644 index 0000000..a05a13c --- /dev/null +++ b/邮件系统课程完整代码/NuGet/Fantasy.Config/Tools/Exporter/ConfigTable/Json/Server/ProcessConfigData.Json @@ -0,0 +1,3 @@ +{"List":[ +{"Id":1,"MachineId":1,"StartupGroup":0} +]} diff --git a/邮件系统课程完整代码/NuGet/Fantasy.Config/Tools/Exporter/ConfigTable/Json/Server/SceneConfigData.Json b/邮件系统课程完整代码/NuGet/Fantasy.Config/Tools/Exporter/ConfigTable/Json/Server/SceneConfigData.Json new file mode 100644 index 0000000..44996e7 --- /dev/null +++ b/邮件系统课程完整代码/NuGet/Fantasy.Config/Tools/Exporter/ConfigTable/Json/Server/SceneConfigData.Json @@ -0,0 +1,6 @@ +{"List":[ +{"Id":1001,"ProcessConfigId":1,"WorldConfigId":1,"SceneRuntimeType":"MultiThread","SceneTypeString":"Addressable","NetworkProtocol":null,"OuterPort":0,"InnerPort":11001,"SceneType":2}, +{"Id":1002,"ProcessConfigId":1,"WorldConfigId":1,"SceneRuntimeType":"MultiThread","SceneTypeString":"Gate","NetworkProtocol":"KCP","OuterPort":20000,"InnerPort":11002,"SceneType":3}, +{"Id":1003,"ProcessConfigId":1,"WorldConfigId":1,"SceneRuntimeType":"MultiThread","SceneTypeString":"Map","NetworkProtocol":null,"OuterPort":0,"InnerPort":11003,"SceneType":4}, +{"Id":1004,"ProcessConfigId":1,"WorldConfigId":1,"SceneRuntimeType":"MultiThread","SceneTypeString":"Chat","NetworkProtocol":null,"OuterPort":0,"InnerPort":11004,"SceneType":8} +]} diff --git a/邮件系统课程完整代码/NuGet/Fantasy.Config/Tools/Exporter/ConfigTable/Json/Server/WorldConfigData.Json b/邮件系统课程完整代码/NuGet/Fantasy.Config/Tools/Exporter/ConfigTable/Json/Server/WorldConfigData.Json new file mode 100644 index 0000000..60dd090 --- /dev/null +++ b/邮件系统课程完整代码/NuGet/Fantasy.Config/Tools/Exporter/ConfigTable/Json/Server/WorldConfigData.Json @@ -0,0 +1,3 @@ +{"List":[ +{"Id":1,"WorldName":"测试服","DbConnection":null,"DbName":"fantasy_main","DbType":"MongoDB"} +]} diff --git a/邮件系统课程完整代码/NuGet/Fantasy.Config/Tools/Exporter/ConfigTable/NetworkProtocol/Inner/InnerMessage.proto b/邮件系统课程完整代码/NuGet/Fantasy.Config/Tools/Exporter/ConfigTable/NetworkProtocol/Inner/InnerMessage.proto new file mode 100644 index 0000000..a8b51b8 --- /dev/null +++ b/邮件系统课程完整代码/NuGet/Fantasy.Config/Tools/Exporter/ConfigTable/NetworkProtocol/Inner/InnerMessage.proto @@ -0,0 +1,27 @@ +syntax = "proto3"; +package Sining.Message; +message G2A_TestRequest // IRouteRequest,G2A_TestResponse +{ + +} +message G2A_TestResponse // IRouteResponse +{ + +} +message G2M_RequestAddressableId // IRouteRequest,M2G_ResponseAddressableId +{ + +} +message M2G_ResponseAddressableId // IRouteResponse +{ + int64 AddressableId = 1; // Map服务器返回的AddressableId +} +/// 通知Chat服务器创建一个RouteId +message G2Chat_CreateRouteRequest // IRouteRequest,Chat2G_CreateRouteResponse +{ + int64 GateRouteId = 1; +} +message Chat2G_CreateRouteResponse // IRouteResponse +{ + int64 ChatRouteId = 1; +} \ No newline at end of file diff --git a/邮件系统课程完整代码/NuGet/Fantasy.Config/Tools/Exporter/ConfigTable/NetworkProtocol/OpCode.Cache b/邮件系统课程完整代码/NuGet/Fantasy.Config/Tools/Exporter/ConfigTable/NetworkProtocol/OpCode.Cache new file mode 100644 index 0000000..9e26dfe --- /dev/null +++ b/邮件系统课程完整代码/NuGet/Fantasy.Config/Tools/Exporter/ConfigTable/NetworkProtocol/OpCode.Cache @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/邮件系统课程完整代码/NuGet/Fantasy.Config/Tools/Exporter/ConfigTable/NetworkProtocol/Outer/OuterMessage.proto b/邮件系统课程完整代码/NuGet/Fantasy.Config/Tools/Exporter/ConfigTable/NetworkProtocol/Outer/OuterMessage.proto new file mode 100644 index 0000000..b036a74 --- /dev/null +++ b/邮件系统课程完整代码/NuGet/Fantasy.Config/Tools/Exporter/ConfigTable/NetworkProtocol/Outer/OuterMessage.proto @@ -0,0 +1,64 @@ +syntax = "proto3"; +package Fantasy.Network.Message; +// 协议分为: +// ProtoBuf:可以在Outer和Inner文件里使用。 +// MemoryPack:可以在Outer和Inner文件里使用。 +// Bson:仅支持在Inner文件里使用。 +// 使用方式: +// 在message协议上方添加// Protocol+空格+协议名字 +// 例如:// Protocol ProtoBuf 或 // Protocol MemoryPack +message C2G_TestMessage // IMessage +{ + string Tag = 1; +} +message C2G_TestRequest // IRequest,G2C_TestResponse +{ + string Tag = 1; +} +message G2C_TestResponse // IResponse +{ + string Tag = 1; +} +message C2G_CreateAddressableRequest // IRequest,G2C_CreateAddressableResponse +{ + +} +message G2C_CreateAddressableResponse // IResponse +{ + +} +message C2M_TestMessage // IAddressableRouteMessage +{ + string Tag = 1; +} +message C2M_TestRequest // IAddressableRouteRequest,M2C_TestResponse +{ + string Tag = 1; +} +message M2C_TestResponse // IAddressableRouteResponse +{ + string Tag = 1; +} +/// 通知Gate服务器创建一个Chat的Route连接 +message C2G_CreateChatRouteRequest // IRequest,G2C_CreateChatRouteResponse +{ + +} +message G2C_CreateChatRouteResponse // IResponse +{ + +} +/// 发送一个Route消息给Chat +message C2Chat_TestMessage // ICustomRouteMessage,ChatRoute +{ + string Tag = 1; +} +/// 发送一个RPCRoute消息给Chat +message C2Chat_TestMessageRequest // ICustomRouteRequest,Chat2C_TestMessageResponse,ChatRoute +{ + string Tag = 1; +} +message Chat2C_TestMessageResponse // ICustomRouteResponse +{ + string Tag = 1; +} \ No newline at end of file diff --git a/邮件系统课程完整代码/NuGet/Fantasy.Config/Tools/Exporter/ConfigTable/NetworkProtocol/RouteType.Config b/邮件系统课程完整代码/NuGet/Fantasy.Config/Tools/Exporter/ConfigTable/NetworkProtocol/RouteType.Config new file mode 100644 index 0000000..66082cf --- /dev/null +++ b/邮件系统课程完整代码/NuGet/Fantasy.Config/Tools/Exporter/ConfigTable/NetworkProtocol/RouteType.Config @@ -0,0 +1,3 @@ +// Route协议定义(需要定义1000以上、因为1000以内的框架预留) +GateRoute = 1001 // Gate +ChatRoute = 1002 // Chat \ No newline at end of file diff --git a/邮件系统课程完整代码/NuGet/Fantasy.Config/Tools/Exporter/ConfigTable/README.md b/邮件系统课程完整代码/NuGet/Fantasy.Config/Tools/Exporter/ConfigTable/README.md new file mode 100644 index 0000000..697ec05 --- /dev/null +++ b/邮件系统课程完整代码/NuGet/Fantasy.Config/Tools/Exporter/ConfigTable/README.md @@ -0,0 +1,16 @@ +# Fantasy-Net.Config +在Config文件夹中,存放着Fantasy所需的各种配置文件。这些文件涵盖了多个方面。每个配置文件都有其特定的格式和功能,通过精心设计的这些配置文件,开发团队能够快速调整框架参数,以实现更好的游戏体验,从而提升Fantasy的整体质量。 +## Excel文件夹 +里面存放了Fantasy.Net所需的四个Excel配置文件。用户可以利用Fantasy-Net.Exporter工具,依据这四个Excel文件生成相应的JSON文件,以供框架使用。这一过程不仅简化了数据处理,还确保了不同组件之间的无缝对接,使得工作流程更加高效。请确保在导出之前,Excel文件的格式和内容符合要求,以避免产生错误。 +## Json文件夹 +在该目录中存放了Fantasy.Net所需的四个JSON配置文件。用户可以根据这四个文件的模板进行添加或修改配置,以满足具体需求。每个项目的功能说明在相应的Excel文件中有详细描述,方便用户理解和使用这些配置文件。我们建议用户仔细阅读Excel文件中的说明,以确保配置的正确性和有效性。 +## NetworkProtocol文件夹 +存放框架所需定义网络协议的模版和文件夹 +### Inner文件夹 +定义服务器之间的网络协议 +### Outer文件夹 +定义客户端和服务器之间的网络协议 +### RouteType.Config +定义自定义Route协议的配置文件 +## 交流与讨论: +__讨论QQ群 : Fantasy服务器开发交流群 569888673 __ \ No newline at end of file diff --git a/邮件系统课程完整代码/NuGet/Fantasy.Config/bin/.DS_Store b/邮件系统课程完整代码/NuGet/Fantasy.Config/bin/.DS_Store new file mode 100644 index 0000000..1dd5fa5 Binary files /dev/null and b/邮件系统课程完整代码/NuGet/Fantasy.Config/bin/.DS_Store differ diff --git a/邮件系统课程完整代码/NuGet/Fantasy.Config/bin/Debug/.DS_Store b/邮件系统课程完整代码/NuGet/Fantasy.Config/bin/Debug/.DS_Store new file mode 100644 index 0000000..d33ac08 Binary files /dev/null and b/邮件系统课程完整代码/NuGet/Fantasy.Config/bin/Debug/.DS_Store differ diff --git a/邮件系统课程完整代码/NuGet/Fantasy.Config/obj/Debug/net8.0/.NETCoreApp,Version=v8.0.AssemblyAttributes.cs b/邮件系统课程完整代码/NuGet/Fantasy.Config/obj/Debug/net8.0/.NETCoreApp,Version=v8.0.AssemblyAttributes.cs new file mode 100644 index 0000000..2217181 --- /dev/null +++ b/邮件系统课程完整代码/NuGet/Fantasy.Config/obj/Debug/net8.0/.NETCoreApp,Version=v8.0.AssemblyAttributes.cs @@ -0,0 +1,4 @@ +// +using System; +using System.Reflection; +[assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute(".NETCoreApp,Version=v8.0", FrameworkDisplayName = ".NET 8.0")] diff --git a/邮件系统课程完整代码/NuGet/Fantasy.Config/obj/Debug/net8.0/Fantasy.Config.AssemblyInfo.cs b/邮件系统课程完整代码/NuGet/Fantasy.Config/obj/Debug/net8.0/Fantasy.Config.AssemblyInfo.cs new file mode 100644 index 0000000..60f7b66 --- /dev/null +++ b/邮件系统课程完整代码/NuGet/Fantasy.Config/obj/Debug/net8.0/Fantasy.Config.AssemblyInfo.cs @@ -0,0 +1,22 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +using System; +using System.Reflection; + +[assembly: System.Reflection.AssemblyCompanyAttribute("Fantasy.Config")] +[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")] +[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")] +[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0")] +[assembly: System.Reflection.AssemblyProductAttribute("Fantasy.Config")] +[assembly: System.Reflection.AssemblyTitleAttribute("Fantasy.Config")] +[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")] + +// 由 MSBuild WriteCodeFragment 类生成。 + diff --git a/邮件系统课程完整代码/NuGet/Fantasy.Config/obj/Debug/net8.0/Fantasy.Config.AssemblyInfoInputs.cache b/邮件系统课程完整代码/NuGet/Fantasy.Config/obj/Debug/net8.0/Fantasy.Config.AssemblyInfoInputs.cache new file mode 100644 index 0000000..1950edd --- /dev/null +++ b/邮件系统课程完整代码/NuGet/Fantasy.Config/obj/Debug/net8.0/Fantasy.Config.AssemblyInfoInputs.cache @@ -0,0 +1 @@ +10b339dabefebaf09b7ba9ea3447b7f3d3308efa4228246ee45a0d671d0fd112 diff --git a/邮件系统课程完整代码/NuGet/Fantasy.Config/obj/Debug/net8.0/Fantasy.Config.GeneratedMSBuildEditorConfig.editorconfig b/邮件系统课程完整代码/NuGet/Fantasy.Config/obj/Debug/net8.0/Fantasy.Config.GeneratedMSBuildEditorConfig.editorconfig new file mode 100644 index 0000000..27a1b5a --- /dev/null +++ b/邮件系统课程完整代码/NuGet/Fantasy.Config/obj/Debug/net8.0/Fantasy.Config.GeneratedMSBuildEditorConfig.editorconfig @@ -0,0 +1,15 @@ +is_global = true +build_property.TargetFramework = net8.0 +build_property.TargetPlatformMinVersion = +build_property.UsingMicrosoftNETSdkWeb = +build_property.ProjectTypeGuids = +build_property.InvariantGlobalization = +build_property.PlatformNeutralAssembly = +build_property.EnforceExtendedAnalyzerRules = +build_property._SupportedPlatformList = Linux,macOS,Windows +build_property.RootNamespace = Fantasy.Config +build_property.ProjectDir = /Users/fantasy/Movies/邮件系统/Lession/NuGet/Fantasy.Config/ +build_property.EnableComHosting = +build_property.EnableGeneratedComInterfaceComImportInterop = +build_property.EffectiveAnalysisLevelStyle = 8.0 +build_property.EnableCodeStyleSeverity = diff --git a/邮件系统课程完整代码/NuGet/Fantasy.Config/obj/Debug/net8.0/Fantasy.Config.GlobalUsings.g.cs b/邮件系统课程完整代码/NuGet/Fantasy.Config/obj/Debug/net8.0/Fantasy.Config.GlobalUsings.g.cs new file mode 100644 index 0000000..8578f3d --- /dev/null +++ b/邮件系统课程完整代码/NuGet/Fantasy.Config/obj/Debug/net8.0/Fantasy.Config.GlobalUsings.g.cs @@ -0,0 +1,8 @@ +// +global using global::System; +global using global::System.Collections.Generic; +global using global::System.IO; +global using global::System.Linq; +global using global::System.Net.Http; +global using global::System.Threading; +global using global::System.Threading.Tasks; diff --git a/邮件系统课程完整代码/NuGet/Fantasy.Config/obj/Debug/net8.0/Fantasy.Config.assets.cache b/邮件系统课程完整代码/NuGet/Fantasy.Config/obj/Debug/net8.0/Fantasy.Config.assets.cache new file mode 100644 index 0000000..c92a7d2 Binary files /dev/null and b/邮件系统课程完整代码/NuGet/Fantasy.Config/obj/Debug/net8.0/Fantasy.Config.assets.cache differ diff --git a/邮件系统课程完整代码/NuGet/Fantasy.Config/obj/Debug/net8.0/Fantasy.Config.csproj.AssemblyReference.cache b/邮件系统课程完整代码/NuGet/Fantasy.Config/obj/Debug/net8.0/Fantasy.Config.csproj.AssemblyReference.cache new file mode 100644 index 0000000..b6b9bb9 Binary files /dev/null and b/邮件系统课程完整代码/NuGet/Fantasy.Config/obj/Debug/net8.0/Fantasy.Config.csproj.AssemblyReference.cache differ diff --git a/邮件系统课程完整代码/NuGet/Fantasy.Config/obj/Fantasy.Config.csproj.nuget.dgspec.json b/邮件系统课程完整代码/NuGet/Fantasy.Config/obj/Fantasy.Config.csproj.nuget.dgspec.json new file mode 100644 index 0000000..3c301d1 --- /dev/null +++ b/邮件系统课程完整代码/NuGet/Fantasy.Config/obj/Fantasy.Config.csproj.nuget.dgspec.json @@ -0,0 +1,74 @@ +{ + "format": 1, + "restore": { + "/Users/fantasy/Movies/邮件系统/Lession/NuGet/Fantasy.Config/Fantasy.Config.csproj": {} + }, + "projects": { + "/Users/fantasy/Movies/邮件系统/Lession/NuGet/Fantasy.Config/Fantasy.Config.csproj": { + "version": "1.0.0", + "restore": { + "projectUniqueName": "/Users/fantasy/Movies/邮件系统/Lession/NuGet/Fantasy.Config/Fantasy.Config.csproj", + "projectName": "Fantasy.Config", + "projectPath": "/Users/fantasy/Movies/邮件系统/Lession/NuGet/Fantasy.Config/Fantasy.Config.csproj", + "packagesPath": "/Users/fantasy/.nuget/packages/", + "outputPath": "/Users/fantasy/Movies/邮件系统/Lession/NuGet/Fantasy.Config/obj/", + "projectStyle": "PackageReference", + "configFilePaths": [ + "/Users/fantasy/.nuget/NuGet/NuGet.Config" + ], + "originalTargetFrameworks": [ + "net8.0" + ], + "sources": { + "/usr/local/share/dotnet/library-packs": {}, + "https://api.nuget.org/v3/index.json": {} + }, + "frameworks": { + "net8.0": { + "targetAlias": "net8.0", + "projectReferences": {} + } + }, + "warningProperties": { + "warnAsError": [ + "NU1605" + ] + }, + "restoreAuditProperties": { + "enableAudit": "true", + "auditLevel": "low", + "auditMode": "all" + }, + "SdkAnalysisLevel": "9.0.100" + }, + "frameworks": { + "net8.0": { + "targetAlias": "net8.0", + "dependencies": { + "Fantasy-Net.Config": { + "target": "Package", + "version": "[2024.1.4, )" + } + }, + "imports": [ + "net461", + "net462", + "net47", + "net471", + "net472", + "net48", + "net481" + ], + "assetTargetFallback": true, + "warn": true, + "frameworkReferences": { + "Microsoft.NETCore.App": { + "privateAssets": "all" + } + }, + "runtimeIdentifierGraphPath": "/usr/local/share/dotnet/sdk/9.0.100/PortableRuntimeIdentifierGraph.json" + } + } + } + } +} \ No newline at end of file diff --git a/邮件系统课程完整代码/NuGet/Fantasy.Config/obj/Fantasy.Config.csproj.nuget.g.props b/邮件系统课程完整代码/NuGet/Fantasy.Config/obj/Fantasy.Config.csproj.nuget.g.props new file mode 100644 index 0000000..610728b --- /dev/null +++ b/邮件系统课程完整代码/NuGet/Fantasy.Config/obj/Fantasy.Config.csproj.nuget.g.props @@ -0,0 +1,18 @@ + + + + True + NuGet + $(MSBuildThisFileDirectory)project.assets.json + /Users/fantasy/.nuget/packages/ + /Users/fantasy/.nuget/packages/ + PackageReference + 6.12.2 + + + + + + /Users/fantasy/.nuget/packages/fantasy-net.config/2024.1.4 + + \ No newline at end of file diff --git a/邮件系统课程完整代码/NuGet/Fantasy.Config/obj/Fantasy.Config.csproj.nuget.g.targets b/邮件系统课程完整代码/NuGet/Fantasy.Config/obj/Fantasy.Config.csproj.nuget.g.targets new file mode 100644 index 0000000..a660f7f --- /dev/null +++ b/邮件系统课程完整代码/NuGet/Fantasy.Config/obj/Fantasy.Config.csproj.nuget.g.targets @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/邮件系统课程完整代码/NuGet/Fantasy.Config/obj/project.assets.json b/邮件系统课程完整代码/NuGet/Fantasy.Config/obj/project.assets.json new file mode 100644 index 0000000..8020077 --- /dev/null +++ b/邮件系统课程完整代码/NuGet/Fantasy.Config/obj/project.assets.json @@ -0,0 +1,126 @@ +{ + "version": 3, + "targets": { + "net8.0": { + "Fantasy-Net.Config/2024.1.4": { + "type": "package", + "compile": { + "lib/net8.0/Fantasy-Net.Config.dll": {} + }, + "runtime": { + "lib/net8.0/Fantasy-Net.Config.dll": {} + }, + "build": { + "buildTransitive/Fantasy-Net.Config.targets": {} + } + } + } + }, + "libraries": { + "Fantasy-Net.Config/2024.1.4": { + "sha512": "zStTIJq91mx3VjCcU7eAtrExAcv1Zg+dAd8UdDvpHu7kTY8ldDQMp8sCmez2s+vUTmNyH1hlOgEE3rJILAijfQ==", + "type": "package", + "path": "fantasy-net.config/2024.1.4", + "hasTools": true, + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "README.md", + "buildTransitive/Fantasy-Net.Config.targets", + "fantasy-net.config.2024.1.4.nupkg.sha512", + "fantasy-net.config.nuspec", + "icon.png", + "lib/net8.0/Fantasy-Net.Config.dll", + "tools/output/Excel/Custom.txt", + "tools/output/Excel/Server/MachineConfig.xlsx", + "tools/output/Excel/Server/ProcessConfig.xlsx", + "tools/output/Excel/Server/SceneConfig.xlsx", + "tools/output/Excel/Server/WorldConfig.xlsx", + "tools/output/Excel/Version.txt", + "tools/output/Json/Server/MachineConfigData.Json", + "tools/output/Json/Server/ProcessConfigData.Json", + "tools/output/Json/Server/SceneConfigData.Json", + "tools/output/Json/Server/WorldConfigData.Json", + "tools/output/NetworkProtocol/Inner/InnerMessage.proto", + "tools/output/NetworkProtocol/OpCode.Cache", + "tools/output/NetworkProtocol/Outer/OuterMessage.proto", + "tools/output/NetworkProtocol/RouteType.Config", + "tools/output/README.md" + ] + } + }, + "projectFileDependencyGroups": { + "net8.0": [ + "Fantasy-Net.Config >= 2024.1.4" + ] + }, + "packageFolders": { + "/Users/fantasy/.nuget/packages/": {} + }, + "project": { + "version": "1.0.0", + "restore": { + "projectUniqueName": "/Users/fantasy/Movies/邮件系统/Lession/NuGet/Fantasy.Config/Fantasy.Config.csproj", + "projectName": "Fantasy.Config", + "projectPath": "/Users/fantasy/Movies/邮件系统/Lession/NuGet/Fantasy.Config/Fantasy.Config.csproj", + "packagesPath": "/Users/fantasy/.nuget/packages/", + "outputPath": "/Users/fantasy/Movies/邮件系统/Lession/NuGet/Fantasy.Config/obj/", + "projectStyle": "PackageReference", + "configFilePaths": [ + "/Users/fantasy/.nuget/NuGet/NuGet.Config" + ], + "originalTargetFrameworks": [ + "net8.0" + ], + "sources": { + "/usr/local/share/dotnet/library-packs": {}, + "https://api.nuget.org/v3/index.json": {} + }, + "frameworks": { + "net8.0": { + "targetAlias": "net8.0", + "projectReferences": {} + } + }, + "warningProperties": { + "warnAsError": [ + "NU1605" + ] + }, + "restoreAuditProperties": { + "enableAudit": "true", + "auditLevel": "low", + "auditMode": "all" + }, + "SdkAnalysisLevel": "9.0.100" + }, + "frameworks": { + "net8.0": { + "targetAlias": "net8.0", + "dependencies": { + "Fantasy-Net.Config": { + "target": "Package", + "version": "[2024.1.4, )" + } + }, + "imports": [ + "net461", + "net462", + "net47", + "net471", + "net472", + "net48", + "net481" + ], + "assetTargetFallback": true, + "warn": true, + "frameworkReferences": { + "Microsoft.NETCore.App": { + "privateAssets": "all" + } + }, + "runtimeIdentifierGraphPath": "/usr/local/share/dotnet/sdk/9.0.100/PortableRuntimeIdentifierGraph.json" + } + } + } +} \ No newline at end of file diff --git a/邮件系统课程完整代码/NuGet/Fantasy.Config/obj/project.nuget.cache b/邮件系统课程完整代码/NuGet/Fantasy.Config/obj/project.nuget.cache new file mode 100644 index 0000000..61f4162 --- /dev/null +++ b/邮件系统课程完整代码/NuGet/Fantasy.Config/obj/project.nuget.cache @@ -0,0 +1,10 @@ +{ + "version": 2, + "dgSpecHash": "Q4ePIhO2blI=", + "success": true, + "projectFilePath": "/Users/fantasy/Movies/邮件系统/Lession/NuGet/Fantasy.Config/Fantasy.Config.csproj", + "expectedPackageFiles": [ + "/Users/fantasy/.nuget/packages/fantasy-net.config/2024.1.4/fantasy-net.config.2024.1.4.nupkg.sha512" + ], + "logs": [] +} \ No newline at end of file diff --git a/邮件系统课程完整代码/NuGet/Fantasy.Config/obj/project.packagespec.json b/邮件系统课程完整代码/NuGet/Fantasy.Config/obj/project.packagespec.json new file mode 100644 index 0000000..6faafa7 --- /dev/null +++ b/邮件系统课程完整代码/NuGet/Fantasy.Config/obj/project.packagespec.json @@ -0,0 +1 @@ +"restore":{"projectUniqueName":"/Users/fantasy/Movies/邮件系统/Lession/NuGet/Fantasy.Config/Fantasy.Config.csproj","projectName":"Fantasy.Config","projectPath":"/Users/fantasy/Movies/邮件系统/Lession/NuGet/Fantasy.Config/Fantasy.Config.csproj","outputPath":"/Users/fantasy/Movies/邮件系统/Lession/NuGet/Fantasy.Config/obj/","projectStyle":"PackageReference","originalTargetFrameworks":["net8.0"],"sources":{"/usr/local/share/dotnet/library-packs":{},"https://api.nuget.org/v3/index.json":{}},"frameworks":{"net8.0":{"targetAlias":"net8.0","projectReferences":{}}},"warningProperties":{"warnAsError":["NU1605"]},"restoreAuditProperties":{"enableAudit":"true","auditLevel":"low","auditMode":"all"},"SdkAnalysisLevel":"9.0.100"}"frameworks":{"net8.0":{"targetAlias":"net8.0","dependencies":{"Fantasy-Net.Config":{"target":"Package","version":"[2024.1.4, )"}},"imports":["net461","net462","net47","net471","net472","net48","net481"],"assetTargetFallback":true,"warn":true,"frameworkReferences":{"Microsoft.NETCore.App":{"privateAssets":"all"}},"runtimeIdentifierGraphPath":"/usr/local/share/dotnet/sdk/9.0.100/PortableRuntimeIdentifierGraph.json"}} \ No newline at end of file diff --git a/邮件系统课程完整代码/NuGet/Fantasy.Config/obj/rider.project.model.nuget.info b/邮件系统课程完整代码/NuGet/Fantasy.Config/obj/rider.project.model.nuget.info new file mode 100644 index 0000000..4a46a46 --- /dev/null +++ b/邮件系统课程完整代码/NuGet/Fantasy.Config/obj/rider.project.model.nuget.info @@ -0,0 +1 @@ +17392438089758258 \ No newline at end of file diff --git a/邮件系统课程完整代码/NuGet/Fantasy.Config/obj/rider.project.restore.info b/邮件系统课程完整代码/NuGet/Fantasy.Config/obj/rider.project.restore.info new file mode 100644 index 0000000..4a46a46 --- /dev/null +++ b/邮件系统课程完整代码/NuGet/Fantasy.Config/obj/rider.project.restore.info @@ -0,0 +1 @@ +17392438089758258 \ No newline at end of file diff --git a/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/.DS_Store b/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/.DS_Store new file mode 100644 index 0000000..986fd0d Binary files /dev/null and b/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/.DS_Store differ diff --git a/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/Fantasy.ConfigTableProtocol.csproj b/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/Fantasy.ConfigTableProtocol.csproj new file mode 100644 index 0000000..49882cd --- /dev/null +++ b/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/Fantasy.ConfigTableProtocol.csproj @@ -0,0 +1,13 @@ + + + + net8.0 + enable + enable + + + + + + + diff --git a/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/Tools/.DS_Store b/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/Tools/.DS_Store new file mode 100644 index 0000000..7977e1e Binary files /dev/null and b/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/Tools/.DS_Store differ diff --git a/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/Tools/Exporter/ConfigTable/CommandLine.dll b/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/Tools/Exporter/ConfigTable/CommandLine.dll new file mode 100644 index 0000000..3eab2be Binary files /dev/null and b/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/Tools/Exporter/ConfigTable/CommandLine.dll differ diff --git a/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/Tools/Exporter/ConfigTable/EPPlus.Interfaces.dll b/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/Tools/Exporter/ConfigTable/EPPlus.Interfaces.dll new file mode 100644 index 0000000..599a767 Binary files /dev/null and b/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/Tools/Exporter/ConfigTable/EPPlus.Interfaces.dll differ diff --git a/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/Tools/Exporter/ConfigTable/EPPlus.System.Drawing.dll b/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/Tools/Exporter/ConfigTable/EPPlus.System.Drawing.dll new file mode 100644 index 0000000..8df125e Binary files /dev/null and b/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/Tools/Exporter/ConfigTable/EPPlus.System.Drawing.dll differ diff --git a/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/Tools/Exporter/ConfigTable/EPPlus.dll b/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/Tools/Exporter/ConfigTable/EPPlus.dll new file mode 100644 index 0000000..b09ea77 Binary files /dev/null and b/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/Tools/Exporter/ConfigTable/EPPlus.dll differ diff --git a/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/Tools/Exporter/ConfigTable/ExporterSettings.json b/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/Tools/Exporter/ConfigTable/ExporterSettings.json new file mode 100644 index 0000000..7499bd6 --- /dev/null +++ b/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/Tools/Exporter/ConfigTable/ExporterSettings.json @@ -0,0 +1,44 @@ +{ + "Export": { + "ExcelProgramPath": { + "Value": "../../../Examples/Config/Excel/", + "Comment": "Excel文件夹的根目录" + }, + "ExcelVersionFile": { + "Value": "../../../Examples/Config/Excel/Version.txt", + "Comment": "Excel的Version文件位置、这个文件用于记录每次导出对比是否需要再次导出的文件" + }, + "ExcelServerFileDirectory": { + "Value": "../../../Examples/Server/Entity/Generate/ConfigTable/Entity/", + "Comment": "Excel生成的代码文件、在服务端文件夹位置" + }, + "ExcelClientFileDirectory": { + "Value": "../../../Examples/Client/Unity/Assets/Scripts/Hotfix/Generate/ConfigTable/Entity/", + "Comment": "Excel生成的代码文件、在客户端文件夹位置" + }, + "ExcelServerBinaryDirectory": { + "Value": "../../../Examples/Config/Binary/", + "Comment": "Excel生成服务器二进制数据文件夹位置" + }, + "ExcelClientBinaryDirectory": { + "Value": "../../../Examples/Client/Unity/Assets/Bundles/Config/", + "Comment": "Excel生成在客户端的二进制数据文件夹位置" + }, + "ExcelServerJsonDirectory": { + "Value": "../../../Examples/Config/Json/Server/", + "Comment": "Excel生成在服务端的Json数据文件夹位置" + }, + "ExcelClientJsonDirectory": { + "Value": "../../../Examples/Config/Json/Client/", + "Comment": "Excel生成在客户端的Json数据文件夹位置" + }, + "ServerCustomExportDirectory": { + "Value": "../../../Examples/Server/Entity/Generate/CustomExport/", + "Comment": "Excel在服务端生成自定义代码的文件夹位置" + }, + "ClientCustomExportDirectory": { + "Value": "../../../Examples/Client/Unity/Assets/Scripts/Hotfix/Generate/CustomExport", + "Comment": "Excel在客户端端生成自定义代码的文件夹位置" + } + } +} \ No newline at end of file diff --git a/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/Tools/Exporter/ConfigTable/Fantasy.Tools.ConfigTable b/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/Tools/Exporter/ConfigTable/Fantasy.Tools.ConfigTable new file mode 100644 index 0000000..434496e Binary files /dev/null and b/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/Tools/Exporter/ConfigTable/Fantasy.Tools.ConfigTable differ diff --git a/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/Tools/Exporter/ConfigTable/Fantasy.Tools.ConfigTable.deps.json b/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/Tools/Exporter/ConfigTable/Fantasy.Tools.ConfigTable.deps.json new file mode 100644 index 0000000..b248849 --- /dev/null +++ b/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/Tools/Exporter/ConfigTable/Fantasy.Tools.ConfigTable.deps.json @@ -0,0 +1,521 @@ +{ + "runtimeTarget": { + "name": ".NETCoreApp,Version=v8.0", + "signature": "" + }, + "compilationOptions": {}, + "targets": { + ".NETCoreApp,Version=v8.0": { + "Fantasy.Tools.ConfigTable/1.0.0": { + "dependencies": { + "CommandLineParser": "2.9.1", + "EPPlus": "7.3.2", + "Microsoft.CodeAnalysis.CSharp": "4.11.0", + "Microsoft.Extensions.Configuration.Json": "8.0.0", + "Newtonsoft.Json": "13.0.3", + "protobuf-net": "3.2.30" + }, + "runtime": { + "Fantasy.Tools.ConfigTable.dll": {} + } + }, + "CommandLineParser/2.9.1": { + "runtime": { + "lib/netstandard2.0/CommandLine.dll": { + "assemblyVersion": "2.9.1.0", + "fileVersion": "2.9.1.0" + } + } + }, + "EPPlus/7.3.2": { + "dependencies": { + "EPPlus.System.Drawing": "6.1.1", + "Microsoft.Extensions.Configuration.Json": "8.0.0", + "Microsoft.IO.RecyclableMemoryStream": "3.0.1", + "System.ComponentModel.Annotations": "5.0.0", + "System.Formats.Asn1": "8.0.1", + "System.Security.Cryptography.Pkcs": "8.0.0", + "System.Text.Encoding.CodePages": "8.0.0", + "System.Text.Json": "8.0.4" + }, + "runtime": { + "lib/net8.0/EPPlus.dll": { + "assemblyVersion": "7.3.2.0", + "fileVersion": "7.3.2.0" + } + } + }, + "EPPlus.Interfaces/6.1.1": { + "runtime": { + "lib/net7.0/EPPlus.Interfaces.dll": { + "assemblyVersion": "6.1.1.0", + "fileVersion": "6.1.1.0" + } + } + }, + "EPPlus.System.Drawing/6.1.1": { + "dependencies": { + "EPPlus.Interfaces": "6.1.1", + "System.Drawing.Common": "7.0.0" + }, + "runtime": { + "lib/net7.0/EPPlus.System.Drawing.dll": { + "assemblyVersion": "6.1.1.0", + "fileVersion": "6.1.1.0" + } + } + }, + "Microsoft.CodeAnalysis.Analyzers/3.3.4": {}, + "Microsoft.CodeAnalysis.Common/4.11.0": { + "dependencies": { + "Microsoft.CodeAnalysis.Analyzers": "3.3.4", + "System.Collections.Immutable": "8.0.0", + "System.Reflection.Metadata": "8.0.0" + }, + "runtime": { + "lib/net8.0/Microsoft.CodeAnalysis.dll": { + "assemblyVersion": "4.11.0.0", + "fileVersion": "4.1100.24.37604" + } + } + }, + "Microsoft.CodeAnalysis.CSharp/4.11.0": { + "dependencies": { + "Microsoft.CodeAnalysis.Analyzers": "3.3.4", + "Microsoft.CodeAnalysis.Common": "4.11.0", + "System.Collections.Immutable": "8.0.0", + "System.Reflection.Metadata": "8.0.0" + }, + "runtime": { + "lib/net8.0/Microsoft.CodeAnalysis.CSharp.dll": { + "assemblyVersion": "4.11.0.0", + "fileVersion": "4.1100.24.37604" + } + } + }, + "Microsoft.Extensions.Configuration/8.0.0": { + "dependencies": { + "Microsoft.Extensions.Configuration.Abstractions": "8.0.0", + "Microsoft.Extensions.Primitives": "8.0.0" + }, + "runtime": { + "lib/net8.0/Microsoft.Extensions.Configuration.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.23.53103" + } + } + }, + "Microsoft.Extensions.Configuration.Abstractions/8.0.0": { + "dependencies": { + "Microsoft.Extensions.Primitives": "8.0.0" + }, + "runtime": { + "lib/net8.0/Microsoft.Extensions.Configuration.Abstractions.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.23.53103" + } + } + }, + "Microsoft.Extensions.Configuration.FileExtensions/8.0.0": { + "dependencies": { + "Microsoft.Extensions.Configuration": "8.0.0", + "Microsoft.Extensions.Configuration.Abstractions": "8.0.0", + "Microsoft.Extensions.FileProviders.Abstractions": "8.0.0", + "Microsoft.Extensions.FileProviders.Physical": "8.0.0", + "Microsoft.Extensions.Primitives": "8.0.0" + }, + "runtime": { + "lib/net8.0/Microsoft.Extensions.Configuration.FileExtensions.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.23.53103" + } + } + }, + "Microsoft.Extensions.Configuration.Json/8.0.0": { + "dependencies": { + "Microsoft.Extensions.Configuration": "8.0.0", + "Microsoft.Extensions.Configuration.Abstractions": "8.0.0", + "Microsoft.Extensions.Configuration.FileExtensions": "8.0.0", + "Microsoft.Extensions.FileProviders.Abstractions": "8.0.0", + "System.Text.Json": "8.0.4" + }, + "runtime": { + "lib/net8.0/Microsoft.Extensions.Configuration.Json.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.23.53103" + } + } + }, + "Microsoft.Extensions.FileProviders.Abstractions/8.0.0": { + "dependencies": { + "Microsoft.Extensions.Primitives": "8.0.0" + }, + "runtime": { + "lib/net8.0/Microsoft.Extensions.FileProviders.Abstractions.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.23.53103" + } + } + }, + "Microsoft.Extensions.FileProviders.Physical/8.0.0": { + "dependencies": { + "Microsoft.Extensions.FileProviders.Abstractions": "8.0.0", + "Microsoft.Extensions.FileSystemGlobbing": "8.0.0", + "Microsoft.Extensions.Primitives": "8.0.0" + }, + "runtime": { + "lib/net8.0/Microsoft.Extensions.FileProviders.Physical.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.23.53103" + } + } + }, + "Microsoft.Extensions.FileSystemGlobbing/8.0.0": { + "runtime": { + "lib/net8.0/Microsoft.Extensions.FileSystemGlobbing.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.23.53103" + } + } + }, + "Microsoft.Extensions.Primitives/8.0.0": { + "runtime": { + "lib/net8.0/Microsoft.Extensions.Primitives.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.23.53103" + } + } + }, + "Microsoft.IO.RecyclableMemoryStream/3.0.1": { + "runtime": { + "lib/net6.0/Microsoft.IO.RecyclableMemoryStream.dll": { + "assemblyVersion": "3.0.1.0", + "fileVersion": "3.0.1.0" + } + } + }, + "Microsoft.Win32.SystemEvents/7.0.0": { + "runtime": { + "lib/net7.0/Microsoft.Win32.SystemEvents.dll": { + "assemblyVersion": "7.0.0.0", + "fileVersion": "7.0.22.51805" + } + }, + "runtimeTargets": { + "runtimes/win/lib/net7.0/Microsoft.Win32.SystemEvents.dll": { + "rid": "win", + "assetType": "runtime", + "assemblyVersion": "7.0.0.0", + "fileVersion": "7.0.22.51805" + } + } + }, + "Newtonsoft.Json/13.0.3": { + "runtime": { + "lib/net6.0/Newtonsoft.Json.dll": { + "assemblyVersion": "13.0.0.0", + "fileVersion": "13.0.3.27908" + } + } + }, + "protobuf-net/3.2.30": { + "dependencies": { + "protobuf-net.Core": "3.2.30" + }, + "runtime": { + "lib/net6.0/protobuf-net.dll": { + "assemblyVersion": "3.0.0.0", + "fileVersion": "3.2.30.709" + } + } + }, + "protobuf-net.Core/3.2.30": { + "dependencies": { + "System.Collections.Immutable": "8.0.0" + }, + "runtime": { + "lib/net6.0/protobuf-net.Core.dll": { + "assemblyVersion": "3.0.0.0", + "fileVersion": "3.2.30.709" + } + } + }, + "System.Collections.Immutable/8.0.0": {}, + "System.ComponentModel.Annotations/5.0.0": {}, + "System.Drawing.Common/7.0.0": { + "dependencies": { + "Microsoft.Win32.SystemEvents": "7.0.0" + }, + "runtime": { + "lib/net7.0/System.Drawing.Common.dll": { + "assemblyVersion": "7.0.0.0", + "fileVersion": "7.0.22.51805" + } + }, + "runtimeTargets": { + "runtimes/win/lib/net7.0/System.Drawing.Common.dll": { + "rid": "win", + "assetType": "runtime", + "assemblyVersion": "7.0.0.0", + "fileVersion": "7.0.22.51805" + } + } + }, + "System.Formats.Asn1/8.0.1": { + "runtime": { + "lib/net8.0/System.Formats.Asn1.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.724.31311" + } + } + }, + "System.Reflection.Metadata/8.0.0": { + "dependencies": { + "System.Collections.Immutable": "8.0.0" + } + }, + "System.Security.Cryptography.Pkcs/8.0.0": { + "dependencies": { + "System.Formats.Asn1": "8.0.1" + }, + "runtime": { + "lib/net8.0/System.Security.Cryptography.Pkcs.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.23.53103" + } + }, + "runtimeTargets": { + "runtimes/win/lib/net8.0/System.Security.Cryptography.Pkcs.dll": { + "rid": "win", + "assetType": "runtime", + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.23.53103" + } + } + }, + "System.Text.Encoding.CodePages/8.0.0": {}, + "System.Text.Encodings.Web/8.0.0": {}, + "System.Text.Json/8.0.4": { + "dependencies": { + "System.Text.Encodings.Web": "8.0.0" + }, + "runtime": { + "lib/net8.0/System.Text.Json.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.724.31311" + } + } + } + } + }, + "libraries": { + "Fantasy.Tools.ConfigTable/1.0.0": { + "type": "project", + "serviceable": false, + "sha512": "" + }, + "CommandLineParser/2.9.1": { + "type": "package", + "serviceable": true, + "sha512": "sha512-OE0sl1/sQ37bjVsPKKtwQlWDgqaxWgtme3xZz7JssWUzg5JpMIyHgCTY9MVMxOg48fJ1AgGT3tgdH5m/kQ5xhA==", + "path": "commandlineparser/2.9.1", + "hashPath": "commandlineparser.2.9.1.nupkg.sha512" + }, + "EPPlus/7.3.2": { + "type": "package", + "serviceable": true, + "sha512": "sha512-9DShQD2VuDZ7QLHp+map1r2HdI1G325YGkvRG+qs4N2fgeMF1Uq0TONCEL5gKCWMNDVGO0ZELJTAIzwNyOZQug==", + "path": "epplus/7.3.2", + "hashPath": "epplus.7.3.2.nupkg.sha512" + }, + "EPPlus.Interfaces/6.1.1": { + "type": "package", + "serviceable": true, + "sha512": "sha512-y7dkrOoE1ZR9Vgy1Jf2rEIaTf3SHlUjYt01NklP+F5Qh7S2ruPbzTcpYLRWMeXiG8XL8h2jqX4CyIkFt3NQGZw==", + "path": "epplus.interfaces/6.1.1", + "hashPath": "epplus.interfaces.6.1.1.nupkg.sha512" + }, + "EPPlus.System.Drawing/6.1.1": { + "type": "package", + "serviceable": true, + "sha512": "sha512-lRF5gHYrmkHOOiLMI0t6q8zNYjUrzRgAM5BCXumv5xiqXko8fx3AWI+HCNZfhEqVFGOop+42KfR5GiUcCoyoMw==", + "path": "epplus.system.drawing/6.1.1", + "hashPath": "epplus.system.drawing.6.1.1.nupkg.sha512" + }, + "Microsoft.CodeAnalysis.Analyzers/3.3.4": { + "type": "package", + "serviceable": true, + "sha512": "sha512-AxkxcPR+rheX0SmvpLVIGLhOUXAKG56a64kV9VQZ4y9gR9ZmPXnqZvHJnmwLSwzrEP6junUF11vuc+aqo5r68g==", + "path": "microsoft.codeanalysis.analyzers/3.3.4", + "hashPath": "microsoft.codeanalysis.analyzers.3.3.4.nupkg.sha512" + }, + "Microsoft.CodeAnalysis.Common/4.11.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-djf8ujmqYImFgB04UGtcsEhHrzVqzHowS+EEl/Yunc5LdrYrZhGBWUTXoCF0NzYXJxtfuD+UVQarWpvrNc94Qg==", + "path": "microsoft.codeanalysis.common/4.11.0", + "hashPath": "microsoft.codeanalysis.common.4.11.0.nupkg.sha512" + }, + "Microsoft.CodeAnalysis.CSharp/4.11.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-6XYi2EusI8JT4y2l/F3VVVS+ISoIX9nqHsZRaG6W5aFeJ5BEuBosHfT/ABb73FN0RZ1Z3cj2j7cL28SToJPXOw==", + "path": "microsoft.codeanalysis.csharp/4.11.0", + "hashPath": "microsoft.codeanalysis.csharp.4.11.0.nupkg.sha512" + }, + "Microsoft.Extensions.Configuration/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-0J/9YNXTMWSZP2p2+nvl8p71zpSwokZXZuJW+VjdErkegAnFdO1XlqtA62SJtgVYHdKu3uPxJHcMR/r35HwFBA==", + "path": "microsoft.extensions.configuration/8.0.0", + "hashPath": "microsoft.extensions.configuration.8.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.Configuration.Abstractions/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-3lE/iLSutpgX1CC0NOW70FJoGARRHbyKmG7dc0klnUZ9Dd9hS6N/POPWhKhMLCEuNN5nXEY5agmlFtH562vqhQ==", + "path": "microsoft.extensions.configuration.abstractions/8.0.0", + "hashPath": "microsoft.extensions.configuration.abstractions.8.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.Configuration.FileExtensions/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-McP+Lz/EKwvtCv48z0YImw+L1gi1gy5rHhNaNIY2CrjloV+XY8gydT8DjMR6zWeL13AFK+DioVpppwAuO1Gi1w==", + "path": "microsoft.extensions.configuration.fileextensions/8.0.0", + "hashPath": "microsoft.extensions.configuration.fileextensions.8.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.Configuration.Json/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-C2wqUoh9OmRL1akaCcKSTmRU8z0kckfImG7zLNI8uyi47Lp+zd5LWAD17waPQEqCz3ioWOCrFUo+JJuoeZLOBw==", + "path": "microsoft.extensions.configuration.json/8.0.0", + "hashPath": "microsoft.extensions.configuration.json.8.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.FileProviders.Abstractions/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-ZbaMlhJlpisjuWbvXr4LdAst/1XxH3vZ6A0BsgTphZ2L4PGuxRLz7Jr/S7mkAAnOn78Vu0fKhEgNF5JO3zfjqQ==", + "path": "microsoft.extensions.fileproviders.abstractions/8.0.0", + "hashPath": "microsoft.extensions.fileproviders.abstractions.8.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.FileProviders.Physical/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-UboiXxpPUpwulHvIAVE36Knq0VSHaAmfrFkegLyBZeaADuKezJ/AIXYAW8F5GBlGk/VaibN2k/Zn1ca8YAfVdA==", + "path": "microsoft.extensions.fileproviders.physical/8.0.0", + "hashPath": "microsoft.extensions.fileproviders.physical.8.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.FileSystemGlobbing/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-OK+670i7esqlQrPjdIKRbsyMCe9g5kSLpRRQGSr4Q58AOYEe/hCnfLZprh7viNisSUUQZmMrbbuDaIrP+V1ebQ==", + "path": "microsoft.extensions.filesystemglobbing/8.0.0", + "hashPath": "microsoft.extensions.filesystemglobbing.8.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.Primitives/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-bXJEZrW9ny8vjMF1JV253WeLhpEVzFo1lyaZu1vQ4ZxWUlVvknZ/+ftFgVheLubb4eZPSwwxBeqS1JkCOjxd8g==", + "path": "microsoft.extensions.primitives/8.0.0", + "hashPath": "microsoft.extensions.primitives.8.0.0.nupkg.sha512" + }, + "Microsoft.IO.RecyclableMemoryStream/3.0.1": { + "type": "package", + "serviceable": true, + "sha512": "sha512-s/s20YTVY9r9TPfTrN5g8zPF1YhwxyqO6PxUkrYTGI2B+OGPe9AdajWZrLhFqXIvqIW23fnUE4+ztrUWNU1+9g==", + "path": "microsoft.io.recyclablememorystream/3.0.1", + "hashPath": "microsoft.io.recyclablememorystream.3.0.1.nupkg.sha512" + }, + "Microsoft.Win32.SystemEvents/7.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-2nXPrhdAyAzir0gLl8Yy8S5Mnm/uBSQQA7jEsILOS1MTyS7DbmV1NgViMtvV1sfCD1ebITpNwb1NIinKeJgUVQ==", + "path": "microsoft.win32.systemevents/7.0.0", + "hashPath": "microsoft.win32.systemevents.7.0.0.nupkg.sha512" + }, + "Newtonsoft.Json/13.0.3": { + "type": "package", + "serviceable": true, + "sha512": "sha512-HrC5BXdl00IP9zeV+0Z848QWPAoCr9P3bDEZguI+gkLcBKAOxix/tLEAAHC+UvDNPv4a2d18lOReHMOagPa+zQ==", + "path": "newtonsoft.json/13.0.3", + "hashPath": "newtonsoft.json.13.0.3.nupkg.sha512" + }, + "protobuf-net/3.2.30": { + "type": "package", + "serviceable": true, + "sha512": "sha512-C/UTlmxEJHAHpqm8xQK1UyJKaIynVCSNG4mVrbLgnZ7ccH28nN49O8iMJvKEodTgVbnimvy+3mIiAdW6mATwnw==", + "path": "protobuf-net/3.2.30", + "hashPath": "protobuf-net.3.2.30.nupkg.sha512" + }, + "protobuf-net.Core/3.2.30": { + "type": "package", + "serviceable": true, + "sha512": "sha512-v2ZxxYrz+X212ukSx+uqkLuPu414bvmSAnTyf+PBUKR9ENJxO4P/csorA/27456MCp1JNoMssDj/f91RDiwBfQ==", + "path": "protobuf-net.core/3.2.30", + "hashPath": "protobuf-net.core.3.2.30.nupkg.sha512" + }, + "System.Collections.Immutable/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-AurL6Y5BA1WotzlEvVaIDpqzpIPvYnnldxru8oXJU2yFxFUy3+pNXjXd1ymO+RA0rq0+590Q8gaz2l3Sr7fmqg==", + "path": "system.collections.immutable/8.0.0", + "hashPath": "system.collections.immutable.8.0.0.nupkg.sha512" + }, + "System.ComponentModel.Annotations/5.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-dMkqfy2el8A8/I76n2Hi1oBFEbG1SfxD2l5nhwXV3XjlnOmwxJlQbYpJH4W51odnU9sARCSAgv7S3CyAFMkpYg==", + "path": "system.componentmodel.annotations/5.0.0", + "hashPath": "system.componentmodel.annotations.5.0.0.nupkg.sha512" + }, + "System.Drawing.Common/7.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-KIX+oBU38pxkKPxvLcLfIkOV5Ien8ReN78wro7OF5/erwcmortzeFx+iBswlh2Vz6gVne0khocQudGwaO1Ey6A==", + "path": "system.drawing.common/7.0.0", + "hashPath": "system.drawing.common.7.0.0.nupkg.sha512" + }, + "System.Formats.Asn1/8.0.1": { + "type": "package", + "serviceable": true, + "sha512": "sha512-XqKba7Mm/koKSjKMfW82olQdmfbI5yqeoLV/tidRp7fbh5rmHAQ5raDI/7SU0swTzv+jgqtUGkzmFxuUg0it1A==", + "path": "system.formats.asn1/8.0.1", + "hashPath": "system.formats.asn1.8.0.1.nupkg.sha512" + }, + "System.Reflection.Metadata/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-ptvgrFh7PvWI8bcVqG5rsA/weWM09EnthFHR5SCnS6IN+P4mj6rE1lBDC4U8HL9/57htKAqy4KQ3bBj84cfYyQ==", + "path": "system.reflection.metadata/8.0.0", + "hashPath": "system.reflection.metadata.8.0.0.nupkg.sha512" + }, + "System.Security.Cryptography.Pkcs/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-ULmp3xoOwNYjOYp4JZ2NK/6NdTgiN1GQXzVVN1njQ7LOZ0d0B9vyMnhyqbIi9Qw4JXj1JgCsitkTShboHRx7Eg==", + "path": "system.security.cryptography.pkcs/8.0.0", + "hashPath": "system.security.cryptography.pkcs.8.0.0.nupkg.sha512" + }, + "System.Text.Encoding.CodePages/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-OZIsVplFGaVY90G2SbpgU7EnCoOO5pw1t4ic21dBF3/1omrJFpAGoNAVpPyMVOC90/hvgkGG3VFqR13YgZMQfg==", + "path": "system.text.encoding.codepages/8.0.0", + "hashPath": "system.text.encoding.codepages.8.0.0.nupkg.sha512" + }, + "System.Text.Encodings.Web/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-yev/k9GHAEGx2Rg3/tU6MQh4HGBXJs70y7j1LaM1i/ER9po+6nnQ6RRqTJn1E7Xu0fbIFK80Nh5EoODxrbxwBQ==", + "path": "system.text.encodings.web/8.0.0", + "hashPath": "system.text.encodings.web.8.0.0.nupkg.sha512" + }, + "System.Text.Json/8.0.4": { + "type": "package", + "serviceable": true, + "sha512": "sha512-bAkhgDJ88XTsqczoxEMliSrpijKZHhbJQldhAmObj/RbrN3sU5dcokuXmWJWsdQAhiMJ9bTayWsL1C9fbbCRhw==", + "path": "system.text.json/8.0.4", + "hashPath": "system.text.json.8.0.4.nupkg.sha512" + } + } +} \ No newline at end of file diff --git a/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/Tools/Exporter/ConfigTable/Fantasy.Tools.ConfigTable.dll b/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/Tools/Exporter/ConfigTable/Fantasy.Tools.ConfigTable.dll new file mode 100644 index 0000000..691c3ec Binary files /dev/null and b/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/Tools/Exporter/ConfigTable/Fantasy.Tools.ConfigTable.dll differ diff --git a/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/Tools/Exporter/ConfigTable/Fantasy.Tools.ConfigTable.pdb b/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/Tools/Exporter/ConfigTable/Fantasy.Tools.ConfigTable.pdb new file mode 100644 index 0000000..e28ebf3 Binary files /dev/null and b/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/Tools/Exporter/ConfigTable/Fantasy.Tools.ConfigTable.pdb differ diff --git a/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/Tools/Exporter/ConfigTable/Fantasy.Tools.ConfigTable.runtimeconfig.json b/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/Tools/Exporter/ConfigTable/Fantasy.Tools.ConfigTable.runtimeconfig.json new file mode 100644 index 0000000..becfaea --- /dev/null +++ b/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/Tools/Exporter/ConfigTable/Fantasy.Tools.ConfigTable.runtimeconfig.json @@ -0,0 +1,12 @@ +{ + "runtimeOptions": { + "tfm": "net8.0", + "framework": { + "name": "Microsoft.NETCore.App", + "version": "8.0.0" + }, + "configProperties": { + "System.Runtime.Serialization.EnableUnsafeBinaryFormatterSerialization": false + } + } +} \ No newline at end of file diff --git a/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/Tools/Exporter/ConfigTable/Microsoft.CodeAnalysis.CSharp.dll b/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/Tools/Exporter/ConfigTable/Microsoft.CodeAnalysis.CSharp.dll new file mode 100644 index 0000000..c23db48 Binary files /dev/null and b/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/Tools/Exporter/ConfigTable/Microsoft.CodeAnalysis.CSharp.dll differ diff --git a/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/Tools/Exporter/ConfigTable/Microsoft.CodeAnalysis.dll b/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/Tools/Exporter/ConfigTable/Microsoft.CodeAnalysis.dll new file mode 100644 index 0000000..de7eadd Binary files /dev/null and b/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/Tools/Exporter/ConfigTable/Microsoft.CodeAnalysis.dll differ diff --git a/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/Tools/Exporter/ConfigTable/Microsoft.Extensions.Configuration.Abstractions.dll b/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/Tools/Exporter/ConfigTable/Microsoft.Extensions.Configuration.Abstractions.dll new file mode 100644 index 0000000..a5ab313 Binary files /dev/null and b/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/Tools/Exporter/ConfigTable/Microsoft.Extensions.Configuration.Abstractions.dll differ diff --git a/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/Tools/Exporter/ConfigTable/Microsoft.Extensions.Configuration.FileExtensions.dll b/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/Tools/Exporter/ConfigTable/Microsoft.Extensions.Configuration.FileExtensions.dll new file mode 100644 index 0000000..4efc1a5 Binary files /dev/null and b/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/Tools/Exporter/ConfigTable/Microsoft.Extensions.Configuration.FileExtensions.dll differ diff --git a/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/Tools/Exporter/ConfigTable/Microsoft.Extensions.Configuration.Json.dll b/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/Tools/Exporter/ConfigTable/Microsoft.Extensions.Configuration.Json.dll new file mode 100644 index 0000000..296db6a Binary files /dev/null and b/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/Tools/Exporter/ConfigTable/Microsoft.Extensions.Configuration.Json.dll differ diff --git a/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/Tools/Exporter/ConfigTable/Microsoft.Extensions.Configuration.dll b/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/Tools/Exporter/ConfigTable/Microsoft.Extensions.Configuration.dll new file mode 100644 index 0000000..d3e5c22 Binary files /dev/null and b/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/Tools/Exporter/ConfigTable/Microsoft.Extensions.Configuration.dll differ diff --git a/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/Tools/Exporter/ConfigTable/Microsoft.Extensions.FileProviders.Abstractions.dll b/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/Tools/Exporter/ConfigTable/Microsoft.Extensions.FileProviders.Abstractions.dll new file mode 100644 index 0000000..f907206 Binary files /dev/null and b/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/Tools/Exporter/ConfigTable/Microsoft.Extensions.FileProviders.Abstractions.dll differ diff --git a/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/Tools/Exporter/ConfigTable/Microsoft.Extensions.FileProviders.Physical.dll b/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/Tools/Exporter/ConfigTable/Microsoft.Extensions.FileProviders.Physical.dll new file mode 100644 index 0000000..6fb7f47 Binary files /dev/null and b/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/Tools/Exporter/ConfigTable/Microsoft.Extensions.FileProviders.Physical.dll differ diff --git a/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/Tools/Exporter/ConfigTable/Microsoft.Extensions.FileSystemGlobbing.dll b/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/Tools/Exporter/ConfigTable/Microsoft.Extensions.FileSystemGlobbing.dll new file mode 100644 index 0000000..e590735 Binary files /dev/null and b/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/Tools/Exporter/ConfigTable/Microsoft.Extensions.FileSystemGlobbing.dll differ diff --git a/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/Tools/Exporter/ConfigTable/Microsoft.Extensions.Primitives.dll b/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/Tools/Exporter/ConfigTable/Microsoft.Extensions.Primitives.dll new file mode 100644 index 0000000..c24f2a0 Binary files /dev/null and b/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/Tools/Exporter/ConfigTable/Microsoft.Extensions.Primitives.dll differ diff --git a/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/Tools/Exporter/ConfigTable/Microsoft.IO.RecyclableMemoryStream.dll b/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/Tools/Exporter/ConfigTable/Microsoft.IO.RecyclableMemoryStream.dll new file mode 100644 index 0000000..6e0ea40 Binary files /dev/null and b/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/Tools/Exporter/ConfigTable/Microsoft.IO.RecyclableMemoryStream.dll differ diff --git a/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/Tools/Exporter/ConfigTable/Microsoft.Win32.SystemEvents.dll b/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/Tools/Exporter/ConfigTable/Microsoft.Win32.SystemEvents.dll new file mode 100644 index 0000000..d40a926 Binary files /dev/null and b/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/Tools/Exporter/ConfigTable/Microsoft.Win32.SystemEvents.dll differ diff --git a/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/Tools/Exporter/ConfigTable/Newtonsoft.Json.dll b/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/Tools/Exporter/ConfigTable/Newtonsoft.Json.dll new file mode 100644 index 0000000..d035c38 Binary files /dev/null and b/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/Tools/Exporter/ConfigTable/Newtonsoft.Json.dll differ diff --git a/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/Tools/Exporter/ConfigTable/Run.bat b/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/Tools/Exporter/ConfigTable/Run.bat new file mode 100644 index 0000000..e166f0e --- /dev/null +++ b/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/Tools/Exporter/ConfigTable/Run.bat @@ -0,0 +1,21 @@ +@echo off + +echo Please select an option: +echo 1. Client +echo 2. Server +echo 3. All + +set /p choice=Please select an option: + +if "%choice%"=="1" ( + echo Client + dotnet Fantasy.Tools.ConfigTable.dll --ExportPlatform 1 +) else if "%choice%"=="2" ( + echo Server + dotnet Fantasy.Tools.ConfigTable.dll --ExportPlatform 2 +) else if "%choice%"=="3" ( + echo All + dotnet Fantasy.Tools.ConfigTable.dll --ExportPlatform 3 +) else ( + echo Invalid option +) diff --git a/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/Tools/Exporter/ConfigTable/Run.sh b/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/Tools/Exporter/ConfigTable/Run.sh new file mode 100644 index 0000000..491d8d9 --- /dev/null +++ b/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/Tools/Exporter/ConfigTable/Run.sh @@ -0,0 +1,23 @@ +#!/bin/bash + +echo "1. Client" +echo "2. Server" +echo "3. All" + +read -n 1 -p "Please select an option:" choice +echo "" +echo "" +case $choice in + 1) + dotnet Fantasy.Tools.ConfigTable.dll --ExportPlatform 1 + ;; + 2) + dotnet Fantasy.Tools.ConfigTable.dll --ExportPlatform 2 + ;; + 3) + dotnet Fantasy.Tools.ConfigTable.dll --ExportPlatform 3 + ;; + *) + echo "Invalid option" + ;; +esac diff --git a/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/Tools/Exporter/ConfigTable/System.Drawing.Common.dll b/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/Tools/Exporter/ConfigTable/System.Drawing.Common.dll new file mode 100644 index 0000000..310d5e8 Binary files /dev/null and b/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/Tools/Exporter/ConfigTable/System.Drawing.Common.dll differ diff --git a/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/Tools/Exporter/ConfigTable/System.Formats.Asn1.dll b/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/Tools/Exporter/ConfigTable/System.Formats.Asn1.dll new file mode 100644 index 0000000..16cc849 Binary files /dev/null and b/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/Tools/Exporter/ConfigTable/System.Formats.Asn1.dll differ diff --git a/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/Tools/Exporter/ConfigTable/System.Security.Cryptography.Pkcs.dll b/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/Tools/Exporter/ConfigTable/System.Security.Cryptography.Pkcs.dll new file mode 100644 index 0000000..a76a14a Binary files /dev/null and b/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/Tools/Exporter/ConfigTable/System.Security.Cryptography.Pkcs.dll differ diff --git a/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/Tools/Exporter/ConfigTable/System.Text.Json.dll b/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/Tools/Exporter/ConfigTable/System.Text.Json.dll new file mode 100644 index 0000000..0c6d406 Binary files /dev/null and b/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/Tools/Exporter/ConfigTable/System.Text.Json.dll differ diff --git a/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/Tools/Exporter/ConfigTable/protobuf-net.Core.dll b/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/Tools/Exporter/ConfigTable/protobuf-net.Core.dll new file mode 100644 index 0000000..845a840 Binary files /dev/null and b/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/Tools/Exporter/ConfigTable/protobuf-net.Core.dll differ diff --git a/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/Tools/Exporter/ConfigTable/protobuf-net.dll b/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/Tools/Exporter/ConfigTable/protobuf-net.dll new file mode 100644 index 0000000..e4b6839 Binary files /dev/null and b/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/Tools/Exporter/ConfigTable/protobuf-net.dll differ diff --git a/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/obj/Debug/net8.0/.NETCoreApp,Version=v8.0.AssemblyAttributes.cs b/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/obj/Debug/net8.0/.NETCoreApp,Version=v8.0.AssemblyAttributes.cs new file mode 100644 index 0000000..2217181 --- /dev/null +++ b/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/obj/Debug/net8.0/.NETCoreApp,Version=v8.0.AssemblyAttributes.cs @@ -0,0 +1,4 @@ +// +using System; +using System.Reflection; +[assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute(".NETCoreApp,Version=v8.0", FrameworkDisplayName = ".NET 8.0")] diff --git a/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/obj/Debug/net8.0/Fantasy.ConfigTableProtocol.AssemblyInfo.cs b/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/obj/Debug/net8.0/Fantasy.ConfigTableProtocol.AssemblyInfo.cs new file mode 100644 index 0000000..4ff77b2 --- /dev/null +++ b/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/obj/Debug/net8.0/Fantasy.ConfigTableProtocol.AssemblyInfo.cs @@ -0,0 +1,22 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +using System; +using System.Reflection; + +[assembly: System.Reflection.AssemblyCompanyAttribute("Fantasy.ConfigTableProtocol")] +[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")] +[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")] +[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0")] +[assembly: System.Reflection.AssemblyProductAttribute("Fantasy.ConfigTableProtocol")] +[assembly: System.Reflection.AssemblyTitleAttribute("Fantasy.ConfigTableProtocol")] +[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")] + +// 由 MSBuild WriteCodeFragment 类生成。 + diff --git a/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/obj/Debug/net8.0/Fantasy.ConfigTableProtocol.AssemblyInfoInputs.cache b/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/obj/Debug/net8.0/Fantasy.ConfigTableProtocol.AssemblyInfoInputs.cache new file mode 100644 index 0000000..4307b69 --- /dev/null +++ b/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/obj/Debug/net8.0/Fantasy.ConfigTableProtocol.AssemblyInfoInputs.cache @@ -0,0 +1 @@ +3db015d912a8f238a0089f4e8455936aa6ede2963b82ba561d63f050fe50f445 diff --git a/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/obj/Debug/net8.0/Fantasy.ConfigTableProtocol.GeneratedMSBuildEditorConfig.editorconfig b/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/obj/Debug/net8.0/Fantasy.ConfigTableProtocol.GeneratedMSBuildEditorConfig.editorconfig new file mode 100644 index 0000000..1c46839 --- /dev/null +++ b/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/obj/Debug/net8.0/Fantasy.ConfigTableProtocol.GeneratedMSBuildEditorConfig.editorconfig @@ -0,0 +1,15 @@ +is_global = true +build_property.TargetFramework = net8.0 +build_property.TargetPlatformMinVersion = +build_property.UsingMicrosoftNETSdkWeb = +build_property.ProjectTypeGuids = +build_property.InvariantGlobalization = +build_property.PlatformNeutralAssembly = +build_property.EnforceExtendedAnalyzerRules = +build_property._SupportedPlatformList = Linux,macOS,Windows +build_property.RootNamespace = Fantasy.ConfigTableProtocol +build_property.ProjectDir = /Users/fantasy/Movies/邮件系统/Lession/NuGet/Fantasy.ConfigTableProtocol/ +build_property.EnableComHosting = +build_property.EnableGeneratedComInterfaceComImportInterop = +build_property.EffectiveAnalysisLevelStyle = 8.0 +build_property.EnableCodeStyleSeverity = diff --git a/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/obj/Debug/net8.0/Fantasy.ConfigTableProtocol.GlobalUsings.g.cs b/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/obj/Debug/net8.0/Fantasy.ConfigTableProtocol.GlobalUsings.g.cs new file mode 100644 index 0000000..8578f3d --- /dev/null +++ b/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/obj/Debug/net8.0/Fantasy.ConfigTableProtocol.GlobalUsings.g.cs @@ -0,0 +1,8 @@ +// +global using global::System; +global using global::System.Collections.Generic; +global using global::System.IO; +global using global::System.Linq; +global using global::System.Net.Http; +global using global::System.Threading; +global using global::System.Threading.Tasks; diff --git a/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/obj/Debug/net8.0/Fantasy.ConfigTableProtocol.assets.cache b/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/obj/Debug/net8.0/Fantasy.ConfigTableProtocol.assets.cache new file mode 100644 index 0000000..93cf46d Binary files /dev/null and b/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/obj/Debug/net8.0/Fantasy.ConfigTableProtocol.assets.cache differ diff --git a/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/obj/Debug/net8.0/Fantasy.ConfigTableProtocol.csproj.AssemblyReference.cache b/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/obj/Debug/net8.0/Fantasy.ConfigTableProtocol.csproj.AssemblyReference.cache new file mode 100644 index 0000000..04e5450 Binary files /dev/null and b/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/obj/Debug/net8.0/Fantasy.ConfigTableProtocol.csproj.AssemblyReference.cache differ diff --git a/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/obj/Fantasy.ConfigTableProtocol.csproj.nuget.dgspec.json b/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/obj/Fantasy.ConfigTableProtocol.csproj.nuget.dgspec.json new file mode 100644 index 0000000..a1d4e6b --- /dev/null +++ b/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/obj/Fantasy.ConfigTableProtocol.csproj.nuget.dgspec.json @@ -0,0 +1,74 @@ +{ + "format": 1, + "restore": { + "/Users/fantasy/Movies/邮件系统/Lession/NuGet/Fantasy.ConfigTableProtocol/Fantasy.ConfigTableProtocol.csproj": {} + }, + "projects": { + "/Users/fantasy/Movies/邮件系统/Lession/NuGet/Fantasy.ConfigTableProtocol/Fantasy.ConfigTableProtocol.csproj": { + "version": "1.0.0", + "restore": { + "projectUniqueName": "/Users/fantasy/Movies/邮件系统/Lession/NuGet/Fantasy.ConfigTableProtocol/Fantasy.ConfigTableProtocol.csproj", + "projectName": "Fantasy.ConfigTableProtocol", + "projectPath": "/Users/fantasy/Movies/邮件系统/Lession/NuGet/Fantasy.ConfigTableProtocol/Fantasy.ConfigTableProtocol.csproj", + "packagesPath": "/Users/fantasy/.nuget/packages/", + "outputPath": "/Users/fantasy/Movies/邮件系统/Lession/NuGet/Fantasy.ConfigTableProtocol/obj/", + "projectStyle": "PackageReference", + "configFilePaths": [ + "/Users/fantasy/.nuget/NuGet/NuGet.Config" + ], + "originalTargetFrameworks": [ + "net8.0" + ], + "sources": { + "/usr/local/share/dotnet/library-packs": {}, + "https://api.nuget.org/v3/index.json": {} + }, + "frameworks": { + "net8.0": { + "targetAlias": "net8.0", + "projectReferences": {} + } + }, + "warningProperties": { + "warnAsError": [ + "NU1605" + ] + }, + "restoreAuditProperties": { + "enableAudit": "true", + "auditLevel": "low", + "auditMode": "all" + }, + "SdkAnalysisLevel": "9.0.100" + }, + "frameworks": { + "net8.0": { + "targetAlias": "net8.0", + "dependencies": { + "Fantasy-Net.Tools.ExporterConfigTable": { + "target": "Package", + "version": "[2024.1.8, )" + } + }, + "imports": [ + "net461", + "net462", + "net47", + "net471", + "net472", + "net48", + "net481" + ], + "assetTargetFallback": true, + "warn": true, + "frameworkReferences": { + "Microsoft.NETCore.App": { + "privateAssets": "all" + } + }, + "runtimeIdentifierGraphPath": "/usr/local/share/dotnet/sdk/9.0.100/PortableRuntimeIdentifierGraph.json" + } + } + } + } +} \ No newline at end of file diff --git a/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/obj/Fantasy.ConfigTableProtocol.csproj.nuget.g.props b/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/obj/Fantasy.ConfigTableProtocol.csproj.nuget.g.props new file mode 100644 index 0000000..7d811bc --- /dev/null +++ b/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/obj/Fantasy.ConfigTableProtocol.csproj.nuget.g.props @@ -0,0 +1,18 @@ + + + + True + NuGet + $(MSBuildThisFileDirectory)project.assets.json + /Users/fantasy/.nuget/packages/ + /Users/fantasy/.nuget/packages/ + PackageReference + 6.12.2 + + + + + + /Users/fantasy/.nuget/packages/fantasy-net.tools.exporterconfigtable/2024.1.8 + + \ No newline at end of file diff --git a/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/obj/Fantasy.ConfigTableProtocol.csproj.nuget.g.targets b/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/obj/Fantasy.ConfigTableProtocol.csproj.nuget.g.targets new file mode 100644 index 0000000..5f6df71 --- /dev/null +++ b/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/obj/Fantasy.ConfigTableProtocol.csproj.nuget.g.targets @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/obj/project.assets.json b/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/obj/project.assets.json new file mode 100644 index 0000000..f6d99be --- /dev/null +++ b/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/obj/project.assets.json @@ -0,0 +1,144 @@ +{ + "version": 3, + "targets": { + "net8.0": { + "Fantasy-Net.Tools.ExporterConfigTable/2024.1.8": { + "type": "package", + "compile": { + "lib/net8.0/Fantasy.Tools.ExporterConfigTable.dll": {} + }, + "runtime": { + "lib/net8.0/Fantasy.Tools.ExporterConfigTable.dll": {} + }, + "build": { + "buildTransitive/Fantasy-Net.Tools.ExporterConfigTable.targets": {} + } + } + } + }, + "libraries": { + "Fantasy-Net.Tools.ExporterConfigTable/2024.1.8": { + "sha512": "Tx6wYQLqkdLt79cqGqBUIDY9YIeoFF8sYrrCo3IRqKKaBDfZXYx8RcsurfE3YzKc4WuYxxQskaoBThS0LvJGOQ==", + "type": "package", + "path": "fantasy-net.tools.exporterconfigtable/2024.1.8", + "hasTools": true, + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "buildTransitive/Fantasy-Net.Tools.ExporterConfigTable.targets", + "fantasy-net.tools.exporterconfigtable.2024.1.8.nupkg.sha512", + "fantasy-net.tools.exporterconfigtable.nuspec", + "icon.png", + "lib/net8.0/Fantasy.Tools.ExporterConfigTable.dll", + "tools/output/CommandLine.dll", + "tools/output/EPPlus.Interfaces.dll", + "tools/output/EPPlus.System.Drawing.dll", + "tools/output/EPPlus.dll", + "tools/output/ExporterSettings.json", + "tools/output/Fantasy.Tools.ConfigTable", + "tools/output/Fantasy.Tools.ConfigTable.deps.json", + "tools/output/Fantasy.Tools.ConfigTable.dll", + "tools/output/Fantasy.Tools.ConfigTable.pdb", + "tools/output/Fantasy.Tools.ConfigTable.runtimeconfig.json", + "tools/output/Microsoft.CodeAnalysis.CSharp.dll", + "tools/output/Microsoft.CodeAnalysis.dll", + "tools/output/Microsoft.Extensions.Configuration.Abstractions.dll", + "tools/output/Microsoft.Extensions.Configuration.FileExtensions.dll", + "tools/output/Microsoft.Extensions.Configuration.Json.dll", + "tools/output/Microsoft.Extensions.Configuration.dll", + "tools/output/Microsoft.Extensions.FileProviders.Abstractions.dll", + "tools/output/Microsoft.Extensions.FileProviders.Physical.dll", + "tools/output/Microsoft.Extensions.FileSystemGlobbing.dll", + "tools/output/Microsoft.Extensions.Primitives.dll", + "tools/output/Microsoft.IO.RecyclableMemoryStream.dll", + "tools/output/Microsoft.Win32.SystemEvents.dll", + "tools/output/Newtonsoft.Json.dll", + "tools/output/Run.bat", + "tools/output/Run.sh", + "tools/output/System.Drawing.Common.dll", + "tools/output/System.Formats.Asn1.dll", + "tools/output/System.Security.Cryptography.Pkcs.dll", + "tools/output/System.Text.Json.dll", + "tools/output/protobuf-net.Core.dll", + "tools/output/protobuf-net.dll", + "tools/output/runtimes/win/lib/net7.0/Microsoft.Win32.SystemEvents.dll", + "tools/output/runtimes/win/lib/net7.0/System.Drawing.Common.dll", + "tools/output/runtimes/win/lib/net8.0/System.Security.Cryptography.Pkcs.dll" + ] + } + }, + "projectFileDependencyGroups": { + "net8.0": [ + "Fantasy-Net.Tools.ExporterConfigTable >= 2024.1.8" + ] + }, + "packageFolders": { + "/Users/fantasy/.nuget/packages/": {} + }, + "project": { + "version": "1.0.0", + "restore": { + "projectUniqueName": "/Users/fantasy/Movies/邮件系统/Lession/NuGet/Fantasy.ConfigTableProtocol/Fantasy.ConfigTableProtocol.csproj", + "projectName": "Fantasy.ConfigTableProtocol", + "projectPath": "/Users/fantasy/Movies/邮件系统/Lession/NuGet/Fantasy.ConfigTableProtocol/Fantasy.ConfigTableProtocol.csproj", + "packagesPath": "/Users/fantasy/.nuget/packages/", + "outputPath": "/Users/fantasy/Movies/邮件系统/Lession/NuGet/Fantasy.ConfigTableProtocol/obj/", + "projectStyle": "PackageReference", + "configFilePaths": [ + "/Users/fantasy/.nuget/NuGet/NuGet.Config" + ], + "originalTargetFrameworks": [ + "net8.0" + ], + "sources": { + "/usr/local/share/dotnet/library-packs": {}, + "https://api.nuget.org/v3/index.json": {} + }, + "frameworks": { + "net8.0": { + "targetAlias": "net8.0", + "projectReferences": {} + } + }, + "warningProperties": { + "warnAsError": [ + "NU1605" + ] + }, + "restoreAuditProperties": { + "enableAudit": "true", + "auditLevel": "low", + "auditMode": "all" + }, + "SdkAnalysisLevel": "9.0.100" + }, + "frameworks": { + "net8.0": { + "targetAlias": "net8.0", + "dependencies": { + "Fantasy-Net.Tools.ExporterConfigTable": { + "target": "Package", + "version": "[2024.1.8, )" + } + }, + "imports": [ + "net461", + "net462", + "net47", + "net471", + "net472", + "net48", + "net481" + ], + "assetTargetFallback": true, + "warn": true, + "frameworkReferences": { + "Microsoft.NETCore.App": { + "privateAssets": "all" + } + }, + "runtimeIdentifierGraphPath": "/usr/local/share/dotnet/sdk/9.0.100/PortableRuntimeIdentifierGraph.json" + } + } + } +} \ No newline at end of file diff --git a/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/obj/project.nuget.cache b/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/obj/project.nuget.cache new file mode 100644 index 0000000..27d7dab --- /dev/null +++ b/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/obj/project.nuget.cache @@ -0,0 +1,10 @@ +{ + "version": 2, + "dgSpecHash": "f9MMX5neGX8=", + "success": true, + "projectFilePath": "/Users/fantasy/Movies/邮件系统/Lession/NuGet/Fantasy.ConfigTableProtocol/Fantasy.ConfigTableProtocol.csproj", + "expectedPackageFiles": [ + "/Users/fantasy/.nuget/packages/fantasy-net.tools.exporterconfigtable/2024.1.8/fantasy-net.tools.exporterconfigtable.2024.1.8.nupkg.sha512" + ], + "logs": [] +} \ No newline at end of file diff --git a/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/obj/project.packagespec.json b/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/obj/project.packagespec.json new file mode 100644 index 0000000..4a7d24d --- /dev/null +++ b/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/obj/project.packagespec.json @@ -0,0 +1 @@ +"restore":{"projectUniqueName":"/Users/fantasy/Movies/邮件系统/Lession/NuGet/Fantasy.ConfigTableProtocol/Fantasy.ConfigTableProtocol.csproj","projectName":"Fantasy.ConfigTableProtocol","projectPath":"/Users/fantasy/Movies/邮件系统/Lession/NuGet/Fantasy.ConfigTableProtocol/Fantasy.ConfigTableProtocol.csproj","outputPath":"/Users/fantasy/Movies/邮件系统/Lession/NuGet/Fantasy.ConfigTableProtocol/obj/","projectStyle":"PackageReference","originalTargetFrameworks":["net8.0"],"sources":{"/usr/local/share/dotnet/library-packs":{},"https://api.nuget.org/v3/index.json":{}},"frameworks":{"net8.0":{"targetAlias":"net8.0","projectReferences":{}}},"warningProperties":{"warnAsError":["NU1605"]},"restoreAuditProperties":{"enableAudit":"true","auditLevel":"low","auditMode":"all"},"SdkAnalysisLevel":"9.0.100"}"frameworks":{"net8.0":{"targetAlias":"net8.0","dependencies":{"Fantasy-Net.Tools.ExporterConfigTable":{"target":"Package","version":"[2024.1.8, )"}},"imports":["net461","net462","net47","net471","net472","net48","net481"],"assetTargetFallback":true,"warn":true,"frameworkReferences":{"Microsoft.NETCore.App":{"privateAssets":"all"}},"runtimeIdentifierGraphPath":"/usr/local/share/dotnet/sdk/9.0.100/PortableRuntimeIdentifierGraph.json"}} \ No newline at end of file diff --git a/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/obj/rider.project.model.nuget.info b/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/obj/rider.project.model.nuget.info new file mode 100644 index 0000000..7e867fc --- /dev/null +++ b/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/obj/rider.project.model.nuget.info @@ -0,0 +1 @@ +17392438089758892 \ No newline at end of file diff --git a/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/obj/rider.project.restore.info b/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/obj/rider.project.restore.info new file mode 100644 index 0000000..7e867fc --- /dev/null +++ b/邮件系统课程完整代码/NuGet/Fantasy.ConfigTableProtocol/obj/rider.project.restore.info @@ -0,0 +1 @@ +17392438089758892 \ No newline at end of file diff --git a/邮件系统课程完整代码/Server/.DS_Store b/邮件系统课程完整代码/Server/.DS_Store new file mode 100644 index 0000000..175fc5c Binary files /dev/null and b/邮件系统课程完整代码/Server/.DS_Store differ diff --git a/邮件系统课程完整代码/Server/App/.DS_Store b/邮件系统课程完整代码/Server/App/.DS_Store new file mode 100644 index 0000000..ed1e62a Binary files /dev/null and b/邮件系统课程完整代码/Server/App/.DS_Store differ diff --git a/邮件系统课程完整代码/Server/App/App.csproj b/邮件系统课程完整代码/Server/App/App.csproj new file mode 100644 index 0000000..817ce5e --- /dev/null +++ b/邮件系统课程完整代码/Server/App/App.csproj @@ -0,0 +1,27 @@ + + + + Exe + net8.0 + enable + enable + + + + ../../Bin/ + + + + ../../Bin + + + + + + + + + + + + diff --git a/邮件系统课程完整代码/Server/App/NLog.config b/邮件系统课程完整代码/Server/App/NLog.config new file mode 100644 index 0000000..4df5ea1 --- /dev/null +++ b/邮件系统课程完整代码/Server/App/NLog.config @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/邮件系统课程完整代码/Server/App/NLog.xsd b/邮件系统课程完整代码/Server/App/NLog.xsd new file mode 100644 index 0000000..63c9a0c --- /dev/null +++ b/邮件系统课程完整代码/Server/App/NLog.xsd @@ -0,0 +1,3483 @@ + + + + + + + + + + + + + + + Watch config file for changes and reload automatically. + + + + + Print internal NLog messages to the console. Default value is: false + + + + + Print internal NLog messages to the console error output. Default value is: false + + + + + Write internal NLog messages to the specified file. + + + + + Log level threshold for internal log messages. Default value is: Info. + + + + + Global log level threshold for application log messages. Messages below this level won't be logged. + + + + + Throw an exception when there is an internal error. Default value is: false. Not recommend to set to true in production! + + + + + Throw an exception when there is a configuration error. If not set, determined by throwExceptions. + + + + + Gets or sets a value indicating whether Variables should be kept on configuration reload. Default value is: false. + + + + + Write internal NLog messages to the System.Diagnostics.Trace. Default value is: false. + + + + + Write timestamps for internal NLog messages. Default value is: true. + + + + + Use InvariantCulture as default culture instead of CurrentCulture. Default value is: false. + + + + + Perform message template parsing and formatting of LogEvent messages (true = Always, false = Never, empty = Auto Detect). Default value is: empty. + + + + + + + + + + + + + + Make all targets within this section asynchronous (creates additional threads but the calling thread isn't blocked by any target writes). + + + + + + + + + + + + + + + + + Prefix for targets/layout renderers/filters/conditions loaded from this assembly. + + + + + Load NLog extensions from the specified file (*.dll) + + + + + Load NLog extensions from the specified assembly. Assembly name should be fully qualified. + + + + + + + + + + Filter on the name of the logger. May include wildcard characters ('*' or '?'). + + + + + Comma separated list of levels that this rule matches. + + + + + Minimum level that this rule matches. + + + + + Maximum level that this rule matches. + + + + + Level that this rule matches. + + + + + Comma separated list of target names. + + + + + Ignore further rules if this one matches. + + + + + Enable this rule. Note: disabled rules aren't available from the API. + + + + + Rule identifier to allow rule lookup with Configuration.FindRuleByName and Configuration.RemoveRuleByName. + + + + + Loggers matching will be restricted to specified minimum level for following rules. + + + + + + + + + + + + + + + Default action if none of the filters match. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Name of the file to be included. You could use * wildcard. The name is relative to the name of the current config file. + + + + + Ignore any errors in the include file. + + + + + + + + Variable value. Note, the 'value' attribute has precedence over this one. + + + + + + Variable name. + + + + + Variable value. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Action to be taken when the lazy writer thread request queue count exceeds the set limit. + + + + + Limit on the number of requests in the lazy writer thread request queue. + + + + + Number of log events that should be processed in a batch by the lazy writer thread. + + + + + Whether to use the locking queue, instead of a lock-free concurrent queue + + + + + Number of batches of P:NLog.Targets.Wrappers.AsyncTargetWrapper.BatchSize to write before yielding into P:NLog.Targets.Wrappers.AsyncTargetWrapper.TimeToSleepBetweenBatches + + + + + Time in milliseconds to sleep between batches. (1 or less means trigger on new activity) + + + + + + + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Delay the flush until the LogEvent has been confirmed as written + + + + + Condition expression. Log events who meet this condition will cause a flush on the wrapped target. + + + + + Only flush when LogEvent matches condition. Ignore explicit-flush, config-reload-flush and shutdown-flush + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Number of log events to be buffered. + + + + + Action to take if the buffer overflows. + + + + + Timeout (in milliseconds) after which the contents of buffer will be flushed if there's no write in the specified period of time. Use -1 to disable timed flushes. + + + + + Indicates whether to use sliding timeout. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Separator for T:NLog.ScopeContext operation-states-stack. + + + + + Stack separator for log4j:NDC in output from T:NLog.ScopeContext nested context. + + + + + Renderer for log4j:event logger-xml-attribute (Default ${logger}) + + + + + Whether to include the contents of the T:NLog.ScopeContext properties-dictionary. + + + + + Whether to include log4j:NDC in output from T:NLog.ScopeContext nested context. + + + + + Indicates whether to include source info (file name and line number) in the information sent over the network. + + + + + Whether to include log4j:NDC in output from T:NLog.ScopeContext nested context. + + + + + Option to include all properties from the log events + + + + + Indicates whether to include call site (class and method name) in the information sent over the network. + + + + + AppInfo field. By default it's the friendly name of the current AppDomain. + + + + + Instance of T:NLog.Layouts.Log4JXmlEventLayout that is used to format log messages. + + + + + Indicates whether to include NLog-specific extensions to log4j schema. + + + + + Action that should be taken, when more connections than P:NLog.Targets.NetworkTarget.MaxConnections. + + + + + SSL/TLS protocols. Default no SSL/TLS is used. Currently only implemented for TCP. + + + + + Action that should be taken, when more pending messages than P:NLog.Targets.NetworkTarget.MaxQueueSize. + + + + + Action that should be taken if the message is larger than P:NLog.Targets.NetworkTarget.MaxMessageSize + + + + + Maximum queue size for a single connection. Requires P:NLog.Targets.NetworkTarget.KeepConnection = true + + + + + Network address. + + + + + Indicates whether to keep connection open whenever possible. + + + + + The number of seconds a connection will remain idle before the first keep-alive probe is sent + + + + + Size of the connection cache (number of connections which are kept alive). Requires P:NLog.Targets.NetworkTarget.KeepConnection = true + + + + + Maximum simultaneous connections. Requires P:NLog.Targets.NetworkTarget.KeepConnection = false + + + + + Type of compression for protocol payload. Useful for UDP where datagram max-size is 8192 bytes. + + + + + Skip compression when protocol payload is below limit to reduce overhead in cpu-usage and additional headers + + + + + Maximum message size in bytes. On limit breach then P:NLog.Targets.NetworkTarget.OnOverflow action is activated. + + + + + Encoding to be used. + + + + + End of line value if a newline is appended at the end of log message P:NLog.Targets.NetworkTarget.NewLine. + + + + + Indicates whether to append newline at the end of log message. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Viewer parameter name. + + + + + Layout that should be use to calculate the value for the parameter. + + + + + Whether an attribute with empty value should be included in the output + + + + + + + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Text to be rendered. + + + + + Header. + + + + + Footer. + + + + + Indicates whether to auto-check if the console is available. - Disables console writing if Environment.UserInteractive = False (Windows Service) - Disables console writing if Console Standard Input is not available (Non-Console-App) + + + + + Enables output using ANSI Color Codes + + + + + The encoding for writing messages to the T:System.Console. + + + + + Indicates whether to send the log messages to the standard error instead of the standard output. + + + + + Indicates whether to auto-flush after M:System.Console.WriteLine + + + + + Indicates whether to auto-check if the console has been redirected to file - Disables coloring logic when System.Console.IsOutputRedirected = true + + + + + Indicates whether to use default row highlighting rules. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Background color. + + + + + Condition that must be met in order to set the specified foreground and background color. + + + + + Foreground color. + + + + + + + + + + + + + + + + + Background color. + + + + + Compile the P:NLog.Targets.ConsoleWordHighlightingRule.Regex? This can improve the performance, but at the costs of more memory usage. If false, the Regex Cache is used. + + + + + Condition that must be met before scanning the row for highlight of words + + + + + Foreground color. + + + + + Indicates whether to ignore case when comparing texts. + + + + + Regular expression to be matched. You must specify either text or regex. + + + + + Text to be matched. You must specify either text or regex. + + + + + Indicates whether to match whole words only. + + + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Text to be rendered. + + + + + Header. + + + + + Footer. + + + + + Indicates whether to auto-flush after M:System.Console.WriteLine + + + + + Indicates whether to auto-check if the console is available - Disables console writing if Environment.UserInteractive = False (Windows Service) - Disables console writing if Console Standard Input is not available (Non-Console-App) + + + + + The encoding for writing messages to the T:System.Console. + + + + + Indicates whether to send the log messages to the standard error instead of the standard output. + + + + + Whether to activate internal buffering to allow batch writing, instead of using M:System.Console.WriteLine + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Database user name. If the ConnectionString is not provided this value will be used to construct the "User ID=" part of the connection string. + + + + + Database password. If the ConnectionString is not provided this value will be used to construct the "Password=" part of the connection string. + + + + + Database name. If the ConnectionString is not provided this value will be used to construct the "Database=" part of the connection string. + + + + + Name of the connection string (as specified in <connectionStrings> configuration section. + + + + + Database host name. If the ConnectionString is not provided this value will be used to construct the "Server=" part of the connection string. + + + + + Indicates whether to keep the database connection open between the log events. + + + + + Name of the database provider. + + + + + Connection string. When provided, it overrides the values specified in DBHost, DBUserName, DBPassword, DBDatabase. + + + + + Connection string using for installation and uninstallation. If not provided, regular ConnectionString is being used. + + + + + Configures isolated transaction batch writing. If supported by the database, then it will improve insert performance. + + + + + Text of the SQL command to be run on each log level. + + + + + Type of the SQL command to be run on each log level. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Convert format of the property value + + + + + Culture used for parsing property string-value for type-conversion + + + + + Value to assign on the object-property + + + + + Name for the object-property + + + + + Type of the object-property + + + + + + + + + + + + + + Type of the command. + + + + + Connection string to run the command against. If not provided, connection string from the target is used. + + + + + Indicates whether to ignore failures. + + + + + Command text. + + + + + + + + + + + + + + + + + + + + Database parameter name. + + + + + Layout that should be use to calculate the value for the parameter. + + + + + Database parameter DbType. + + + + + Database parameter size. + + + + + Database parameter precision. + + + + + Database parameter scale. + + + + + Type of the parameter. + + + + + Fallback value when result value is not available + + + + + Convert format of the database parameter value. + + + + + Culture used for parsing parameter string-value for type-conversion + + + + + Whether empty value should translate into DbNull. Requires database column to allow NULL values. + + + + + + + + + + + + + + + Name of the target. + + + + + Text to be rendered. + + + + + Header. + + + + + Footer. + + + + + + + + + + + + + + + + + Name of the target. + + + + + Text to be rendered. + + + + + Header. + + + + + Footer. + + + + + + + + + + + + + + + Name of the target. + + + + + Layout used to format log messages. + + + + + + + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Layout used to format log messages. + + + + + Layout that renders event Category. + + + + + Optional entry type. When not set, or when not convertible to T:System.Diagnostics.EventLogEntryType then determined by T:NLog.LogLevel + + + + + Layout that renders event ID. + + + + + Name of the Event Log to write to. This can be System, Application or any user-defined name. + + + + + Name of the machine on which Event Log service is running. + + + + + Maximum Event log size in kilobytes. + + + + + Message length limit to write to the Event Log. + + + + + Value to be used as the event Source. + + + + + Action to take if the message is larger than the P:NLog.Targets.EventLogTarget.MaxMessageLength option. + + + + + + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Indicates whether to return to the first target after any successful write. + + + + + Whether to enable batching, but fallback will be handled individually + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Name of the file to write to. + + + + + Text to be rendered. + + + + + Header. + + + + + Footer. + + + + + Indicates whether the footer should be written only when the file is archived. + + + + + Maximum number of archive files that should be kept. + + + + + Maximum days of archive files that should be kept. + + + + + Value of the file size threshold to archive old log file on startup. + + + + + Indicates whether to archive old log file on startup. + + + + + Indicates whether to compress archive files into the zip archive format. + + + + + Name of the file to be used for an archive. + + + + + Is the P:NLog.Targets.FileTarget.ArchiveFileName an absolute or relative path? + + + + + Indicates whether to automatically archive log files every time the specified time passes. + + + + + Value specifying the date format to use when archiving files. + + + + + Size in bytes above which log files will be automatically archived. + + + + + Way file archives are numbered. + + + + + Indicates whether to create directories if they do not exist. + + + + + Indicates whether file creation calls should be synchronized by a system global mutex. + + + + + Gets or set a value indicating whether a managed file stream is forced, instead of using the native implementation. + + + + + Is the P:NLog.Targets.FileTarget.FileName an absolute or relative path? + + + + + File attributes (Windows only). + + + + + Cleanup invalid values in a filename, e.g. slashes in a filename. If set to true, this can impact the performance of massive writes. If set to false, nothing gets written when the filename is wrong. + + + + + Indicates whether to write BOM (byte order mark) in created files. Defaults to true for UTF-16 and UTF-32 + + + + + Indicates whether to enable log file(s) to be deleted. + + + + + Indicates whether to delete old log file on startup. + + + + + File encoding. + + + + + Indicates whether to replace file contents on each write instead of appending log message at the end. + + + + + Line ending mode. + + + + + Number of times the write is appended on the file before NLog discards the log message. + + + + + Delay in milliseconds to wait before attempting to write to the file again. + + + + + Maximum number of seconds before open files are flushed. Zero or negative means disabled. + + + + + Maximum number of seconds that files are kept open. Zero or negative means disabled. + + + + + Indicates whether concurrent writes to the log file by multiple processes on different network hosts. + + + + + Log file buffer size in bytes. + + + + + Indicates whether to automatically flush the file buffers after each log message. + + + + + Indicates whether to keep log file open instead of opening and closing it on each logging event. + + + + + Indicates whether concurrent writes to the log file by multiple processes on the same host. + + + + + Whether or not this target should just discard all data that its asked to write. Mostly used for when testing NLog Stack except final write + + + + + Number of files to be kept open. Setting this to a higher value may improve performance in a situation where a single File target is writing to many files (such as splitting by level or by logger). + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Condition expression. Log events who meet this condition will be forwarded to the wrapped target. + + + + + + + + + + + + + + + Name of the target. + + + + + Identifier to perform group-by + + + + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Windows domain name to change context to. + + + + + Required impersonation level. + + + + + Type of the logon provider. + + + + + Logon Type. + + + + + User account password. + + + + + Indicates whether to revert to the credentials of the process instead of impersonating another user. + + + + + Username to change context to. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Interval in which messages will be written up to the P:NLog.Targets.Wrappers.LimitingTargetWrapper.MessageLimit number of messages. + + + + + Maximum allowed number of messages written per P:NLog.Targets.Wrappers.LimitingTargetWrapper.Interval. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Text to be rendered. + + + + + Header. + + + + + Footer. + + + + + Indicates whether NewLine characters in the body should be replaced with tags. + + + + + Priority used for sending mails. + + + + + Encoding to be used for sending e-mail. + + + + + BCC email addresses separated by semicolons (e.g. john@domain.com;jane@domain.com). + + + + + CC email addresses separated by semicolons (e.g. john@domain.com;jane@domain.com). + + + + + Indicates whether to add new lines between log entries. + + + + + Indicates whether to send message as HTML instead of plain text. + + + + + Sender's email address (e.g. joe@domain.com). + + + + + Mail message body (repeated for each log message send in one mail). + + + + + Mail subject. + + + + + Recipients' email addresses separated by semicolons (e.g. john@domain.com;jane@domain.com). + + + + + Specifies how outgoing email messages will be handled. + + + + + SMTP Server to be used for sending. + + + + + SMTP Authentication mode. + + + + + Username used to connect to SMTP server (used when SmtpAuthentication is set to "basic"). + + + + + Password used to authenticate against SMTP server (used when SmtpAuthentication is set to "basic"). + + + + + Indicates whether SSL (secure sockets layer) should be used when communicating with SMTP server. + + + + + Port number that SMTP Server is listening on. + + + + + Indicates whether the default Settings from System.Net.MailSettings should be used. + + + + + Folder where applications save mail messages to be processed by the local SMTP server. + + + + + Indicates the SMTP client timeout. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Text to be rendered. + + + + + Header. + + + + + Footer. + + + + + Max number of items to have in memory + + + + + + + + + + + + + + + + + Name of the target. + + + + + Class name. + + + + + Method name. The method must be public and static. Use the AssemblyQualifiedName , https://msdn.microsoft.com/en-us/library/system.type.assemblyqualifiedname(v=vs.110).aspx e.g. + + + + + + + + + + + + + + + Name of the parameter. + + + + + Layout that should be use to calculate the value for the parameter. + + + + + Fallback value when result value is not available + + + + + Type of the parameter. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Layout used to format log messages. + + + + + SSL/TLS protocols. Default no SSL/TLS is used. Currently only implemented for TCP. + + + + + Action that should be taken, when more pending messages than P:NLog.Targets.NetworkTarget.MaxQueueSize. + + + + + Action that should be taken if the message is larger than P:NLog.Targets.NetworkTarget.MaxMessageSize + + + + + Maximum queue size for a single connection. Requires P:NLog.Targets.NetworkTarget.KeepConnection = true + + + + + Action that should be taken, when more connections than P:NLog.Targets.NetworkTarget.MaxConnections. + + + + + Indicates whether to keep connection open whenever possible. + + + + + The number of seconds a connection will remain idle before the first keep-alive probe is sent + + + + + Size of the connection cache (number of connections which are kept alive). Requires P:NLog.Targets.NetworkTarget.KeepConnection = true + + + + + Network address. + + + + + Maximum simultaneous connections. Requires P:NLog.Targets.NetworkTarget.KeepConnection = false + + + + + Type of compression for protocol payload. Useful for UDP where datagram max-size is 8192 bytes. + + + + + Skip compression when protocol payload is below limit to reduce overhead in cpu-usage and additional headers + + + + + Maximum message size in bytes. On limit breach then P:NLog.Targets.NetworkTarget.OnOverflow action is activated. + + + + + Encoding to be used. + + + + + End of line value if a newline is appended at the end of log message P:NLog.Targets.NetworkTarget.NewLine. + + + + + Indicates whether to append newline at the end of log message. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Separator for T:NLog.ScopeContext operation-states-stack. + + + + + Stack separator for log4j:NDC in output from T:NLog.ScopeContext nested context. + + + + + Renderer for log4j:event logger-xml-attribute (Default ${logger}) + + + + + Whether to include the contents of the T:NLog.ScopeContext properties-dictionary. + + + + + Whether to include log4j:NDC in output from T:NLog.ScopeContext nested context. + + + + + Indicates whether to include source info (file name and line number) in the information sent over the network. + + + + + Whether to include log4j:NDC in output from T:NLog.ScopeContext nested context. + + + + + Option to include all properties from the log events + + + + + Indicates whether to include call site (class and method name) in the information sent over the network. + + + + + AppInfo field. By default it's the friendly name of the current AppDomain. + + + + + Instance of T:NLog.Layouts.Log4JXmlEventLayout that is used to format log messages. + + + + + Indicates whether to include NLog-specific extensions to log4j schema. + + + + + Action that should be taken, when more connections than P:NLog.Targets.NetworkTarget.MaxConnections. + + + + + SSL/TLS protocols. Default no SSL/TLS is used. Currently only implemented for TCP. + + + + + Action that should be taken, when more pending messages than P:NLog.Targets.NetworkTarget.MaxQueueSize. + + + + + Action that should be taken if the message is larger than P:NLog.Targets.NetworkTarget.MaxMessageSize + + + + + Maximum queue size for a single connection. Requires P:NLog.Targets.NetworkTarget.KeepConnection = true + + + + + Network address. + + + + + Indicates whether to keep connection open whenever possible. + + + + + The number of seconds a connection will remain idle before the first keep-alive probe is sent + + + + + Size of the connection cache (number of connections which are kept alive). Requires P:NLog.Targets.NetworkTarget.KeepConnection = true + + + + + Maximum simultaneous connections. Requires P:NLog.Targets.NetworkTarget.KeepConnection = false + + + + + Type of compression for protocol payload. Useful for UDP where datagram max-size is 8192 bytes. + + + + + Skip compression when protocol payload is below limit to reduce overhead in cpu-usage and additional headers + + + + + Maximum message size in bytes. On limit breach then P:NLog.Targets.NetworkTarget.OnOverflow action is activated. + + + + + Encoding to be used. + + + + + End of line value if a newline is appended at the end of log message P:NLog.Targets.NetworkTarget.NewLine. + + + + + Indicates whether to append newline at the end of log message. + + + + + + + + + + + + + + + + Name of the target. + + + + + Layout used to format log messages. + + + + + Indicates whether to perform layout calculation. + + + + + + + + + + + + + + + + Name of the target. + + + + + Default filter to be applied when no specific rule matches. + + + + + + + + + + + + + Condition to be tested. + + + + + Resulting filter to be applied when the condition matches. + + + + + + + + + + + + Name of the target. + + + + + + + + + + + + + + + Name of the target. + + + + + Number of times to repeat each log message. + + + + + + + + + + + + + + + + + Name of the target. + + + + + Whether to enable batching, and only apply single delay when a whole batch fails + + + + + Number of retries that should be attempted on the wrapped target in case of a failure. + + + + + Time to wait between retries in milliseconds. + + + + + + + + + + + + + + Name of the target. + + + + + + + + + + + + + + Name of the target. + + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Text to be rendered. + + + + + Header. + + + + + Footer. + + + + + Forward F:NLog.LogLevel.Fatal to M:System.Diagnostics.Trace.Fail(System.String) (Instead of M:System.Diagnostics.Trace.TraceError(System.String)) + + + + + Force use M:System.Diagnostics.Trace.WriteLine(System.String) independent of T:NLog.LogLevel + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Indicates whether to pre-authenticate the HttpWebRequest (Requires 'Authorization' in P:NLog.Targets.WebServiceTarget.Headers parameters) + + + + + Value whether escaping be done according to Rfc3986 (Supports Internationalized Resource Identifiers - IRIs) + + + + + Value whether escaping be done according to the old NLog style (Very non-standard) + + + + + Value of the User-agent HTTP header. + + + + + Web service URL. + + + + + Proxy configuration when calling web service + + + + + Custom proxy address, include port separated by a colon + + + + + Protocol to be used when calling web service. + + + + + Web service namespace. Only used with Soap. + + + + + Web service method name. Only used with Soap. + + + + + Should we include the BOM (Byte-order-mark) for UTF? Influences the P:NLog.Targets.WebServiceTarget.Encoding property. This will only work for UTF-8. + + + + + Encoding. + + + + + Name of the root XML element, if POST of XML document chosen. If so, this property must not be null. (see P:NLog.Targets.WebServiceTarget.Protocol and F:NLog.Targets.WebServiceProtocol.XmlPost). + + + + + (optional) root namespace of the XML document, if POST of XML document chosen. (see P:NLog.Targets.WebServiceTarget.Protocol and F:NLog.Targets.WebServiceProtocol.XmlPost). + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Custom column delimiter value (valid when ColumnDelimiter is set to 'Custom'). + + + + + Column delimiter. + + + + + Footer layout. + + + + + Header layout. + + + + + Body layout (can be repeated multiple times). + + + + + Quote Character. + + + + + Quoting mode. + + + + + Indicates whether CVS should include header. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Name of the column. + + + + + Layout of the column. + + + + + Override of Quoting mode + + + + + + + + + + + + + + Option to render the empty object value {} + + + + + Option to suppress the extra spaces in the output json + + + + + + + + + + + + + + + + + + + + + + + Option to include all properties from the log event (as JSON) + + + + + Indicates whether to include contents of the T:NLog.GlobalDiagnosticsContext dictionary. + + + + + Whether to include the contents of the T:NLog.ScopeContext dictionary. + + + + + Should forward slashes be escaped? If true, / will be converted to \/ + + + + + Option to exclude null/empty properties from the log event (as JSON) + + + + + List of property names to exclude when P:NLog.Layouts.JsonLayout.IncludeAllProperties is true + + + + + How far should the JSON serializer follow object references before backing off + + + + + Option to render the empty object value {} + + + + + Option to suppress the extra spaces in the output json + + + + + + + + + + + + + + + + + + + Name of the attribute. + + + + + Layout that will be rendered as the attribute's value. + + + + + Fallback value when result value is not available + + + + + Determines whether or not this attribute will be Json encoded. + + + + + Should forward slashes be escaped? If true, / will be converted to \/ + + + + + Indicates whether to escape non-ascii characters + + + + + Whether an attribute with empty value should be included in the output + + + + + Result value type, for conversion of layout rendering output + + + + + + + + + + + + + + Footer layout. + + + + + Header layout. + + + + + Body layout (can be repeated multiple times). + + + + + + + + + + + + + + + + + + + + + + + Option to include all properties from the log events + + + + + Whether to include log4j:NDC in output from T:NLog.ScopeContext nested context. + + + + + Whether to include log4j:NDC in output from T:NLog.ScopeContext nested context. + + + + + Whether to include the contents of the T:NLog.ScopeContext properties-dictionary. + + + + + AppInfo field. By default it's the friendly name of the current AppDomain. + + + + + Indicates whether to include call site (class and method name) in the information sent over the network. + + + + + Indicates whether to include source info (file name and line number) in the information sent over the network. + + + + + Log4j:event logger-xml-attribute (Default ${logger}) + + + + + Whether the log4j:throwable xml-element should be written as CDATA + + + + + + + + + + + + + + Layout text. + + + + + + + + + + + + + + + + + + + + + + + + + + + + Name of the root XML element + + + + + Value inside the root XML element + + + + + Whether to include the contents of the T:NLog.ScopeContext dictionary. + + + + + Determines whether or not this attribute will be Xml encoded. + + + + + List of property names to exclude when P:NLog.Layouts.XmlElementBase.IncludeAllProperties is true + + + + + Whether a ElementValue with empty value should be included in the output + + + + + Auto indent and create new lines + + + + + How far should the XML serializer follow object references before backing off + + + + + XML element name to use for rendering IList-collections items + + + + + XML attribute name to use when rendering property-key When null (or empty) then key-attribute is not included + + + + + XML element name to use when rendering properties + + + + + XML attribute name to use when rendering property-value When null (or empty) then value-attribute is not included and value is formatted as XML-element-value + + + + + Option to include all properties from the log event (as XML) + + + + + + + + + + + + + + + + + Name of the attribute. + + + + + Layout that will be rendered as the attribute's value. + + + + + Fallback value when result value is not available + + + + + Determines whether or not this attribute will be Xml encoded. + + + + + Whether an attribute with empty value should be included in the output + + + + + Result value type, for conversion of layout rendering output + + + + + + + + + + + + + + + + + + + + + + + + Name of the element + + + + + Whether to include the contents of the T:NLog.ScopeContext dictionary. + + + + + Value inside the element + + + + + Determines whether or not this attribute will be Xml encoded. + + + + + List of property names to exclude when P:NLog.Layouts.XmlElementBase.IncludeAllProperties is true + + + + + Whether a ElementValue with empty value should be included in the output + + + + + Auto indent and create new lines + + + + + How far should the XML serializer follow object references before backing off + + + + + XML element name to use for rendering IList-collections items + + + + + XML attribute name to use when rendering property-key When null (or empty) then key-attribute is not included + + + + + XML element name to use when rendering properties + + + + + XML attribute name to use when rendering property-value When null (or empty) then value-attribute is not included and value is formatted as XML-element-value + + + + + Option to include all properties from the log event (as XML) + + + + + + + + + + + + + Action to be taken when filter matches. + + + + + Condition expression. + + + + + + + + + + + + + + + + + + + + + + + + + + Action to be taken when filter matches. + + + + + Indicates whether to ignore case when comparing strings. + + + + + Layout to be used to filter log messages. + + + + + Substring to be matched. + + + + + + + + + + + + + + + + + Action to be taken when filter matches. + + + + + String to compare the layout to. + + + + + Indicates whether to ignore case when comparing strings. + + + + + Layout to be used to filter log messages. + + + + + + + + + + + + + + + + + Action to be taken when filter matches. + + + + + Indicates whether to ignore case when comparing strings. + + + + + Layout to be used to filter log messages. + + + + + Substring to be matched. + + + + + + + + + + + + + + + + + Action to be taken when filter matches. + + + + + String to compare the layout to. + + + + + Indicates whether to ignore case when comparing strings. + + + + + Layout to be used to filter log messages. + + + + + + + + + + + + + + + + + + + + + + + Action to be taken when filter matches. + + + + + Append FilterCount to the P:NLog.LogEventInfo.Message when an event is no longer filtered + + + + + Insert FilterCount value into P:NLog.LogEventInfo.Properties when an event is no longer filtered + + + + + Applies the configured action to the initial logevent that starts the timeout period. Used to configure that it should ignore all events until timeout. + + + + + Layout to be used to filter log messages. + + + + + Max length of filter values, will truncate if above limit + + + + + How long before a filter expires, and logging is accepted again + + + + + Default number of unique filter values to expect, will automatically increase if needed + + + + + Max number of unique filter values to expect simultaneously + + + + + Default buffer size for the internal buffers + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/邮件系统课程完整代码/Server/App/Program.cs b/邮件系统课程完整代码/Server/App/Program.cs new file mode 100644 index 0000000..2956dff --- /dev/null +++ b/邮件系统课程完整代码/Server/App/Program.cs @@ -0,0 +1,23 @@ +using Fantasy.Helper; +using Fantasy.IdFactory; +using Fantasy.Platform.Net; +// 获取配置文件 +// 比如通过远程获取这个配置文件,这样可以多组服务器共享一套配置了 +var machineConfigText = await FileHelper.GetTextByRelativePath("../../Config/Json/Server/MachineConfigData.Json"); +var processConfigText = await FileHelper.GetTextByRelativePath("../../Config/Json/Server/ProcessConfigData.Json"); +var worldConfigText = await FileHelper.GetTextByRelativePath("../../Config/Json/Server/WorldConfigData.Json"); +var sceneConfigText = await FileHelper.GetTextByRelativePath("../../Config/Json/Server/SceneConfigData.Json"); +// 初始化配置文件 +// 如果重复初始化方法会覆盖掉上一次的数据,非常适合热重载时使用 +MachineConfigData.Initialize(machineConfigText); +ProcessConfigData.Initialize(processConfigText); +WorldConfigData.Initialize(worldConfigText); +SceneConfigData.Initialize(sceneConfigText); +// 注册日志模块到框架 +// 开发者可以自己注册日志系统到框架,只要实现Fantasy.ILog接口就可以。 +// 这里用的是NLog日志系统注册到框架中。 +Fantasy.Log.Register(new Fantasy.NLog("Server")); +// 初始化框架,添加程序集到框架中 +Fantasy.Platform.Net.Entry.Initialize(Fantasy.AssemblyHelper.Assemblies); +// 启动Fantasy.Net +await Fantasy.Platform.Net.Entry.Start(); \ No newline at end of file diff --git a/邮件系统课程完整代码/Server/App/Properties/launchSettings.json b/邮件系统课程完整代码/Server/App/Properties/launchSettings.json new file mode 100644 index 0000000..851188d --- /dev/null +++ b/邮件系统课程完整代码/Server/App/Properties/launchSettings.json @@ -0,0 +1,10 @@ +{ + "$schema": "http://json.schemastore.org/launchsettings.json", + "profiles": { + "App": { + "commandName": "Project", + "environmentVariables": {}, + "commandLineArgs": "--m Develop" + } + } +} diff --git a/邮件系统课程完整代码/Server/App/bin/.DS_Store b/邮件系统课程完整代码/Server/App/bin/.DS_Store new file mode 100644 index 0000000..fd5f0b1 Binary files /dev/null and b/邮件系统课程完整代码/Server/App/bin/.DS_Store differ diff --git a/邮件系统课程完整代码/Server/App/bin/Debug/.DS_Store b/邮件系统课程完整代码/Server/App/bin/Debug/.DS_Store new file mode 100644 index 0000000..cc729a0 Binary files /dev/null and b/邮件系统课程完整代码/Server/App/bin/Debug/.DS_Store differ diff --git a/邮件系统课程完整代码/Server/App/obj/App.csproj.nuget.dgspec.json b/邮件系统课程完整代码/Server/App/obj/App.csproj.nuget.dgspec.json new file mode 100644 index 0000000..76d9cdf --- /dev/null +++ b/邮件系统课程完整代码/Server/App/obj/App.csproj.nuget.dgspec.json @@ -0,0 +1,211 @@ +{ + "format": 1, + "restore": { + "/Users/fantasy/Movies/邮件系统/Lession/Server/App/App.csproj": {} + }, + "projects": { + "/Users/fantasy/Movies/邮件系统/Lession/Server/App/App.csproj": { + "version": "1.0.0", + "restore": { + "projectUniqueName": "/Users/fantasy/Movies/邮件系统/Lession/Server/App/App.csproj", + "projectName": "App", + "projectPath": "/Users/fantasy/Movies/邮件系统/Lession/Server/App/App.csproj", + "packagesPath": "/Users/fantasy/.nuget/packages/", + "outputPath": "/Users/fantasy/Movies/邮件系统/Lession/Server/App/obj/", + "projectStyle": "PackageReference", + "configFilePaths": [ + "/Users/fantasy/.nuget/NuGet/NuGet.Config" + ], + "originalTargetFrameworks": [ + "net8.0" + ], + "sources": { + "/usr/local/share/dotnet/library-packs": {}, + "https://api.nuget.org/v3/index.json": {} + }, + "frameworks": { + "net8.0": { + "targetAlias": "net8.0", + "projectReferences": { + "/Users/fantasy/Movies/邮件系统/Lession/Server/Entity/Entity.csproj": { + "projectPath": "/Users/fantasy/Movies/邮件系统/Lession/Server/Entity/Entity.csproj" + }, + "/Users/fantasy/Movies/邮件系统/Lession/Server/Hotfix/Hotfix.csproj": { + "projectPath": "/Users/fantasy/Movies/邮件系统/Lession/Server/Hotfix/Hotfix.csproj" + } + } + } + }, + "warningProperties": { + "warnAsError": [ + "NU1605" + ] + }, + "restoreAuditProperties": { + "enableAudit": "true", + "auditLevel": "low", + "auditMode": "all" + }, + "SdkAnalysisLevel": "9.0.100" + }, + "frameworks": { + "net8.0": { + "targetAlias": "net8.0", + "dependencies": { + "Fantasy-Net.NLog": { + "target": "Package", + "version": "[2024.1.20, )" + } + }, + "imports": [ + "net461", + "net462", + "net47", + "net471", + "net472", + "net48", + "net481" + ], + "assetTargetFallback": true, + "warn": true, + "frameworkReferences": { + "Microsoft.NETCore.App": { + "privateAssets": "all" + } + }, + "runtimeIdentifierGraphPath": "/usr/local/share/dotnet/sdk/9.0.100/PortableRuntimeIdentifierGraph.json" + } + } + }, + "/Users/fantasy/Movies/邮件系统/Lession/Server/Entity/Entity.csproj": { + "version": "1.0.0", + "restore": { + "projectUniqueName": "/Users/fantasy/Movies/邮件系统/Lession/Server/Entity/Entity.csproj", + "projectName": "Entity", + "projectPath": "/Users/fantasy/Movies/邮件系统/Lession/Server/Entity/Entity.csproj", + "packagesPath": "/Users/fantasy/.nuget/packages/", + "outputPath": "/Users/fantasy/Movies/邮件系统/Lession/Server/Entity/obj/", + "projectStyle": "PackageReference", + "configFilePaths": [ + "/Users/fantasy/.nuget/NuGet/NuGet.Config" + ], + "originalTargetFrameworks": [ + "net8.0" + ], + "sources": { + "/usr/local/share/dotnet/library-packs": {}, + "https://api.nuget.org/v3/index.json": {} + }, + "frameworks": { + "net8.0": { + "targetAlias": "net8.0", + "projectReferences": {} + } + }, + "warningProperties": { + "warnAsError": [ + "NU1605" + ] + }, + "restoreAuditProperties": { + "enableAudit": "true", + "auditLevel": "low", + "auditMode": "all" + }, + "SdkAnalysisLevel": "9.0.100" + }, + "frameworks": { + "net8.0": { + "targetAlias": "net8.0", + "dependencies": { + "Fantasy-Net": { + "target": "Package", + "version": "[2024.2.22, )" + } + }, + "imports": [ + "net461", + "net462", + "net47", + "net471", + "net472", + "net48", + "net481" + ], + "assetTargetFallback": true, + "warn": true, + "frameworkReferences": { + "Microsoft.NETCore.App": { + "privateAssets": "all" + } + }, + "runtimeIdentifierGraphPath": "/usr/local/share/dotnet/sdk/9.0.100/PortableRuntimeIdentifierGraph.json" + } + } + }, + "/Users/fantasy/Movies/邮件系统/Lession/Server/Hotfix/Hotfix.csproj": { + "version": "1.0.0", + "restore": { + "projectUniqueName": "/Users/fantasy/Movies/邮件系统/Lession/Server/Hotfix/Hotfix.csproj", + "projectName": "Hotfix", + "projectPath": "/Users/fantasy/Movies/邮件系统/Lession/Server/Hotfix/Hotfix.csproj", + "packagesPath": "/Users/fantasy/.nuget/packages/", + "outputPath": "/Users/fantasy/Movies/邮件系统/Lession/Server/Hotfix/obj/", + "projectStyle": "PackageReference", + "configFilePaths": [ + "/Users/fantasy/.nuget/NuGet/NuGet.Config" + ], + "originalTargetFrameworks": [ + "net8.0" + ], + "sources": { + "/usr/local/share/dotnet/library-packs": {}, + "https://api.nuget.org/v3/index.json": {} + }, + "frameworks": { + "net8.0": { + "targetAlias": "net8.0", + "projectReferences": { + "/Users/fantasy/Movies/邮件系统/Lession/Server/Entity/Entity.csproj": { + "projectPath": "/Users/fantasy/Movies/邮件系统/Lession/Server/Entity/Entity.csproj" + } + } + } + }, + "warningProperties": { + "warnAsError": [ + "NU1605" + ] + }, + "restoreAuditProperties": { + "enableAudit": "true", + "auditLevel": "low", + "auditMode": "all" + }, + "SdkAnalysisLevel": "9.0.100" + }, + "frameworks": { + "net8.0": { + "targetAlias": "net8.0", + "imports": [ + "net461", + "net462", + "net47", + "net471", + "net472", + "net48", + "net481" + ], + "assetTargetFallback": true, + "warn": true, + "frameworkReferences": { + "Microsoft.NETCore.App": { + "privateAssets": "all" + } + }, + "runtimeIdentifierGraphPath": "/usr/local/share/dotnet/sdk/9.0.100/PortableRuntimeIdentifierGraph.json" + } + } + } + } +} \ No newline at end of file diff --git a/邮件系统课程完整代码/Server/App/obj/App.csproj.nuget.g.props b/邮件系统课程完整代码/Server/App/obj/App.csproj.nuget.g.props new file mode 100644 index 0000000..f402062 --- /dev/null +++ b/邮件系统课程完整代码/Server/App/obj/App.csproj.nuget.g.props @@ -0,0 +1,15 @@ + + + + True + NuGet + $(MSBuildThisFileDirectory)project.assets.json + /Users/fantasy/.nuget/packages/ + /Users/fantasy/.nuget/packages/ + PackageReference + 6.12.2 + + + + + \ No newline at end of file diff --git a/邮件系统课程完整代码/Server/App/obj/App.csproj.nuget.g.targets b/邮件系统课程完整代码/Server/App/obj/App.csproj.nuget.g.targets new file mode 100644 index 0000000..bc9c080 --- /dev/null +++ b/邮件系统课程完整代码/Server/App/obj/App.csproj.nuget.g.targets @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/邮件系统课程完整代码/Server/App/obj/Debug/net8.0/.NETCoreApp,Version=v8.0.AssemblyAttributes.cs b/邮件系统课程完整代码/Server/App/obj/Debug/net8.0/.NETCoreApp,Version=v8.0.AssemblyAttributes.cs new file mode 100644 index 0000000..2217181 --- /dev/null +++ b/邮件系统课程完整代码/Server/App/obj/Debug/net8.0/.NETCoreApp,Version=v8.0.AssemblyAttributes.cs @@ -0,0 +1,4 @@ +// +using System; +using System.Reflection; +[assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute(".NETCoreApp,Version=v8.0", FrameworkDisplayName = ".NET 8.0")] diff --git a/邮件系统课程完整代码/Server/App/obj/Debug/net8.0/App.AssemblyInfo.cs b/邮件系统课程完整代码/Server/App/obj/Debug/net8.0/App.AssemblyInfo.cs new file mode 100644 index 0000000..1dd5157 --- /dev/null +++ b/邮件系统课程完整代码/Server/App/obj/Debug/net8.0/App.AssemblyInfo.cs @@ -0,0 +1,22 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +using System; +using System.Reflection; + +[assembly: System.Reflection.AssemblyCompanyAttribute("App")] +[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")] +[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")] +[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0")] +[assembly: System.Reflection.AssemblyProductAttribute("App")] +[assembly: System.Reflection.AssemblyTitleAttribute("App")] +[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")] + +// 由 MSBuild WriteCodeFragment 类生成。 + diff --git a/邮件系统课程完整代码/Server/App/obj/Debug/net8.0/App.AssemblyInfoInputs.cache b/邮件系统课程完整代码/Server/App/obj/Debug/net8.0/App.AssemblyInfoInputs.cache new file mode 100644 index 0000000..1c48eff --- /dev/null +++ b/邮件系统课程完整代码/Server/App/obj/Debug/net8.0/App.AssemblyInfoInputs.cache @@ -0,0 +1 @@ +821daf211998e642fd8571f61784d5b8d6071e65f77b7ed22cfcfb2a43a9388a diff --git a/邮件系统课程完整代码/Server/App/obj/Debug/net8.0/App.GeneratedMSBuildEditorConfig.editorconfig b/邮件系统课程完整代码/Server/App/obj/Debug/net8.0/App.GeneratedMSBuildEditorConfig.editorconfig new file mode 100644 index 0000000..1e1b0e3 --- /dev/null +++ b/邮件系统课程完整代码/Server/App/obj/Debug/net8.0/App.GeneratedMSBuildEditorConfig.editorconfig @@ -0,0 +1,15 @@ +is_global = true +build_property.TargetFramework = net8.0 +build_property.TargetPlatformMinVersion = +build_property.UsingMicrosoftNETSdkWeb = +build_property.ProjectTypeGuids = +build_property.InvariantGlobalization = +build_property.PlatformNeutralAssembly = +build_property.EnforceExtendedAnalyzerRules = +build_property._SupportedPlatformList = Linux,macOS,Windows +build_property.RootNamespace = App +build_property.ProjectDir = /Users/fantasy/Movies/邮件系统/Lession/Server/App/ +build_property.EnableComHosting = +build_property.EnableGeneratedComInterfaceComImportInterop = +build_property.EffectiveAnalysisLevelStyle = 8.0 +build_property.EnableCodeStyleSeverity = diff --git a/邮件系统课程完整代码/Server/App/obj/Debug/net8.0/App.GlobalUsings.g.cs b/邮件系统课程完整代码/Server/App/obj/Debug/net8.0/App.GlobalUsings.g.cs new file mode 100644 index 0000000..8578f3d --- /dev/null +++ b/邮件系统课程完整代码/Server/App/obj/Debug/net8.0/App.GlobalUsings.g.cs @@ -0,0 +1,8 @@ +// +global using global::System; +global using global::System.Collections.Generic; +global using global::System.IO; +global using global::System.Linq; +global using global::System.Net.Http; +global using global::System.Threading; +global using global::System.Threading.Tasks; diff --git a/邮件系统课程完整代码/Server/App/obj/Debug/net8.0/App.assets.cache b/邮件系统课程完整代码/Server/App/obj/Debug/net8.0/App.assets.cache new file mode 100644 index 0000000..1f02193 Binary files /dev/null and b/邮件系统课程完整代码/Server/App/obj/Debug/net8.0/App.assets.cache differ diff --git a/邮件系统课程完整代码/Server/App/obj/Debug/net8.0/App.csproj.AssemblyReference.cache b/邮件系统课程完整代码/Server/App/obj/Debug/net8.0/App.csproj.AssemblyReference.cache new file mode 100644 index 0000000..96d908f Binary files /dev/null and b/邮件系统课程完整代码/Server/App/obj/Debug/net8.0/App.csproj.AssemblyReference.cache differ diff --git a/邮件系统课程完整代码/Server/App/obj/Debug/net8.0/App.csproj.CoreCompileInputs.cache b/邮件系统课程完整代码/Server/App/obj/Debug/net8.0/App.csproj.CoreCompileInputs.cache new file mode 100644 index 0000000..e314f38 --- /dev/null +++ b/邮件系统课程完整代码/Server/App/obj/Debug/net8.0/App.csproj.CoreCompileInputs.cache @@ -0,0 +1 @@ +6ea5d9eb7371ff0fdba6e9dd9f3ce9a46fdad1c2971d1d6a0432963b1d7c5398 diff --git a/邮件系统课程完整代码/Server/App/obj/Debug/net8.0/App.csproj.FileListAbsolute.txt b/邮件系统课程完整代码/Server/App/obj/Debug/net8.0/App.csproj.FileListAbsolute.txt new file mode 100644 index 0000000..2bea4e3 --- /dev/null +++ b/邮件系统课程完整代码/Server/App/obj/Debug/net8.0/App.csproj.FileListAbsolute.txt @@ -0,0 +1,18 @@ +/Users/fantasy/Movies/邮件系统/Lession/Server/App/obj/Debug/net8.0/App.csproj.AssemblyReference.cache +/Users/fantasy/Movies/邮件系统/Lession/Server/App/obj/Debug/net8.0/App.GeneratedMSBuildEditorConfig.editorconfig +/Users/fantasy/Movies/邮件系统/Lession/Server/App/obj/Debug/net8.0/App.AssemblyInfoInputs.cache +/Users/fantasy/Movies/邮件系统/Lession/Server/App/obj/Debug/net8.0/App.AssemblyInfo.cs +/Users/fantasy/Movies/邮件系统/Lession/Server/App/obj/Debug/net8.0/App.csproj.CoreCompileInputs.cache +/Users/fantasy/Movies/邮件系统/Lession/Server/App/obj/Debug/net8.0/App.csproj.Up2Date +/Users/fantasy/Movies/邮件系统/Lession/Server/App/obj/Debug/net8.0/App.dll +/Users/fantasy/Movies/邮件系统/Lession/Server/App/obj/Debug/net8.0/refint/App.dll +/Users/fantasy/Movies/邮件系统/Lession/Server/App/obj/Debug/net8.0/App.pdb +/Users/fantasy/Movies/邮件系统/Lession/Server/App/obj/Debug/net8.0/App.genruntimeconfig.cache +/Users/fantasy/Movies/邮件系统/Lession/Server/App/obj/Debug/net8.0/ref/App.dll +/Users/fantasy/Movies/邮件系统/Lession/Bin/net8.0/App +/Users/fantasy/Movies/邮件系统/Lession/Bin/net8.0/NLog.config +/Users/fantasy/Movies/邮件系统/Lession/Bin/net8.0/NLog.xsd +/Users/fantasy/Movies/邮件系统/Lession/Bin/net8.0/App.deps.json +/Users/fantasy/Movies/邮件系统/Lession/Bin/net8.0/App.runtimeconfig.json +/Users/fantasy/Movies/邮件系统/Lession/Bin/net8.0/App.dll +/Users/fantasy/Movies/邮件系统/Lession/Bin/net8.0/App.pdb diff --git a/邮件系统课程完整代码/Server/App/obj/Debug/net8.0/App.csproj.Up2Date b/邮件系统课程完整代码/Server/App/obj/Debug/net8.0/App.csproj.Up2Date new file mode 100644 index 0000000..e69de29 diff --git a/邮件系统课程完整代码/Server/App/obj/Debug/net8.0/App.dll b/邮件系统课程完整代码/Server/App/obj/Debug/net8.0/App.dll new file mode 100644 index 0000000..6625e40 Binary files /dev/null and b/邮件系统课程完整代码/Server/App/obj/Debug/net8.0/App.dll differ diff --git a/邮件系统课程完整代码/Server/App/obj/Debug/net8.0/App.genruntimeconfig.cache b/邮件系统课程完整代码/Server/App/obj/Debug/net8.0/App.genruntimeconfig.cache new file mode 100644 index 0000000..c94de24 --- /dev/null +++ b/邮件系统课程完整代码/Server/App/obj/Debug/net8.0/App.genruntimeconfig.cache @@ -0,0 +1 @@ +43c0ad4056946926b0891319e5039496ccf3772662f3c5f77d051184ee024242 diff --git a/邮件系统课程完整代码/Server/App/obj/Debug/net8.0/App.pdb b/邮件系统课程完整代码/Server/App/obj/Debug/net8.0/App.pdb new file mode 100644 index 0000000..b109dba Binary files /dev/null and b/邮件系统课程完整代码/Server/App/obj/Debug/net8.0/App.pdb differ diff --git a/邮件系统课程完整代码/Server/App/obj/Debug/net8.0/apphost b/邮件系统课程完整代码/Server/App/obj/Debug/net8.0/apphost new file mode 100644 index 0000000..92db307 Binary files /dev/null and b/邮件系统课程完整代码/Server/App/obj/Debug/net8.0/apphost differ diff --git a/邮件系统课程完整代码/Server/App/obj/Debug/net8.0/ref/App.dll b/邮件系统课程完整代码/Server/App/obj/Debug/net8.0/ref/App.dll new file mode 100644 index 0000000..2f24239 Binary files /dev/null and b/邮件系统课程完整代码/Server/App/obj/Debug/net8.0/ref/App.dll differ diff --git a/邮件系统课程完整代码/Server/App/obj/Debug/net8.0/refint/App.dll b/邮件系统课程完整代码/Server/App/obj/Debug/net8.0/refint/App.dll new file mode 100644 index 0000000..2f24239 Binary files /dev/null and b/邮件系统课程完整代码/Server/App/obj/Debug/net8.0/refint/App.dll differ diff --git a/邮件系统课程完整代码/Server/App/obj/project.assets.json b/邮件系统课程完整代码/Server/App/obj/project.assets.json new file mode 100644 index 0000000..8bb3d9f --- /dev/null +++ b/邮件系统课程完整代码/Server/App/obj/project.assets.json @@ -0,0 +1,1064 @@ +{ + "version": 3, + "targets": { + "net8.0": { + "CommandLineParser/2.9.1": { + "type": "package", + "compile": { + "lib/netstandard2.0/CommandLine.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netstandard2.0/CommandLine.dll": { + "related": ".xml" + } + } + }, + "DnsClient/1.6.1": { + "type": "package", + "dependencies": { + "Microsoft.Win32.Registry": "5.0.0" + }, + "compile": { + "lib/net5.0/DnsClient.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net5.0/DnsClient.dll": { + "related": ".xml" + } + } + }, + "Fantasy-Net/2024.2.22": { + "type": "package", + "dependencies": { + "CommandLineParser": "2.9.1", + "MongoDB.Bson": "3.1.0", + "MongoDB.Driver": "3.1.0", + "Newtonsoft.Json": "13.0.3", + "System.IO.Pipelines": "9.0.0", + "protobuf-net": "3.2.45" + }, + "compile": { + "lib/net8.0/Fantasy-Net.dll": {} + }, + "runtime": { + "lib/net8.0/Fantasy-Net.dll": {} + }, + "frameworkReferences": [ + "Microsoft.AspNetCore.App" + ], + "build": { + "buildTransitive/Fantasy-Net.targets": {} + } + }, + "Fantasy-Net.NLog/2024.1.20": { + "type": "package", + "dependencies": { + "Fantasy-Net": "2024.1.3", + "NLog": "5.3.4" + }, + "compile": { + "lib/net8.0/Fantasy-Net.NLog.dll": {} + }, + "runtime": { + "lib/net8.0/Fantasy-Net.NLog.dll": {} + }, + "build": { + "buildTransitive/Fantasy-Net.NLog.targets": {} + } + }, + "Microsoft.Extensions.Logging.Abstractions/2.0.0": { + "type": "package", + "compile": { + "lib/netstandard2.0/Microsoft.Extensions.Logging.Abstractions.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netstandard2.0/Microsoft.Extensions.Logging.Abstractions.dll": { + "related": ".xml" + } + } + }, + "Microsoft.NETCore.Platforms/5.0.0": { + "type": "package", + "compile": { + "lib/netstandard1.0/_._": {} + }, + "runtime": { + "lib/netstandard1.0/_._": {} + } + }, + "Microsoft.Win32.Registry/5.0.0": { + "type": "package", + "dependencies": { + "System.Security.AccessControl": "5.0.0", + "System.Security.Principal.Windows": "5.0.0" + }, + "compile": { + "ref/netstandard2.0/Microsoft.Win32.Registry.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netstandard2.0/Microsoft.Win32.Registry.dll": { + "related": ".xml" + } + }, + "runtimeTargets": { + "runtimes/win/lib/netstandard2.0/Microsoft.Win32.Registry.dll": { + "assetType": "runtime", + "rid": "win" + } + } + }, + "MongoDB.Bson/3.1.0": { + "type": "package", + "dependencies": { + "System.Memory": "4.5.5", + "System.Runtime.CompilerServices.Unsafe": "5.0.0" + }, + "compile": { + "lib/net6.0/MongoDB.Bson.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net6.0/MongoDB.Bson.dll": { + "related": ".xml" + } + } + }, + "MongoDB.Driver/3.1.0": { + "type": "package", + "dependencies": { + "DnsClient": "1.6.1", + "Microsoft.Extensions.Logging.Abstractions": "2.0.0", + "MongoDB.Bson": "3.1.0", + "SharpCompress": "0.30.1", + "Snappier": "1.0.0", + "System.Buffers": "4.5.1", + "ZstdSharp.Port": "0.7.3" + }, + "compile": { + "lib/net6.0/MongoDB.Driver.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net6.0/MongoDB.Driver.dll": { + "related": ".xml" + } + } + }, + "Newtonsoft.Json/13.0.3": { + "type": "package", + "compile": { + "lib/net6.0/Newtonsoft.Json.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net6.0/Newtonsoft.Json.dll": { + "related": ".xml" + } + } + }, + "NLog/5.3.4": { + "type": "package", + "compile": { + "lib/netstandard2.0/NLog.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netstandard2.0/NLog.dll": { + "related": ".xml" + } + } + }, + "protobuf-net/3.2.45": { + "type": "package", + "dependencies": { + "protobuf-net.Core": "3.2.45" + }, + "compile": { + "lib/net6.0/protobuf-net.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net6.0/protobuf-net.dll": { + "related": ".xml" + } + } + }, + "protobuf-net.Core/3.2.45": { + "type": "package", + "dependencies": { + "System.Collections.Immutable": "7.0.0" + }, + "compile": { + "lib/net6.0/protobuf-net.Core.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net6.0/protobuf-net.Core.dll": { + "related": ".xml" + } + } + }, + "SharpCompress/0.30.1": { + "type": "package", + "compile": { + "lib/net5.0/SharpCompress.dll": {} + }, + "runtime": { + "lib/net5.0/SharpCompress.dll": {} + } + }, + "Snappier/1.0.0": { + "type": "package", + "compile": { + "lib/net5.0/Snappier.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net5.0/Snappier.dll": { + "related": ".xml" + } + } + }, + "System.Buffers/4.5.1": { + "type": "package", + "compile": { + "ref/netcoreapp2.0/_._": {} + }, + "runtime": { + "lib/netcoreapp2.0/_._": {} + } + }, + "System.Collections.Immutable/7.0.0": { + "type": "package", + "compile": { + "lib/net7.0/System.Collections.Immutable.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net7.0/System.Collections.Immutable.dll": { + "related": ".xml" + } + }, + "build": { + "buildTransitive/net6.0/_._": {} + } + }, + "System.IO.Pipelines/9.0.0": { + "type": "package", + "compile": { + "lib/net8.0/System.IO.Pipelines.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net8.0/System.IO.Pipelines.dll": { + "related": ".xml" + } + }, + "build": { + "buildTransitive/net8.0/_._": {} + } + }, + "System.Memory/4.5.5": { + "type": "package", + "compile": { + "ref/netcoreapp2.1/_._": {} + }, + "runtime": { + "lib/netcoreapp2.1/_._": {} + } + }, + "System.Runtime.CompilerServices.Unsafe/5.0.0": { + "type": "package", + "compile": { + "ref/netstandard2.1/System.Runtime.CompilerServices.Unsafe.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netcoreapp2.0/System.Runtime.CompilerServices.Unsafe.dll": { + "related": ".xml" + } + } + }, + "System.Security.AccessControl/5.0.0": { + "type": "package", + "dependencies": { + "Microsoft.NETCore.Platforms": "5.0.0", + "System.Security.Principal.Windows": "5.0.0" + }, + "compile": { + "ref/netstandard2.0/System.Security.AccessControl.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netstandard2.0/System.Security.AccessControl.dll": { + "related": ".xml" + } + }, + "runtimeTargets": { + "runtimes/win/lib/netcoreapp2.0/System.Security.AccessControl.dll": { + "assetType": "runtime", + "rid": "win" + } + } + }, + "System.Security.Principal.Windows/5.0.0": { + "type": "package", + "compile": { + "ref/netcoreapp3.0/System.Security.Principal.Windows.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netstandard2.0/System.Security.Principal.Windows.dll": { + "related": ".xml" + } + }, + "runtimeTargets": { + "runtimes/unix/lib/netcoreapp2.1/System.Security.Principal.Windows.dll": { + "assetType": "runtime", + "rid": "unix" + }, + "runtimes/win/lib/netcoreapp2.1/System.Security.Principal.Windows.dll": { + "assetType": "runtime", + "rid": "win" + } + } + }, + "ZstdSharp.Port/0.7.3": { + "type": "package", + "compile": { + "lib/net7.0/ZstdSharp.dll": {} + }, + "runtime": { + "lib/net7.0/ZstdSharp.dll": {} + } + }, + "Entity/1.0.0": { + "type": "project", + "framework": ".NETCoreApp,Version=v8.0", + "dependencies": { + "Fantasy-Net": "2024.2.22" + }, + "compile": { + "bin/placeholder/Entity.dll": {} + }, + "runtime": { + "bin/placeholder/Entity.dll": {} + } + }, + "Hotfix/1.0.0": { + "type": "project", + "framework": ".NETCoreApp,Version=v8.0", + "dependencies": { + "Entity": "1.0.0" + }, + "compile": { + "bin/placeholder/Hotfix.dll": {} + }, + "runtime": { + "bin/placeholder/Hotfix.dll": {} + } + } + } + }, + "libraries": { + "CommandLineParser/2.9.1": { + "sha512": "OE0sl1/sQ37bjVsPKKtwQlWDgqaxWgtme3xZz7JssWUzg5JpMIyHgCTY9MVMxOg48fJ1AgGT3tgdH5m/kQ5xhA==", + "type": "package", + "path": "commandlineparser/2.9.1", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "CommandLine20.png", + "License.md", + "README.md", + "commandlineparser.2.9.1.nupkg.sha512", + "commandlineparser.nuspec", + "lib/net40/CommandLine.dll", + "lib/net40/CommandLine.xml", + "lib/net45/CommandLine.dll", + "lib/net45/CommandLine.xml", + "lib/net461/CommandLine.dll", + "lib/net461/CommandLine.xml", + "lib/netstandard2.0/CommandLine.dll", + "lib/netstandard2.0/CommandLine.xml" + ] + }, + "DnsClient/1.6.1": { + "sha512": "4H/f2uYJOZ+YObZjpY9ABrKZI+JNw3uizp6oMzTXwDw6F+2qIPhpRl/1t68O/6e98+vqNiYGu+lswmwdYUy3gg==", + "type": "package", + "path": "dnsclient/1.6.1", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "dnsclient.1.6.1.nupkg.sha512", + "dnsclient.nuspec", + "icon.png", + "lib/net45/DnsClient.dll", + "lib/net45/DnsClient.xml", + "lib/net471/DnsClient.dll", + "lib/net471/DnsClient.xml", + "lib/net5.0/DnsClient.dll", + "lib/net5.0/DnsClient.xml", + "lib/netstandard1.3/DnsClient.dll", + "lib/netstandard1.3/DnsClient.xml", + "lib/netstandard2.0/DnsClient.dll", + "lib/netstandard2.0/DnsClient.xml", + "lib/netstandard2.1/DnsClient.dll", + "lib/netstandard2.1/DnsClient.xml" + ] + }, + "Fantasy-Net/2024.2.22": { + "sha512": "cT6B0YJ5JmbPHBLYgLeVgg2WbXYxxa1tudoIase88uMzAuqU9t7EQ7dFZGSWjP41c5JOQ/0f1q9lzGWTh/hskw==", + "type": "package", + "path": "fantasy-net/2024.2.22", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "LICENSE", + "README.md", + "buildTransitive/Fantasy-Net.targets", + "fantasy-net.2024.2.22.nupkg.sha512", + "fantasy-net.nuspec", + "icon.png", + "lib/net8.0/Fantasy-Net.dll", + "lib/net9.0/Fantasy-Net.dll" + ] + }, + "Fantasy-Net.NLog/2024.1.20": { + "sha512": "HJuHfecWrD7tcQYEZezJzgayvG5leAbdWlgvo9ft/CUuwTtAB+tkeKP3e3VtbkCoPaAZO4VAUN0Y30Ute2/vrQ==", + "type": "package", + "path": "fantasy-net.nlog/2024.1.20", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "build/NLog.config", + "build/NLog.xsd", + "buildTransitive/Fantasy-Net.NLog.targets", + "fantasy-net.nlog.2024.1.20.nupkg.sha512", + "fantasy-net.nlog.nuspec", + "icon.png", + "lib/net8.0/Fantasy-Net.NLog.dll" + ] + }, + "Microsoft.Extensions.Logging.Abstractions/2.0.0": { + "sha512": "6ZCllUYGFukkymSTx3Yr0G/ajRxoNJp7/FqSxSB4fGISST54ifBhgu4Nc0ItGi3i6DqwuNd8SUyObmiC++AO2Q==", + "type": "package", + "path": "microsoft.extensions.logging.abstractions/2.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "lib/netstandard2.0/Microsoft.Extensions.Logging.Abstractions.dll", + "lib/netstandard2.0/Microsoft.Extensions.Logging.Abstractions.xml", + "microsoft.extensions.logging.abstractions.2.0.0.nupkg.sha512", + "microsoft.extensions.logging.abstractions.nuspec" + ] + }, + "Microsoft.NETCore.Platforms/5.0.0": { + "sha512": "VyPlqzH2wavqquTcYpkIIAQ6WdenuKoFN0BdYBbCWsclXacSOHNQn66Gt4z5NBqEYW0FAPm5rlvki9ZiCij5xQ==", + "type": "package", + "path": "microsoft.netcore.platforms/5.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "LICENSE.TXT", + "THIRD-PARTY-NOTICES.TXT", + "lib/netstandard1.0/_._", + "microsoft.netcore.platforms.5.0.0.nupkg.sha512", + "microsoft.netcore.platforms.nuspec", + "runtime.json", + "useSharedDesignerContext.txt", + "version.txt" + ] + }, + "Microsoft.Win32.Registry/5.0.0": { + "sha512": "dDoKi0PnDz31yAyETfRntsLArTlVAVzUzCIvvEDsDsucrl33Dl8pIJG06ePTJTI3tGpeyHS9Cq7Foc/s4EeKcg==", + "type": "package", + "path": "microsoft.win32.registry/5.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "LICENSE.TXT", + "THIRD-PARTY-NOTICES.TXT", + "lib/net46/Microsoft.Win32.Registry.dll", + "lib/net461/Microsoft.Win32.Registry.dll", + "lib/net461/Microsoft.Win32.Registry.xml", + "lib/netstandard1.3/Microsoft.Win32.Registry.dll", + "lib/netstandard2.0/Microsoft.Win32.Registry.dll", + "lib/netstandard2.0/Microsoft.Win32.Registry.xml", + "microsoft.win32.registry.5.0.0.nupkg.sha512", + "microsoft.win32.registry.nuspec", + "ref/net46/Microsoft.Win32.Registry.dll", + "ref/net461/Microsoft.Win32.Registry.dll", + "ref/net461/Microsoft.Win32.Registry.xml", + "ref/netstandard1.3/Microsoft.Win32.Registry.dll", + "ref/netstandard1.3/Microsoft.Win32.Registry.xml", + "ref/netstandard1.3/de/Microsoft.Win32.Registry.xml", + "ref/netstandard1.3/es/Microsoft.Win32.Registry.xml", + "ref/netstandard1.3/fr/Microsoft.Win32.Registry.xml", + "ref/netstandard1.3/it/Microsoft.Win32.Registry.xml", + "ref/netstandard1.3/ja/Microsoft.Win32.Registry.xml", + "ref/netstandard1.3/ko/Microsoft.Win32.Registry.xml", + "ref/netstandard1.3/ru/Microsoft.Win32.Registry.xml", + "ref/netstandard1.3/zh-hans/Microsoft.Win32.Registry.xml", + "ref/netstandard1.3/zh-hant/Microsoft.Win32.Registry.xml", + "ref/netstandard2.0/Microsoft.Win32.Registry.dll", + "ref/netstandard2.0/Microsoft.Win32.Registry.xml", + "runtimes/win/lib/net46/Microsoft.Win32.Registry.dll", + "runtimes/win/lib/net461/Microsoft.Win32.Registry.dll", + "runtimes/win/lib/net461/Microsoft.Win32.Registry.xml", + "runtimes/win/lib/netstandard1.3/Microsoft.Win32.Registry.dll", + "runtimes/win/lib/netstandard2.0/Microsoft.Win32.Registry.dll", + "runtimes/win/lib/netstandard2.0/Microsoft.Win32.Registry.xml", + "useSharedDesignerContext.txt", + "version.txt" + ] + }, + "MongoDB.Bson/3.1.0": { + "sha512": "3dhaZhz18B5vUoEP13o2j8A6zQfkHdZhwBvLZEjDJum4BTLLv1/Z8bt25UQEtpqvYwLgde4R6ekWZ7XAYUMxuw==", + "type": "package", + "path": "mongodb.bson/3.1.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "README.md", + "lib/net472/MongoDB.Bson.dll", + "lib/net472/MongoDB.Bson.xml", + "lib/net6.0/MongoDB.Bson.dll", + "lib/net6.0/MongoDB.Bson.xml", + "lib/netstandard2.1/MongoDB.Bson.dll", + "lib/netstandard2.1/MongoDB.Bson.xml", + "mongodb.bson.3.1.0.nupkg.sha512", + "mongodb.bson.nuspec", + "packageIcon.png" + ] + }, + "MongoDB.Driver/3.1.0": { + "sha512": "+O7lKaIl7VUHptE0hqTd7UY1G5KDp/o8S4upG7YL4uChMNKD/U6tz9i17nMGHaD/L2AiPLgaJcaDe2XACsegGA==", + "type": "package", + "path": "mongodb.driver/3.1.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "README.md", + "lib/net472/MongoDB.Driver.dll", + "lib/net472/MongoDB.Driver.xml", + "lib/net6.0/MongoDB.Driver.dll", + "lib/net6.0/MongoDB.Driver.xml", + "lib/netstandard2.1/MongoDB.Driver.dll", + "lib/netstandard2.1/MongoDB.Driver.xml", + "mongodb.driver.3.1.0.nupkg.sha512", + "mongodb.driver.nuspec", + "packageIcon.png" + ] + }, + "Newtonsoft.Json/13.0.3": { + "sha512": "HrC5BXdl00IP9zeV+0Z848QWPAoCr9P3bDEZguI+gkLcBKAOxix/tLEAAHC+UvDNPv4a2d18lOReHMOagPa+zQ==", + "type": "package", + "path": "newtonsoft.json/13.0.3", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "LICENSE.md", + "README.md", + "lib/net20/Newtonsoft.Json.dll", + "lib/net20/Newtonsoft.Json.xml", + "lib/net35/Newtonsoft.Json.dll", + "lib/net35/Newtonsoft.Json.xml", + "lib/net40/Newtonsoft.Json.dll", + "lib/net40/Newtonsoft.Json.xml", + "lib/net45/Newtonsoft.Json.dll", + "lib/net45/Newtonsoft.Json.xml", + "lib/net6.0/Newtonsoft.Json.dll", + "lib/net6.0/Newtonsoft.Json.xml", + "lib/netstandard1.0/Newtonsoft.Json.dll", + "lib/netstandard1.0/Newtonsoft.Json.xml", + "lib/netstandard1.3/Newtonsoft.Json.dll", + "lib/netstandard1.3/Newtonsoft.Json.xml", + "lib/netstandard2.0/Newtonsoft.Json.dll", + "lib/netstandard2.0/Newtonsoft.Json.xml", + "newtonsoft.json.13.0.3.nupkg.sha512", + "newtonsoft.json.nuspec", + "packageIcon.png" + ] + }, + "NLog/5.3.4": { + "sha512": "gLy7+O1hEYJXIlcTr1/VWjGXrZTQFZzYNO18IWasD64pNwz0BreV+nHLxWKXWZzERRzoKnsk2XYtwLkTVk7J1A==", + "type": "package", + "path": "nlog/5.3.4", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "N.png", + "lib/net35/NLog.dll", + "lib/net35/NLog.xml", + "lib/net45/NLog.dll", + "lib/net45/NLog.xml", + "lib/net46/NLog.dll", + "lib/net46/NLog.xml", + "lib/netstandard1.3/NLog.dll", + "lib/netstandard1.3/NLog.xml", + "lib/netstandard1.5/NLog.dll", + "lib/netstandard1.5/NLog.xml", + "lib/netstandard2.0/NLog.dll", + "lib/netstandard2.0/NLog.xml", + "nlog.5.3.4.nupkg.sha512", + "nlog.nuspec" + ] + }, + "protobuf-net/3.2.45": { + "sha512": "5UZ/ukUHcGbFSl7vNMrHsfjqdxusdd9w7w0fCEXzf3UUtsrGNVCzV5SmF+sCHAbnRV2qPcD1ixiDP7Aj8lX/HA==", + "type": "package", + "path": "protobuf-net/3.2.45", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "lib/net462/protobuf-net.dll", + "lib/net462/protobuf-net.xml", + "lib/net6.0/protobuf-net.dll", + "lib/net6.0/protobuf-net.xml", + "lib/netstandard2.0/protobuf-net.dll", + "lib/netstandard2.0/protobuf-net.xml", + "lib/netstandard2.1/protobuf-net.dll", + "lib/netstandard2.1/protobuf-net.xml", + "protobuf-net.3.2.45.nupkg.sha512", + "protobuf-net.nuspec", + "protobuf-net.png", + "readme.md" + ] + }, + "protobuf-net.Core/3.2.45": { + "sha512": "PMWatW2NrT1uTXD7etJ4VdQ0wWZLFrIfdRGppD2QX7nzZ0+kIzqhq551u6ZiXJHWJgG4hWFEkSnUnt2aB6posg==", + "type": "package", + "path": "protobuf-net.core/3.2.45", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "lib/net462/protobuf-net.Core.dll", + "lib/net462/protobuf-net.Core.xml", + "lib/net6.0/protobuf-net.Core.dll", + "lib/net6.0/protobuf-net.Core.xml", + "lib/netstandard2.0/protobuf-net.Core.dll", + "lib/netstandard2.0/protobuf-net.Core.xml", + "lib/netstandard2.1/protobuf-net.Core.dll", + "lib/netstandard2.1/protobuf-net.Core.xml", + "protobuf-net.core.3.2.45.nupkg.sha512", + "protobuf-net.core.nuspec", + "protobuf-net.png", + "readme.md" + ] + }, + "SharpCompress/0.30.1": { + "sha512": "XqD4TpfyYGa7QTPzaGlMVbcecKnXy4YmYLDWrU+JIj7IuRNl7DH2END+Ll7ekWIY8o3dAMWLFDE1xdhfIWD1nw==", + "type": "package", + "path": "sharpcompress/0.30.1", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "lib/net461/SharpCompress.dll", + "lib/net5.0/SharpCompress.dll", + "lib/netcoreapp3.1/SharpCompress.dll", + "lib/netstandard2.0/SharpCompress.dll", + "lib/netstandard2.1/SharpCompress.dll", + "sharpcompress.0.30.1.nupkg.sha512", + "sharpcompress.nuspec" + ] + }, + "Snappier/1.0.0": { + "sha512": "rFtK2KEI9hIe8gtx3a0YDXdHOpedIf9wYCEYtBEmtlyiWVX3XlCNV03JrmmAi/Cdfn7dxK+k0sjjcLv4fpHnqA==", + "type": "package", + "path": "snappier/1.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "COPYING.txt", + "lib/net5.0/Snappier.dll", + "lib/net5.0/Snappier.xml", + "lib/netcoreapp3.0/Snappier.dll", + "lib/netcoreapp3.0/Snappier.xml", + "lib/netstandard2.0/Snappier.dll", + "lib/netstandard2.0/Snappier.xml", + "lib/netstandard2.1/Snappier.dll", + "lib/netstandard2.1/Snappier.xml", + "snappier.1.0.0.nupkg.sha512", + "snappier.nuspec" + ] + }, + "System.Buffers/4.5.1": { + "sha512": "Rw7ijyl1qqRS0YQD/WycNst8hUUMgrMH4FCn1nNm27M4VxchZ1js3fVjQaANHO5f3sN4isvP4a+Met9Y4YomAg==", + "type": "package", + "path": "system.buffers/4.5.1", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "LICENSE.TXT", + "THIRD-PARTY-NOTICES.TXT", + "lib/net461/System.Buffers.dll", + "lib/net461/System.Buffers.xml", + "lib/netcoreapp2.0/_._", + "lib/netstandard1.1/System.Buffers.dll", + "lib/netstandard1.1/System.Buffers.xml", + "lib/netstandard2.0/System.Buffers.dll", + "lib/netstandard2.0/System.Buffers.xml", + "lib/uap10.0.16299/_._", + "ref/net45/System.Buffers.dll", + "ref/net45/System.Buffers.xml", + "ref/netcoreapp2.0/_._", + "ref/netstandard1.1/System.Buffers.dll", + "ref/netstandard1.1/System.Buffers.xml", + "ref/netstandard2.0/System.Buffers.dll", + "ref/netstandard2.0/System.Buffers.xml", + "ref/uap10.0.16299/_._", + "system.buffers.4.5.1.nupkg.sha512", + "system.buffers.nuspec", + "useSharedDesignerContext.txt", + "version.txt" + ] + }, + "System.Collections.Immutable/7.0.0": { + "sha512": "dQPcs0U1IKnBdRDBkrCTi1FoajSTBzLcVTpjO4MBCMC7f4pDOIPzgBoX8JjG7X6uZRJ8EBxsi8+DR1JuwjnzOQ==", + "type": "package", + "path": "system.collections.immutable/7.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "LICENSE.TXT", + "README.md", + "THIRD-PARTY-NOTICES.TXT", + "buildTransitive/net461/System.Collections.Immutable.targets", + "buildTransitive/net462/_._", + "buildTransitive/net6.0/_._", + "buildTransitive/netcoreapp2.0/System.Collections.Immutable.targets", + "lib/net462/System.Collections.Immutable.dll", + "lib/net462/System.Collections.Immutable.xml", + "lib/net6.0/System.Collections.Immutable.dll", + "lib/net6.0/System.Collections.Immutable.xml", + "lib/net7.0/System.Collections.Immutable.dll", + "lib/net7.0/System.Collections.Immutable.xml", + "lib/netstandard2.0/System.Collections.Immutable.dll", + "lib/netstandard2.0/System.Collections.Immutable.xml", + "system.collections.immutable.7.0.0.nupkg.sha512", + "system.collections.immutable.nuspec", + "useSharedDesignerContext.txt" + ] + }, + "System.IO.Pipelines/9.0.0": { + "sha512": "eA3cinogwaNB4jdjQHOP3Z3EuyiDII7MT35jgtnsA4vkn0LUrrSHsU0nzHTzFzmaFYeKV7MYyMxOocFzsBHpTw==", + "type": "package", + "path": "system.io.pipelines/9.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "LICENSE.TXT", + "PACKAGE.md", + "THIRD-PARTY-NOTICES.TXT", + "buildTransitive/net461/System.IO.Pipelines.targets", + "buildTransitive/net462/_._", + "buildTransitive/net8.0/_._", + "buildTransitive/netcoreapp2.0/System.IO.Pipelines.targets", + "lib/net462/System.IO.Pipelines.dll", + "lib/net462/System.IO.Pipelines.xml", + "lib/net8.0/System.IO.Pipelines.dll", + "lib/net8.0/System.IO.Pipelines.xml", + "lib/net9.0/System.IO.Pipelines.dll", + "lib/net9.0/System.IO.Pipelines.xml", + "lib/netstandard2.0/System.IO.Pipelines.dll", + "lib/netstandard2.0/System.IO.Pipelines.xml", + "system.io.pipelines.9.0.0.nupkg.sha512", + "system.io.pipelines.nuspec", + "useSharedDesignerContext.txt" + ] + }, + "System.Memory/4.5.5": { + "sha512": "XIWiDvKPXaTveaB7HVganDlOCRoj03l+jrwNvcge/t8vhGYKvqV+dMv6G4SAX2NoNmN0wZfVPTAlFwZcZvVOUw==", + "type": "package", + "path": "system.memory/4.5.5", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "LICENSE.TXT", + "THIRD-PARTY-NOTICES.TXT", + "lib/net461/System.Memory.dll", + "lib/net461/System.Memory.xml", + "lib/netcoreapp2.1/_._", + "lib/netstandard1.1/System.Memory.dll", + "lib/netstandard1.1/System.Memory.xml", + "lib/netstandard2.0/System.Memory.dll", + "lib/netstandard2.0/System.Memory.xml", + "ref/netcoreapp2.1/_._", + "system.memory.4.5.5.nupkg.sha512", + "system.memory.nuspec", + "useSharedDesignerContext.txt", + "version.txt" + ] + }, + "System.Runtime.CompilerServices.Unsafe/5.0.0": { + "sha512": "ZD9TMpsmYJLrxbbmdvhwt9YEgG5WntEnZ/d1eH8JBX9LBp+Ju8BSBhUGbZMNVHHomWo2KVImJhTDl2hIgw/6MA==", + "type": "package", + "path": "system.runtime.compilerservices.unsafe/5.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "LICENSE.TXT", + "THIRD-PARTY-NOTICES.TXT", + "lib/net45/System.Runtime.CompilerServices.Unsafe.dll", + "lib/net45/System.Runtime.CompilerServices.Unsafe.xml", + "lib/netcoreapp2.0/System.Runtime.CompilerServices.Unsafe.dll", + "lib/netcoreapp2.0/System.Runtime.CompilerServices.Unsafe.xml", + "lib/netstandard1.0/System.Runtime.CompilerServices.Unsafe.dll", + "lib/netstandard1.0/System.Runtime.CompilerServices.Unsafe.xml", + "lib/netstandard2.0/System.Runtime.CompilerServices.Unsafe.dll", + "lib/netstandard2.0/System.Runtime.CompilerServices.Unsafe.xml", + "ref/net461/System.Runtime.CompilerServices.Unsafe.dll", + "ref/net461/System.Runtime.CompilerServices.Unsafe.xml", + "ref/netstandard1.0/System.Runtime.CompilerServices.Unsafe.dll", + "ref/netstandard1.0/System.Runtime.CompilerServices.Unsafe.xml", + "ref/netstandard2.0/System.Runtime.CompilerServices.Unsafe.dll", + "ref/netstandard2.0/System.Runtime.CompilerServices.Unsafe.xml", + "ref/netstandard2.1/System.Runtime.CompilerServices.Unsafe.dll", + "ref/netstandard2.1/System.Runtime.CompilerServices.Unsafe.xml", + "system.runtime.compilerservices.unsafe.5.0.0.nupkg.sha512", + "system.runtime.compilerservices.unsafe.nuspec", + "useSharedDesignerContext.txt", + "version.txt" + ] + }, + "System.Security.AccessControl/5.0.0": { + "sha512": "dagJ1mHZO3Ani8GH0PHpPEe/oYO+rVdbQjvjJkBRNQkX4t0r1iaeGn8+/ybkSLEan3/slM0t59SVdHzuHf2jmw==", + "type": "package", + "path": "system.security.accesscontrol/5.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "LICENSE.TXT", + "THIRD-PARTY-NOTICES.TXT", + "lib/net46/System.Security.AccessControl.dll", + "lib/net461/System.Security.AccessControl.dll", + "lib/net461/System.Security.AccessControl.xml", + "lib/netstandard1.3/System.Security.AccessControl.dll", + "lib/netstandard2.0/System.Security.AccessControl.dll", + "lib/netstandard2.0/System.Security.AccessControl.xml", + "lib/uap10.0.16299/_._", + "ref/net46/System.Security.AccessControl.dll", + "ref/net461/System.Security.AccessControl.dll", + "ref/net461/System.Security.AccessControl.xml", + "ref/netstandard1.3/System.Security.AccessControl.dll", + "ref/netstandard1.3/System.Security.AccessControl.xml", + "ref/netstandard1.3/de/System.Security.AccessControl.xml", + "ref/netstandard1.3/es/System.Security.AccessControl.xml", + "ref/netstandard1.3/fr/System.Security.AccessControl.xml", + "ref/netstandard1.3/it/System.Security.AccessControl.xml", + "ref/netstandard1.3/ja/System.Security.AccessControl.xml", + "ref/netstandard1.3/ko/System.Security.AccessControl.xml", + "ref/netstandard1.3/ru/System.Security.AccessControl.xml", + "ref/netstandard1.3/zh-hans/System.Security.AccessControl.xml", + "ref/netstandard1.3/zh-hant/System.Security.AccessControl.xml", + "ref/netstandard2.0/System.Security.AccessControl.dll", + "ref/netstandard2.0/System.Security.AccessControl.xml", + "ref/uap10.0.16299/_._", + "runtimes/win/lib/net46/System.Security.AccessControl.dll", + "runtimes/win/lib/net461/System.Security.AccessControl.dll", + "runtimes/win/lib/net461/System.Security.AccessControl.xml", + "runtimes/win/lib/netcoreapp2.0/System.Security.AccessControl.dll", + "runtimes/win/lib/netcoreapp2.0/System.Security.AccessControl.xml", + "runtimes/win/lib/netstandard1.3/System.Security.AccessControl.dll", + "runtimes/win/lib/uap10.0.16299/_._", + "system.security.accesscontrol.5.0.0.nupkg.sha512", + "system.security.accesscontrol.nuspec", + "useSharedDesignerContext.txt", + "version.txt" + ] + }, + "System.Security.Principal.Windows/5.0.0": { + "sha512": "t0MGLukB5WAVU9bO3MGzvlGnyJPgUlcwerXn1kzBRjwLKixT96XV0Uza41W49gVd8zEMFu9vQEFlv0IOrytICA==", + "type": "package", + "path": "system.security.principal.windows/5.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "LICENSE.TXT", + "THIRD-PARTY-NOTICES.TXT", + "lib/net46/System.Security.Principal.Windows.dll", + "lib/net461/System.Security.Principal.Windows.dll", + "lib/net461/System.Security.Principal.Windows.xml", + "lib/netstandard1.3/System.Security.Principal.Windows.dll", + "lib/netstandard2.0/System.Security.Principal.Windows.dll", + "lib/netstandard2.0/System.Security.Principal.Windows.xml", + "lib/uap10.0.16299/_._", + "ref/net46/System.Security.Principal.Windows.dll", + "ref/net461/System.Security.Principal.Windows.dll", + "ref/net461/System.Security.Principal.Windows.xml", + "ref/netcoreapp3.0/System.Security.Principal.Windows.dll", + "ref/netcoreapp3.0/System.Security.Principal.Windows.xml", + "ref/netstandard1.3/System.Security.Principal.Windows.dll", + "ref/netstandard1.3/System.Security.Principal.Windows.xml", + "ref/netstandard1.3/de/System.Security.Principal.Windows.xml", + "ref/netstandard1.3/es/System.Security.Principal.Windows.xml", + "ref/netstandard1.3/fr/System.Security.Principal.Windows.xml", + "ref/netstandard1.3/it/System.Security.Principal.Windows.xml", + "ref/netstandard1.3/ja/System.Security.Principal.Windows.xml", + "ref/netstandard1.3/ko/System.Security.Principal.Windows.xml", + "ref/netstandard1.3/ru/System.Security.Principal.Windows.xml", + "ref/netstandard1.3/zh-hans/System.Security.Principal.Windows.xml", + "ref/netstandard1.3/zh-hant/System.Security.Principal.Windows.xml", + "ref/netstandard2.0/System.Security.Principal.Windows.dll", + "ref/netstandard2.0/System.Security.Principal.Windows.xml", + "ref/uap10.0.16299/_._", + "runtimes/unix/lib/netcoreapp2.0/System.Security.Principal.Windows.dll", + "runtimes/unix/lib/netcoreapp2.0/System.Security.Principal.Windows.xml", + "runtimes/unix/lib/netcoreapp2.1/System.Security.Principal.Windows.dll", + "runtimes/unix/lib/netcoreapp2.1/System.Security.Principal.Windows.xml", + "runtimes/win/lib/net46/System.Security.Principal.Windows.dll", + "runtimes/win/lib/net461/System.Security.Principal.Windows.dll", + "runtimes/win/lib/net461/System.Security.Principal.Windows.xml", + "runtimes/win/lib/netcoreapp2.0/System.Security.Principal.Windows.dll", + "runtimes/win/lib/netcoreapp2.0/System.Security.Principal.Windows.xml", + "runtimes/win/lib/netcoreapp2.1/System.Security.Principal.Windows.dll", + "runtimes/win/lib/netcoreapp2.1/System.Security.Principal.Windows.xml", + "runtimes/win/lib/netstandard1.3/System.Security.Principal.Windows.dll", + "runtimes/win/lib/uap10.0.16299/_._", + "system.security.principal.windows.5.0.0.nupkg.sha512", + "system.security.principal.windows.nuspec", + "useSharedDesignerContext.txt", + "version.txt" + ] + }, + "ZstdSharp.Port/0.7.3": { + "sha512": "U9Ix4l4cl58Kzz1rJzj5hoVTjmbx1qGMwzAcbv1j/d3NzrFaESIurQyg+ow4mivCgkE3S413y+U9k4WdnEIkRA==", + "type": "package", + "path": "zstdsharp.port/0.7.3", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "lib/net461/ZstdSharp.dll", + "lib/net5.0/ZstdSharp.dll", + "lib/net6.0/ZstdSharp.dll", + "lib/net7.0/ZstdSharp.dll", + "lib/netcoreapp3.1/ZstdSharp.dll", + "lib/netstandard2.0/ZstdSharp.dll", + "lib/netstandard2.1/ZstdSharp.dll", + "zstdsharp.port.0.7.3.nupkg.sha512", + "zstdsharp.port.nuspec" + ] + }, + "Entity/1.0.0": { + "type": "project", + "path": "../Entity/Entity.csproj", + "msbuildProject": "../Entity/Entity.csproj" + }, + "Hotfix/1.0.0": { + "type": "project", + "path": "../Hotfix/Hotfix.csproj", + "msbuildProject": "../Hotfix/Hotfix.csproj" + } + }, + "projectFileDependencyGroups": { + "net8.0": [ + "Entity >= 1.0.0", + "Fantasy-Net.NLog >= 2024.1.20", + "Hotfix >= 1.0.0" + ] + }, + "packageFolders": { + "/Users/fantasy/.nuget/packages/": {} + }, + "project": { + "version": "1.0.0", + "restore": { + "projectUniqueName": "/Users/fantasy/Movies/邮件系统/Lession/Server/App/App.csproj", + "projectName": "App", + "projectPath": "/Users/fantasy/Movies/邮件系统/Lession/Server/App/App.csproj", + "packagesPath": "/Users/fantasy/.nuget/packages/", + "outputPath": "/Users/fantasy/Movies/邮件系统/Lession/Server/App/obj/", + "projectStyle": "PackageReference", + "configFilePaths": [ + "/Users/fantasy/.nuget/NuGet/NuGet.Config" + ], + "originalTargetFrameworks": [ + "net8.0" + ], + "sources": { + "/usr/local/share/dotnet/library-packs": {}, + "https://api.nuget.org/v3/index.json": {} + }, + "frameworks": { + "net8.0": { + "targetAlias": "net8.0", + "projectReferences": { + "/Users/fantasy/Movies/邮件系统/Lession/Server/Entity/Entity.csproj": { + "projectPath": "/Users/fantasy/Movies/邮件系统/Lession/Server/Entity/Entity.csproj" + }, + "/Users/fantasy/Movies/邮件系统/Lession/Server/Hotfix/Hotfix.csproj": { + "projectPath": "/Users/fantasy/Movies/邮件系统/Lession/Server/Hotfix/Hotfix.csproj" + } + } + } + }, + "warningProperties": { + "warnAsError": [ + "NU1605" + ] + }, + "restoreAuditProperties": { + "enableAudit": "true", + "auditLevel": "low", + "auditMode": "all" + }, + "SdkAnalysisLevel": "9.0.100" + }, + "frameworks": { + "net8.0": { + "targetAlias": "net8.0", + "dependencies": { + "Fantasy-Net.NLog": { + "target": "Package", + "version": "[2024.1.20, )" + } + }, + "imports": [ + "net461", + "net462", + "net47", + "net471", + "net472", + "net48", + "net481" + ], + "assetTargetFallback": true, + "warn": true, + "frameworkReferences": { + "Microsoft.NETCore.App": { + "privateAssets": "all" + } + }, + "runtimeIdentifierGraphPath": "/usr/local/share/dotnet/sdk/9.0.100/PortableRuntimeIdentifierGraph.json" + } + } + } +} \ No newline at end of file diff --git a/邮件系统课程完整代码/Server/App/obj/project.nuget.cache b/邮件系统课程完整代码/Server/App/obj/project.nuget.cache new file mode 100644 index 0000000..cca901e --- /dev/null +++ b/邮件系统课程完整代码/Server/App/obj/project.nuget.cache @@ -0,0 +1,32 @@ +{ + "version": 2, + "dgSpecHash": "KiiXK9qXJ3M=", + "success": true, + "projectFilePath": "/Users/fantasy/Movies/邮件系统/Lession/Server/App/App.csproj", + "expectedPackageFiles": [ + "/Users/fantasy/.nuget/packages/commandlineparser/2.9.1/commandlineparser.2.9.1.nupkg.sha512", + "/Users/fantasy/.nuget/packages/dnsclient/1.6.1/dnsclient.1.6.1.nupkg.sha512", + "/Users/fantasy/.nuget/packages/fantasy-net/2024.2.22/fantasy-net.2024.2.22.nupkg.sha512", + "/Users/fantasy/.nuget/packages/fantasy-net.nlog/2024.1.20/fantasy-net.nlog.2024.1.20.nupkg.sha512", + "/Users/fantasy/.nuget/packages/microsoft.extensions.logging.abstractions/2.0.0/microsoft.extensions.logging.abstractions.2.0.0.nupkg.sha512", + "/Users/fantasy/.nuget/packages/microsoft.netcore.platforms/5.0.0/microsoft.netcore.platforms.5.0.0.nupkg.sha512", + "/Users/fantasy/.nuget/packages/microsoft.win32.registry/5.0.0/microsoft.win32.registry.5.0.0.nupkg.sha512", + "/Users/fantasy/.nuget/packages/mongodb.bson/3.1.0/mongodb.bson.3.1.0.nupkg.sha512", + "/Users/fantasy/.nuget/packages/mongodb.driver/3.1.0/mongodb.driver.3.1.0.nupkg.sha512", + "/Users/fantasy/.nuget/packages/newtonsoft.json/13.0.3/newtonsoft.json.13.0.3.nupkg.sha512", + "/Users/fantasy/.nuget/packages/nlog/5.3.4/nlog.5.3.4.nupkg.sha512", + "/Users/fantasy/.nuget/packages/protobuf-net/3.2.45/protobuf-net.3.2.45.nupkg.sha512", + "/Users/fantasy/.nuget/packages/protobuf-net.core/3.2.45/protobuf-net.core.3.2.45.nupkg.sha512", + "/Users/fantasy/.nuget/packages/sharpcompress/0.30.1/sharpcompress.0.30.1.nupkg.sha512", + "/Users/fantasy/.nuget/packages/snappier/1.0.0/snappier.1.0.0.nupkg.sha512", + "/Users/fantasy/.nuget/packages/system.buffers/4.5.1/system.buffers.4.5.1.nupkg.sha512", + "/Users/fantasy/.nuget/packages/system.collections.immutable/7.0.0/system.collections.immutable.7.0.0.nupkg.sha512", + "/Users/fantasy/.nuget/packages/system.io.pipelines/9.0.0/system.io.pipelines.9.0.0.nupkg.sha512", + "/Users/fantasy/.nuget/packages/system.memory/4.5.5/system.memory.4.5.5.nupkg.sha512", + "/Users/fantasy/.nuget/packages/system.runtime.compilerservices.unsafe/5.0.0/system.runtime.compilerservices.unsafe.5.0.0.nupkg.sha512", + "/Users/fantasy/.nuget/packages/system.security.accesscontrol/5.0.0/system.security.accesscontrol.5.0.0.nupkg.sha512", + "/Users/fantasy/.nuget/packages/system.security.principal.windows/5.0.0/system.security.principal.windows.5.0.0.nupkg.sha512", + "/Users/fantasy/.nuget/packages/zstdsharp.port/0.7.3/zstdsharp.port.0.7.3.nupkg.sha512" + ], + "logs": [] +} \ No newline at end of file diff --git a/邮件系统课程完整代码/Server/App/obj/project.packagespec.json b/邮件系统课程完整代码/Server/App/obj/project.packagespec.json new file mode 100644 index 0000000..6021521 --- /dev/null +++ b/邮件系统课程完整代码/Server/App/obj/project.packagespec.json @@ -0,0 +1 @@ +"restore":{"projectUniqueName":"/Users/fantasy/Movies/邮件系统/Lession/Server/App/App.csproj","projectName":"App","projectPath":"/Users/fantasy/Movies/邮件系统/Lession/Server/App/App.csproj","outputPath":"/Users/fantasy/Movies/邮件系统/Lession/Server/App/obj/","projectStyle":"PackageReference","originalTargetFrameworks":["net8.0"],"sources":{"/usr/local/share/dotnet/library-packs":{},"https://api.nuget.org/v3/index.json":{}},"frameworks":{"net8.0":{"targetAlias":"net8.0","projectReferences":{"/Users/fantasy/Movies/邮件系统/Lession/Server/Entity/Entity.csproj":{"projectPath":"/Users/fantasy/Movies/邮件系统/Lession/Server/Entity/Entity.csproj"},"/Users/fantasy/Movies/邮件系统/Lession/Server/Hotfix/Hotfix.csproj":{"projectPath":"/Users/fantasy/Movies/邮件系统/Lession/Server/Hotfix/Hotfix.csproj"}}}},"warningProperties":{"warnAsError":["NU1605"]},"restoreAuditProperties":{"enableAudit":"true","auditLevel":"low","auditMode":"all"},"SdkAnalysisLevel":"9.0.100"}"frameworks":{"net8.0":{"targetAlias":"net8.0","dependencies":{"Fantasy-Net.NLog":{"target":"Package","version":"[2024.1.20, )"}},"imports":["net461","net462","net47","net471","net472","net48","net481"],"assetTargetFallback":true,"warn":true,"frameworkReferences":{"Microsoft.NETCore.App":{"privateAssets":"all"}},"runtimeIdentifierGraphPath":"/usr/local/share/dotnet/sdk/9.0.100/PortableRuntimeIdentifierGraph.json"}} \ No newline at end of file diff --git a/邮件系统课程完整代码/Server/App/obj/rider.project.model.nuget.info b/邮件系统课程完整代码/Server/App/obj/rider.project.model.nuget.info new file mode 100644 index 0000000..60a5b31 --- /dev/null +++ b/邮件系统课程完整代码/Server/App/obj/rider.project.model.nuget.info @@ -0,0 +1 @@ +17392438089775705 \ No newline at end of file diff --git a/邮件系统课程完整代码/Server/App/obj/rider.project.restore.info b/邮件系统课程完整代码/Server/App/obj/rider.project.restore.info new file mode 100644 index 0000000..60a5b31 --- /dev/null +++ b/邮件系统课程完整代码/Server/App/obj/rider.project.restore.info @@ -0,0 +1 @@ +17392438089775705 \ No newline at end of file diff --git a/邮件系统课程完整代码/Server/Entity/.DS_Store b/邮件系统课程完整代码/Server/Entity/.DS_Store new file mode 100644 index 0000000..b187a9b Binary files /dev/null and b/邮件系统课程完整代码/Server/Entity/.DS_Store differ diff --git a/邮件系统课程完整代码/Server/Entity/AssemblyHelper.cs b/邮件系统课程完整代码/Server/Entity/AssemblyHelper.cs new file mode 100644 index 0000000..4b391e1 --- /dev/null +++ b/邮件系统课程完整代码/Server/Entity/AssemblyHelper.cs @@ -0,0 +1,39 @@ +using System.Runtime.Loader; + +namespace Fantasy; + +public static class AssemblyHelper +{ + private const string HotfixDll = "Hotfix"; + private static AssemblyLoadContext? _assemblyLoadContext = null; + + public static System.Reflection.Assembly[] Assemblies + { + get + { + var assemblies = new System.Reflection.Assembly[2]; + assemblies[0] = LoadEntityAssembly(); + assemblies[1] = LoadHotfixAssembly(); + return assemblies; + } + } + + private static System.Reflection.Assembly LoadEntityAssembly() + { + return typeof(AssemblyHelper).Assembly; + } + + private static System.Reflection.Assembly LoadHotfixAssembly() + { + if (_assemblyLoadContext != null) + { + _assemblyLoadContext.Unload(); + System.GC.Collect(); + } + + _assemblyLoadContext = new AssemblyLoadContext(HotfixDll, true); + var dllBytes = File.ReadAllBytes(Path.Combine(Environment.CurrentDirectory, $"{HotfixDll}.dll")); + var pdbBytes = File.ReadAllBytes(Path.Combine(Environment.CurrentDirectory, $"{HotfixDll}.pdb")); + return _assemblyLoadContext.LoadFromStream(new MemoryStream(dllBytes), new MemoryStream(pdbBytes)); + } +} \ No newline at end of file diff --git a/邮件系统课程完整代码/Server/Entity/Entity.csproj b/邮件系统课程完整代码/Server/Entity/Entity.csproj new file mode 100644 index 0000000..3e1d9ce --- /dev/null +++ b/邮件系统课程完整代码/Server/Entity/Entity.csproj @@ -0,0 +1,13 @@ + + + + net8.0 + enable + enable + + + + + + + diff --git a/邮件系统课程完整代码/Server/Entity/Enum/CoroutineLockConst.cs b/邮件系统课程完整代码/Server/Entity/Enum/CoroutineLockConst.cs new file mode 100644 index 0000000..61fd1b5 --- /dev/null +++ b/邮件系统课程完整代码/Server/Entity/Enum/CoroutineLockConst.cs @@ -0,0 +1,6 @@ +namespace Fantasy; + +public static class CoroutineLockConst +{ + public const long LoginKey = 1; +} \ No newline at end of file diff --git a/邮件系统课程完整代码/Server/Entity/Gate/Entity/Account.cs b/邮件系统课程完整代码/Server/Entity/Gate/Entity/Account.cs new file mode 100644 index 0000000..439d358 --- /dev/null +++ b/邮件系统课程完整代码/Server/Entity/Gate/Entity/Account.cs @@ -0,0 +1,12 @@ +using Fantasy.Entitas; +using MongoDB.Bson.Serialization.Attributes; + +namespace Fantasy; + +public sealed class Account : Entity +{ + public string Name; + public long CreateTime; + [BsonIgnore] + public long MailRouteId; +} \ No newline at end of file diff --git a/邮件系统课程完整代码/Server/Entity/Gate/Entity/GateAccountFlagComponent.cs b/邮件系统课程完整代码/Server/Entity/Gate/Entity/GateAccountFlagComponent.cs new file mode 100644 index 0000000..de5236e --- /dev/null +++ b/邮件系统课程完整代码/Server/Entity/Gate/Entity/GateAccountFlagComponent.cs @@ -0,0 +1,8 @@ +using Fantasy.Entitas; + +namespace Fantasy; + +public sealed class GateAccountFlagComponent : Entity +{ + public Account Account; +} \ No newline at end of file diff --git a/邮件系统课程完整代码/Server/Entity/Generate/.DS_Store b/邮件系统课程完整代码/Server/Entity/Generate/.DS_Store new file mode 100644 index 0000000..1b5f696 Binary files /dev/null and b/邮件系统课程完整代码/Server/Entity/Generate/.DS_Store differ diff --git a/邮件系统课程完整代码/Server/Entity/Generate/CustomExport/SceneType.cs b/邮件系统课程完整代码/Server/Entity/Generate/CustomExport/SceneType.cs new file mode 100644 index 0000000..1f1571b --- /dev/null +++ b/邮件系统课程完整代码/Server/Entity/Generate/CustomExport/SceneType.cs @@ -0,0 +1,29 @@ +namespace Fantasy +{ + // 生成器自动生成,请不要手动编辑。 + public static class SceneType + { + public const int Authentication = 1; + public const int Addressable = 2; + public const int Gate = 3; + public const int Map = 4; + public const int CopyDispatcher = 5; + public const int CopyManager = 6; + public const int Copy = 7; + public const int Chat = 8; + public const int Mail = 9; + + public static readonly Dictionary SceneTypeDic = new Dictionary() + { + { "Authentication", 1 }, + { "Addressable", 2 }, + { "Gate", 3 }, + { "Map", 4 }, + { "CopyDispatcher", 5 }, + { "CopyManager", 6 }, + { "Copy", 7 }, + { "Chat", 8 }, + { "Mail", 9 }, + }; + } +} diff --git a/邮件系统课程完整代码/Server/Entity/Generate/NetworkProtocol/InnerMessage.cs b/邮件系统课程完整代码/Server/Entity/Generate/NetworkProtocol/InnerMessage.cs new file mode 100644 index 0000000..c58449b --- /dev/null +++ b/邮件系统课程完整代码/Server/Entity/Generate/NetworkProtocol/InnerMessage.cs @@ -0,0 +1,171 @@ +using ProtoBuf; + +using System.Collections.Generic; +using MongoDB.Bson.Serialization.Attributes; +using Fantasy; +using Fantasy.Network.Interface; +using Fantasy.Serialize; +// ReSharper disable InconsistentNaming +// ReSharper disable RedundantUsingDirective +// ReSharper disable RedundantOverriddenMember +// ReSharper disable PartialTypeWithSinglePart +// ReSharper disable UnusedAutoPropertyAccessor.Global +// ReSharper disable MemberCanBePrivate.Global +// ReSharper disable CheckNamespace +#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. +#pragma warning disable CS8618 + +namespace Fantasy +{ + /// + /// Gate服务器登陆到Mail服务器 + /// + [ProtoContract] + public partial class G2Mail_LoginRequest : AMessage, IRouteRequest, IProto + { + public static G2Mail_LoginRequest Create(Scene scene) + { + return scene.MessagePoolComponent.Rent(); + } + public override void Dispose() + { + Name = default; + AccountId = default; + CreateTime = default; + GateRouteId = default; +#if FANTASY_NET || FANTASY_UNITY + GetScene().MessagePoolComponent.Return(this); +#endif + } + [ProtoIgnore] + public Mail2G_LoginResponse ResponseType { get; set; } + public uint OpCode() { return InnerOpcode.G2Mail_LoginRequest; } + [ProtoMember(1)] + public string Name { get; set; } + [ProtoMember(2)] + public long AccountId { get; set; } + [ProtoMember(3)] + public long CreateTime { get; set; } + [ProtoMember(4)] + public long GateRouteId { get; set; } + } + [ProtoContract] + public partial class Mail2G_LoginResponse : AMessage, IRouteResponse, IProto + { + public static Mail2G_LoginResponse Create(Scene scene) + { + return scene.MessagePoolComponent.Rent(); + } + public override void Dispose() + { + ErrorCode = default; + MailUnitRouteId = default; +#if FANTASY_NET || FANTASY_UNITY + GetScene().MessagePoolComponent.Return(this); +#endif + } + public uint OpCode() { return InnerOpcode.Mail2G_LoginResponse; } + [ProtoMember(1)] + public long MailUnitRouteId { get; set; } + [ProtoMember(2)] + public uint ErrorCode { get; set; } + } + /// + /// 发送一个Gate服务器发送给Mail之间的测试协议 + /// + [ProtoContract] + public partial class G2Mail_TestMessage : AMessage, IRouteMessage, IProto + { + public static G2Mail_TestMessage Create(Scene scene) + { + return scene.MessagePoolComponent.Rent(); + } + public override void Dispose() + { + Tag = default; +#if FANTASY_NET || FANTASY_UNITY + GetScene().MessagePoolComponent.Return(this); +#endif + } + public uint OpCode() { return InnerOpcode.G2Mail_TestMessage; } + [ProtoMember(1)] + public string Tag { get; set; } + } + /// + /// 发送给Mail服务器进行下线 + /// + [ProtoContract] + public partial class G2Mail_ExitRequest : AMessage, IRouteRequest, IProto + { + public static G2Mail_ExitRequest Create(Scene scene) + { + return scene.MessagePoolComponent.Rent(); + } + public override void Dispose() + { +#if FANTASY_NET || FANTASY_UNITY + GetScene().MessagePoolComponent.Return(this); +#endif + } + [ProtoIgnore] + public Mail2G_ExitResponse ResponseType { get; set; } + public uint OpCode() { return InnerOpcode.G2Mail_ExitRequest; } + } + [ProtoContract] + public partial class Mail2G_ExitResponse : AMessage, IRouteResponse, IProto + { + public static Mail2G_ExitResponse Create(Scene scene) + { + return scene.MessagePoolComponent.Rent(); + } + public override void Dispose() + { + ErrorCode = default; +#if FANTASY_NET || FANTASY_UNITY + GetScene().MessagePoolComponent.Return(this); +#endif + } + public uint OpCode() { return InnerOpcode.Mail2G_ExitResponse; } + [ProtoMember(1)] + public uint ErrorCode { get; set; } + } + /// + /// 其他服务器发送邮件 + /// + public partial class Other2Mail_SendMailRequest : AMessage, IRouteRequest + { + public static Other2Mail_SendMailRequest Create(Scene scene) + { + return scene.MessagePoolComponent.Rent(); + } + public override void Dispose() + { + MailBox = default; +#if FANTASY_NET || FANTASY_UNITY + GetScene().MessagePoolComponent.Return(this); +#endif + } + [BsonIgnore] + public Mail2Other_SendMailResponse ResponseType { get; set; } + public uint OpCode() { return InnerOpcode.Other2Mail_SendMailRequest; } + public MailBox MailBox { get; set; } + } + [ProtoContract] + public partial class Mail2Other_SendMailResponse : AMessage, IRouteResponse, IProto + { + public static Mail2Other_SendMailResponse Create(Scene scene) + { + return scene.MessagePoolComponent.Rent(); + } + public override void Dispose() + { + ErrorCode = default; +#if FANTASY_NET || FANTASY_UNITY + GetScene().MessagePoolComponent.Return(this); +#endif + } + public uint OpCode() { return InnerOpcode.Mail2Other_SendMailResponse; } + [ProtoMember(1)] + public uint ErrorCode { get; set; } + } +} diff --git a/邮件系统课程完整代码/Server/Entity/Generate/NetworkProtocol/InnerOpcode.cs b/邮件系统课程完整代码/Server/Entity/Generate/NetworkProtocol/InnerOpcode.cs new file mode 100644 index 0000000..b58270f --- /dev/null +++ b/邮件系统课程完整代码/Server/Entity/Generate/NetworkProtocol/InnerOpcode.cs @@ -0,0 +1,13 @@ +namespace Fantasy +{ + public static partial class InnerOpcode + { + public const uint G2Mail_LoginRequest = 1073751825; + public const uint Mail2G_LoginResponse = 1207969553; + public const uint G2Mail_TestMessage = 939534097; + public const uint G2Mail_ExitRequest = 1073751826; + public const uint Mail2G_ExitResponse = 1207969554; + public const uint Other2Mail_SendMailRequest = 1082140435; + public const uint Mail2Other_SendMailResponse = 1207969555; + } +} diff --git a/邮件系统课程完整代码/Server/Entity/Generate/NetworkProtocol/OuterMessage.cs b/邮件系统课程完整代码/Server/Entity/Generate/NetworkProtocol/OuterMessage.cs new file mode 100644 index 0000000..20885b7 --- /dev/null +++ b/邮件系统课程完整代码/Server/Entity/Generate/NetworkProtocol/OuterMessage.cs @@ -0,0 +1,524 @@ +using ProtoBuf; + +using System.Collections.Generic; +using MongoDB.Bson.Serialization.Attributes; +using Fantasy; +using Fantasy.Network.Interface; +using Fantasy.Serialize; +// ReSharper disable InconsistentNaming +// ReSharper disable RedundantUsingDirective +// ReSharper disable RedundantOverriddenMember +// ReSharper disable PartialTypeWithSinglePart +// ReSharper disable UnusedAutoPropertyAccessor.Global +// ReSharper disable MemberCanBePrivate.Global +// ReSharper disable CheckNamespace +#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. +#pragma warning disable CS8618 + +namespace Fantasy +{ + /// + /// 登陆到Gate服务器 + /// + [ProtoContract] + public partial class C2G_LoginRequest : AMessage, IRequest, IProto + { + public static C2G_LoginRequest Create(Scene scene) + { + return scene.MessagePoolComponent.Rent(); + } + public override void Dispose() + { + Name = default; +#if FANTASY_NET || FANTASY_UNITY + GetScene().MessagePoolComponent.Return(this); +#endif + } + [ProtoIgnore] + public G2C_LoginResponse ResponseType { get; set; } + public uint OpCode() { return OuterOpcode.C2G_LoginRequest; } + [ProtoMember(1)] + public string Name { get; set; } + } + [ProtoContract] + public partial class G2C_LoginResponse : AMessage, IResponse, IProto + { + public static G2C_LoginResponse Create(Scene scene) + { + return scene.MessagePoolComponent.Rent(); + } + public override void Dispose() + { + ErrorCode = default; +#if FANTASY_NET || FANTASY_UNITY + GetScene().MessagePoolComponent.Return(this); +#endif + } + public uint OpCode() { return OuterOpcode.G2C_LoginResponse; } + [ProtoMember(1)] + public uint ErrorCode { get; set; } + } + /// + /// 客户端通知服务器退出游戏 + /// + [ProtoContract] + public partial class C2G_Exit : AMessage, IMessage, IProto + { + public static C2G_Exit Create(Scene scene) + { + return scene.MessagePoolComponent.Rent(); + } + public override void Dispose() + { +#if FANTASY_NET || FANTASY_UNITY + GetScene().MessagePoolComponent.Return(this); +#endif + } + public uint OpCode() { return OuterOpcode.C2G_Exit; } + } + /// + /// 测试Mail自定义Route协议 + /// + [ProtoContract] + public partial class C2Mail_TestRequest : AMessage, ICustomRouteRequest, IProto + { + public static C2Mail_TestRequest Create(Scene scene) + { + return scene.MessagePoolComponent.Rent(); + } + public override void Dispose() + { + Tag = default; +#if FANTASY_NET || FANTASY_UNITY + GetScene().MessagePoolComponent.Return(this); +#endif + } + [ProtoIgnore] + public Mail2C_TestResponse ResponseType { get; set; } + public uint OpCode() { return OuterOpcode.C2Mail_TestRequest; } + [ProtoIgnore] + public int RouteType => Fantasy.RouteType.MailRoute; + [ProtoMember(1)] + public string Tag { get; set; } + } + [ProtoContract] + public partial class Mail2C_TestResponse : AMessage, ICustomRouteResponse, IProto + { + public static Mail2C_TestResponse Create(Scene scene) + { + return scene.MessagePoolComponent.Rent(); + } + public override void Dispose() + { + ErrorCode = default; + Tag = default; +#if FANTASY_NET || FANTASY_UNITY + GetScene().MessagePoolComponent.Return(this); +#endif + } + public uint OpCode() { return OuterOpcode.Mail2C_TestResponse; } + [ProtoMember(1)] + public string Tag { get; set; } + [ProtoMember(2)] + public uint ErrorCode { get; set; } + } + /// + /// 一个邮件的完整信息 + /// + [ProtoContract] + public partial class MailInfo : AMessage, IProto + { + public static MailInfo Create(Scene scene) + { + return scene.MessagePoolComponent.Rent(); + } + public override void Dispose() + { + MailId = default; + OwnerId = default; + Title = default; + Content = default; + CreateTime = default; + ExpireTime = default; + Money = default; + MailState = default; + MailType = default; + Items.Clear(); +#if FANTASY_NET || FANTASY_UNITY + GetScene().MessagePoolComponent.Return(this); +#endif + } + [ProtoMember(1)] + public long MailId { get; set; } + [ProtoMember(2)] + public long OwnerId { get; set; } + [ProtoMember(3)] + public string Title { get; set; } + [ProtoMember(4)] + public string Content { get; set; } + [ProtoMember(5)] + public long CreateTime { get; set; } + [ProtoMember(6)] + public long ExpireTime { get; set; } + [ProtoMember(7)] + public int Money { get; set; } + [ProtoMember(8)] + public int MailState { get; set; } + [ProtoMember(9)] + public int MailType { get; set; } + [ProtoMember(10)] + public List Items = new List(); + } + /// + /// 一个邮件的简单版消息 + /// + [ProtoContract] + public partial class MailSimplifyInfo : AMessage, IProto + { + public static MailSimplifyInfo Create(Scene scene) + { + return scene.MessagePoolComponent.Rent(); + } + public override void Dispose() + { + MailId = default; + OwnerId = default; + Title = default; + Content = default; + CreateTime = default; + ExpireTime = default; + MailState = default; + MailType = default; +#if FANTASY_NET || FANTASY_UNITY + GetScene().MessagePoolComponent.Return(this); +#endif + } + [ProtoMember(1)] + public long MailId { get; set; } + [ProtoMember(2)] + public long OwnerId { get; set; } + [ProtoMember(3)] + public string Title { get; set; } + [ProtoMember(4)] + public string Content { get; set; } + [ProtoMember(5)] + public long CreateTime { get; set; } + [ProtoMember(6)] + public long ExpireTime { get; set; } + [ProtoMember(7)] + public int MailState { get; set; } + [ProtoMember(8)] + public int MailType { get; set; } + } + /// + /// 一个简单的物品信息 + /// + [ProtoContract] + public partial class ItemInfo : AMessage, IProto + { + public static ItemInfo Create(Scene scene) + { + return scene.MessagePoolComponent.Rent(); + } + public override void Dispose() + { + ItemId = default; + Name = default; +#if FANTASY_NET || FANTASY_UNITY + GetScene().MessagePoolComponent.Return(this); +#endif + } + [ProtoMember(1)] + public long ItemId { get; set; } + [ProtoMember(2)] + public string Name { get; set; } + } + /// + /// Mail通知客户端有新的邮件 + /// + [ProtoContract] + public partial class Mail2C_HaveMail : AMessage, ICustomRouteMessage, IProto + { + public static Mail2C_HaveMail Create(Scene scene) + { + return scene.MessagePoolComponent.Rent(); + } + public override void Dispose() + { + Mail = default; +#if FANTASY_NET || FANTASY_UNITY + GetScene().MessagePoolComponent.Return(this); +#endif + } + public uint OpCode() { return OuterOpcode.Mail2C_HaveMail; } + [ProtoIgnore] + public int RouteType => Fantasy.RouteType.MailRoute; + [ProtoMember(1)] + public MailSimplifyInfo Mail { get; set; } + } + /// + /// Mail通知客户端邮件状态变化 + /// + [ProtoContract] + public partial class Mail2C_MailState : AMessage, ICustomRouteMessage, IProto + { + public static Mail2C_MailState Create(Scene scene) + { + return scene.MessagePoolComponent.Rent(); + } + public override void Dispose() + { + MailState = default; + MailId = default; +#if FANTASY_NET || FANTASY_UNITY + GetScene().MessagePoolComponent.Return(this); +#endif + } + public uint OpCode() { return OuterOpcode.Mail2C_MailState; } + [ProtoIgnore] + public int RouteType => Fantasy.RouteType.MailRoute; + [ProtoMember(1)] + public int MailState { get; set; } + [ProtoMember(2)] + public long MailId { get; set; } + } + /// + /// 客户端获取档期所有邮件的信息 + /// + [ProtoContract] + public partial class C2Mail_GetHaveMailRequest : AMessage, ICustomRouteRequest, IProto + { + public static C2Mail_GetHaveMailRequest Create(Scene scene) + { + return scene.MessagePoolComponent.Rent(); + } + public override void Dispose() + { +#if FANTASY_NET || FANTASY_UNITY + GetScene().MessagePoolComponent.Return(this); +#endif + } + [ProtoIgnore] + public Mail2C_GetHaveMailResposne ResponseType { get; set; } + public uint OpCode() { return OuterOpcode.C2Mail_GetHaveMailRequest; } + [ProtoIgnore] + public int RouteType => Fantasy.RouteType.MailRoute; + } + [ProtoContract] + public partial class Mail2C_GetHaveMailResposne : AMessage, ICustomRouteResponse, IProto + { + public static Mail2C_GetHaveMailResposne Create(Scene scene) + { + return scene.MessagePoolComponent.Rent(); + } + public override void Dispose() + { + ErrorCode = default; + Mails.Clear(); +#if FANTASY_NET || FANTASY_UNITY + GetScene().MessagePoolComponent.Return(this); +#endif + } + public uint OpCode() { return OuterOpcode.Mail2C_GetHaveMailResposne; } + [ProtoMember(1)] + public List Mails = new List(); + [ProtoMember(2)] + public uint ErrorCode { get; set; } + } + /// + /// 客户端发开一个邮件 + /// + [ProtoContract] + public partial class C2Mail_OpenMailRequest : AMessage, ICustomRouteRequest, IProto + { + public static C2Mail_OpenMailRequest Create(Scene scene) + { + return scene.MessagePoolComponent.Rent(); + } + public override void Dispose() + { + MailId = default; + ReturnMailInfo = default; +#if FANTASY_NET || FANTASY_UNITY + GetScene().MessagePoolComponent.Return(this); +#endif + } + [ProtoIgnore] + public Mail2C_OpenMailResposne ResponseType { get; set; } + public uint OpCode() { return OuterOpcode.C2Mail_OpenMailRequest; } + [ProtoIgnore] + public int RouteType => Fantasy.RouteType.MailRoute; + [ProtoMember(1)] + public long MailId { get; set; } + [ProtoMember(2)] + public bool ReturnMailInfo { get; set; } + } + [ProtoContract] + public partial class Mail2C_OpenMailResposne : AMessage, ICustomRouteResponse, IProto + { + public static Mail2C_OpenMailResposne Create(Scene scene) + { + return scene.MessagePoolComponent.Rent(); + } + public override void Dispose() + { + ErrorCode = default; + MailInfo = default; +#if FANTASY_NET || FANTASY_UNITY + GetScene().MessagePoolComponent.Return(this); +#endif + } + public uint OpCode() { return OuterOpcode.Mail2C_OpenMailResposne; } + [ProtoMember(1)] + public MailInfo MailInfo { get; set; } + [ProtoMember(2)] + public uint ErrorCode { get; set; } + } + /// + /// 客户端领取邮件的附件 + /// + [ProtoContract] + public partial class C2Mail_ReceiveMailRequest : AMessage, ICustomRouteRequest, IProto + { + public static C2Mail_ReceiveMailRequest Create(Scene scene) + { + return scene.MessagePoolComponent.Rent(); + } + public override void Dispose() + { + MailId = default; + Money = default; + ItemId.Clear(); +#if FANTASY_NET || FANTASY_UNITY + GetScene().MessagePoolComponent.Return(this); +#endif + } + [ProtoIgnore] + public Mail2C_ReceiveMailResponse ResponseType { get; set; } + public uint OpCode() { return OuterOpcode.C2Mail_ReceiveMailRequest; } + [ProtoIgnore] + public int RouteType => Fantasy.RouteType.MailRoute; + [ProtoMember(1)] + public long MailId { get; set; } + [ProtoMember(2)] + public bool Money { get; set; } + [ProtoMember(3)] + public List ItemId = new List(); + } + [ProtoContract] + public partial class Mail2C_ReceiveMailResponse : AMessage, ICustomRouteResponse, IProto + { + public static Mail2C_ReceiveMailResponse Create(Scene scene) + { + return scene.MessagePoolComponent.Rent(); + } + public override void Dispose() + { + ErrorCode = default; +#if FANTASY_NET || FANTASY_UNITY + GetScene().MessagePoolComponent.Return(this); +#endif + } + public uint OpCode() { return OuterOpcode.Mail2C_ReceiveMailResponse; } + [ProtoMember(1)] + public uint ErrorCode { get; set; } + } + /// + /// 客户端通知服务器删除一个邮件 + /// + [ProtoContract] + public partial class C2Mail_RemoveMailRequest : AMessage, ICustomRouteRequest, IProto + { + public static C2Mail_RemoveMailRequest Create(Scene scene) + { + return scene.MessagePoolComponent.Rent(); + } + public override void Dispose() + { + MailId = default; +#if FANTASY_NET || FANTASY_UNITY + GetScene().MessagePoolComponent.Return(this); +#endif + } + [ProtoIgnore] + public Mail2C_RemoveMailResponse ResponseType { get; set; } + public uint OpCode() { return OuterOpcode.C2Mail_RemoveMailRequest; } + [ProtoIgnore] + public int RouteType => Fantasy.RouteType.MailRoute; + [ProtoMember(1)] + public long MailId { get; set; } + } + [ProtoContract] + public partial class Mail2C_RemoveMailResponse : AMessage, ICustomRouteResponse, IProto + { + public static Mail2C_RemoveMailResponse Create(Scene scene) + { + return scene.MessagePoolComponent.Rent(); + } + public override void Dispose() + { + ErrorCode = default; +#if FANTASY_NET || FANTASY_UNITY + GetScene().MessagePoolComponent.Return(this); +#endif + } + public uint OpCode() { return OuterOpcode.Mail2C_RemoveMailResponse; } + [ProtoMember(1)] + public uint ErrorCode { get; set; } + } + /// + /// 客户端玩家发送邮件到另外一个玩家 + /// + [ProtoContract] + public partial class C2Mail_SendMailRequest : AMessage, ICustomRouteRequest, IProto + { + public static C2Mail_SendMailRequest Create(Scene scene) + { + return scene.MessagePoolComponent.Rent(); + } + public override void Dispose() + { + UserName = default; + Title = default; + Content = default; + Money = default; + ItemId.Clear(); +#if FANTASY_NET || FANTASY_UNITY + GetScene().MessagePoolComponent.Return(this); +#endif + } + [ProtoIgnore] + public Mail2C_SendMailResponse ResponseType { get; set; } + public uint OpCode() { return OuterOpcode.C2Mail_SendMailRequest; } + [ProtoIgnore] + public int RouteType => Fantasy.RouteType.MailRoute; + [ProtoMember(1)] + public string UserName { get; set; } + [ProtoMember(2)] + public string Title { get; set; } + [ProtoMember(3)] + public string Content { get; set; } + [ProtoMember(4)] + public int Money { get; set; } + [ProtoMember(5)] + public List ItemId = new List(); + } + [ProtoContract] + public partial class Mail2C_SendMailResponse : AMessage, ICustomRouteResponse, IProto + { + public static Mail2C_SendMailResponse Create(Scene scene) + { + return scene.MessagePoolComponent.Rent(); + } + public override void Dispose() + { + ErrorCode = default; +#if FANTASY_NET || FANTASY_UNITY + GetScene().MessagePoolComponent.Return(this); +#endif + } + public uint OpCode() { return OuterOpcode.Mail2C_SendMailResponse; } + [ProtoMember(1)] + public uint ErrorCode { get; set; } + } +} diff --git a/邮件系统课程完整代码/Server/Entity/Generate/NetworkProtocol/OuterOpcode.cs b/邮件系统课程完整代码/Server/Entity/Generate/NetworkProtocol/OuterOpcode.cs new file mode 100644 index 0000000..43b59e1 --- /dev/null +++ b/邮件系统课程完整代码/Server/Entity/Generate/NetworkProtocol/OuterOpcode.cs @@ -0,0 +1,23 @@ +namespace Fantasy +{ + public static partial class OuterOpcode + { + public const uint C2G_LoginRequest = 268445457; + public const uint G2C_LoginResponse = 402663185; + public const uint C2G_Exit = 134227729; + public const uint C2Mail_TestRequest = 2281711377; + public const uint Mail2C_TestResponse = 2415929105; + public const uint Mail2C_HaveMail = 2147493649; + public const uint Mail2C_MailState = 2147493650; + public const uint C2Mail_GetHaveMailRequest = 2281711378; + public const uint Mail2C_GetHaveMailResposne = 2415929106; + public const uint C2Mail_OpenMailRequest = 2281711379; + public const uint Mail2C_OpenMailResposne = 2415929107; + public const uint C2Mail_ReceiveMailRequest = 2281711380; + public const uint Mail2C_ReceiveMailResponse = 2415929108; + public const uint C2Mail_RemoveMailRequest = 2281711381; + public const uint Mail2C_RemoveMailResponse = 2415929109; + public const uint C2Mail_SendMailRequest = 2281711382; + public const uint Mail2C_SendMailResponse = 2415929110; + } +} diff --git a/邮件系统课程完整代码/Server/Entity/Generate/NetworkProtocol/RouteType.cs b/邮件系统课程完整代码/Server/Entity/Generate/NetworkProtocol/RouteType.cs new file mode 100644 index 0000000..84968b2 --- /dev/null +++ b/邮件系统课程完整代码/Server/Entity/Generate/NetworkProtocol/RouteType.cs @@ -0,0 +1,8 @@ +namespace Fantasy +{ + // Route协议定义(需要定义1000以上、因为1000以内的框架预留) + public static class RouteType + { + public const int MailRoute = 1001; // Mail + } +} diff --git a/邮件系统课程完整代码/Server/Entity/Mail/Components/MailBoxManageComponent.cs b/邮件系统课程完整代码/Server/Entity/Mail/Components/MailBoxManageComponent.cs new file mode 100644 index 0000000..3f76a2f --- /dev/null +++ b/邮件系统课程完整代码/Server/Entity/Mail/Components/MailBoxManageComponent.cs @@ -0,0 +1,28 @@ +using Fantasy.DataStructure.Collection; +using Fantasy.Entitas; + +namespace Fantasy; + +/// +/// 邮件物流中转中心,用来存放所有离线的邮件。 +/// 玩家可以在上线的第一时间去这里领取属于自己的邮件。 +/// +public class MailBoxManageComponent : Entity +{ + // 定时清楚过期邮件的时间 + public const int MailCheckTIme = 10000; + // 存放所有邮箱都会在这里,包括发送给个人的和所有人的邮件。 + public readonly Dictionary MailBoxes = new Dictionary(); + // 个人领取邮件列表 + public readonly OneToManyList MailsByAccount = new OneToManyList(); + // 按照邮件箱类型存储 + public readonly OneToManyList MailsByMailBoxType = new OneToManyList(); + // 按照时间排序的邮件箱 + public readonly SortedOneToManyList Timers = new SortedOneToManyList(); + // 临时的存放过期时间的队列 + public readonly Queue TimeOutQueue = new Queue(); + // 时间任务的Id + public long TimerId; + // 最小的时间 + public long MinTime; +} \ No newline at end of file diff --git a/邮件系统课程完整代码/Server/Entity/Mail/Components/MailComponent.cs b/邮件系统课程完整代码/Server/Entity/Mail/Components/MailComponent.cs new file mode 100644 index 0000000..0d0de20 --- /dev/null +++ b/邮件系统课程完整代码/Server/Entity/Mail/Components/MailComponent.cs @@ -0,0 +1,23 @@ +using Fantasy.DataStructure.Collection; +using Fantasy.Entitas; +using MongoDB.Bson.Serialization.Attributes; +using MongoDB.Bson.Serialization.Options; + +namespace Fantasy; + +/// +/// 这个代表一个用户身上所有邮件的组件 +/// +public sealed class MailComponent : Entity +{ + // 最大的邮件数量 + public const int MaxMailCount = 50; + // 邮件的过期时间,这个是过期7天时间。 + public const int MailExpireTime = 1000 * 60 * 60 * 24 * 7; + // 玩家的邮件 + [BsonDictionaryOptions(DictionaryRepresentation.ArrayOfArrays)] + public Dictionary Mails = new Dictionary(); + // 按照时间进行排序 + [BsonIgnore] + public readonly SortedOneToManyList Timer = new SortedOneToManyList(); +} \ No newline at end of file diff --git a/邮件系统课程完整代码/Server/Entity/Mail/Components/MailUnitManageComponent.cs b/邮件系统课程完整代码/Server/Entity/Mail/Components/MailUnitManageComponent.cs new file mode 100644 index 0000000..697bdce --- /dev/null +++ b/邮件系统课程完整代码/Server/Entity/Mail/Components/MailUnitManageComponent.cs @@ -0,0 +1,10 @@ +using Fantasy.Entitas; + +namespace Fantasy; + +public sealed class MailUnitManageComponent : Entity +{ + public readonly Dictionary Online = new Dictionary(); + public readonly Dictionary UnitByName = new Dictionary(); + public readonly Dictionary UnitByAccountId = new Dictionary(); +} \ No newline at end of file diff --git a/邮件系统课程完整代码/Server/Entity/Mail/Entity/Item.cs b/邮件系统课程完整代码/Server/Entity/Mail/Entity/Item.cs new file mode 100644 index 0000000..10de9b5 --- /dev/null +++ b/邮件系统课程完整代码/Server/Entity/Mail/Entity/Item.cs @@ -0,0 +1,8 @@ +using Fantasy.Entitas; + +namespace Fantasy; + +public sealed class Item : Entity +{ + public string Name; +} \ No newline at end of file diff --git a/邮件系统课程完整代码/Server/Entity/Mail/Entity/Mail.cs b/邮件系统课程完整代码/Server/Entity/Mail/Entity/Mail.cs new file mode 100644 index 0000000..d68d129 --- /dev/null +++ b/邮件系统课程完整代码/Server/Entity/Mail/Entity/Mail.cs @@ -0,0 +1,25 @@ +using Fantasy.Entitas; +using MongoDB.Bson.Serialization.Attributes; +using MongoDB.Bson.Serialization.Options; + +namespace Fantasy; + +/// +/// 代表游戏中的一封邮件实体 +/// +public sealed class Mail : Entity +{ + // 这个代表里游戏中的一封邮件 + // 标题、内容、金钱、物品 + public long OwnerId; // 邮件拥有者的Id(AccountId、UnitId、RoleId) + public string Title; // 邮件的标题 + public string Content; // 邮件的内容 + public long CreateTime; // 邮件的创建时间 + public long ExpireTime; // 邮件的过期时间(决定这个实体的生命周期) + public int Money; // 邮件的中钱 + public MailState MailState; // 邮件的状态 + public MailType MailType; // 邮件的类型 + public List Items = new List(); // 邮件中的物品 + // [BsonDictionaryOptions(DictionaryRepresentation.ArrayOfArrays)] + // public Dictionary Items = new Dictionary(); +} \ No newline at end of file diff --git a/邮件系统课程完整代码/Server/Entity/Mail/Entity/MailBox.cs b/邮件系统课程完整代码/Server/Entity/Mail/Entity/MailBox.cs new file mode 100644 index 0000000..a390a80 --- /dev/null +++ b/邮件系统课程完整代码/Server/Entity/Mail/Entity/MailBox.cs @@ -0,0 +1,24 @@ +using Fantasy.Entitas; + +namespace Fantasy; + +/// +/// 邮件箱 +/// +public sealed class MailBox : Entity +{ + // 快递 + // 快递包装、用盒子。然后这个盒子上有一个标签、收件人、发件人、快递的公司。 + // 这个盒子了。可以装任何不同种类的东西。 + // 一对一、我发一个快递,给张三和李四。 + + // 但是邮件可能会有这个的功能,比如给某一个范围的人发送同一份邮件,比如补偿、或者奖励。 + + public Mail Mail; // 邮件 + public long CreateTime; // 箱子的创建时间 + public long ExpireTime; // 箱子的过期时间 + public MailBoxType MailBoxType; // 箱子的类型 + public HashSet AccountId = new HashSet(); // 收件人 + public HashSet Received = new HashSet(); // 领取过的人 + public long SendAccountId; // 发件人/发送人 +} \ No newline at end of file diff --git a/邮件系统课程完整代码/Server/Entity/Mail/Entity/MailUnit.cs b/邮件系统课程完整代码/Server/Entity/Mail/Entity/MailUnit.cs new file mode 100644 index 0000000..98aafcc --- /dev/null +++ b/邮件系统课程完整代码/Server/Entity/Mail/Entity/MailUnit.cs @@ -0,0 +1,13 @@ +using Fantasy.Entitas; +using MongoDB.Bson.Serialization.Attributes; + +namespace Fantasy; + +public sealed class MailUnit : Entity +{ + public string Name; + public long AccountId; + public long CreateTime; + [BsonIgnore] + public long GateRouteId; +} \ No newline at end of file diff --git a/邮件系统课程完整代码/Server/Entity/Mail/Enum/MailEnum.cs b/邮件系统课程完整代码/Server/Entity/Mail/Enum/MailEnum.cs new file mode 100644 index 0000000..0239a64 --- /dev/null +++ b/邮件系统课程完整代码/Server/Entity/Mail/Enum/MailEnum.cs @@ -0,0 +1,37 @@ +using CommandLine; + +namespace Fantasy; + +public enum MailType +{ + None = 0, + System = 1, // 系统邮件 + Rewards = 2, // 奖励邮件(擂台、有奖问答) + User = 3, // 个人邮件(玩家给玩家之间发送) +} + +public enum MailState +{ + None = 0, + Unread = 1, // 未读 + HaveRead = 2, // 已读 + NotClaimed = 3, // 未领取 + Received = 4, // 已领取 +} + +public enum MailBoxType +{ + None = 0, + Specify = 1, // 指定目标 + Online = 2, // 给在线所有人发送邮件 + All = 3, // 所有人 + AllToDate = 4, // 根据玩家注册的时间发送邮件 +} + +public enum MailRemoveActionType +{ + None = 0, + Remove = 1, // 手动移除 + ExpireTimeRemove = 2, // 过期时间移除 + Overtop = 3, // 超过邮件上限移除 +} \ No newline at end of file diff --git a/邮件系统课程完整代码/Server/Entity/bin/.DS_Store b/邮件系统课程完整代码/Server/Entity/bin/.DS_Store new file mode 100644 index 0000000..fd5f0b1 Binary files /dev/null and b/邮件系统课程完整代码/Server/Entity/bin/.DS_Store differ diff --git a/邮件系统课程完整代码/Server/Entity/bin/Debug/.DS_Store b/邮件系统课程完整代码/Server/Entity/bin/Debug/.DS_Store new file mode 100644 index 0000000..cc729a0 Binary files /dev/null and b/邮件系统课程完整代码/Server/Entity/bin/Debug/.DS_Store differ diff --git a/邮件系统课程完整代码/Server/Entity/bin/Debug/net8.0/Entity.deps.json b/邮件系统课程完整代码/Server/Entity/bin/Debug/net8.0/Entity.deps.json new file mode 100644 index 0000000..cd36897 --- /dev/null +++ b/邮件系统课程完整代码/Server/Entity/bin/Debug/net8.0/Entity.deps.json @@ -0,0 +1,318 @@ +{ + "runtimeTarget": { + "name": ".NETCoreApp,Version=v8.0", + "signature": "" + }, + "compilationOptions": {}, + "targets": { + ".NETCoreApp,Version=v8.0": { + "Entity/1.0.0": { + "dependencies": { + "Fantasy-Net": "2024.2.22" + }, + "runtime": { + "Entity.dll": {} + } + }, + "CommandLineParser/2.9.1": { + "runtime": { + "lib/netstandard2.0/CommandLine.dll": { + "assemblyVersion": "2.9.1.0", + "fileVersion": "2.9.1.0" + } + } + }, + "DnsClient/1.6.1": { + "dependencies": { + "Microsoft.Win32.Registry": "5.0.0" + }, + "runtime": { + "lib/net5.0/DnsClient.dll": { + "assemblyVersion": "1.6.1.0", + "fileVersion": "1.6.1.0" + } + } + }, + "Fantasy-Net/2024.2.22": { + "dependencies": { + "CommandLineParser": "2.9.1", + "MongoDB.Bson": "3.1.0", + "MongoDB.Driver": "3.1.0", + "Newtonsoft.Json": "13.0.3", + "System.IO.Pipelines": "9.0.0", + "protobuf-net": "3.2.45" + }, + "runtime": { + "lib/net8.0/Fantasy-Net.dll": { + "assemblyVersion": "1.0.0.0", + "fileVersion": "1.0.0.0" + } + } + }, + "Microsoft.Extensions.Logging.Abstractions/2.0.0": {}, + "Microsoft.NETCore.Platforms/5.0.0": {}, + "Microsoft.Win32.Registry/5.0.0": { + "dependencies": { + "System.Security.AccessControl": "5.0.0", + "System.Security.Principal.Windows": "5.0.0" + } + }, + "MongoDB.Bson/3.1.0": { + "dependencies": { + "System.Memory": "4.5.5", + "System.Runtime.CompilerServices.Unsafe": "5.0.0" + }, + "runtime": { + "lib/net6.0/MongoDB.Bson.dll": { + "assemblyVersion": "3.1.0.0", + "fileVersion": "3.1.0.0" + } + } + }, + "MongoDB.Driver/3.1.0": { + "dependencies": { + "DnsClient": "1.6.1", + "Microsoft.Extensions.Logging.Abstractions": "2.0.0", + "MongoDB.Bson": "3.1.0", + "SharpCompress": "0.30.1", + "Snappier": "1.0.0", + "System.Buffers": "4.5.1", + "ZstdSharp.Port": "0.7.3" + }, + "runtime": { + "lib/net6.0/MongoDB.Driver.dll": { + "assemblyVersion": "3.1.0.0", + "fileVersion": "3.1.0.0" + } + } + }, + "Newtonsoft.Json/13.0.3": { + "runtime": { + "lib/net6.0/Newtonsoft.Json.dll": { + "assemblyVersion": "13.0.0.0", + "fileVersion": "13.0.3.27908" + } + } + }, + "protobuf-net/3.2.45": { + "dependencies": { + "protobuf-net.Core": "3.2.45" + }, + "runtime": { + "lib/net6.0/protobuf-net.dll": { + "assemblyVersion": "3.0.0.0", + "fileVersion": "3.2.45.36865" + } + } + }, + "protobuf-net.Core/3.2.45": { + "dependencies": { + "System.Collections.Immutable": "7.0.0" + }, + "runtime": { + "lib/net6.0/protobuf-net.Core.dll": { + "assemblyVersion": "3.0.0.0", + "fileVersion": "3.2.45.36865" + } + } + }, + "SharpCompress/0.30.1": { + "runtime": { + "lib/net5.0/SharpCompress.dll": { + "assemblyVersion": "0.30.1.0", + "fileVersion": "0.30.1.0" + } + } + }, + "Snappier/1.0.0": { + "runtime": { + "lib/net5.0/Snappier.dll": { + "assemblyVersion": "1.0.0.0", + "fileVersion": "1.0.0.0" + } + } + }, + "System.Buffers/4.5.1": {}, + "System.Collections.Immutable/7.0.0": {}, + "System.IO.Pipelines/9.0.0": { + "runtime": { + "lib/net8.0/System.IO.Pipelines.dll": { + "assemblyVersion": "9.0.0.0", + "fileVersion": "9.0.24.52809" + } + } + }, + "System.Memory/4.5.5": {}, + "System.Runtime.CompilerServices.Unsafe/5.0.0": {}, + "System.Security.AccessControl/5.0.0": { + "dependencies": { + "Microsoft.NETCore.Platforms": "5.0.0", + "System.Security.Principal.Windows": "5.0.0" + } + }, + "System.Security.Principal.Windows/5.0.0": {}, + "ZstdSharp.Port/0.7.3": { + "runtime": { + "lib/net7.0/ZstdSharp.dll": { + "assemblyVersion": "0.7.3.0", + "fileVersion": "0.7.3.0" + } + } + } + } + }, + "libraries": { + "Entity/1.0.0": { + "type": "project", + "serviceable": false, + "sha512": "" + }, + "CommandLineParser/2.9.1": { + "type": "package", + "serviceable": true, + "sha512": "sha512-OE0sl1/sQ37bjVsPKKtwQlWDgqaxWgtme3xZz7JssWUzg5JpMIyHgCTY9MVMxOg48fJ1AgGT3tgdH5m/kQ5xhA==", + "path": "commandlineparser/2.9.1", + "hashPath": "commandlineparser.2.9.1.nupkg.sha512" + }, + "DnsClient/1.6.1": { + "type": "package", + "serviceable": true, + "sha512": "sha512-4H/f2uYJOZ+YObZjpY9ABrKZI+JNw3uizp6oMzTXwDw6F+2qIPhpRl/1t68O/6e98+vqNiYGu+lswmwdYUy3gg==", + "path": "dnsclient/1.6.1", + "hashPath": "dnsclient.1.6.1.nupkg.sha512" + }, + "Fantasy-Net/2024.2.22": { + "type": "package", + "serviceable": true, + "sha512": "sha512-cT6B0YJ5JmbPHBLYgLeVgg2WbXYxxa1tudoIase88uMzAuqU9t7EQ7dFZGSWjP41c5JOQ/0f1q9lzGWTh/hskw==", + "path": "fantasy-net/2024.2.22", + "hashPath": "fantasy-net.2024.2.22.nupkg.sha512" + }, + "Microsoft.Extensions.Logging.Abstractions/2.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-6ZCllUYGFukkymSTx3Yr0G/ajRxoNJp7/FqSxSB4fGISST54ifBhgu4Nc0ItGi3i6DqwuNd8SUyObmiC++AO2Q==", + "path": "microsoft.extensions.logging.abstractions/2.0.0", + "hashPath": "microsoft.extensions.logging.abstractions.2.0.0.nupkg.sha512" + }, + "Microsoft.NETCore.Platforms/5.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-VyPlqzH2wavqquTcYpkIIAQ6WdenuKoFN0BdYBbCWsclXacSOHNQn66Gt4z5NBqEYW0FAPm5rlvki9ZiCij5xQ==", + "path": "microsoft.netcore.platforms/5.0.0", + "hashPath": "microsoft.netcore.platforms.5.0.0.nupkg.sha512" + }, + "Microsoft.Win32.Registry/5.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-dDoKi0PnDz31yAyETfRntsLArTlVAVzUzCIvvEDsDsucrl33Dl8pIJG06ePTJTI3tGpeyHS9Cq7Foc/s4EeKcg==", + "path": "microsoft.win32.registry/5.0.0", + "hashPath": "microsoft.win32.registry.5.0.0.nupkg.sha512" + }, + "MongoDB.Bson/3.1.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-3dhaZhz18B5vUoEP13o2j8A6zQfkHdZhwBvLZEjDJum4BTLLv1/Z8bt25UQEtpqvYwLgde4R6ekWZ7XAYUMxuw==", + "path": "mongodb.bson/3.1.0", + "hashPath": "mongodb.bson.3.1.0.nupkg.sha512" + }, + "MongoDB.Driver/3.1.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-+O7lKaIl7VUHptE0hqTd7UY1G5KDp/o8S4upG7YL4uChMNKD/U6tz9i17nMGHaD/L2AiPLgaJcaDe2XACsegGA==", + "path": "mongodb.driver/3.1.0", + "hashPath": "mongodb.driver.3.1.0.nupkg.sha512" + }, + "Newtonsoft.Json/13.0.3": { + "type": "package", + "serviceable": true, + "sha512": "sha512-HrC5BXdl00IP9zeV+0Z848QWPAoCr9P3bDEZguI+gkLcBKAOxix/tLEAAHC+UvDNPv4a2d18lOReHMOagPa+zQ==", + "path": "newtonsoft.json/13.0.3", + "hashPath": "newtonsoft.json.13.0.3.nupkg.sha512" + }, + "protobuf-net/3.2.45": { + "type": "package", + "serviceable": true, + "sha512": "sha512-5UZ/ukUHcGbFSl7vNMrHsfjqdxusdd9w7w0fCEXzf3UUtsrGNVCzV5SmF+sCHAbnRV2qPcD1ixiDP7Aj8lX/HA==", + "path": "protobuf-net/3.2.45", + "hashPath": "protobuf-net.3.2.45.nupkg.sha512" + }, + "protobuf-net.Core/3.2.45": { + "type": "package", + "serviceable": true, + "sha512": "sha512-PMWatW2NrT1uTXD7etJ4VdQ0wWZLFrIfdRGppD2QX7nzZ0+kIzqhq551u6ZiXJHWJgG4hWFEkSnUnt2aB6posg==", + "path": "protobuf-net.core/3.2.45", + "hashPath": "protobuf-net.core.3.2.45.nupkg.sha512" + }, + "SharpCompress/0.30.1": { + "type": "package", + "serviceable": true, + "sha512": "sha512-XqD4TpfyYGa7QTPzaGlMVbcecKnXy4YmYLDWrU+JIj7IuRNl7DH2END+Ll7ekWIY8o3dAMWLFDE1xdhfIWD1nw==", + "path": "sharpcompress/0.30.1", + "hashPath": "sharpcompress.0.30.1.nupkg.sha512" + }, + "Snappier/1.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-rFtK2KEI9hIe8gtx3a0YDXdHOpedIf9wYCEYtBEmtlyiWVX3XlCNV03JrmmAi/Cdfn7dxK+k0sjjcLv4fpHnqA==", + "path": "snappier/1.0.0", + "hashPath": "snappier.1.0.0.nupkg.sha512" + }, + "System.Buffers/4.5.1": { + "type": "package", + "serviceable": true, + "sha512": "sha512-Rw7ijyl1qqRS0YQD/WycNst8hUUMgrMH4FCn1nNm27M4VxchZ1js3fVjQaANHO5f3sN4isvP4a+Met9Y4YomAg==", + "path": "system.buffers/4.5.1", + "hashPath": "system.buffers.4.5.1.nupkg.sha512" + }, + "System.Collections.Immutable/7.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-dQPcs0U1IKnBdRDBkrCTi1FoajSTBzLcVTpjO4MBCMC7f4pDOIPzgBoX8JjG7X6uZRJ8EBxsi8+DR1JuwjnzOQ==", + "path": "system.collections.immutable/7.0.0", + "hashPath": "system.collections.immutable.7.0.0.nupkg.sha512" + }, + "System.IO.Pipelines/9.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-eA3cinogwaNB4jdjQHOP3Z3EuyiDII7MT35jgtnsA4vkn0LUrrSHsU0nzHTzFzmaFYeKV7MYyMxOocFzsBHpTw==", + "path": "system.io.pipelines/9.0.0", + "hashPath": "system.io.pipelines.9.0.0.nupkg.sha512" + }, + "System.Memory/4.5.5": { + "type": "package", + "serviceable": true, + "sha512": "sha512-XIWiDvKPXaTveaB7HVganDlOCRoj03l+jrwNvcge/t8vhGYKvqV+dMv6G4SAX2NoNmN0wZfVPTAlFwZcZvVOUw==", + "path": "system.memory/4.5.5", + "hashPath": "system.memory.4.5.5.nupkg.sha512" + }, + "System.Runtime.CompilerServices.Unsafe/5.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-ZD9TMpsmYJLrxbbmdvhwt9YEgG5WntEnZ/d1eH8JBX9LBp+Ju8BSBhUGbZMNVHHomWo2KVImJhTDl2hIgw/6MA==", + "path": "system.runtime.compilerservices.unsafe/5.0.0", + "hashPath": "system.runtime.compilerservices.unsafe.5.0.0.nupkg.sha512" + }, + "System.Security.AccessControl/5.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-dagJ1mHZO3Ani8GH0PHpPEe/oYO+rVdbQjvjJkBRNQkX4t0r1iaeGn8+/ybkSLEan3/slM0t59SVdHzuHf2jmw==", + "path": "system.security.accesscontrol/5.0.0", + "hashPath": "system.security.accesscontrol.5.0.0.nupkg.sha512" + }, + "System.Security.Principal.Windows/5.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-t0MGLukB5WAVU9bO3MGzvlGnyJPgUlcwerXn1kzBRjwLKixT96XV0Uza41W49gVd8zEMFu9vQEFlv0IOrytICA==", + "path": "system.security.principal.windows/5.0.0", + "hashPath": "system.security.principal.windows.5.0.0.nupkg.sha512" + }, + "ZstdSharp.Port/0.7.3": { + "type": "package", + "serviceable": true, + "sha512": "sha512-U9Ix4l4cl58Kzz1rJzj5hoVTjmbx1qGMwzAcbv1j/d3NzrFaESIurQyg+ow4mivCgkE3S413y+U9k4WdnEIkRA==", + "path": "zstdsharp.port/0.7.3", + "hashPath": "zstdsharp.port.0.7.3.nupkg.sha512" + } + } +} \ No newline at end of file diff --git a/邮件系统课程完整代码/Server/Entity/bin/Debug/net8.0/Entity.dll b/邮件系统课程完整代码/Server/Entity/bin/Debug/net8.0/Entity.dll new file mode 100644 index 0000000..7a53135 Binary files /dev/null and b/邮件系统课程完整代码/Server/Entity/bin/Debug/net8.0/Entity.dll differ diff --git a/邮件系统课程完整代码/Server/Entity/bin/Debug/net8.0/Entity.pdb b/邮件系统课程完整代码/Server/Entity/bin/Debug/net8.0/Entity.pdb new file mode 100644 index 0000000..46121e0 Binary files /dev/null and b/邮件系统课程完整代码/Server/Entity/bin/Debug/net8.0/Entity.pdb differ diff --git a/邮件系统课程完整代码/Server/Entity/obj/Debug/net8.0/.NETCoreApp,Version=v8.0.AssemblyAttributes.cs b/邮件系统课程完整代码/Server/Entity/obj/Debug/net8.0/.NETCoreApp,Version=v8.0.AssemblyAttributes.cs new file mode 100644 index 0000000..2217181 --- /dev/null +++ b/邮件系统课程完整代码/Server/Entity/obj/Debug/net8.0/.NETCoreApp,Version=v8.0.AssemblyAttributes.cs @@ -0,0 +1,4 @@ +// +using System; +using System.Reflection; +[assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute(".NETCoreApp,Version=v8.0", FrameworkDisplayName = ".NET 8.0")] diff --git a/邮件系统课程完整代码/Server/Entity/obj/Debug/net8.0/Entity.AssemblyInfo.cs b/邮件系统课程完整代码/Server/Entity/obj/Debug/net8.0/Entity.AssemblyInfo.cs new file mode 100644 index 0000000..b1f9a04 --- /dev/null +++ b/邮件系统课程完整代码/Server/Entity/obj/Debug/net8.0/Entity.AssemblyInfo.cs @@ -0,0 +1,22 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +using System; +using System.Reflection; + +[assembly: System.Reflection.AssemblyCompanyAttribute("Entity")] +[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")] +[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")] +[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0")] +[assembly: System.Reflection.AssemblyProductAttribute("Entity")] +[assembly: System.Reflection.AssemblyTitleAttribute("Entity")] +[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")] + +// 由 MSBuild WriteCodeFragment 类生成。 + diff --git a/邮件系统课程完整代码/Server/Entity/obj/Debug/net8.0/Entity.AssemblyInfoInputs.cache b/邮件系统课程完整代码/Server/Entity/obj/Debug/net8.0/Entity.AssemblyInfoInputs.cache new file mode 100644 index 0000000..b4d28d5 --- /dev/null +++ b/邮件系统课程完整代码/Server/Entity/obj/Debug/net8.0/Entity.AssemblyInfoInputs.cache @@ -0,0 +1 @@ +b7ceabf79c524d6ee0475da740239235018950a5f2c92d51c77f832004e64e6c diff --git a/邮件系统课程完整代码/Server/Entity/obj/Debug/net8.0/Entity.GeneratedMSBuildEditorConfig.editorconfig b/邮件系统课程完整代码/Server/Entity/obj/Debug/net8.0/Entity.GeneratedMSBuildEditorConfig.editorconfig new file mode 100644 index 0000000..0d6df24 --- /dev/null +++ b/邮件系统课程完整代码/Server/Entity/obj/Debug/net8.0/Entity.GeneratedMSBuildEditorConfig.editorconfig @@ -0,0 +1,15 @@ +is_global = true +build_property.TargetFramework = net8.0 +build_property.TargetPlatformMinVersion = +build_property.UsingMicrosoftNETSdkWeb = +build_property.ProjectTypeGuids = +build_property.InvariantGlobalization = +build_property.PlatformNeutralAssembly = +build_property.EnforceExtendedAnalyzerRules = +build_property._SupportedPlatformList = Linux,macOS,Windows +build_property.RootNamespace = Entity +build_property.ProjectDir = /Users/fantasy/Movies/邮件系统/Lession/Server/Entity/ +build_property.EnableComHosting = +build_property.EnableGeneratedComInterfaceComImportInterop = +build_property.EffectiveAnalysisLevelStyle = 8.0 +build_property.EnableCodeStyleSeverity = diff --git a/邮件系统课程完整代码/Server/Entity/obj/Debug/net8.0/Entity.GlobalUsings.g.cs b/邮件系统课程完整代码/Server/Entity/obj/Debug/net8.0/Entity.GlobalUsings.g.cs new file mode 100644 index 0000000..8578f3d --- /dev/null +++ b/邮件系统课程完整代码/Server/Entity/obj/Debug/net8.0/Entity.GlobalUsings.g.cs @@ -0,0 +1,8 @@ +// +global using global::System; +global using global::System.Collections.Generic; +global using global::System.IO; +global using global::System.Linq; +global using global::System.Net.Http; +global using global::System.Threading; +global using global::System.Threading.Tasks; diff --git a/邮件系统课程完整代码/Server/Entity/obj/Debug/net8.0/Entity.assets.cache b/邮件系统课程完整代码/Server/Entity/obj/Debug/net8.0/Entity.assets.cache new file mode 100644 index 0000000..1c83466 Binary files /dev/null and b/邮件系统课程完整代码/Server/Entity/obj/Debug/net8.0/Entity.assets.cache differ diff --git a/邮件系统课程完整代码/Server/Entity/obj/Debug/net8.0/Entity.csproj.AssemblyReference.cache b/邮件系统课程完整代码/Server/Entity/obj/Debug/net8.0/Entity.csproj.AssemblyReference.cache new file mode 100644 index 0000000..4f61b22 Binary files /dev/null and b/邮件系统课程完整代码/Server/Entity/obj/Debug/net8.0/Entity.csproj.AssemblyReference.cache differ diff --git a/邮件系统课程完整代码/Server/Entity/obj/Debug/net8.0/Entity.csproj.CoreCompileInputs.cache b/邮件系统课程完整代码/Server/Entity/obj/Debug/net8.0/Entity.csproj.CoreCompileInputs.cache new file mode 100644 index 0000000..b33b2a0 --- /dev/null +++ b/邮件系统课程完整代码/Server/Entity/obj/Debug/net8.0/Entity.csproj.CoreCompileInputs.cache @@ -0,0 +1 @@ +a2b05708cd015f9fdc4519d2f605ab8a519052de738a75c6155c82fb3f874598 diff --git a/邮件系统课程完整代码/Server/Entity/obj/Debug/net8.0/Entity.csproj.FileListAbsolute.txt b/邮件系统课程完整代码/Server/Entity/obj/Debug/net8.0/Entity.csproj.FileListAbsolute.txt new file mode 100644 index 0000000..5762527 --- /dev/null +++ b/邮件系统课程完整代码/Server/Entity/obj/Debug/net8.0/Entity.csproj.FileListAbsolute.txt @@ -0,0 +1,12 @@ +/Users/fantasy/Movies/邮件系统/Lession/Server/Entity/bin/Debug/net8.0/Entity.deps.json +/Users/fantasy/Movies/邮件系统/Lession/Server/Entity/bin/Debug/net8.0/Entity.dll +/Users/fantasy/Movies/邮件系统/Lession/Server/Entity/bin/Debug/net8.0/Entity.pdb +/Users/fantasy/Movies/邮件系统/Lession/Server/Entity/obj/Debug/net8.0/Entity.csproj.AssemblyReference.cache +/Users/fantasy/Movies/邮件系统/Lession/Server/Entity/obj/Debug/net8.0/Entity.GeneratedMSBuildEditorConfig.editorconfig +/Users/fantasy/Movies/邮件系统/Lession/Server/Entity/obj/Debug/net8.0/Entity.AssemblyInfoInputs.cache +/Users/fantasy/Movies/邮件系统/Lession/Server/Entity/obj/Debug/net8.0/Entity.AssemblyInfo.cs +/Users/fantasy/Movies/邮件系统/Lession/Server/Entity/obj/Debug/net8.0/Entity.csproj.CoreCompileInputs.cache +/Users/fantasy/Movies/邮件系统/Lession/Server/Entity/obj/Debug/net8.0/Entity.dll +/Users/fantasy/Movies/邮件系统/Lession/Server/Entity/obj/Debug/net8.0/refint/Entity.dll +/Users/fantasy/Movies/邮件系统/Lession/Server/Entity/obj/Debug/net8.0/Entity.pdb +/Users/fantasy/Movies/邮件系统/Lession/Server/Entity/obj/Debug/net8.0/ref/Entity.dll diff --git a/邮件系统课程完整代码/Server/Entity/obj/Debug/net8.0/Entity.dll b/邮件系统课程完整代码/Server/Entity/obj/Debug/net8.0/Entity.dll new file mode 100644 index 0000000..7a53135 Binary files /dev/null and b/邮件系统课程完整代码/Server/Entity/obj/Debug/net8.0/Entity.dll differ diff --git a/邮件系统课程完整代码/Server/Entity/obj/Debug/net8.0/Entity.pdb b/邮件系统课程完整代码/Server/Entity/obj/Debug/net8.0/Entity.pdb new file mode 100644 index 0000000..46121e0 Binary files /dev/null and b/邮件系统课程完整代码/Server/Entity/obj/Debug/net8.0/Entity.pdb differ diff --git a/邮件系统课程完整代码/Server/Entity/obj/Debug/net8.0/ref/Entity.dll b/邮件系统课程完整代码/Server/Entity/obj/Debug/net8.0/ref/Entity.dll new file mode 100644 index 0000000..322c9cf Binary files /dev/null and b/邮件系统课程完整代码/Server/Entity/obj/Debug/net8.0/ref/Entity.dll differ diff --git a/邮件系统课程完整代码/Server/Entity/obj/Debug/net8.0/refint/Entity.dll b/邮件系统课程完整代码/Server/Entity/obj/Debug/net8.0/refint/Entity.dll new file mode 100644 index 0000000..322c9cf Binary files /dev/null and b/邮件系统课程完整代码/Server/Entity/obj/Debug/net8.0/refint/Entity.dll differ diff --git a/邮件系统课程完整代码/Server/Entity/obj/Entity.csproj.nuget.dgspec.json b/邮件系统课程完整代码/Server/Entity/obj/Entity.csproj.nuget.dgspec.json new file mode 100644 index 0000000..cd63e02 --- /dev/null +++ b/邮件系统课程完整代码/Server/Entity/obj/Entity.csproj.nuget.dgspec.json @@ -0,0 +1,74 @@ +{ + "format": 1, + "restore": { + "/Users/fantasy/Movies/邮件系统/Lession/Server/Entity/Entity.csproj": {} + }, + "projects": { + "/Users/fantasy/Movies/邮件系统/Lession/Server/Entity/Entity.csproj": { + "version": "1.0.0", + "restore": { + "projectUniqueName": "/Users/fantasy/Movies/邮件系统/Lession/Server/Entity/Entity.csproj", + "projectName": "Entity", + "projectPath": "/Users/fantasy/Movies/邮件系统/Lession/Server/Entity/Entity.csproj", + "packagesPath": "/Users/fantasy/.nuget/packages/", + "outputPath": "/Users/fantasy/Movies/邮件系统/Lession/Server/Entity/obj/", + "projectStyle": "PackageReference", + "configFilePaths": [ + "/Users/fantasy/.nuget/NuGet/NuGet.Config" + ], + "originalTargetFrameworks": [ + "net8.0" + ], + "sources": { + "/usr/local/share/dotnet/library-packs": {}, + "https://api.nuget.org/v3/index.json": {} + }, + "frameworks": { + "net8.0": { + "targetAlias": "net8.0", + "projectReferences": {} + } + }, + "warningProperties": { + "warnAsError": [ + "NU1605" + ] + }, + "restoreAuditProperties": { + "enableAudit": "true", + "auditLevel": "low", + "auditMode": "all" + }, + "SdkAnalysisLevel": "9.0.100" + }, + "frameworks": { + "net8.0": { + "targetAlias": "net8.0", + "dependencies": { + "Fantasy-Net": { + "target": "Package", + "version": "[2024.2.22, )" + } + }, + "imports": [ + "net461", + "net462", + "net47", + "net471", + "net472", + "net48", + "net481" + ], + "assetTargetFallback": true, + "warn": true, + "frameworkReferences": { + "Microsoft.NETCore.App": { + "privateAssets": "all" + } + }, + "runtimeIdentifierGraphPath": "/usr/local/share/dotnet/sdk/9.0.100/PortableRuntimeIdentifierGraph.json" + } + } + } + } +} \ No newline at end of file diff --git a/邮件系统课程完整代码/Server/Entity/obj/Entity.csproj.nuget.g.props b/邮件系统课程完整代码/Server/Entity/obj/Entity.csproj.nuget.g.props new file mode 100644 index 0000000..f402062 --- /dev/null +++ b/邮件系统课程完整代码/Server/Entity/obj/Entity.csproj.nuget.g.props @@ -0,0 +1,15 @@ + + + + True + NuGet + $(MSBuildThisFileDirectory)project.assets.json + /Users/fantasy/.nuget/packages/ + /Users/fantasy/.nuget/packages/ + PackageReference + 6.12.2 + + + + + \ No newline at end of file diff --git a/邮件系统课程完整代码/Server/Entity/obj/Entity.csproj.nuget.g.targets b/邮件系统课程完整代码/Server/Entity/obj/Entity.csproj.nuget.g.targets new file mode 100644 index 0000000..2412468 --- /dev/null +++ b/邮件系统课程完整代码/Server/Entity/obj/Entity.csproj.nuget.g.targets @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/邮件系统课程完整代码/Server/Entity/obj/project.assets.json b/邮件系统课程完整代码/Server/Entity/obj/project.assets.json new file mode 100644 index 0000000..b707908 --- /dev/null +++ b/邮件系统课程完整代码/Server/Entity/obj/project.assets.json @@ -0,0 +1,950 @@ +{ + "version": 3, + "targets": { + "net8.0": { + "CommandLineParser/2.9.1": { + "type": "package", + "compile": { + "lib/netstandard2.0/CommandLine.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netstandard2.0/CommandLine.dll": { + "related": ".xml" + } + } + }, + "DnsClient/1.6.1": { + "type": "package", + "dependencies": { + "Microsoft.Win32.Registry": "5.0.0" + }, + "compile": { + "lib/net5.0/DnsClient.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net5.0/DnsClient.dll": { + "related": ".xml" + } + } + }, + "Fantasy-Net/2024.2.22": { + "type": "package", + "dependencies": { + "CommandLineParser": "2.9.1", + "MongoDB.Bson": "3.1.0", + "MongoDB.Driver": "3.1.0", + "Newtonsoft.Json": "13.0.3", + "System.IO.Pipelines": "9.0.0", + "protobuf-net": "3.2.45" + }, + "compile": { + "lib/net8.0/Fantasy-Net.dll": {} + }, + "runtime": { + "lib/net8.0/Fantasy-Net.dll": {} + }, + "frameworkReferences": [ + "Microsoft.AspNetCore.App" + ], + "build": { + "buildTransitive/Fantasy-Net.targets": {} + } + }, + "Microsoft.Extensions.Logging.Abstractions/2.0.0": { + "type": "package", + "compile": { + "lib/netstandard2.0/Microsoft.Extensions.Logging.Abstractions.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netstandard2.0/Microsoft.Extensions.Logging.Abstractions.dll": { + "related": ".xml" + } + } + }, + "Microsoft.NETCore.Platforms/5.0.0": { + "type": "package", + "compile": { + "lib/netstandard1.0/_._": {} + }, + "runtime": { + "lib/netstandard1.0/_._": {} + } + }, + "Microsoft.Win32.Registry/5.0.0": { + "type": "package", + "dependencies": { + "System.Security.AccessControl": "5.0.0", + "System.Security.Principal.Windows": "5.0.0" + }, + "compile": { + "ref/netstandard2.0/Microsoft.Win32.Registry.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netstandard2.0/Microsoft.Win32.Registry.dll": { + "related": ".xml" + } + }, + "runtimeTargets": { + "runtimes/win/lib/netstandard2.0/Microsoft.Win32.Registry.dll": { + "assetType": "runtime", + "rid": "win" + } + } + }, + "MongoDB.Bson/3.1.0": { + "type": "package", + "dependencies": { + "System.Memory": "4.5.5", + "System.Runtime.CompilerServices.Unsafe": "5.0.0" + }, + "compile": { + "lib/net6.0/MongoDB.Bson.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net6.0/MongoDB.Bson.dll": { + "related": ".xml" + } + } + }, + "MongoDB.Driver/3.1.0": { + "type": "package", + "dependencies": { + "DnsClient": "1.6.1", + "Microsoft.Extensions.Logging.Abstractions": "2.0.0", + "MongoDB.Bson": "3.1.0", + "SharpCompress": "0.30.1", + "Snappier": "1.0.0", + "System.Buffers": "4.5.1", + "ZstdSharp.Port": "0.7.3" + }, + "compile": { + "lib/net6.0/MongoDB.Driver.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net6.0/MongoDB.Driver.dll": { + "related": ".xml" + } + } + }, + "Newtonsoft.Json/13.0.3": { + "type": "package", + "compile": { + "lib/net6.0/Newtonsoft.Json.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net6.0/Newtonsoft.Json.dll": { + "related": ".xml" + } + } + }, + "protobuf-net/3.2.45": { + "type": "package", + "dependencies": { + "protobuf-net.Core": "3.2.45" + }, + "compile": { + "lib/net6.0/protobuf-net.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net6.0/protobuf-net.dll": { + "related": ".xml" + } + } + }, + "protobuf-net.Core/3.2.45": { + "type": "package", + "dependencies": { + "System.Collections.Immutable": "7.0.0" + }, + "compile": { + "lib/net6.0/protobuf-net.Core.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net6.0/protobuf-net.Core.dll": { + "related": ".xml" + } + } + }, + "SharpCompress/0.30.1": { + "type": "package", + "compile": { + "lib/net5.0/SharpCompress.dll": {} + }, + "runtime": { + "lib/net5.0/SharpCompress.dll": {} + } + }, + "Snappier/1.0.0": { + "type": "package", + "compile": { + "lib/net5.0/Snappier.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net5.0/Snappier.dll": { + "related": ".xml" + } + } + }, + "System.Buffers/4.5.1": { + "type": "package", + "compile": { + "ref/netcoreapp2.0/_._": {} + }, + "runtime": { + "lib/netcoreapp2.0/_._": {} + } + }, + "System.Collections.Immutable/7.0.0": { + "type": "package", + "compile": { + "lib/net7.0/System.Collections.Immutable.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net7.0/System.Collections.Immutable.dll": { + "related": ".xml" + } + }, + "build": { + "buildTransitive/net6.0/_._": {} + } + }, + "System.IO.Pipelines/9.0.0": { + "type": "package", + "compile": { + "lib/net8.0/System.IO.Pipelines.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net8.0/System.IO.Pipelines.dll": { + "related": ".xml" + } + }, + "build": { + "buildTransitive/net8.0/_._": {} + } + }, + "System.Memory/4.5.5": { + "type": "package", + "compile": { + "ref/netcoreapp2.1/_._": {} + }, + "runtime": { + "lib/netcoreapp2.1/_._": {} + } + }, + "System.Runtime.CompilerServices.Unsafe/5.0.0": { + "type": "package", + "compile": { + "ref/netstandard2.1/System.Runtime.CompilerServices.Unsafe.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netcoreapp2.0/System.Runtime.CompilerServices.Unsafe.dll": { + "related": ".xml" + } + } + }, + "System.Security.AccessControl/5.0.0": { + "type": "package", + "dependencies": { + "Microsoft.NETCore.Platforms": "5.0.0", + "System.Security.Principal.Windows": "5.0.0" + }, + "compile": { + "ref/netstandard2.0/System.Security.AccessControl.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netstandard2.0/System.Security.AccessControl.dll": { + "related": ".xml" + } + }, + "runtimeTargets": { + "runtimes/win/lib/netcoreapp2.0/System.Security.AccessControl.dll": { + "assetType": "runtime", + "rid": "win" + } + } + }, + "System.Security.Principal.Windows/5.0.0": { + "type": "package", + "compile": { + "ref/netcoreapp3.0/System.Security.Principal.Windows.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netstandard2.0/System.Security.Principal.Windows.dll": { + "related": ".xml" + } + }, + "runtimeTargets": { + "runtimes/unix/lib/netcoreapp2.1/System.Security.Principal.Windows.dll": { + "assetType": "runtime", + "rid": "unix" + }, + "runtimes/win/lib/netcoreapp2.1/System.Security.Principal.Windows.dll": { + "assetType": "runtime", + "rid": "win" + } + } + }, + "ZstdSharp.Port/0.7.3": { + "type": "package", + "compile": { + "lib/net7.0/ZstdSharp.dll": {} + }, + "runtime": { + "lib/net7.0/ZstdSharp.dll": {} + } + } + } + }, + "libraries": { + "CommandLineParser/2.9.1": { + "sha512": "OE0sl1/sQ37bjVsPKKtwQlWDgqaxWgtme3xZz7JssWUzg5JpMIyHgCTY9MVMxOg48fJ1AgGT3tgdH5m/kQ5xhA==", + "type": "package", + "path": "commandlineparser/2.9.1", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "CommandLine20.png", + "License.md", + "README.md", + "commandlineparser.2.9.1.nupkg.sha512", + "commandlineparser.nuspec", + "lib/net40/CommandLine.dll", + "lib/net40/CommandLine.xml", + "lib/net45/CommandLine.dll", + "lib/net45/CommandLine.xml", + "lib/net461/CommandLine.dll", + "lib/net461/CommandLine.xml", + "lib/netstandard2.0/CommandLine.dll", + "lib/netstandard2.0/CommandLine.xml" + ] + }, + "DnsClient/1.6.1": { + "sha512": "4H/f2uYJOZ+YObZjpY9ABrKZI+JNw3uizp6oMzTXwDw6F+2qIPhpRl/1t68O/6e98+vqNiYGu+lswmwdYUy3gg==", + "type": "package", + "path": "dnsclient/1.6.1", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "dnsclient.1.6.1.nupkg.sha512", + "dnsclient.nuspec", + "icon.png", + "lib/net45/DnsClient.dll", + "lib/net45/DnsClient.xml", + "lib/net471/DnsClient.dll", + "lib/net471/DnsClient.xml", + "lib/net5.0/DnsClient.dll", + "lib/net5.0/DnsClient.xml", + "lib/netstandard1.3/DnsClient.dll", + "lib/netstandard1.3/DnsClient.xml", + "lib/netstandard2.0/DnsClient.dll", + "lib/netstandard2.0/DnsClient.xml", + "lib/netstandard2.1/DnsClient.dll", + "lib/netstandard2.1/DnsClient.xml" + ] + }, + "Fantasy-Net/2024.2.22": { + "sha512": "cT6B0YJ5JmbPHBLYgLeVgg2WbXYxxa1tudoIase88uMzAuqU9t7EQ7dFZGSWjP41c5JOQ/0f1q9lzGWTh/hskw==", + "type": "package", + "path": "fantasy-net/2024.2.22", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "LICENSE", + "README.md", + "buildTransitive/Fantasy-Net.targets", + "fantasy-net.2024.2.22.nupkg.sha512", + "fantasy-net.nuspec", + "icon.png", + "lib/net8.0/Fantasy-Net.dll", + "lib/net9.0/Fantasy-Net.dll" + ] + }, + "Microsoft.Extensions.Logging.Abstractions/2.0.0": { + "sha512": "6ZCllUYGFukkymSTx3Yr0G/ajRxoNJp7/FqSxSB4fGISST54ifBhgu4Nc0ItGi3i6DqwuNd8SUyObmiC++AO2Q==", + "type": "package", + "path": "microsoft.extensions.logging.abstractions/2.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "lib/netstandard2.0/Microsoft.Extensions.Logging.Abstractions.dll", + "lib/netstandard2.0/Microsoft.Extensions.Logging.Abstractions.xml", + "microsoft.extensions.logging.abstractions.2.0.0.nupkg.sha512", + "microsoft.extensions.logging.abstractions.nuspec" + ] + }, + "Microsoft.NETCore.Platforms/5.0.0": { + "sha512": "VyPlqzH2wavqquTcYpkIIAQ6WdenuKoFN0BdYBbCWsclXacSOHNQn66Gt4z5NBqEYW0FAPm5rlvki9ZiCij5xQ==", + "type": "package", + "path": "microsoft.netcore.platforms/5.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "LICENSE.TXT", + "THIRD-PARTY-NOTICES.TXT", + "lib/netstandard1.0/_._", + "microsoft.netcore.platforms.5.0.0.nupkg.sha512", + "microsoft.netcore.platforms.nuspec", + "runtime.json", + "useSharedDesignerContext.txt", + "version.txt" + ] + }, + "Microsoft.Win32.Registry/5.0.0": { + "sha512": "dDoKi0PnDz31yAyETfRntsLArTlVAVzUzCIvvEDsDsucrl33Dl8pIJG06ePTJTI3tGpeyHS9Cq7Foc/s4EeKcg==", + "type": "package", + "path": "microsoft.win32.registry/5.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "LICENSE.TXT", + "THIRD-PARTY-NOTICES.TXT", + "lib/net46/Microsoft.Win32.Registry.dll", + "lib/net461/Microsoft.Win32.Registry.dll", + "lib/net461/Microsoft.Win32.Registry.xml", + "lib/netstandard1.3/Microsoft.Win32.Registry.dll", + "lib/netstandard2.0/Microsoft.Win32.Registry.dll", + "lib/netstandard2.0/Microsoft.Win32.Registry.xml", + "microsoft.win32.registry.5.0.0.nupkg.sha512", + "microsoft.win32.registry.nuspec", + "ref/net46/Microsoft.Win32.Registry.dll", + "ref/net461/Microsoft.Win32.Registry.dll", + "ref/net461/Microsoft.Win32.Registry.xml", + "ref/netstandard1.3/Microsoft.Win32.Registry.dll", + "ref/netstandard1.3/Microsoft.Win32.Registry.xml", + "ref/netstandard1.3/de/Microsoft.Win32.Registry.xml", + "ref/netstandard1.3/es/Microsoft.Win32.Registry.xml", + "ref/netstandard1.3/fr/Microsoft.Win32.Registry.xml", + "ref/netstandard1.3/it/Microsoft.Win32.Registry.xml", + "ref/netstandard1.3/ja/Microsoft.Win32.Registry.xml", + "ref/netstandard1.3/ko/Microsoft.Win32.Registry.xml", + "ref/netstandard1.3/ru/Microsoft.Win32.Registry.xml", + "ref/netstandard1.3/zh-hans/Microsoft.Win32.Registry.xml", + "ref/netstandard1.3/zh-hant/Microsoft.Win32.Registry.xml", + "ref/netstandard2.0/Microsoft.Win32.Registry.dll", + "ref/netstandard2.0/Microsoft.Win32.Registry.xml", + "runtimes/win/lib/net46/Microsoft.Win32.Registry.dll", + "runtimes/win/lib/net461/Microsoft.Win32.Registry.dll", + "runtimes/win/lib/net461/Microsoft.Win32.Registry.xml", + "runtimes/win/lib/netstandard1.3/Microsoft.Win32.Registry.dll", + "runtimes/win/lib/netstandard2.0/Microsoft.Win32.Registry.dll", + "runtimes/win/lib/netstandard2.0/Microsoft.Win32.Registry.xml", + "useSharedDesignerContext.txt", + "version.txt" + ] + }, + "MongoDB.Bson/3.1.0": { + "sha512": "3dhaZhz18B5vUoEP13o2j8A6zQfkHdZhwBvLZEjDJum4BTLLv1/Z8bt25UQEtpqvYwLgde4R6ekWZ7XAYUMxuw==", + "type": "package", + "path": "mongodb.bson/3.1.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "README.md", + "lib/net472/MongoDB.Bson.dll", + "lib/net472/MongoDB.Bson.xml", + "lib/net6.0/MongoDB.Bson.dll", + "lib/net6.0/MongoDB.Bson.xml", + "lib/netstandard2.1/MongoDB.Bson.dll", + "lib/netstandard2.1/MongoDB.Bson.xml", + "mongodb.bson.3.1.0.nupkg.sha512", + "mongodb.bson.nuspec", + "packageIcon.png" + ] + }, + "MongoDB.Driver/3.1.0": { + "sha512": "+O7lKaIl7VUHptE0hqTd7UY1G5KDp/o8S4upG7YL4uChMNKD/U6tz9i17nMGHaD/L2AiPLgaJcaDe2XACsegGA==", + "type": "package", + "path": "mongodb.driver/3.1.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "README.md", + "lib/net472/MongoDB.Driver.dll", + "lib/net472/MongoDB.Driver.xml", + "lib/net6.0/MongoDB.Driver.dll", + "lib/net6.0/MongoDB.Driver.xml", + "lib/netstandard2.1/MongoDB.Driver.dll", + "lib/netstandard2.1/MongoDB.Driver.xml", + "mongodb.driver.3.1.0.nupkg.sha512", + "mongodb.driver.nuspec", + "packageIcon.png" + ] + }, + "Newtonsoft.Json/13.0.3": { + "sha512": "HrC5BXdl00IP9zeV+0Z848QWPAoCr9P3bDEZguI+gkLcBKAOxix/tLEAAHC+UvDNPv4a2d18lOReHMOagPa+zQ==", + "type": "package", + "path": "newtonsoft.json/13.0.3", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "LICENSE.md", + "README.md", + "lib/net20/Newtonsoft.Json.dll", + "lib/net20/Newtonsoft.Json.xml", + "lib/net35/Newtonsoft.Json.dll", + "lib/net35/Newtonsoft.Json.xml", + "lib/net40/Newtonsoft.Json.dll", + "lib/net40/Newtonsoft.Json.xml", + "lib/net45/Newtonsoft.Json.dll", + "lib/net45/Newtonsoft.Json.xml", + "lib/net6.0/Newtonsoft.Json.dll", + "lib/net6.0/Newtonsoft.Json.xml", + "lib/netstandard1.0/Newtonsoft.Json.dll", + "lib/netstandard1.0/Newtonsoft.Json.xml", + "lib/netstandard1.3/Newtonsoft.Json.dll", + "lib/netstandard1.3/Newtonsoft.Json.xml", + "lib/netstandard2.0/Newtonsoft.Json.dll", + "lib/netstandard2.0/Newtonsoft.Json.xml", + "newtonsoft.json.13.0.3.nupkg.sha512", + "newtonsoft.json.nuspec", + "packageIcon.png" + ] + }, + "protobuf-net/3.2.45": { + "sha512": "5UZ/ukUHcGbFSl7vNMrHsfjqdxusdd9w7w0fCEXzf3UUtsrGNVCzV5SmF+sCHAbnRV2qPcD1ixiDP7Aj8lX/HA==", + "type": "package", + "path": "protobuf-net/3.2.45", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "lib/net462/protobuf-net.dll", + "lib/net462/protobuf-net.xml", + "lib/net6.0/protobuf-net.dll", + "lib/net6.0/protobuf-net.xml", + "lib/netstandard2.0/protobuf-net.dll", + "lib/netstandard2.0/protobuf-net.xml", + "lib/netstandard2.1/protobuf-net.dll", + "lib/netstandard2.1/protobuf-net.xml", + "protobuf-net.3.2.45.nupkg.sha512", + "protobuf-net.nuspec", + "protobuf-net.png", + "readme.md" + ] + }, + "protobuf-net.Core/3.2.45": { + "sha512": "PMWatW2NrT1uTXD7etJ4VdQ0wWZLFrIfdRGppD2QX7nzZ0+kIzqhq551u6ZiXJHWJgG4hWFEkSnUnt2aB6posg==", + "type": "package", + "path": "protobuf-net.core/3.2.45", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "lib/net462/protobuf-net.Core.dll", + "lib/net462/protobuf-net.Core.xml", + "lib/net6.0/protobuf-net.Core.dll", + "lib/net6.0/protobuf-net.Core.xml", + "lib/netstandard2.0/protobuf-net.Core.dll", + "lib/netstandard2.0/protobuf-net.Core.xml", + "lib/netstandard2.1/protobuf-net.Core.dll", + "lib/netstandard2.1/protobuf-net.Core.xml", + "protobuf-net.core.3.2.45.nupkg.sha512", + "protobuf-net.core.nuspec", + "protobuf-net.png", + "readme.md" + ] + }, + "SharpCompress/0.30.1": { + "sha512": "XqD4TpfyYGa7QTPzaGlMVbcecKnXy4YmYLDWrU+JIj7IuRNl7DH2END+Ll7ekWIY8o3dAMWLFDE1xdhfIWD1nw==", + "type": "package", + "path": "sharpcompress/0.30.1", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "lib/net461/SharpCompress.dll", + "lib/net5.0/SharpCompress.dll", + "lib/netcoreapp3.1/SharpCompress.dll", + "lib/netstandard2.0/SharpCompress.dll", + "lib/netstandard2.1/SharpCompress.dll", + "sharpcompress.0.30.1.nupkg.sha512", + "sharpcompress.nuspec" + ] + }, + "Snappier/1.0.0": { + "sha512": "rFtK2KEI9hIe8gtx3a0YDXdHOpedIf9wYCEYtBEmtlyiWVX3XlCNV03JrmmAi/Cdfn7dxK+k0sjjcLv4fpHnqA==", + "type": "package", + "path": "snappier/1.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "COPYING.txt", + "lib/net5.0/Snappier.dll", + "lib/net5.0/Snappier.xml", + "lib/netcoreapp3.0/Snappier.dll", + "lib/netcoreapp3.0/Snappier.xml", + "lib/netstandard2.0/Snappier.dll", + "lib/netstandard2.0/Snappier.xml", + "lib/netstandard2.1/Snappier.dll", + "lib/netstandard2.1/Snappier.xml", + "snappier.1.0.0.nupkg.sha512", + "snappier.nuspec" + ] + }, + "System.Buffers/4.5.1": { + "sha512": "Rw7ijyl1qqRS0YQD/WycNst8hUUMgrMH4FCn1nNm27M4VxchZ1js3fVjQaANHO5f3sN4isvP4a+Met9Y4YomAg==", + "type": "package", + "path": "system.buffers/4.5.1", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "LICENSE.TXT", + "THIRD-PARTY-NOTICES.TXT", + "lib/net461/System.Buffers.dll", + "lib/net461/System.Buffers.xml", + "lib/netcoreapp2.0/_._", + "lib/netstandard1.1/System.Buffers.dll", + "lib/netstandard1.1/System.Buffers.xml", + "lib/netstandard2.0/System.Buffers.dll", + "lib/netstandard2.0/System.Buffers.xml", + "lib/uap10.0.16299/_._", + "ref/net45/System.Buffers.dll", + "ref/net45/System.Buffers.xml", + "ref/netcoreapp2.0/_._", + "ref/netstandard1.1/System.Buffers.dll", + "ref/netstandard1.1/System.Buffers.xml", + "ref/netstandard2.0/System.Buffers.dll", + "ref/netstandard2.0/System.Buffers.xml", + "ref/uap10.0.16299/_._", + "system.buffers.4.5.1.nupkg.sha512", + "system.buffers.nuspec", + "useSharedDesignerContext.txt", + "version.txt" + ] + }, + "System.Collections.Immutable/7.0.0": { + "sha512": "dQPcs0U1IKnBdRDBkrCTi1FoajSTBzLcVTpjO4MBCMC7f4pDOIPzgBoX8JjG7X6uZRJ8EBxsi8+DR1JuwjnzOQ==", + "type": "package", + "path": "system.collections.immutable/7.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "LICENSE.TXT", + "README.md", + "THIRD-PARTY-NOTICES.TXT", + "buildTransitive/net461/System.Collections.Immutable.targets", + "buildTransitive/net462/_._", + "buildTransitive/net6.0/_._", + "buildTransitive/netcoreapp2.0/System.Collections.Immutable.targets", + "lib/net462/System.Collections.Immutable.dll", + "lib/net462/System.Collections.Immutable.xml", + "lib/net6.0/System.Collections.Immutable.dll", + "lib/net6.0/System.Collections.Immutable.xml", + "lib/net7.0/System.Collections.Immutable.dll", + "lib/net7.0/System.Collections.Immutable.xml", + "lib/netstandard2.0/System.Collections.Immutable.dll", + "lib/netstandard2.0/System.Collections.Immutable.xml", + "system.collections.immutable.7.0.0.nupkg.sha512", + "system.collections.immutable.nuspec", + "useSharedDesignerContext.txt" + ] + }, + "System.IO.Pipelines/9.0.0": { + "sha512": "eA3cinogwaNB4jdjQHOP3Z3EuyiDII7MT35jgtnsA4vkn0LUrrSHsU0nzHTzFzmaFYeKV7MYyMxOocFzsBHpTw==", + "type": "package", + "path": "system.io.pipelines/9.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "LICENSE.TXT", + "PACKAGE.md", + "THIRD-PARTY-NOTICES.TXT", + "buildTransitive/net461/System.IO.Pipelines.targets", + "buildTransitive/net462/_._", + "buildTransitive/net8.0/_._", + "buildTransitive/netcoreapp2.0/System.IO.Pipelines.targets", + "lib/net462/System.IO.Pipelines.dll", + "lib/net462/System.IO.Pipelines.xml", + "lib/net8.0/System.IO.Pipelines.dll", + "lib/net8.0/System.IO.Pipelines.xml", + "lib/net9.0/System.IO.Pipelines.dll", + "lib/net9.0/System.IO.Pipelines.xml", + "lib/netstandard2.0/System.IO.Pipelines.dll", + "lib/netstandard2.0/System.IO.Pipelines.xml", + "system.io.pipelines.9.0.0.nupkg.sha512", + "system.io.pipelines.nuspec", + "useSharedDesignerContext.txt" + ] + }, + "System.Memory/4.5.5": { + "sha512": "XIWiDvKPXaTveaB7HVganDlOCRoj03l+jrwNvcge/t8vhGYKvqV+dMv6G4SAX2NoNmN0wZfVPTAlFwZcZvVOUw==", + "type": "package", + "path": "system.memory/4.5.5", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "LICENSE.TXT", + "THIRD-PARTY-NOTICES.TXT", + "lib/net461/System.Memory.dll", + "lib/net461/System.Memory.xml", + "lib/netcoreapp2.1/_._", + "lib/netstandard1.1/System.Memory.dll", + "lib/netstandard1.1/System.Memory.xml", + "lib/netstandard2.0/System.Memory.dll", + "lib/netstandard2.0/System.Memory.xml", + "ref/netcoreapp2.1/_._", + "system.memory.4.5.5.nupkg.sha512", + "system.memory.nuspec", + "useSharedDesignerContext.txt", + "version.txt" + ] + }, + "System.Runtime.CompilerServices.Unsafe/5.0.0": { + "sha512": "ZD9TMpsmYJLrxbbmdvhwt9YEgG5WntEnZ/d1eH8JBX9LBp+Ju8BSBhUGbZMNVHHomWo2KVImJhTDl2hIgw/6MA==", + "type": "package", + "path": "system.runtime.compilerservices.unsafe/5.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "LICENSE.TXT", + "THIRD-PARTY-NOTICES.TXT", + "lib/net45/System.Runtime.CompilerServices.Unsafe.dll", + "lib/net45/System.Runtime.CompilerServices.Unsafe.xml", + "lib/netcoreapp2.0/System.Runtime.CompilerServices.Unsafe.dll", + "lib/netcoreapp2.0/System.Runtime.CompilerServices.Unsafe.xml", + "lib/netstandard1.0/System.Runtime.CompilerServices.Unsafe.dll", + "lib/netstandard1.0/System.Runtime.CompilerServices.Unsafe.xml", + "lib/netstandard2.0/System.Runtime.CompilerServices.Unsafe.dll", + "lib/netstandard2.0/System.Runtime.CompilerServices.Unsafe.xml", + "ref/net461/System.Runtime.CompilerServices.Unsafe.dll", + "ref/net461/System.Runtime.CompilerServices.Unsafe.xml", + "ref/netstandard1.0/System.Runtime.CompilerServices.Unsafe.dll", + "ref/netstandard1.0/System.Runtime.CompilerServices.Unsafe.xml", + "ref/netstandard2.0/System.Runtime.CompilerServices.Unsafe.dll", + "ref/netstandard2.0/System.Runtime.CompilerServices.Unsafe.xml", + "ref/netstandard2.1/System.Runtime.CompilerServices.Unsafe.dll", + "ref/netstandard2.1/System.Runtime.CompilerServices.Unsafe.xml", + "system.runtime.compilerservices.unsafe.5.0.0.nupkg.sha512", + "system.runtime.compilerservices.unsafe.nuspec", + "useSharedDesignerContext.txt", + "version.txt" + ] + }, + "System.Security.AccessControl/5.0.0": { + "sha512": "dagJ1mHZO3Ani8GH0PHpPEe/oYO+rVdbQjvjJkBRNQkX4t0r1iaeGn8+/ybkSLEan3/slM0t59SVdHzuHf2jmw==", + "type": "package", + "path": "system.security.accesscontrol/5.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "LICENSE.TXT", + "THIRD-PARTY-NOTICES.TXT", + "lib/net46/System.Security.AccessControl.dll", + "lib/net461/System.Security.AccessControl.dll", + "lib/net461/System.Security.AccessControl.xml", + "lib/netstandard1.3/System.Security.AccessControl.dll", + "lib/netstandard2.0/System.Security.AccessControl.dll", + "lib/netstandard2.0/System.Security.AccessControl.xml", + "lib/uap10.0.16299/_._", + "ref/net46/System.Security.AccessControl.dll", + "ref/net461/System.Security.AccessControl.dll", + "ref/net461/System.Security.AccessControl.xml", + "ref/netstandard1.3/System.Security.AccessControl.dll", + "ref/netstandard1.3/System.Security.AccessControl.xml", + "ref/netstandard1.3/de/System.Security.AccessControl.xml", + "ref/netstandard1.3/es/System.Security.AccessControl.xml", + "ref/netstandard1.3/fr/System.Security.AccessControl.xml", + "ref/netstandard1.3/it/System.Security.AccessControl.xml", + "ref/netstandard1.3/ja/System.Security.AccessControl.xml", + "ref/netstandard1.3/ko/System.Security.AccessControl.xml", + "ref/netstandard1.3/ru/System.Security.AccessControl.xml", + "ref/netstandard1.3/zh-hans/System.Security.AccessControl.xml", + "ref/netstandard1.3/zh-hant/System.Security.AccessControl.xml", + "ref/netstandard2.0/System.Security.AccessControl.dll", + "ref/netstandard2.0/System.Security.AccessControl.xml", + "ref/uap10.0.16299/_._", + "runtimes/win/lib/net46/System.Security.AccessControl.dll", + "runtimes/win/lib/net461/System.Security.AccessControl.dll", + "runtimes/win/lib/net461/System.Security.AccessControl.xml", + "runtimes/win/lib/netcoreapp2.0/System.Security.AccessControl.dll", + "runtimes/win/lib/netcoreapp2.0/System.Security.AccessControl.xml", + "runtimes/win/lib/netstandard1.3/System.Security.AccessControl.dll", + "runtimes/win/lib/uap10.0.16299/_._", + "system.security.accesscontrol.5.0.0.nupkg.sha512", + "system.security.accesscontrol.nuspec", + "useSharedDesignerContext.txt", + "version.txt" + ] + }, + "System.Security.Principal.Windows/5.0.0": { + "sha512": "t0MGLukB5WAVU9bO3MGzvlGnyJPgUlcwerXn1kzBRjwLKixT96XV0Uza41W49gVd8zEMFu9vQEFlv0IOrytICA==", + "type": "package", + "path": "system.security.principal.windows/5.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "LICENSE.TXT", + "THIRD-PARTY-NOTICES.TXT", + "lib/net46/System.Security.Principal.Windows.dll", + "lib/net461/System.Security.Principal.Windows.dll", + "lib/net461/System.Security.Principal.Windows.xml", + "lib/netstandard1.3/System.Security.Principal.Windows.dll", + "lib/netstandard2.0/System.Security.Principal.Windows.dll", + "lib/netstandard2.0/System.Security.Principal.Windows.xml", + "lib/uap10.0.16299/_._", + "ref/net46/System.Security.Principal.Windows.dll", + "ref/net461/System.Security.Principal.Windows.dll", + "ref/net461/System.Security.Principal.Windows.xml", + "ref/netcoreapp3.0/System.Security.Principal.Windows.dll", + "ref/netcoreapp3.0/System.Security.Principal.Windows.xml", + "ref/netstandard1.3/System.Security.Principal.Windows.dll", + "ref/netstandard1.3/System.Security.Principal.Windows.xml", + "ref/netstandard1.3/de/System.Security.Principal.Windows.xml", + "ref/netstandard1.3/es/System.Security.Principal.Windows.xml", + "ref/netstandard1.3/fr/System.Security.Principal.Windows.xml", + "ref/netstandard1.3/it/System.Security.Principal.Windows.xml", + "ref/netstandard1.3/ja/System.Security.Principal.Windows.xml", + "ref/netstandard1.3/ko/System.Security.Principal.Windows.xml", + "ref/netstandard1.3/ru/System.Security.Principal.Windows.xml", + "ref/netstandard1.3/zh-hans/System.Security.Principal.Windows.xml", + "ref/netstandard1.3/zh-hant/System.Security.Principal.Windows.xml", + "ref/netstandard2.0/System.Security.Principal.Windows.dll", + "ref/netstandard2.0/System.Security.Principal.Windows.xml", + "ref/uap10.0.16299/_._", + "runtimes/unix/lib/netcoreapp2.0/System.Security.Principal.Windows.dll", + "runtimes/unix/lib/netcoreapp2.0/System.Security.Principal.Windows.xml", + "runtimes/unix/lib/netcoreapp2.1/System.Security.Principal.Windows.dll", + "runtimes/unix/lib/netcoreapp2.1/System.Security.Principal.Windows.xml", + "runtimes/win/lib/net46/System.Security.Principal.Windows.dll", + "runtimes/win/lib/net461/System.Security.Principal.Windows.dll", + "runtimes/win/lib/net461/System.Security.Principal.Windows.xml", + "runtimes/win/lib/netcoreapp2.0/System.Security.Principal.Windows.dll", + "runtimes/win/lib/netcoreapp2.0/System.Security.Principal.Windows.xml", + "runtimes/win/lib/netcoreapp2.1/System.Security.Principal.Windows.dll", + "runtimes/win/lib/netcoreapp2.1/System.Security.Principal.Windows.xml", + "runtimes/win/lib/netstandard1.3/System.Security.Principal.Windows.dll", + "runtimes/win/lib/uap10.0.16299/_._", + "system.security.principal.windows.5.0.0.nupkg.sha512", + "system.security.principal.windows.nuspec", + "useSharedDesignerContext.txt", + "version.txt" + ] + }, + "ZstdSharp.Port/0.7.3": { + "sha512": "U9Ix4l4cl58Kzz1rJzj5hoVTjmbx1qGMwzAcbv1j/d3NzrFaESIurQyg+ow4mivCgkE3S413y+U9k4WdnEIkRA==", + "type": "package", + "path": "zstdsharp.port/0.7.3", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "lib/net461/ZstdSharp.dll", + "lib/net5.0/ZstdSharp.dll", + "lib/net6.0/ZstdSharp.dll", + "lib/net7.0/ZstdSharp.dll", + "lib/netcoreapp3.1/ZstdSharp.dll", + "lib/netstandard2.0/ZstdSharp.dll", + "lib/netstandard2.1/ZstdSharp.dll", + "zstdsharp.port.0.7.3.nupkg.sha512", + "zstdsharp.port.nuspec" + ] + } + }, + "projectFileDependencyGroups": { + "net8.0": [ + "Fantasy-Net >= 2024.2.22" + ] + }, + "packageFolders": { + "/Users/fantasy/.nuget/packages/": {} + }, + "project": { + "version": "1.0.0", + "restore": { + "projectUniqueName": "/Users/fantasy/Movies/邮件系统/Lession/Server/Entity/Entity.csproj", + "projectName": "Entity", + "projectPath": "/Users/fantasy/Movies/邮件系统/Lession/Server/Entity/Entity.csproj", + "packagesPath": "/Users/fantasy/.nuget/packages/", + "outputPath": "/Users/fantasy/Movies/邮件系统/Lession/Server/Entity/obj/", + "projectStyle": "PackageReference", + "configFilePaths": [ + "/Users/fantasy/.nuget/NuGet/NuGet.Config" + ], + "originalTargetFrameworks": [ + "net8.0" + ], + "sources": { + "/usr/local/share/dotnet/library-packs": {}, + "https://api.nuget.org/v3/index.json": {} + }, + "frameworks": { + "net8.0": { + "targetAlias": "net8.0", + "projectReferences": {} + } + }, + "warningProperties": { + "warnAsError": [ + "NU1605" + ] + }, + "restoreAuditProperties": { + "enableAudit": "true", + "auditLevel": "low", + "auditMode": "all" + }, + "SdkAnalysisLevel": "9.0.100" + }, + "frameworks": { + "net8.0": { + "targetAlias": "net8.0", + "dependencies": { + "Fantasy-Net": { + "target": "Package", + "version": "[2024.2.22, )" + } + }, + "imports": [ + "net461", + "net462", + "net47", + "net471", + "net472", + "net48", + "net481" + ], + "assetTargetFallback": true, + "warn": true, + "frameworkReferences": { + "Microsoft.NETCore.App": { + "privateAssets": "all" + } + }, + "runtimeIdentifierGraphPath": "/usr/local/share/dotnet/sdk/9.0.100/PortableRuntimeIdentifierGraph.json" + } + } + } +} \ No newline at end of file diff --git a/邮件系统课程完整代码/Server/Entity/obj/project.nuget.cache b/邮件系统课程完整代码/Server/Entity/obj/project.nuget.cache new file mode 100644 index 0000000..7153d1e --- /dev/null +++ b/邮件系统课程完整代码/Server/Entity/obj/project.nuget.cache @@ -0,0 +1,30 @@ +{ + "version": 2, + "dgSpecHash": "KLcJ+imhZmA=", + "success": true, + "projectFilePath": "/Users/fantasy/Movies/邮件系统/Lession/Server/Entity/Entity.csproj", + "expectedPackageFiles": [ + "/Users/fantasy/.nuget/packages/commandlineparser/2.9.1/commandlineparser.2.9.1.nupkg.sha512", + "/Users/fantasy/.nuget/packages/dnsclient/1.6.1/dnsclient.1.6.1.nupkg.sha512", + "/Users/fantasy/.nuget/packages/fantasy-net/2024.2.22/fantasy-net.2024.2.22.nupkg.sha512", + "/Users/fantasy/.nuget/packages/microsoft.extensions.logging.abstractions/2.0.0/microsoft.extensions.logging.abstractions.2.0.0.nupkg.sha512", + "/Users/fantasy/.nuget/packages/microsoft.netcore.platforms/5.0.0/microsoft.netcore.platforms.5.0.0.nupkg.sha512", + "/Users/fantasy/.nuget/packages/microsoft.win32.registry/5.0.0/microsoft.win32.registry.5.0.0.nupkg.sha512", + "/Users/fantasy/.nuget/packages/mongodb.bson/3.1.0/mongodb.bson.3.1.0.nupkg.sha512", + "/Users/fantasy/.nuget/packages/mongodb.driver/3.1.0/mongodb.driver.3.1.0.nupkg.sha512", + "/Users/fantasy/.nuget/packages/newtonsoft.json/13.0.3/newtonsoft.json.13.0.3.nupkg.sha512", + "/Users/fantasy/.nuget/packages/protobuf-net/3.2.45/protobuf-net.3.2.45.nupkg.sha512", + "/Users/fantasy/.nuget/packages/protobuf-net.core/3.2.45/protobuf-net.core.3.2.45.nupkg.sha512", + "/Users/fantasy/.nuget/packages/sharpcompress/0.30.1/sharpcompress.0.30.1.nupkg.sha512", + "/Users/fantasy/.nuget/packages/snappier/1.0.0/snappier.1.0.0.nupkg.sha512", + "/Users/fantasy/.nuget/packages/system.buffers/4.5.1/system.buffers.4.5.1.nupkg.sha512", + "/Users/fantasy/.nuget/packages/system.collections.immutable/7.0.0/system.collections.immutable.7.0.0.nupkg.sha512", + "/Users/fantasy/.nuget/packages/system.io.pipelines/9.0.0/system.io.pipelines.9.0.0.nupkg.sha512", + "/Users/fantasy/.nuget/packages/system.memory/4.5.5/system.memory.4.5.5.nupkg.sha512", + "/Users/fantasy/.nuget/packages/system.runtime.compilerservices.unsafe/5.0.0/system.runtime.compilerservices.unsafe.5.0.0.nupkg.sha512", + "/Users/fantasy/.nuget/packages/system.security.accesscontrol/5.0.0/system.security.accesscontrol.5.0.0.nupkg.sha512", + "/Users/fantasy/.nuget/packages/system.security.principal.windows/5.0.0/system.security.principal.windows.5.0.0.nupkg.sha512", + "/Users/fantasy/.nuget/packages/zstdsharp.port/0.7.3/zstdsharp.port.0.7.3.nupkg.sha512" + ], + "logs": [] +} \ No newline at end of file diff --git a/邮件系统课程完整代码/Server/Entity/obj/project.packagespec.json b/邮件系统课程完整代码/Server/Entity/obj/project.packagespec.json new file mode 100644 index 0000000..79ff1de --- /dev/null +++ b/邮件系统课程完整代码/Server/Entity/obj/project.packagespec.json @@ -0,0 +1 @@ +"restore":{"projectUniqueName":"/Users/fantasy/Movies/邮件系统/Lession/Server/Entity/Entity.csproj","projectName":"Entity","projectPath":"/Users/fantasy/Movies/邮件系统/Lession/Server/Entity/Entity.csproj","outputPath":"/Users/fantasy/Movies/邮件系统/Lession/Server/Entity/obj/","projectStyle":"PackageReference","originalTargetFrameworks":["net8.0"],"sources":{"/usr/local/share/dotnet/library-packs":{},"https://api.nuget.org/v3/index.json":{}},"frameworks":{"net8.0":{"targetAlias":"net8.0","projectReferences":{}}},"warningProperties":{"warnAsError":["NU1605"]},"restoreAuditProperties":{"enableAudit":"true","auditLevel":"low","auditMode":"all"},"SdkAnalysisLevel":"9.0.100"}"frameworks":{"net8.0":{"targetAlias":"net8.0","dependencies":{"Fantasy-Net":{"target":"Package","version":"[2024.2.22, )"}},"imports":["net461","net462","net47","net471","net472","net48","net481"],"assetTargetFallback":true,"warn":true,"frameworkReferences":{"Microsoft.NETCore.App":{"privateAssets":"all"}},"runtimeIdentifierGraphPath":"/usr/local/share/dotnet/sdk/9.0.100/PortableRuntimeIdentifierGraph.json"}} \ No newline at end of file diff --git a/邮件系统课程完整代码/Server/Entity/obj/rider.project.model.nuget.info b/邮件系统课程完整代码/Server/Entity/obj/rider.project.model.nuget.info new file mode 100644 index 0000000..10367cb --- /dev/null +++ b/邮件系统课程完整代码/Server/Entity/obj/rider.project.model.nuget.info @@ -0,0 +1 @@ +17392438089776433 \ No newline at end of file diff --git a/邮件系统课程完整代码/Server/Entity/obj/rider.project.restore.info b/邮件系统课程完整代码/Server/Entity/obj/rider.project.restore.info new file mode 100644 index 0000000..10367cb --- /dev/null +++ b/邮件系统课程完整代码/Server/Entity/obj/rider.project.restore.info @@ -0,0 +1 @@ +17392438089776433 \ No newline at end of file diff --git a/邮件系统课程完整代码/Server/Hotfix/.DS_Store b/邮件系统课程完整代码/Server/Hotfix/.DS_Store new file mode 100644 index 0000000..96ee58b Binary files /dev/null and b/邮件系统课程完整代码/Server/Hotfix/.DS_Store differ diff --git a/邮件系统课程完整代码/Server/Hotfix/Gate/Components/GateAccountFlagComponentSystem.cs b/邮件系统课程完整代码/Server/Hotfix/Gate/Components/GateAccountFlagComponentSystem.cs new file mode 100644 index 0000000..a426ea3 --- /dev/null +++ b/邮件系统课程完整代码/Server/Hotfix/Gate/Components/GateAccountFlagComponentSystem.cs @@ -0,0 +1,36 @@ +using Fantasy.Async; +using Fantasy.Entitas.Interface; +// ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract +#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. + +namespace Fantasy; + +public sealed class GateAccountFlagComponentSystem : DestroySystem +{ + protected override void Destroy(GateAccountFlagComponent self) + { + // DestroyAsync(self).Coroutine(); + + var selfAccount = self.Account; + if (selfAccount == null) + { + return; + } + var selfAccountMailRouteId = selfAccount.MailRouteId; + GateLoginHelper.Offline(self.Scene, selfAccountMailRouteId).Coroutine(); + self.Account = null; + selfAccount.Dispose(); + } + + // private async FTask DestroyAsync(GateAccountFlagComponent self) + // { + // var selfAccount = self.Account; + // if (selfAccount == null) + // { + // return; + // } + // await GateLoginHelper.Offline(self.Scene,selfAccount.MailRouteId) + // self.Account = null; + // selfAccount.Dispose(); + // } +} \ No newline at end of file diff --git a/邮件系统课程完整代码/Server/Hotfix/Gate/Handler/C2G_ExitHandler.cs b/邮件系统课程完整代码/Server/Hotfix/Gate/Handler/C2G_ExitHandler.cs new file mode 100644 index 0000000..20941ef --- /dev/null +++ b/邮件系统课程完整代码/Server/Hotfix/Gate/Handler/C2G_ExitHandler.cs @@ -0,0 +1,23 @@ +using Fantasy.Async; +using Fantasy.Network; +using Fantasy.Network.Interface; +// ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract + +namespace Fantasy; + +public sealed class C2G_ExitHandler : Message +{ + protected override async FTask Run(Session session, C2G_Exit message) + { + var gateAccountFlagComponent = session.GetComponent(); + if (gateAccountFlagComponent == null) + { + Log.Warning($"有用户不是通过正常途径访问到这个接口,IP:{session.RemoteEndPoint.ToString()}"); + return; + } + Log.Debug($"用户名:{gateAccountFlagComponent.Account.Name} 退出游戏的协议。"); + // 如果执行了这个session.Dispose,就会断开这个连接,这样的情况下,客户端也会断开。 + session.Dispose(); + await FTask.CompletedTask; + } +} \ No newline at end of file diff --git a/邮件系统课程完整代码/Server/Hotfix/Gate/Handler/C2G_LoginRequestHandler.cs b/邮件系统课程完整代码/Server/Hotfix/Gate/Handler/C2G_LoginRequestHandler.cs new file mode 100644 index 0000000..0a61aba --- /dev/null +++ b/邮件系统课程完整代码/Server/Hotfix/Gate/Handler/C2G_LoginRequestHandler.cs @@ -0,0 +1,57 @@ +using Fantasy.Async; +using Fantasy.Entitas; +using Fantasy.Helper; +using Fantasy.Network; +using Fantasy.Network.Interface; +#pragma warning disable CS8600 // Converting null literal or possible null value to non-nullable type. + +namespace Fantasy; + +public sealed class C2G_LoginRequestHandler : MessageRPC +{ + protected override async FTask Run(Session session, C2G_LoginRequest request, G2C_LoginResponse response, Action reply) + { + var scene = session.Scene; + if (string.IsNullOrEmpty(request.Name)) + { + // 返回的1代表的用户名为空。 + response.ErrorCode = 1; + return; + } + Log.Debug($"登陆的用户名为:{request.Name}"); + // 检查用户是否存在 + Account account = null; + var worldDataBase = scene.World.DataBase; + // 用协程锁来处理,异步逻辑的原子问题。 + using (await scene.CoroutineLockComponent.Wait(CoroutineLockConst.LoginKey, request.Name.GetHashCode())) + { + account = await worldDataBase.First(d => d.Name == request.Name, true); + // 如果用户不存在,则创建一个用户。并且保存到数据库中. + if (account == null) + { + account = Entity.Create(scene, true, true); + account.Name = request.Name; + account.CreateTime = TimeHelper.Now; + await worldDataBase.Save(account); + Log.Debug($"当前账号:{request.Name} 不存在,所以创建了一个新的账号。"); + } + else + { + Log.Debug($"当前账号:{request.Name} 已经存在,直接登陆。"); + } + } + // 跟Session关联上Account,下次发送消息,直接可以通过GateAccountFlagComponent来获取Account。 + session.AddComponent().Account = account; + // 登陆到其他服务器。 + var result = await GateLoginHelper.Online(session, account); + if (result != 0) + { + response.ErrorCode = result; + Log.Error($"登陆到其他服务器失败,ErrorCode:{result}"); + return; + } + Log.Debug($"登陆成功 Name:{account.Name}"); + // 用这个方法来暂时消除async的黄色波浪线。这个只是为了消除黄色的波浪线,如果有await这个就可以不用。 + // await FTask.CompletedTask; + } +} \ No newline at end of file diff --git a/邮件系统课程完整代码/Server/Hotfix/Gate/Helper/GateLoginHelper.cs b/邮件系统课程完整代码/Server/Hotfix/Gate/Helper/GateLoginHelper.cs new file mode 100644 index 0000000..8a06528 --- /dev/null +++ b/邮件系统课程完整代码/Server/Hotfix/Gate/Helper/GateLoginHelper.cs @@ -0,0 +1,69 @@ +using Fantasy.Async; +using Fantasy.Network; +using Fantasy.Platform.Net; + +namespace Fantasy; + +public static class GateLoginHelper +{ + /// + /// Gate服务器登陆到其他服务器接口 + /// + /// + /// + /// + public static async FTask Online(Session session, Account account) + { + // 这里应该编写登陆到其他服务器的逻辑,现在没有暂时空着. + // 1、如何得到Mail服务器的地址。✅ + // 2、如何做到发送到Gate服务器自动中间消息给Mail。 + // 3、就算是Gate可以中间Mail消息到Mail服务器了,那Mail如何发送消息给Gate再让Gate自动的发送消息给客户端呢。 + var scene = session.Scene; + + var mailConfig = SceneConfigData.Instance.GetSceneBySceneType(SceneType.Mail)[0]; + // 挂载自定义路由协议组件,挂载了这个组件后,就可以自动转发Route协议了。 + var routeComponent = session.GetOrAddComponent(); + // var mailAddress = "127.0.0.1" + mailConfig.InnerPort; + //mailConfig.RouteId 423423445678974 + // 发送服务器之间的消息,需要通过当前Scene的NetworkMessagingComponent组件来进行发送。 + var response = (Mail2G_LoginResponse)await scene.NetworkMessagingComponent.CallInnerRoute(mailConfig.RouteId, new G2Mail_LoginRequest() + { + AccountId = account.Id, + Name = account.Name, + CreateTime = account.CreateTime, + GateRouteId = session.RuntimeId + }); + if (response.ErrorCode != 0) + { + return response.ErrorCode; + } + // 保存这个MailUnitRouteId,用于后续的下线等操作。 + account.MailRouteId = response.MailUnitRouteId; + // 添加自定义路由协议地址。 + routeComponent.AddAddress(RouteType.MailRoute, response.MailUnitRouteId); + // // Gate服务器发送一个消息给Mail服务器 + // scene.NetworkMessagingComponent.SendInnerRoute(response.MailUnitRouteId,new G2Mail_TestMessage() + // { + // Tag = "666" + // }); + return 0; + } + + /// + /// Gate服务器下线其他服务器接口 + /// + /// + /// + /// + public static async FTask Offline(Scene scene, long mailRouteId) + { + // 给Mail服务器发送下线消息 + var mailResponse = (Mail2G_ExitResponse)await scene.NetworkMessagingComponent.CallInnerRoute(mailRouteId, new G2Mail_ExitRequest()); + if (mailResponse.ErrorCode != 0) + { + Log.Error($"Mail服务器无法正常下线 ErrorCode:{mailResponse.ErrorCode}"); + return mailResponse.ErrorCode; + } + return 0; + } +} \ No newline at end of file diff --git a/邮件系统课程完整代码/Server/Hotfix/Hotfix.csproj b/邮件系统课程完整代码/Server/Hotfix/Hotfix.csproj new file mode 100644 index 0000000..4f09b61 --- /dev/null +++ b/邮件系统课程完整代码/Server/Hotfix/Hotfix.csproj @@ -0,0 +1,13 @@ + + + + net8.0 + enable + enable + + + + + + + diff --git a/邮件系统课程完整代码/Server/Hotfix/Mail/Components/MailBoxManageComponentSystem.cs b/邮件系统课程完整代码/Server/Hotfix/Mail/Components/MailBoxManageComponentSystem.cs new file mode 100644 index 0000000..40c2986 --- /dev/null +++ b/邮件系统课程完整代码/Server/Hotfix/Mail/Components/MailBoxManageComponentSystem.cs @@ -0,0 +1,225 @@ +using Fantasy.Async; +using Fantasy.DataStructure.Collection; +using Fantasy.Entitas.Interface; +using Fantasy.Helper; + +namespace Fantasy; + +public class MailBoxManageComponentDestroySystem : DestroySystem +{ + protected override void Destroy(MailBoxManageComponent self) + { + if (self.TimerId != 0) + { + self.Scene.TimerComponent.Net.Remove(ref self.TimerId); + } + + foreach (var (_, mailBox) in self.MailBoxes) + { + mailBox.Dispose(); + } + + self.MinTime = 0; + self.MailsByAccount.Clear(); + self.MailsByMailBoxType.Clear(); + self.Timers.Clear(); + self.TimeOutQueue.Clear(); + } +} + +public static class MailBoxManageComponentSystem +{ + public static async FTask Init(this MailBoxManageComponent self) + { + // 获取数据库中所有的没有处理完成的MailBox + + var mailBoxes = await self.Scene.World.DataBase.Query(d => true); + + foreach (var mailBox in mailBoxes) + { + self.MailBoxes.Add(mailBox.Id, mailBox); + + switch (mailBox.MailBoxType) + { + case MailBoxType.Specify: + { + foreach (var accountId in mailBox.AccountId) + { + self.MailsByAccount.Add(accountId, mailBox); + } + + break; + } + case MailBoxType.All: + case MailBoxType.AllToDate: + { + self.MailsByMailBoxType.Add((int)mailBox.MailBoxType, mailBox); + break; + } + } + } + + self.TimerId = self.Scene.TimerComponent.Net.RepeatedTimer(MailBoxManageComponent.MailCheckTIme, self.Timeout); + } + + private static void Timeout(this MailBoxManageComponent self) + { + var currentTime = TimeHelper.Now; + + if (currentTime < self.MinTime) + { + return; + } + + // 检查当然时候有过期的邮件箱需要处理 + + foreach (var (timeKey, _) in self.Timers) + { + if (timeKey > currentTime) + { + self.MinTime = timeKey; + break; + } + + self.TimeOutQueue.Enqueue(timeKey); + } + + while (self.TimeOutQueue.TryDequeue(out var timeKey)) + { + foreach (var mailBoxId in self.Timers[timeKey]) + { + Log.Info($"MailBox:{mailBoxId} 过期了!"); + self.Remove(mailBoxId).Coroutine(); + } + + self.Timers.RemoveKey(timeKey); + } + } + + public static async FTask Remove(this MailBoxManageComponent self, long mailBoxId) + { + if (!self.MailBoxes.Remove(mailBoxId, out var mailBox)) + { + return; + } + + // 先删除按照分类存储的邮箱 + self.MailsByMailBoxType.RemoveValue((int)mailBox.MailBoxType, mailBox); + // 删除个人邮件的邮件箱 + self.MailsByAccount.RemoveValue(mailBoxId, mailBox); + // 在数据库中删除这个邮件 + await self.Scene.World.DataBase.Remove(mailBoxId); + // 销毁这个MailBox + mailBox.Dispose(); + } + + public static async FTask GetHaveMail(this MailBoxManageComponent self, MailUnit mailUnit, bool sync) + { + var now = TimeHelper.Now; + var worldDataBase = self.Scene.World.DataBase; + var mailComponent = mailUnit.GetComponent(); + + // 玩家领取范围邮件的逻辑处理 + + foreach (var (mailBoxType, mailBoxList) in self.MailsByMailBoxType) + { + using var removeMailBox = ListPool.Create(); + switch ((MailBoxType)mailBoxType) + { + // 发送给所有人的邮件 + case MailBoxType.All: + { + foreach (var mailBox in mailBoxList) + { + if (!mailBox.Received.Contains(mailUnit.Id)) + { + // 如果是没有领取过这个邮件,首先要把自己添加到领取过的名单中。 + mailBox.Received.Add(mailUnit.Id); + // 发送给自己的邮件列表里添加邮件。 + await mailUnit.GetComponent().Add(MailFactory.Serializer.Clone(mailBox.Mail), true); + } + + if (mailBox.ExpireTime <= now) + { + // 邮件已经过期了,要进行清理这个邮件的操作了 + removeMailBox.Add(mailBox); + continue; + } + + // 保存邮件箱状态到数据库中。 + await worldDataBase.Save(mailBox); + } + + foreach (var mailBox in removeMailBox) + { + await self.Remove(mailBox.Id); + } + + // 这里有一个小的细节要处理,这里大家课下自己实现一下。 + break; + } + case MailBoxType.AllToDate: + { + foreach (var mailBox in mailBoxList) + { + Log.Debug($"mailBox.CreateTime >= mailUnit.CreateTime {mailBox.CreateTime} >= {mailUnit.CreateTime}"); + if (mailBox.CreateTime >= mailUnit.CreateTime && !mailBox.Received.Contains(mailUnit.Id)) + { + // 如果是没有领取过这个邮件,首先要把自己添加到领取过的名单中。 + mailBox.Received.Add(mailUnit.Id); + // 发送给自己的邮件列表里添加邮件。 + await mailUnit.GetComponent().Add(MailFactory.Serializer.Clone(mailBox.Mail), true); + } + + if (mailBox.ExpireTime <= now) + { + // 邮件已经过期了,要进行清理这个邮件的操作了 + removeMailBox.Add(mailBox); + continue; + } + + // 保存邮件箱状态到数据库中。 + await worldDataBase.Save(mailBox); + } + + foreach (var mailBox in removeMailBox) + { + await self.Remove(mailBox.Id); + } + + break; + } + } + } + + + if (self.MailsByAccount.TryGetValue(mailUnit.AccountId, out var mailBoxes)) + { + using var removeMailBox = ListPool.Create(); + foreach (var mailBox in mailBoxes) + { + var cloneMail = MailFactory.Serializer.Clone(mailBox.Mail); + await mailComponent.Add(cloneMail, sync); + mailBox.AccountId.Remove(mailUnit.AccountId); + Log.Debug($"领取了一个离线邮件 MailId:{cloneMail.Id}"); + + if (mailBox.AccountId.Count <= 0) + { + // 当邮件箱里没有要发送的玩家了,就表示这个邮件箱已经没有用处,可以删除了。 + removeMailBox.Add(mailBox); + } + } + + foreach (var mailBox in removeMailBox) + { + await self.Remove(mailBox.Id); + } + + if (mailBoxes.Count <= 0) + { + // 如果MailsByAccount里的邮件箱已经没有邮件了,就删除这个邮件箱的缓存。 + self.MailsByAccount.RemoveByKey(mailUnit.AccountId); + } + } + } +} \ No newline at end of file diff --git a/邮件系统课程完整代码/Server/Hotfix/Mail/Components/MailComponentSystem.cs b/邮件系统课程完整代码/Server/Hotfix/Mail/Components/MailComponentSystem.cs new file mode 100644 index 0000000..92a8450 --- /dev/null +++ b/邮件系统课程完整代码/Server/Hotfix/Mail/Components/MailComponentSystem.cs @@ -0,0 +1,226 @@ +using Fantasy.Async; +using Fantasy.DataStructure.Collection; +using Fantasy.Entitas.Interface; +using Fantasy.Helper; +#pragma warning disable CS8619 // Nullability of reference types in value doesn't match target type. + +namespace Fantasy; + +public class MailComponentDestroySystem : DestroySystem +{ + protected override void Destroy(MailComponent self) + { + foreach (var (_, mail) in self.Mails) + { + mail.Dispose(); + } + + self.Mails.Clear(); + self.Timer.Clear(); + } +} + +public class MailComponentDeserializeSystem : DeserializeSystem +{ + protected override void Deserialize(MailComponent self) + { + self.Timer.Clear(); + foreach (var (_, mail) in self.Mails) + { + self.Timer.Add(mail.ExpireTime, mail.Id); + } + } +} + +public static class MailComponentSystem +{ + public static async FTask Add(this MailComponent self, Mail mail, bool sync) + { + mail.CreateTime = TimeHelper.Now; + mail.ExpireTime = mail.CreateTime + MailComponent.MailExpireTime; + + // 如果身上的邮件数量,大于了设置的最大数量怎么办? + // 先不用考虑,稍后咱们再解决问题。 + if (self.Mails.Count >= MailComponent.MaxMailCount) + { + // 删除最老的邮件。 + var (_, value) = self.Timer.First(); + var removeId = value[0]; + await self.Remove(removeId, MailRemoveActionType.Overtop, sync); + } + + self.Mails.Add(mail.Id, mail); + self.Timer.Add(mail.ExpireTime, mail.Id); + + if (sync) + { + // 同步邮件状态给客户端。 + self.Scene.NetworkMessagingComponent.SendInnerRoute(self.GetParent().GateRouteId, new Mail2C_HaveMail() + { + Mail = mail.ToMailSimplifyInfo() + }); + } + + // 这里的保存,也可以不用,这里看情况而定。 + await self.Scene.World.DataBase.Save(self); + Log.Info($"MailComponentSystem Add {mail.Id} Count:{self.Mails.Count}"); + } + + public static async FTask Remove(this MailComponent self, long mailId, MailRemoveActionType mailRemoveActionType ,bool sync) + { + if (!self.Mails.Remove(mailId, out var mail)) + { + // 这里的1代表的没有找到对应邮件。 + return 1; + } + + self.Timer.RemoveValue(mail.ExpireTime, mail.Id); + mail.Dispose(); + + if (sync) + { + // 同步给客户端,邮件删除的消息。 + self.Scene.NetworkMessagingComponent.SendInnerRoute(self.GetParent().GateRouteId, + new Mail2C_MailState() + { + MailState = (int)mailRemoveActionType, MailId = mailId + }); + } + + // 保存下数据库。 + await self.Scene.World.DataBase.Save(self); + Log.Info($"MailComponentSystem Remove {mailId} mailRemoveActionType:{mailRemoveActionType} Count:{self.Mails.Count}"); + return 0; + } + + public static async FTask CheckTimeOut(this MailComponent self) + { + var now = TimeHelper.Now; + using var listPool = ListPool.Create(); + + foreach (var (_, mail) in self.Mails) + { + if (mail.ExpireTime > now) + { + continue; + } + + listPool.Add(mail.Id); + } + + foreach (var mailId in listPool) + { + await self.Remove(mailId, MailRemoveActionType.ExpireTimeRemove,false); + } + + Log.Info($"MailComponentSystem CheckTimeOut Count:{listPool.Count}"); + } + + public static async FTask<(uint ErrorCode, Mail mail)> OpenMail(this MailComponent self, long mailId) + { + if (!self.Mails.TryGetValue(mailId, out var mail)) + { + // 这个1代表的是没有找到对应邮件 + return (1, null); + } + + if (mail.ExpireTime < TimeHelper.Now) + { + // 如果邮件已经过期了,需要清楚这个邮件。 + await self.Remove(mailId, MailRemoveActionType.ExpireTimeRemove, true); + // 这里2代表的是邮件已经过期。 + return (2, null); + } + + mail.MailState = MailState.HaveRead; + // 这个保存数据库不是必须要保存的,因为一个邮件的查看状态并不能影响游戏的逻辑。 + // 这里的话,大家看自己的需求而定。 + await self.Scene.World.DataBase.Save(self); + return (0, mail); + } + + public static void GetMailSimplifyInfos(this MailComponent self, ICollection mailSimplifyInfos) + { + foreach (var (_, mail) in self.Mails) + { + mailSimplifyInfos.Add(mail.ToMailSimplifyInfo()); + } + } + + public static void GetMailSimplifyInfos(this MailComponent self, ICollection mailSimplifyInfos, int pageIndex, int pageSize) + { + foreach (var (_, mail) in self.Mails.Skip((pageIndex -1) * pageSize).Take(pageSize)) + { + mailSimplifyInfos.Add(mail.ToMailSimplifyInfo()); + } + } + + public static async FTask Receive(this MailComponent self, long mailId, bool money, List item, bool sync) + { + if (!self.Mails.TryGetValue(mailId, out var mail)) + { + // 这里的1代表是没有找到该邮件。 + return 1; + } + + var needSave = false; + + if (money && mail.Money > 0) + { + // 领取金钱一般都是在玩家身上,但现在咱们所在的服务器是Mail服务器,玩家并不在这个服务器. + // 所以一般金钱的操作会有一个专用的接口来操作。这个接口无论在什么服务器上,都会正确的发送到用户所在的服务器上进行金钱操作。 + // 假设下面的增加金钱的一个异步接口。 + // var resposne = await MoneyHelper.Add(self.Scene, mail.Money, sync); + // if (resposne.ErrorCode != 0) + // { + // // 这里的2代表的是金钱添加失败。 + // return 2; + // } + // 再假设增加金钱是成功的,那么咱们就要处理邮件相关信息了。 + mail.Money = 0; + needSave = true; + } + + if (item != null && item.Count > 0) + { + using var listItem = ListPool.Create(); + foreach (var itemId in item) + { + var rItem = mail.Items.FirstOrDefault(d => d.Id == itemId); + if (rItem == null) + { + continue; + } + listItem.Add(rItem); + } + + // 假设背包在其他服务器,需要调用某一个接口来添加物品到目标服务器的背包身上。 + // var response = await BagHelper.Add(self.Scene, listItem, sync); + // if (response.ErrorCode != 0) + // { + // return 2; + // } + // 还有一种情况,就是背包里的空间只有一个空余位置了,也就是只能放进一个物品了,但是邮件领取的是2个物品. + // 会有下面2中情况,当然这个情况是要策划来决定怎么处理: + // 1、只领取一个物品到背包中,另外一个不领取,然后提示用户背包已满。 + // 2、一个都不领取,直接提示用户背包已满。 + // 如果是是第一种情况下,把BagHelper.Add接口,就需要返回添加成功的物品ID,方便邮件来处理。 + // 假设全部物品都领取成功了,就可以执行下面的逻辑了。 + + foreach (var item1 in listItem) + { + mail.Items.Remove(item1); + item1.Dispose(); + } + + needSave = true; + } + + if (needSave) + { + await self.Scene.World.DataBase.Save(self); + } + + return 0; + } +} \ No newline at end of file diff --git a/邮件系统课程完整代码/Server/Hotfix/Mail/Components/MailUnitManageComponentSystem.cs b/邮件系统课程完整代码/Server/Hotfix/Mail/Components/MailUnitManageComponentSystem.cs new file mode 100644 index 0000000..07cdef2 --- /dev/null +++ b/邮件系统课程完整代码/Server/Hotfix/Mail/Components/MailUnitManageComponentSystem.cs @@ -0,0 +1,176 @@ +using Fantasy.Async; +using Fantasy.Entitas; +using Fantasy.Entitas.Interface; +using Fantasy.Helper; +// ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract +#pragma warning disable CS8601 // Possible null reference assignment. + +namespace Fantasy; + +public sealed class MailUnitManageComponentDestroySystem : DestroySystem +{ + protected override void Destroy(MailUnitManageComponent self) + { + // 如果不是在.net8的环境下,比如是Unity里。这个的foreach有可能会出现问题 + // 问题的原因是有可能你在mailUnit组件的销毁的时候,去UnitByAccountId删除。 + // 这样就会出现了一个经典的错误,就是无法再foreach里删除或改变元素。 + foreach (var (_, mailUnit) in self.UnitByAccountId) + { + mailUnit.Dispose(); + } + + self.UnitByAccountId.Clear(); + self.UnitByName.Clear(); + self.Online.Clear(); + } +} + +public static class MailUnitManageComponentSystem +{ + public static async FTask Init(this MailUnitManageComponent self) + { + var units = await self.Scene.World.DataBase.Query(d => true, true); + foreach (var mailUnit in units) + { + self.UnitByName.Add(mailUnit.Name, mailUnit); + self.UnitByAccountId.Add(mailUnit.AccountId,mailUnit); + } + Log.Debug($"MailUnitManageComponent Init units:{units.Count}"); + } + + /// + /// 用户中心登录逻辑,如果有更新的数据,会自动更新。 + /// + /// + /// + /// + /// + /// + public static async FTask Online(this MailUnitManageComponent self, long accountId, string unitName, long gateRouteId) + { + var selfScene = self.Scene; + + if (self.UnitByAccountId.TryGetValue(accountId, out var mailUnit)) + { + Log.Debug($"用户已经存在行不需要重新创建 Name:{unitName} mailUnit:{mailUnit.RuntimeId}"); + if (mailUnit.Name != unitName) + { + // 如果不一致的情况,要先删除之前的缓存,然后再添加到缓存。 + self.UnitByName.Remove(mailUnit.Name); + self.UnitByName.Add(unitName, mailUnit); + mailUnit.Name = unitName; + } + } + else + { + // 创建新的MailUnit实体。 + mailUnit = Entity.Create(selfScene,accountId, true, true); + mailUnit.Name = unitName; + mailUnit.AccountId = accountId; + mailUnit.CreateTime = TimeHelper.Now; + // 把创建好的实体添加到缓存中,方便后面使用。 + self.UnitByAccountId.Add(accountId, mailUnit); + self.UnitByName.Add(unitName,mailUnit); + Log.Debug($"用户不存在行需要创建 Name:{unitName} mailUnit:{mailUnit.RuntimeId}"); + } + // 设置GateRouteId + mailUnit.GateRouteId = gateRouteId; + // 设置MailComponent + if (mailUnit.GetComponent() == null) + { + // 数据库中查询这个组件是否存在。 + var mailComponent = await selfScene.World.DataBase.Query(mailUnit.Id, true); + if (mailComponent == null) + { + // MailUnit没有这个MailComponent组件,就给添加一个新的组件。 + mailUnit.AddComponent(); + } + else + { + mailUnit.AddComponent(mailComponent); + } + } + // 可选,如果你不需要保存到数据库,那么可以忽略下面的代码。 + await selfScene.World.DataBase.Save(mailUnit); + // 领取下离线的邮件。如果有的情况下。 + await selfScene.GetComponent().GetHaveMail(mailUnit, true); + // 把用户添加到在线的列表 + self.Online.Add(mailUnit.Id, mailUnit); + // 返回MailUnit实体。 + return mailUnit; + } + + /// + /// 退出登录逻辑,会自动保存数据。 + /// + /// + /// + public static async FTask Exit(this MailUnitManageComponent self, MailUnit mailUnit) + { + var mailComponent = mailUnit.GetComponent(); + if (mailComponent == null) + { + return; + } + + // 保存mailComponent到数据库中。 + await self.Scene.World.DataBase.Save(mailComponent); + // 移除这个组件。 + mailUnit.RemoveComponent(); + // 在在线列表的容器中,移除这个MailUnit实体。 + self.Online.Remove(mailUnit.Id); + Log.Debug($"AccountId:{mailUnit.AccountId} Name:{mailUnit.Name} Exit!"); + } + + /// + /// 根据UnitName获取MailUnit实体 + /// + /// + /// + /// + /// + public static bool TryGet(this MailUnitManageComponent self, string unitName, out MailUnit mailUnit) + { + return self.UnitByName.TryGetValue(unitName, out mailUnit); + } + + /// + /// 根据AccountId获取MailUnit实体 + /// + /// + /// + /// + /// + public static bool TryGet(this MailUnitManageComponent self, long accountId, out MailUnit mailUnit) + { + return self.UnitByAccountId.TryGetValue(accountId, out mailUnit); + } + + /// + /// 删除MailUnit实体。 + /// + /// + /// + /// + public static async FTask Remove(this MailUnitManageComponent self, long accountId) + { + // if (!self.UnitByAccountId.TryGetValue(accountId, out var mailUnit)) + // { + // // 这个1代表的是没有找到对应的MailUnit + // return 1; + // } + + if (!self.UnitByAccountId.Remove(accountId, out var mailUnit)) + { + // 这个1代表的是没有找到对应的MailUnit + return 1; + } + + self.UnitByName.Remove(mailUnit.Name); + // 在数据库中删除MailUnit实体 + await self.Scene.World.DataBase.Remove(mailUnit.Id); + // 销毁这个MailUnit + mailUnit.Dispose(); + return 0; + } +} \ No newline at end of file diff --git a/邮件系统课程完整代码/Server/Hotfix/Mail/Entity/MailBoxSystem.cs b/邮件系统课程完整代码/Server/Hotfix/Mail/Entity/MailBoxSystem.cs new file mode 100644 index 0000000..47dee76 --- /dev/null +++ b/邮件系统课程完整代码/Server/Hotfix/Mail/Entity/MailBoxSystem.cs @@ -0,0 +1,22 @@ +using Fantasy.Entitas.Interface; + +namespace Fantasy; + +public class MailBoxDestroySystem : DestroySystem +{ + protected override void Destroy(MailBox self) + { + if (self.Mail != null) + { + self.Mail.Dispose(); + self.Mail = null; + } + + self.MailBoxType = MailBoxType.None; + self.CreateTime = 0; + self.ExpireTime = 0; + self.SendAccountId = 0; + self.AccountId.Clear(); + self.Received.Clear(); + } +} \ No newline at end of file diff --git a/邮件系统课程完整代码/Server/Hotfix/Mail/Entity/MailSystem.cs b/邮件系统课程完整代码/Server/Hotfix/Mail/Entity/MailSystem.cs new file mode 100644 index 0000000..897f4b5 --- /dev/null +++ b/邮件系统课程完整代码/Server/Hotfix/Mail/Entity/MailSystem.cs @@ -0,0 +1,69 @@ +using Fantasy.Entitas.Interface; + +namespace Fantasy; + +public sealed class MailDestroySystem : DestroySystem +{ + protected override void Destroy(Mail self) + { + self.OwnerId = 0; + self.Title = null; + self.Content = null; + self.CreateTime = 0; + self.ExpireTime = 0; + self.Money = 0; + self.MailState = MailState.None; + self.MailType = MailType.None; + + foreach (var selfItem in self.Items) + { + selfItem.Dispose(); + } + + self.Items.Clear(); + } +} + +public static class MailSystem +{ + public static MailSimplifyInfo ToMailSimplifyInfo(this Mail self) + { + return new MailSimplifyInfo() + { + MailId = self.Id, + OwnerId = self.OwnerId, + Title = self.Title, + Content = self.Content, + CreateTime = self.CreateTime, + ExpireTime = self.ExpireTime, + MailState = (int)self.MailState, + MailType = (int)self.MailType + }; + } + + public static MailInfo ToMailInfo(this Mail self) + { + var mailInfo = new MailInfo() + { + MailId = self.Id, + OwnerId = self.OwnerId, + Title = self.Title, + Content = self.Content, + CreateTime = self.CreateTime, + ExpireTime = self.ExpireTime, + Money = self.Money, + MailState = (int)self.MailState, + MailType = (int)self.MailType + }; + + foreach (var selfItem in self.Items) + { + mailInfo.Items.Add(new ItemInfo() + { + Name = selfItem.Name, + }); + } + + return mailInfo; + } +} \ No newline at end of file diff --git a/邮件系统课程完整代码/Server/Hotfix/Mail/Entity/MailUnitSystem.cs b/邮件系统课程完整代码/Server/Hotfix/Mail/Entity/MailUnitSystem.cs new file mode 100644 index 0000000..0af77bc --- /dev/null +++ b/邮件系统课程完整代码/Server/Hotfix/Mail/Entity/MailUnitSystem.cs @@ -0,0 +1,14 @@ +using Fantasy.Entitas.Interface; + +namespace Fantasy; + +public class MailUnitDestroySystem: DestroySystem +{ + protected override void Destroy(MailUnit self) + { + self.Name = null; + self.AccountId = 0; + self.CreateTime = 0; + self.GateRouteId = 0; + } +} \ No newline at end of file diff --git a/邮件系统课程完整代码/Server/Hotfix/Mail/Handler/Inner/Other2Mail_SendRequestHandler.cs b/邮件系统课程完整代码/Server/Hotfix/Mail/Handler/Inner/Other2Mail_SendRequestHandler.cs new file mode 100644 index 0000000..ae89e6d --- /dev/null +++ b/邮件系统课程完整代码/Server/Hotfix/Mail/Handler/Inner/Other2Mail_SendRequestHandler.cs @@ -0,0 +1,12 @@ +using Fantasy.Async; +using Fantasy.Network.Interface; + +namespace Fantasy; + +public class Other2Mail_SendRequestHandler : RouteRPC +{ + protected override async FTask Run(Scene scene, Other2Mail_SendMailRequest request, Mail2Other_SendMailResponse response, Action reply) + { + await MailHelper.Send(scene, request.MailBox); + } +} \ No newline at end of file diff --git a/邮件系统课程完整代码/Server/Hotfix/Mail/Handler/Outer/C2Mail_GetHaveMailRequestHandler.cs b/邮件系统课程完整代码/Server/Hotfix/Mail/Handler/Outer/C2Mail_GetHaveMailRequestHandler.cs new file mode 100644 index 0000000..36ee135 --- /dev/null +++ b/邮件系统课程完整代码/Server/Hotfix/Mail/Handler/Outer/C2Mail_GetHaveMailRequestHandler.cs @@ -0,0 +1,25 @@ +using Fantasy.Async; +using Fantasy.Network.Interface; +// ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract + +namespace Fantasy; + +public sealed class C2Mail_GetHaveMailRequestHandler : RouteRPC +{ + protected override async FTask Run(MailUnit mailUnit, C2Mail_GetHaveMailRequest request, Mail2C_GetHaveMailResposne response, Action reply) + { + var mailComponent = mailUnit.GetComponent(); + + // 这个mailComponent是不是可能会为空?答案是可能的。 + // 那如果是空的怎么办呢,这样情况只能是别人恶意发包了。 + + if (mailComponent == null) + { + return; + } + // 检查是否有超时的邮件。如果有那就清楚掉 + await mailComponent.CheckTimeOut(); + // 领取当前的邮件 + mailComponent.GetMailSimplifyInfos(response.Mails); + } +} \ No newline at end of file diff --git a/邮件系统课程完整代码/Server/Hotfix/Mail/Handler/Outer/C2Mail_OpenMailRequestHandler.cs b/邮件系统课程完整代码/Server/Hotfix/Mail/Handler/Outer/C2Mail_OpenMailRequestHandler.cs new file mode 100644 index 0000000..40f9cff --- /dev/null +++ b/邮件系统课程完整代码/Server/Hotfix/Mail/Handler/Outer/C2Mail_OpenMailRequestHandler.cs @@ -0,0 +1,32 @@ +using Fantasy.Async; +using Fantasy.Network.Interface; + +namespace Fantasy; + +public class C2Mail_OpenMailRequestHandler : RouteRPC +{ + protected override async FTask Run(MailUnit mailUnit, C2Mail_OpenMailRequest request, Mail2C_OpenMailResposne response, Action reply) + { + if (request.MailId <= 0) + { + response.ErrorCode = 100; + return; + } + + // 根据这个MailId来拿到邮件的详细信息 + var (errorCode, mail) = await mailUnit.GetComponent().OpenMail(request.MailId); + + if (errorCode != 0) + { + response.ErrorCode = errorCode; + return; + } + + if (!request.ReturnMailInfo) + { + return; + } + + response.MailInfo = mail.ToMailInfo(); + } +} \ No newline at end of file diff --git a/邮件系统课程完整代码/Server/Hotfix/Mail/Handler/Outer/C2Mail_ReceiveMailRequestHandler.cs b/邮件系统课程完整代码/Server/Hotfix/Mail/Handler/Outer/C2Mail_ReceiveMailRequestHandler.cs new file mode 100644 index 0000000..e86b935 --- /dev/null +++ b/邮件系统课程完整代码/Server/Hotfix/Mail/Handler/Outer/C2Mail_ReceiveMailRequestHandler.cs @@ -0,0 +1,19 @@ +using Fantasy.Async; +using Fantasy.Network.Interface; + +namespace Fantasy; + +public class C2Mail_ReceiveMailRequestHandler : RouteRPC +{ + protected override async FTask Run(MailUnit mailUnit, C2Mail_ReceiveMailRequest request, Mail2C_ReceiveMailResponse response, Action reply) + { + if (request.MailId <= 0) + { + response.ErrorCode = 100; + return; + } + + response.ErrorCode = await mailUnit.GetComponent() + .Receive(request.MailId, request.Money, request.ItemId, true); + } +} \ No newline at end of file diff --git a/邮件系统课程完整代码/Server/Hotfix/Mail/Handler/Outer/C2Mail_RemoveMailRequestHandler.cs b/邮件系统课程完整代码/Server/Hotfix/Mail/Handler/Outer/C2Mail_RemoveMailRequestHandler.cs new file mode 100644 index 0000000..bb2454e --- /dev/null +++ b/邮件系统课程完整代码/Server/Hotfix/Mail/Handler/Outer/C2Mail_RemoveMailRequestHandler.cs @@ -0,0 +1,21 @@ +using Fantasy.Async; +using Fantasy.Network.Interface; + +namespace Fantasy; + +public class C2Mail_RemoveMailRequestHandler : RouteRPC +{ + protected override async FTask Run(MailUnit mailUnit, C2Mail_RemoveMailRequest request, Mail2C_RemoveMailResponse response, Action reply) + { + if (request.MailId <= 0) + { + // 这里的1代表MailId不正确。 + response.ErrorCode = 1; + return; + } + + response.ErrorCode = await mailUnit.GetComponent() + .Remove(request.MailId, MailRemoveActionType.Remove, true); + + } +} \ No newline at end of file diff --git a/邮件系统课程完整代码/Server/Hotfix/Mail/Handler/Outer/C2Mail_SendMailRequestHandler.cs b/邮件系统课程完整代码/Server/Hotfix/Mail/Handler/Outer/C2Mail_SendMailRequestHandler.cs new file mode 100644 index 0000000..edda479 --- /dev/null +++ b/邮件系统课程完整代码/Server/Hotfix/Mail/Handler/Outer/C2Mail_SendMailRequestHandler.cs @@ -0,0 +1,67 @@ +using Fantasy.Async; +using Fantasy.DataStructure.Collection; +using Fantasy.Network.Interface; + +namespace Fantasy; + +public class C2Mail_SendMailRequestHandler : RouteRPC +{ + protected override async FTask Run(MailUnit mailUnit, C2Mail_SendMailRequest request, Mail2C_SendMailResponse response, Action reply) + { + if (string.IsNullOrEmpty(request.UserName)) + { + // 这里的1代表的是发送的接收玩家名字不正确。 + response.ErrorCode = 1; + return; + } + + if (string.IsNullOrEmpty(request.Title) || string.IsNullOrEmpty(request.Content)) + { + // 这里的2代表的是发送的邮件标题或者内容不正确。 + response.ErrorCode = 2; + return; + } + + if (request.ItemId.Count > 10) + { + // 这里的3代表的是发送的邮件附件超出了最大范围。 + response.ErrorCode = 3; + return; + } + + if (!mailUnit.Scene.GetComponent().TryGet(request.UserName, out var receiveMailUnit)) + { + // 这里的4代表的是没有该玩家。 + response.ErrorCode = 4; + return; + } + + if (request.Money > 0) + { + // 如果大于0,就要调用某一个接口去货币所在的服务器上面去扣除玩家的钱。 + // var moneyResposne = await MoneyHelper.Cost(mailUnit.Scene, request.Money); + // if (moneyResposne.ErrorCode != 0) + // { + // response.ErrorCode = moneyResposne.ErrorCode; + // return; + // } + } + + using var mailItems = ListPool.Create(); + if (request.ItemId.Count > 0) + { + // var itemResposne = await BagHelper.Get(mailUnit.Scene, request.ItemId); + // if (itemResposne.ErrorCode != 0) + // { + // response.ErrorCode = itemResposne.ErrorCode; + // return; + // } + // mailItems.AddRange(itemResposne.Items); + } + + var accountId = ListPool.Create(receiveMailUnit.AccountId); + var mail = MailFactory.Create(mailUnit.Scene, MailType.User, request.Title, request.Content, request.Money, mailItems); + var mailBox = MailBoxFactory.Create(mailUnit.Scene, MailBoxType.Specify, mailUnit.AccountId, mail, 1000 * 60 * 60, accountId); + await MailHelper.Send(mailUnit.Scene, mailBox); + } +} \ No newline at end of file diff --git a/邮件系统课程完整代码/Server/Hotfix/Mail/Handler/Outer/C2Mail_TestRequestHandler.cs b/邮件系统课程完整代码/Server/Hotfix/Mail/Handler/Outer/C2Mail_TestRequestHandler.cs new file mode 100644 index 0000000..ed4dc3e --- /dev/null +++ b/邮件系统课程完整代码/Server/Hotfix/Mail/Handler/Outer/C2Mail_TestRequestHandler.cs @@ -0,0 +1,19 @@ +using Fantasy.Async; +using Fantasy.DataStructure.Collection; +using Fantasy.Network.Interface; + +namespace Fantasy; + +public class C2Mail_TestRequestHandler : RouteRPC +{ + protected override async FTask Run(MailUnit mailUnit, C2Mail_TestRequest request, Mail2C_TestResponse response, Action reply) + { + Log.Debug($"这是一个测试的自定义消息协议 Tag:{mailUnit.Name}"); + response.Tag = "666"; + // using var accountId = ListPool.Create(65491190472245249); + var mail = MailFactory.Create(mailUnit.Scene, MailType.System, "测试所有人指定日期玩家邮件", "测试所有人指定日期玩家邮件内容", 9991); + var mailBox = MailBoxFactory.Create(mailUnit.Scene, MailBoxType.AllToDate, mailUnit.AccountId, mail, + 1000 * 60 * 60); + await MailHelper.Send(mailUnit.Scene, mailBox); + } +} \ No newline at end of file diff --git a/邮件系统课程完整代码/Server/Hotfix/Mail/Handler/Outer/G2Mail_ExitRequestHandler.cs b/邮件系统课程完整代码/Server/Hotfix/Mail/Handler/Outer/G2Mail_ExitRequestHandler.cs new file mode 100644 index 0000000..508e45e --- /dev/null +++ b/邮件系统课程完整代码/Server/Hotfix/Mail/Handler/Outer/G2Mail_ExitRequestHandler.cs @@ -0,0 +1,12 @@ +using Fantasy.Async; +using Fantasy.Network.Interface; + +namespace Fantasy; + +public class G2Mail_ExitRequestHandler : RouteRPC +{ + protected override async FTask Run(MailUnit mailUnit, G2Mail_ExitRequest request, Mail2G_ExitResponse response, Action reply) + { + await mailUnit.Scene.GetComponent().Exit(mailUnit); + } +} \ No newline at end of file diff --git a/邮件系统课程完整代码/Server/Hotfix/Mail/Handler/Outer/G2Mail_LoginRequestHandler.cs b/邮件系统课程完整代码/Server/Hotfix/Mail/Handler/Outer/G2Mail_LoginRequestHandler.cs new file mode 100644 index 0000000..9f6ec1a --- /dev/null +++ b/邮件系统课程完整代码/Server/Hotfix/Mail/Handler/Outer/G2Mail_LoginRequestHandler.cs @@ -0,0 +1,26 @@ +using Fantasy.Async; +using Fantasy.Entitas; +using Fantasy.Network.Interface; + +namespace Fantasy; + +public sealed class G2Mail_LoginRequestHandler : RouteRPC +{ + protected override async FTask Run(Scene scene, G2Mail_LoginRequest request, Mail2G_LoginResponse response, Action reply) + { + // Scene也是继承Entity + // 只要能知道Entity的RuntimeId,就可以通过这个RuntimeId发送消息了。 + // 并且接收消息的Handler,第一个参数的实体可以变成这个Entity的实体 + // 也可以理解为这个RuntimeId其实就是RouteId + + // var mailUnit = Entity.Create(scene, request.AccountId, true, true); + // mailUnit.Name = request.Name; + // Log.Debug($"SceneType:{scene.SceneType} Name:{request.Name} mailUnit:{mailUnit.RuntimeId}"); + // response.MailUnitRouteId = mailUnit.RuntimeId; + + var mailUnit = await scene.GetComponent() + .Online(request.AccountId, request.Name, request.GateRouteId); + response.MailUnitRouteId = mailUnit.RuntimeId; + await FTask.CompletedTask; + } +} \ No newline at end of file diff --git a/邮件系统课程完整代码/Server/Hotfix/Mail/Handler/Outer/G2Mail_TestMessageHandler.cs b/邮件系统课程完整代码/Server/Hotfix/Mail/Handler/Outer/G2Mail_TestMessageHandler.cs new file mode 100644 index 0000000..95efab0 --- /dev/null +++ b/邮件系统课程完整代码/Server/Hotfix/Mail/Handler/Outer/G2Mail_TestMessageHandler.cs @@ -0,0 +1,13 @@ +using Fantasy.Async; +using Fantasy.Network.Interface; + +namespace Fantasy; + +public sealed class G2Mail_TestMessageHandler : Route +{ + protected override async FTask Run(MailUnit mailUnit, G2Mail_TestMessage message) + { + Log.Debug($"这是一个测试的消息协议 Tag:{mailUnit.Name}"); + await FTask.CompletedTask; + } +} \ No newline at end of file diff --git a/邮件系统课程完整代码/Server/Hotfix/Mail/Helper/MailBoxFactory.cs b/邮件系统课程完整代码/Server/Hotfix/Mail/Helper/MailBoxFactory.cs new file mode 100644 index 0000000..8c34d23 --- /dev/null +++ b/邮件系统课程完整代码/Server/Hotfix/Mail/Helper/MailBoxFactory.cs @@ -0,0 +1,62 @@ +using Fantasy.Entitas; +using Fantasy.Helper; +// ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract +#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. + +namespace Fantasy; + +public static class MailBoxFactory +{ + /// + /// 创建一个邮件箱 + /// + /// + /// + /// + /// + /// + /// + /// + public static MailBox Create(Scene scene, MailBoxType mailBoxType, long sendAccountId, Mail mail, int expireTime, List accountId = null) + { + var mailBox = Entity.Create(scene, true, true); + mailBox.SendAccountId = sendAccountId; + mailBox.Mail = mail; + mailBox.MailBoxType = mailBoxType; + mailBox.CreateTime = TimeHelper.Now; + mailBox.ExpireTime = mailBox.CreateTime + expireTime; + + if (accountId == null || accountId.Count <= 0) + { + return mailBox; + } + + foreach (var raId in accountId) + { + mailBox.AccountId.Add(raId); + } + + return mailBox; + } + + /// + /// 创建一个邮件箱 + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + public static MailBox Create(Scene scene, MailType mailType, MailBoxType mailBoxType, string title, string content, int money, List items, + long sendAccountId, int expireTime, List accountId = null) + { + var mail = MailFactory.Create(scene, mailType,title, content, money, items); + return Create(scene, mailBoxType, sendAccountId, mail, expireTime, accountId); + } +} \ No newline at end of file diff --git a/邮件系统课程完整代码/Server/Hotfix/Mail/Helper/MailFactory.cs b/邮件系统课程完整代码/Server/Hotfix/Mail/Helper/MailFactory.cs new file mode 100644 index 0000000..4bdf41f --- /dev/null +++ b/邮件系统课程完整代码/Server/Hotfix/Mail/Helper/MailFactory.cs @@ -0,0 +1,47 @@ +using Fantasy.Entitas; +using Fantasy.Serialize; +#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type. + +namespace Fantasy; + +public static class MailFactory +{ + public static readonly ISerialize Serializer = SerializerManager.GetSerializer(FantasySerializerType.Bson); + + /// + /// 创建一个基础的邮件 + /// + /// + /// + /// + /// + /// + /// + /// + public static Mail Create(Scene scene, MailType mailType, string title, string content, int money = 0, List items = null) + { + var mail = Entity.Create(scene, true, true); + mail.Title = title; + mail.Content = content; + mail.Money = money; + mail.MailType = mailType; + mail.MailState = MailState.Unread; + + // if (items is not { Count: > 0 }) + // { + // + // } + if (items != null && items.Count > 0) + { + foreach (var item in items) + { + // 最好的是要个这个Item给克隆出一份来。 + // 这样就可以保证,无论外面怎么改变也不会影响这个邮件的东西了。 + var cloneItem = Serializer.Clone(item); + mail.Items.Add(cloneItem); + } + } + + return mail; + } +} \ No newline at end of file diff --git a/邮件系统课程完整代码/Server/Hotfix/Mail/Helper/MailHelper.cs b/邮件系统课程完整代码/Server/Hotfix/Mail/Helper/MailHelper.cs new file mode 100644 index 0000000..a3be485 --- /dev/null +++ b/邮件系统课程完整代码/Server/Hotfix/Mail/Helper/MailHelper.cs @@ -0,0 +1,193 @@ +using Fantasy.Async; +using Fantasy.DataStructure.Collection; +using Fantasy.Platform.Net; + +// ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract + +namespace Fantasy; + +/// +/// 发送邮件的唯一接口 +/// 如果不是通过这个接口发送的邮件、出现任何问题,后果自负 +/// +public static class MailHelper +{ + /// + /// 发送邮件 + /// + /// + /// 发送完成后,记着一定要销毁这个MailBox,不然会有GC。 + public static async FTask Send(Scene scene, MailBox mailBox) + { + if (scene.SceneType == SceneType.Mail) + { + await InnerSend(scene, mailBox); + return; + } + + // 如果不在同一个Scene下,就需要发送内部的网络消息给这个Scene了 + var mailSceneConfig = SceneConfigData.Instance.GetSceneBySceneType(SceneType.Mail)[0]; + await scene.NetworkMessagingComponent.CallInnerRoute(mailSceneConfig.RouteId, new Other2Mail_SendMailRequest() + { + MailBox = mailBox + }); + } + + /// + /// 发送邮件 + /// + /// + /// + /// + private static async FTask InnerSend(Scene scene, MailBox mailBox) + { + // 现在的情况,这个接口只能是在Mail这个服务器下可以操作 + // 但是真实的情况,其他同时开发的逻辑,调用这个接口一般都是在其他的服务器。 + // 这个问题其实很好解决,只需要判定当前Scene不是Mail、那就做一个协议,自动发送到这个MailScene就可以了。 + + if (mailBox.MailBoxType == MailBoxType.None) + { + Log.Error("MailBoxType MailBoxType.None not support!"); + return; + } + + var mailUnitManageComponent = scene.GetComponent(); + var mailBoxManageComponent = scene.GetComponent(); + mailBoxManageComponent.MailBoxes.Add(mailBox.Id, mailBox); + + switch (mailBox.MailBoxType) + { + case MailBoxType.Specify: + { + if (mailBox.AccountId.Count <= 0) + { + Log.Error($"{mailBox.Id} AccountId is 0!"); + return; + } + + // 这里可能有几种情况 + // 1、AccountId里面可能只有一个人。 + // 2、AccountId里面有多个人。 + + using var sendAccountIds = ListPool.Create(); + + foreach (var accountId in mailBox.AccountId) + { + if (!mailUnitManageComponent.TryGet(accountId, out var mailUnit)) + { + // 如果没有的话,代表这个用户根本不存在。 + // 那这样的情况就不需要做任何处理。 + continue; + } + + // 如果有的话,那么就给这个用户发送邮件。 + // 这个玩家是否在线? + var mailComponent = mailUnit.GetComponent(); + // 在线的话,就直接发送邮件给这个玩家就可以了。 + if (mailComponent != null) + { + await mailComponent.Add(MailFactory.Serializer.Clone(mailBox.Mail), true); + sendAccountIds.Add(accountId); + } + else + { + // 不在线 + // 首先 + // 1、如果玩家不在线,那就把这个邮件在数据库中拿出来,然后把邮件插入到玩家的邮件列表里。然后再保存 + // 这样的做法是不推荐的,因为咱们游戏所有的东西都是有状态的,但是你拿出来的邮件是没有状态的。这样可能会导致一些问题的出现。 + // 正确的做做法: + // 把这个邮件方法一个地方,比如是一个处理中心,当玩家上线的时候,主动去这个中心领取这个邮件。 + // 快递驿站、菜鸟、 + mailBoxManageComponent.MailsByAccount.Add(accountId, mailBox); + Log.Debug("发送离线邮件成功,用户上线第一时间会领取这个邮件。"); + } + } + + // 移除掉发送成功的账号。 + + foreach (var sendAccountId in sendAccountIds) + { + mailBox.AccountId.Remove(sendAccountId); + } + + // 如果没有任何收件人了、就可以把这个邮箱给删除了。 + + if (mailBox.AccountId.Count <= 0) + { + mailBox.Dispose(); + } + else + { + // 当这个邮件箱还有没有接收的玩家时候,要保存到数据库中,方便下次停服维护再重新启动的时候,加载这个邮件箱。 + await scene.World.DataBase.Save(mailBox); + Log.Debug("保存离线邮件成功"); + } + + break; + } + case MailBoxType.Online: + { + // // 这里有个问题,如何知道在线的人呢? + // foreach (var (_, mailUnit) in mailUnitManageComponent.UnitByAccountId) + // { + // var mailComponent = mailUnit.GetComponent(); + // if (mailComponent == null) + // { + // continue; + // } + // // 能指定到这里的都是在线的玩家。 + // await mailComponent.Add(MailFactory.Serializer.Clone(mailBox.Mail), true); + // } + try + { + foreach (var (_, mailUnit) in mailUnitManageComponent.Online) + { + await mailUnit.GetComponent().Add(MailFactory.Serializer.Clone(mailBox.Mail), true); + } + } + finally + { + mailBox.Dispose(); + } + break; + } + case MailBoxType.All: + { + // 要保证这个邮件一定要有一个生命周期。并且这个周期一定要短,如果是想要实现永久的,可以比如30天发送一次。 + mailBoxManageComponent.MailsByMailBoxType.Add((int)MailBoxType.All, mailBox); + // 首先给所有在线的玩家发送。 + foreach (var (_, mailUnit) in mailUnitManageComponent.Online) + { + await mailUnit.GetComponent().Add(MailFactory.Serializer.Clone(mailBox.Mail), true); + // 在邮件盒子中记录下玩家领取的记录,避免重复领取。 + mailBox.Received.Add(mailUnit.Id); + } + // 保存邮件箱到数据库。 + await scene.World.DataBase.Save(mailBox); + break; + } + case MailBoxType.AllToDate: + { + mailBoxManageComponent.MailsByMailBoxType.Add((int)MailBoxType.AllToDate, mailBox); + foreach (var (_, mailUnit) in mailUnitManageComponent.Online) + { + if (mailUnit.CreateTime > mailBox.CreateTime) + { + // 如果执行到这里,表示这里用户是这个邮件创建之后的用户。这个就不要发送了 + continue; + } + + // 所以这个邮件类型的逻辑就是,给当前邮件创建时间之前的玩家发送。 + await mailUnit.GetComponent().Add(MailFactory.Serializer.Clone(mailBox.Mail), true); + // 在邮件盒子中记录下玩家领取的记录,避免重复领取。 + mailBox.Received.Add(mailUnit.Id); + } + // 保存邮件箱到数据库。 + await scene.World.DataBase.Save(mailBox); + break; + } + // 根据玩家等级、等等这样的邮件箱类型,都可以自行扩展了 + // 课下作业、自己实现一个起来类型的邮箱。 + } + } +} \ No newline at end of file diff --git a/邮件系统课程完整代码/Server/Hotfix/OnCreateScene_Init.cs b/邮件系统课程完整代码/Server/Hotfix/OnCreateScene_Init.cs new file mode 100644 index 0000000..f75a9aa --- /dev/null +++ b/邮件系统课程完整代码/Server/Hotfix/OnCreateScene_Init.cs @@ -0,0 +1,24 @@ +using Fantasy.Async; +using Fantasy.Event; + +namespace Fantasy; + +public sealed class OnCreateScene_Init : AsyncEventSystem +{ + protected override async FTask Handler(OnCreateScene self) + { + var scene = self.Scene; + + switch (scene.SceneType) + { + case SceneType.Mail: + { + // 离线邮件箱管理组件。 + await scene.AddComponent().Init(); + // 邮件的用户信息管理组件。 + await scene.AddComponent().Init(); + break; + } + } + } +} \ No newline at end of file diff --git a/邮件系统课程完整代码/Server/Hotfix/bin/Debug/net8.0/Entity.dll b/邮件系统课程完整代码/Server/Hotfix/bin/Debug/net8.0/Entity.dll new file mode 100644 index 0000000..7a53135 Binary files /dev/null and b/邮件系统课程完整代码/Server/Hotfix/bin/Debug/net8.0/Entity.dll differ diff --git a/邮件系统课程完整代码/Server/Hotfix/bin/Debug/net8.0/Entity.pdb b/邮件系统课程完整代码/Server/Hotfix/bin/Debug/net8.0/Entity.pdb new file mode 100644 index 0000000..46121e0 Binary files /dev/null and b/邮件系统课程完整代码/Server/Hotfix/bin/Debug/net8.0/Entity.pdb differ diff --git a/邮件系统课程完整代码/Server/Hotfix/bin/Debug/net8.0/Hotfix.deps.json b/邮件系统课程完整代码/Server/Hotfix/bin/Debug/net8.0/Hotfix.deps.json new file mode 100644 index 0000000..f70f15a --- /dev/null +++ b/邮件系统课程完整代码/Server/Hotfix/bin/Debug/net8.0/Hotfix.deps.json @@ -0,0 +1,334 @@ +{ + "runtimeTarget": { + "name": ".NETCoreApp,Version=v8.0", + "signature": "" + }, + "compilationOptions": {}, + "targets": { + ".NETCoreApp,Version=v8.0": { + "Hotfix/1.0.0": { + "dependencies": { + "Entity": "1.0.0" + }, + "runtime": { + "Hotfix.dll": {} + } + }, + "CommandLineParser/2.9.1": { + "runtime": { + "lib/netstandard2.0/CommandLine.dll": { + "assemblyVersion": "2.9.1.0", + "fileVersion": "2.9.1.0" + } + } + }, + "DnsClient/1.6.1": { + "dependencies": { + "Microsoft.Win32.Registry": "5.0.0" + }, + "runtime": { + "lib/net5.0/DnsClient.dll": { + "assemblyVersion": "1.6.1.0", + "fileVersion": "1.6.1.0" + } + } + }, + "Fantasy-Net/2024.2.22": { + "dependencies": { + "CommandLineParser": "2.9.1", + "MongoDB.Bson": "3.1.0", + "MongoDB.Driver": "3.1.0", + "Newtonsoft.Json": "13.0.3", + "System.IO.Pipelines": "9.0.0", + "protobuf-net": "3.2.45" + }, + "runtime": { + "lib/net8.0/Fantasy-Net.dll": { + "assemblyVersion": "1.0.0.0", + "fileVersion": "1.0.0.0" + } + } + }, + "Microsoft.Extensions.Logging.Abstractions/2.0.0": {}, + "Microsoft.NETCore.Platforms/5.0.0": {}, + "Microsoft.Win32.Registry/5.0.0": { + "dependencies": { + "System.Security.AccessControl": "5.0.0", + "System.Security.Principal.Windows": "5.0.0" + } + }, + "MongoDB.Bson/3.1.0": { + "dependencies": { + "System.Memory": "4.5.5", + "System.Runtime.CompilerServices.Unsafe": "5.0.0" + }, + "runtime": { + "lib/net6.0/MongoDB.Bson.dll": { + "assemblyVersion": "3.1.0.0", + "fileVersion": "3.1.0.0" + } + } + }, + "MongoDB.Driver/3.1.0": { + "dependencies": { + "DnsClient": "1.6.1", + "Microsoft.Extensions.Logging.Abstractions": "2.0.0", + "MongoDB.Bson": "3.1.0", + "SharpCompress": "0.30.1", + "Snappier": "1.0.0", + "System.Buffers": "4.5.1", + "ZstdSharp.Port": "0.7.3" + }, + "runtime": { + "lib/net6.0/MongoDB.Driver.dll": { + "assemblyVersion": "3.1.0.0", + "fileVersion": "3.1.0.0" + } + } + }, + "Newtonsoft.Json/13.0.3": { + "runtime": { + "lib/net6.0/Newtonsoft.Json.dll": { + "assemblyVersion": "13.0.0.0", + "fileVersion": "13.0.3.27908" + } + } + }, + "protobuf-net/3.2.45": { + "dependencies": { + "protobuf-net.Core": "3.2.45" + }, + "runtime": { + "lib/net6.0/protobuf-net.dll": { + "assemblyVersion": "3.0.0.0", + "fileVersion": "3.2.45.36865" + } + } + }, + "protobuf-net.Core/3.2.45": { + "dependencies": { + "System.Collections.Immutable": "7.0.0" + }, + "runtime": { + "lib/net6.0/protobuf-net.Core.dll": { + "assemblyVersion": "3.0.0.0", + "fileVersion": "3.2.45.36865" + } + } + }, + "SharpCompress/0.30.1": { + "runtime": { + "lib/net5.0/SharpCompress.dll": { + "assemblyVersion": "0.30.1.0", + "fileVersion": "0.30.1.0" + } + } + }, + "Snappier/1.0.0": { + "runtime": { + "lib/net5.0/Snappier.dll": { + "assemblyVersion": "1.0.0.0", + "fileVersion": "1.0.0.0" + } + } + }, + "System.Buffers/4.5.1": {}, + "System.Collections.Immutable/7.0.0": {}, + "System.IO.Pipelines/9.0.0": { + "runtime": { + "lib/net8.0/System.IO.Pipelines.dll": { + "assemblyVersion": "9.0.0.0", + "fileVersion": "9.0.24.52809" + } + } + }, + "System.Memory/4.5.5": {}, + "System.Runtime.CompilerServices.Unsafe/5.0.0": {}, + "System.Security.AccessControl/5.0.0": { + "dependencies": { + "Microsoft.NETCore.Platforms": "5.0.0", + "System.Security.Principal.Windows": "5.0.0" + } + }, + "System.Security.Principal.Windows/5.0.0": {}, + "ZstdSharp.Port/0.7.3": { + "runtime": { + "lib/net7.0/ZstdSharp.dll": { + "assemblyVersion": "0.7.3.0", + "fileVersion": "0.7.3.0" + } + } + }, + "Entity/1.0.0": { + "dependencies": { + "Fantasy-Net": "2024.2.22" + }, + "runtime": { + "Entity.dll": { + "assemblyVersion": "1.0.0", + "fileVersion": "1.0.0.0" + } + } + } + } + }, + "libraries": { + "Hotfix/1.0.0": { + "type": "project", + "serviceable": false, + "sha512": "" + }, + "CommandLineParser/2.9.1": { + "type": "package", + "serviceable": true, + "sha512": "sha512-OE0sl1/sQ37bjVsPKKtwQlWDgqaxWgtme3xZz7JssWUzg5JpMIyHgCTY9MVMxOg48fJ1AgGT3tgdH5m/kQ5xhA==", + "path": "commandlineparser/2.9.1", + "hashPath": "commandlineparser.2.9.1.nupkg.sha512" + }, + "DnsClient/1.6.1": { + "type": "package", + "serviceable": true, + "sha512": "sha512-4H/f2uYJOZ+YObZjpY9ABrKZI+JNw3uizp6oMzTXwDw6F+2qIPhpRl/1t68O/6e98+vqNiYGu+lswmwdYUy3gg==", + "path": "dnsclient/1.6.1", + "hashPath": "dnsclient.1.6.1.nupkg.sha512" + }, + "Fantasy-Net/2024.2.22": { + "type": "package", + "serviceable": true, + "sha512": "sha512-cT6B0YJ5JmbPHBLYgLeVgg2WbXYxxa1tudoIase88uMzAuqU9t7EQ7dFZGSWjP41c5JOQ/0f1q9lzGWTh/hskw==", + "path": "fantasy-net/2024.2.22", + "hashPath": "fantasy-net.2024.2.22.nupkg.sha512" + }, + "Microsoft.Extensions.Logging.Abstractions/2.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-6ZCllUYGFukkymSTx3Yr0G/ajRxoNJp7/FqSxSB4fGISST54ifBhgu4Nc0ItGi3i6DqwuNd8SUyObmiC++AO2Q==", + "path": "microsoft.extensions.logging.abstractions/2.0.0", + "hashPath": "microsoft.extensions.logging.abstractions.2.0.0.nupkg.sha512" + }, + "Microsoft.NETCore.Platforms/5.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-VyPlqzH2wavqquTcYpkIIAQ6WdenuKoFN0BdYBbCWsclXacSOHNQn66Gt4z5NBqEYW0FAPm5rlvki9ZiCij5xQ==", + "path": "microsoft.netcore.platforms/5.0.0", + "hashPath": "microsoft.netcore.platforms.5.0.0.nupkg.sha512" + }, + "Microsoft.Win32.Registry/5.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-dDoKi0PnDz31yAyETfRntsLArTlVAVzUzCIvvEDsDsucrl33Dl8pIJG06ePTJTI3tGpeyHS9Cq7Foc/s4EeKcg==", + "path": "microsoft.win32.registry/5.0.0", + "hashPath": "microsoft.win32.registry.5.0.0.nupkg.sha512" + }, + "MongoDB.Bson/3.1.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-3dhaZhz18B5vUoEP13o2j8A6zQfkHdZhwBvLZEjDJum4BTLLv1/Z8bt25UQEtpqvYwLgde4R6ekWZ7XAYUMxuw==", + "path": "mongodb.bson/3.1.0", + "hashPath": "mongodb.bson.3.1.0.nupkg.sha512" + }, + "MongoDB.Driver/3.1.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-+O7lKaIl7VUHptE0hqTd7UY1G5KDp/o8S4upG7YL4uChMNKD/U6tz9i17nMGHaD/L2AiPLgaJcaDe2XACsegGA==", + "path": "mongodb.driver/3.1.0", + "hashPath": "mongodb.driver.3.1.0.nupkg.sha512" + }, + "Newtonsoft.Json/13.0.3": { + "type": "package", + "serviceable": true, + "sha512": "sha512-HrC5BXdl00IP9zeV+0Z848QWPAoCr9P3bDEZguI+gkLcBKAOxix/tLEAAHC+UvDNPv4a2d18lOReHMOagPa+zQ==", + "path": "newtonsoft.json/13.0.3", + "hashPath": "newtonsoft.json.13.0.3.nupkg.sha512" + }, + "protobuf-net/3.2.45": { + "type": "package", + "serviceable": true, + "sha512": "sha512-5UZ/ukUHcGbFSl7vNMrHsfjqdxusdd9w7w0fCEXzf3UUtsrGNVCzV5SmF+sCHAbnRV2qPcD1ixiDP7Aj8lX/HA==", + "path": "protobuf-net/3.2.45", + "hashPath": "protobuf-net.3.2.45.nupkg.sha512" + }, + "protobuf-net.Core/3.2.45": { + "type": "package", + "serviceable": true, + "sha512": "sha512-PMWatW2NrT1uTXD7etJ4VdQ0wWZLFrIfdRGppD2QX7nzZ0+kIzqhq551u6ZiXJHWJgG4hWFEkSnUnt2aB6posg==", + "path": "protobuf-net.core/3.2.45", + "hashPath": "protobuf-net.core.3.2.45.nupkg.sha512" + }, + "SharpCompress/0.30.1": { + "type": "package", + "serviceable": true, + "sha512": "sha512-XqD4TpfyYGa7QTPzaGlMVbcecKnXy4YmYLDWrU+JIj7IuRNl7DH2END+Ll7ekWIY8o3dAMWLFDE1xdhfIWD1nw==", + "path": "sharpcompress/0.30.1", + "hashPath": "sharpcompress.0.30.1.nupkg.sha512" + }, + "Snappier/1.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-rFtK2KEI9hIe8gtx3a0YDXdHOpedIf9wYCEYtBEmtlyiWVX3XlCNV03JrmmAi/Cdfn7dxK+k0sjjcLv4fpHnqA==", + "path": "snappier/1.0.0", + "hashPath": "snappier.1.0.0.nupkg.sha512" + }, + "System.Buffers/4.5.1": { + "type": "package", + "serviceable": true, + "sha512": "sha512-Rw7ijyl1qqRS0YQD/WycNst8hUUMgrMH4FCn1nNm27M4VxchZ1js3fVjQaANHO5f3sN4isvP4a+Met9Y4YomAg==", + "path": "system.buffers/4.5.1", + "hashPath": "system.buffers.4.5.1.nupkg.sha512" + }, + "System.Collections.Immutable/7.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-dQPcs0U1IKnBdRDBkrCTi1FoajSTBzLcVTpjO4MBCMC7f4pDOIPzgBoX8JjG7X6uZRJ8EBxsi8+DR1JuwjnzOQ==", + "path": "system.collections.immutable/7.0.0", + "hashPath": "system.collections.immutable.7.0.0.nupkg.sha512" + }, + "System.IO.Pipelines/9.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-eA3cinogwaNB4jdjQHOP3Z3EuyiDII7MT35jgtnsA4vkn0LUrrSHsU0nzHTzFzmaFYeKV7MYyMxOocFzsBHpTw==", + "path": "system.io.pipelines/9.0.0", + "hashPath": "system.io.pipelines.9.0.0.nupkg.sha512" + }, + "System.Memory/4.5.5": { + "type": "package", + "serviceable": true, + "sha512": "sha512-XIWiDvKPXaTveaB7HVganDlOCRoj03l+jrwNvcge/t8vhGYKvqV+dMv6G4SAX2NoNmN0wZfVPTAlFwZcZvVOUw==", + "path": "system.memory/4.5.5", + "hashPath": "system.memory.4.5.5.nupkg.sha512" + }, + "System.Runtime.CompilerServices.Unsafe/5.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-ZD9TMpsmYJLrxbbmdvhwt9YEgG5WntEnZ/d1eH8JBX9LBp+Ju8BSBhUGbZMNVHHomWo2KVImJhTDl2hIgw/6MA==", + "path": "system.runtime.compilerservices.unsafe/5.0.0", + "hashPath": "system.runtime.compilerservices.unsafe.5.0.0.nupkg.sha512" + }, + "System.Security.AccessControl/5.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-dagJ1mHZO3Ani8GH0PHpPEe/oYO+rVdbQjvjJkBRNQkX4t0r1iaeGn8+/ybkSLEan3/slM0t59SVdHzuHf2jmw==", + "path": "system.security.accesscontrol/5.0.0", + "hashPath": "system.security.accesscontrol.5.0.0.nupkg.sha512" + }, + "System.Security.Principal.Windows/5.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-t0MGLukB5WAVU9bO3MGzvlGnyJPgUlcwerXn1kzBRjwLKixT96XV0Uza41W49gVd8zEMFu9vQEFlv0IOrytICA==", + "path": "system.security.principal.windows/5.0.0", + "hashPath": "system.security.principal.windows.5.0.0.nupkg.sha512" + }, + "ZstdSharp.Port/0.7.3": { + "type": "package", + "serviceable": true, + "sha512": "sha512-U9Ix4l4cl58Kzz1rJzj5hoVTjmbx1qGMwzAcbv1j/d3NzrFaESIurQyg+ow4mivCgkE3S413y+U9k4WdnEIkRA==", + "path": "zstdsharp.port/0.7.3", + "hashPath": "zstdsharp.port.0.7.3.nupkg.sha512" + }, + "Entity/1.0.0": { + "type": "project", + "serviceable": false, + "sha512": "" + } + } +} \ No newline at end of file diff --git a/邮件系统课程完整代码/Server/Hotfix/bin/Debug/net8.0/Hotfix.dll b/邮件系统课程完整代码/Server/Hotfix/bin/Debug/net8.0/Hotfix.dll new file mode 100644 index 0000000..5cc9998 Binary files /dev/null and b/邮件系统课程完整代码/Server/Hotfix/bin/Debug/net8.0/Hotfix.dll differ diff --git a/邮件系统课程完整代码/Server/Hotfix/bin/Debug/net8.0/Hotfix.pdb b/邮件系统课程完整代码/Server/Hotfix/bin/Debug/net8.0/Hotfix.pdb new file mode 100644 index 0000000..0388ba5 Binary files /dev/null and b/邮件系统课程完整代码/Server/Hotfix/bin/Debug/net8.0/Hotfix.pdb differ diff --git a/邮件系统课程完整代码/Server/Hotfix/obj/Debug/net8.0/.NETCoreApp,Version=v8.0.AssemblyAttributes.cs b/邮件系统课程完整代码/Server/Hotfix/obj/Debug/net8.0/.NETCoreApp,Version=v8.0.AssemblyAttributes.cs new file mode 100644 index 0000000..2217181 --- /dev/null +++ b/邮件系统课程完整代码/Server/Hotfix/obj/Debug/net8.0/.NETCoreApp,Version=v8.0.AssemblyAttributes.cs @@ -0,0 +1,4 @@ +// +using System; +using System.Reflection; +[assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute(".NETCoreApp,Version=v8.0", FrameworkDisplayName = ".NET 8.0")] diff --git a/邮件系统课程完整代码/Server/Hotfix/obj/Debug/net8.0/Hotfix.AssemblyInfo.cs b/邮件系统课程完整代码/Server/Hotfix/obj/Debug/net8.0/Hotfix.AssemblyInfo.cs new file mode 100644 index 0000000..10dae85 --- /dev/null +++ b/邮件系统课程完整代码/Server/Hotfix/obj/Debug/net8.0/Hotfix.AssemblyInfo.cs @@ -0,0 +1,22 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +using System; +using System.Reflection; + +[assembly: System.Reflection.AssemblyCompanyAttribute("Hotfix")] +[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")] +[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")] +[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0")] +[assembly: System.Reflection.AssemblyProductAttribute("Hotfix")] +[assembly: System.Reflection.AssemblyTitleAttribute("Hotfix")] +[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")] + +// 由 MSBuild WriteCodeFragment 类生成。 + diff --git a/邮件系统课程完整代码/Server/Hotfix/obj/Debug/net8.0/Hotfix.AssemblyInfoInputs.cache b/邮件系统课程完整代码/Server/Hotfix/obj/Debug/net8.0/Hotfix.AssemblyInfoInputs.cache new file mode 100644 index 0000000..fba9c22 --- /dev/null +++ b/邮件系统课程完整代码/Server/Hotfix/obj/Debug/net8.0/Hotfix.AssemblyInfoInputs.cache @@ -0,0 +1 @@ +28c7ffb99846e407a4d90a66ddc760b2a3412294f39e5810dd7ee1d10f0462a6 diff --git a/邮件系统课程完整代码/Server/Hotfix/obj/Debug/net8.0/Hotfix.GeneratedMSBuildEditorConfig.editorconfig b/邮件系统课程完整代码/Server/Hotfix/obj/Debug/net8.0/Hotfix.GeneratedMSBuildEditorConfig.editorconfig new file mode 100644 index 0000000..de99d88 --- /dev/null +++ b/邮件系统课程完整代码/Server/Hotfix/obj/Debug/net8.0/Hotfix.GeneratedMSBuildEditorConfig.editorconfig @@ -0,0 +1,15 @@ +is_global = true +build_property.TargetFramework = net8.0 +build_property.TargetPlatformMinVersion = +build_property.UsingMicrosoftNETSdkWeb = +build_property.ProjectTypeGuids = +build_property.InvariantGlobalization = +build_property.PlatformNeutralAssembly = +build_property.EnforceExtendedAnalyzerRules = +build_property._SupportedPlatformList = Linux,macOS,Windows +build_property.RootNamespace = Hotfix +build_property.ProjectDir = /Users/fantasy/Movies/邮件系统/Lession/Server/Hotfix/ +build_property.EnableComHosting = +build_property.EnableGeneratedComInterfaceComImportInterop = +build_property.EffectiveAnalysisLevelStyle = 8.0 +build_property.EnableCodeStyleSeverity = diff --git a/邮件系统课程完整代码/Server/Hotfix/obj/Debug/net8.0/Hotfix.GlobalUsings.g.cs b/邮件系统课程完整代码/Server/Hotfix/obj/Debug/net8.0/Hotfix.GlobalUsings.g.cs new file mode 100644 index 0000000..8578f3d --- /dev/null +++ b/邮件系统课程完整代码/Server/Hotfix/obj/Debug/net8.0/Hotfix.GlobalUsings.g.cs @@ -0,0 +1,8 @@ +// +global using global::System; +global using global::System.Collections.Generic; +global using global::System.IO; +global using global::System.Linq; +global using global::System.Net.Http; +global using global::System.Threading; +global using global::System.Threading.Tasks; diff --git a/邮件系统课程完整代码/Server/Hotfix/obj/Debug/net8.0/Hotfix.assets.cache b/邮件系统课程完整代码/Server/Hotfix/obj/Debug/net8.0/Hotfix.assets.cache new file mode 100644 index 0000000..1a134e9 Binary files /dev/null and b/邮件系统课程完整代码/Server/Hotfix/obj/Debug/net8.0/Hotfix.assets.cache differ diff --git a/邮件系统课程完整代码/Server/Hotfix/obj/Debug/net8.0/Hotfix.csproj.AssemblyReference.cache b/邮件系统课程完整代码/Server/Hotfix/obj/Debug/net8.0/Hotfix.csproj.AssemblyReference.cache new file mode 100644 index 0000000..79dfa6e Binary files /dev/null and b/邮件系统课程完整代码/Server/Hotfix/obj/Debug/net8.0/Hotfix.csproj.AssemblyReference.cache differ diff --git a/邮件系统课程完整代码/Server/Hotfix/obj/Debug/net8.0/Hotfix.csproj.CoreCompileInputs.cache b/邮件系统课程完整代码/Server/Hotfix/obj/Debug/net8.0/Hotfix.csproj.CoreCompileInputs.cache new file mode 100644 index 0000000..15e88f8 --- /dev/null +++ b/邮件系统课程完整代码/Server/Hotfix/obj/Debug/net8.0/Hotfix.csproj.CoreCompileInputs.cache @@ -0,0 +1 @@ +be5105afde1a71cd525a8ea82816450929933f775a7199cdb8dd8fa966b6d325 diff --git a/邮件系统课程完整代码/Server/Hotfix/obj/Debug/net8.0/Hotfix.csproj.FileListAbsolute.txt b/邮件系统课程完整代码/Server/Hotfix/obj/Debug/net8.0/Hotfix.csproj.FileListAbsolute.txt new file mode 100644 index 0000000..59faea0 --- /dev/null +++ b/邮件系统课程完整代码/Server/Hotfix/obj/Debug/net8.0/Hotfix.csproj.FileListAbsolute.txt @@ -0,0 +1,15 @@ +/Users/fantasy/Movies/邮件系统/Lession/Server/Hotfix/bin/Debug/net8.0/Hotfix.deps.json +/Users/fantasy/Movies/邮件系统/Lession/Server/Hotfix/bin/Debug/net8.0/Hotfix.dll +/Users/fantasy/Movies/邮件系统/Lession/Server/Hotfix/bin/Debug/net8.0/Hotfix.pdb +/Users/fantasy/Movies/邮件系统/Lession/Server/Hotfix/bin/Debug/net8.0/Entity.dll +/Users/fantasy/Movies/邮件系统/Lession/Server/Hotfix/bin/Debug/net8.0/Entity.pdb +/Users/fantasy/Movies/邮件系统/Lession/Server/Hotfix/obj/Debug/net8.0/Hotfix.csproj.AssemblyReference.cache +/Users/fantasy/Movies/邮件系统/Lession/Server/Hotfix/obj/Debug/net8.0/Hotfix.GeneratedMSBuildEditorConfig.editorconfig +/Users/fantasy/Movies/邮件系统/Lession/Server/Hotfix/obj/Debug/net8.0/Hotfix.AssemblyInfoInputs.cache +/Users/fantasy/Movies/邮件系统/Lession/Server/Hotfix/obj/Debug/net8.0/Hotfix.AssemblyInfo.cs +/Users/fantasy/Movies/邮件系统/Lession/Server/Hotfix/obj/Debug/net8.0/Hotfix.csproj.CoreCompileInputs.cache +/Users/fantasy/Movies/邮件系统/Lession/Server/Hotfix/obj/Debug/net8.0/Hotfix.csproj.Up2Date +/Users/fantasy/Movies/邮件系统/Lession/Server/Hotfix/obj/Debug/net8.0/Hotfix.dll +/Users/fantasy/Movies/邮件系统/Lession/Server/Hotfix/obj/Debug/net8.0/refint/Hotfix.dll +/Users/fantasy/Movies/邮件系统/Lession/Server/Hotfix/obj/Debug/net8.0/Hotfix.pdb +/Users/fantasy/Movies/邮件系统/Lession/Server/Hotfix/obj/Debug/net8.0/ref/Hotfix.dll diff --git a/邮件系统课程完整代码/Server/Hotfix/obj/Debug/net8.0/Hotfix.csproj.Up2Date b/邮件系统课程完整代码/Server/Hotfix/obj/Debug/net8.0/Hotfix.csproj.Up2Date new file mode 100644 index 0000000..e69de29 diff --git a/邮件系统课程完整代码/Server/Hotfix/obj/Debug/net8.0/Hotfix.dll b/邮件系统课程完整代码/Server/Hotfix/obj/Debug/net8.0/Hotfix.dll new file mode 100644 index 0000000..5cc9998 Binary files /dev/null and b/邮件系统课程完整代码/Server/Hotfix/obj/Debug/net8.0/Hotfix.dll differ diff --git a/邮件系统课程完整代码/Server/Hotfix/obj/Debug/net8.0/Hotfix.pdb b/邮件系统课程完整代码/Server/Hotfix/obj/Debug/net8.0/Hotfix.pdb new file mode 100644 index 0000000..0388ba5 Binary files /dev/null and b/邮件系统课程完整代码/Server/Hotfix/obj/Debug/net8.0/Hotfix.pdb differ diff --git a/邮件系统课程完整代码/Server/Hotfix/obj/Debug/net8.0/ref/Hotfix.dll b/邮件系统课程完整代码/Server/Hotfix/obj/Debug/net8.0/ref/Hotfix.dll new file mode 100644 index 0000000..180ffed Binary files /dev/null and b/邮件系统课程完整代码/Server/Hotfix/obj/Debug/net8.0/ref/Hotfix.dll differ diff --git a/邮件系统课程完整代码/Server/Hotfix/obj/Debug/net8.0/refint/Hotfix.dll b/邮件系统课程完整代码/Server/Hotfix/obj/Debug/net8.0/refint/Hotfix.dll new file mode 100644 index 0000000..180ffed Binary files /dev/null and b/邮件系统课程完整代码/Server/Hotfix/obj/Debug/net8.0/refint/Hotfix.dll differ diff --git a/邮件系统课程完整代码/Server/Hotfix/obj/Hotfix.csproj.nuget.dgspec.json b/邮件系统课程完整代码/Server/Hotfix/obj/Hotfix.csproj.nuget.dgspec.json new file mode 100644 index 0000000..ac2c091 --- /dev/null +++ b/邮件系统课程完整代码/Server/Hotfix/obj/Hotfix.csproj.nuget.dgspec.json @@ -0,0 +1,138 @@ +{ + "format": 1, + "restore": { + "/Users/fantasy/Movies/邮件系统/Lession/Server/Hotfix/Hotfix.csproj": {} + }, + "projects": { + "/Users/fantasy/Movies/邮件系统/Lession/Server/Entity/Entity.csproj": { + "version": "1.0.0", + "restore": { + "projectUniqueName": "/Users/fantasy/Movies/邮件系统/Lession/Server/Entity/Entity.csproj", + "projectName": "Entity", + "projectPath": "/Users/fantasy/Movies/邮件系统/Lession/Server/Entity/Entity.csproj", + "packagesPath": "/Users/fantasy/.nuget/packages/", + "outputPath": "/Users/fantasy/Movies/邮件系统/Lession/Server/Entity/obj/", + "projectStyle": "PackageReference", + "configFilePaths": [ + "/Users/fantasy/.nuget/NuGet/NuGet.Config" + ], + "originalTargetFrameworks": [ + "net8.0" + ], + "sources": { + "/usr/local/share/dotnet/library-packs": {}, + "https://api.nuget.org/v3/index.json": {} + }, + "frameworks": { + "net8.0": { + "targetAlias": "net8.0", + "projectReferences": {} + } + }, + "warningProperties": { + "warnAsError": [ + "NU1605" + ] + }, + "restoreAuditProperties": { + "enableAudit": "true", + "auditLevel": "low", + "auditMode": "all" + }, + "SdkAnalysisLevel": "9.0.100" + }, + "frameworks": { + "net8.0": { + "targetAlias": "net8.0", + "dependencies": { + "Fantasy-Net": { + "target": "Package", + "version": "[2024.2.22, )" + } + }, + "imports": [ + "net461", + "net462", + "net47", + "net471", + "net472", + "net48", + "net481" + ], + "assetTargetFallback": true, + "warn": true, + "frameworkReferences": { + "Microsoft.NETCore.App": { + "privateAssets": "all" + } + }, + "runtimeIdentifierGraphPath": "/usr/local/share/dotnet/sdk/9.0.100/PortableRuntimeIdentifierGraph.json" + } + } + }, + "/Users/fantasy/Movies/邮件系统/Lession/Server/Hotfix/Hotfix.csproj": { + "version": "1.0.0", + "restore": { + "projectUniqueName": "/Users/fantasy/Movies/邮件系统/Lession/Server/Hotfix/Hotfix.csproj", + "projectName": "Hotfix", + "projectPath": "/Users/fantasy/Movies/邮件系统/Lession/Server/Hotfix/Hotfix.csproj", + "packagesPath": "/Users/fantasy/.nuget/packages/", + "outputPath": "/Users/fantasy/Movies/邮件系统/Lession/Server/Hotfix/obj/", + "projectStyle": "PackageReference", + "configFilePaths": [ + "/Users/fantasy/.nuget/NuGet/NuGet.Config" + ], + "originalTargetFrameworks": [ + "net8.0" + ], + "sources": { + "/usr/local/share/dotnet/library-packs": {}, + "https://api.nuget.org/v3/index.json": {} + }, + "frameworks": { + "net8.0": { + "targetAlias": "net8.0", + "projectReferences": { + "/Users/fantasy/Movies/邮件系统/Lession/Server/Entity/Entity.csproj": { + "projectPath": "/Users/fantasy/Movies/邮件系统/Lession/Server/Entity/Entity.csproj" + } + } + } + }, + "warningProperties": { + "warnAsError": [ + "NU1605" + ] + }, + "restoreAuditProperties": { + "enableAudit": "true", + "auditLevel": "low", + "auditMode": "all" + }, + "SdkAnalysisLevel": "9.0.100" + }, + "frameworks": { + "net8.0": { + "targetAlias": "net8.0", + "imports": [ + "net461", + "net462", + "net47", + "net471", + "net472", + "net48", + "net481" + ], + "assetTargetFallback": true, + "warn": true, + "frameworkReferences": { + "Microsoft.NETCore.App": { + "privateAssets": "all" + } + }, + "runtimeIdentifierGraphPath": "/usr/local/share/dotnet/sdk/9.0.100/PortableRuntimeIdentifierGraph.json" + } + } + } + } +} \ No newline at end of file diff --git a/邮件系统课程完整代码/Server/Hotfix/obj/Hotfix.csproj.nuget.g.props b/邮件系统课程完整代码/Server/Hotfix/obj/Hotfix.csproj.nuget.g.props new file mode 100644 index 0000000..f402062 --- /dev/null +++ b/邮件系统课程完整代码/Server/Hotfix/obj/Hotfix.csproj.nuget.g.props @@ -0,0 +1,15 @@ + + + + True + NuGet + $(MSBuildThisFileDirectory)project.assets.json + /Users/fantasy/.nuget/packages/ + /Users/fantasy/.nuget/packages/ + PackageReference + 6.12.2 + + + + + \ No newline at end of file diff --git a/邮件系统课程完整代码/Server/Hotfix/obj/Hotfix.csproj.nuget.g.targets b/邮件系统课程完整代码/Server/Hotfix/obj/Hotfix.csproj.nuget.g.targets new file mode 100644 index 0000000..2412468 --- /dev/null +++ b/邮件系统课程完整代码/Server/Hotfix/obj/Hotfix.csproj.nuget.g.targets @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/邮件系统课程完整代码/Server/Hotfix/obj/project.assets.json b/邮件系统课程完整代码/Server/Hotfix/obj/project.assets.json new file mode 100644 index 0000000..e62a608 --- /dev/null +++ b/邮件系统课程完整代码/Server/Hotfix/obj/project.assets.json @@ -0,0 +1,966 @@ +{ + "version": 3, + "targets": { + "net8.0": { + "CommandLineParser/2.9.1": { + "type": "package", + "compile": { + "lib/netstandard2.0/CommandLine.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netstandard2.0/CommandLine.dll": { + "related": ".xml" + } + } + }, + "DnsClient/1.6.1": { + "type": "package", + "dependencies": { + "Microsoft.Win32.Registry": "5.0.0" + }, + "compile": { + "lib/net5.0/DnsClient.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net5.0/DnsClient.dll": { + "related": ".xml" + } + } + }, + "Fantasy-Net/2024.2.22": { + "type": "package", + "dependencies": { + "CommandLineParser": "2.9.1", + "MongoDB.Bson": "3.1.0", + "MongoDB.Driver": "3.1.0", + "Newtonsoft.Json": "13.0.3", + "System.IO.Pipelines": "9.0.0", + "protobuf-net": "3.2.45" + }, + "compile": { + "lib/net8.0/Fantasy-Net.dll": {} + }, + "runtime": { + "lib/net8.0/Fantasy-Net.dll": {} + }, + "frameworkReferences": [ + "Microsoft.AspNetCore.App" + ], + "build": { + "buildTransitive/Fantasy-Net.targets": {} + } + }, + "Microsoft.Extensions.Logging.Abstractions/2.0.0": { + "type": "package", + "compile": { + "lib/netstandard2.0/Microsoft.Extensions.Logging.Abstractions.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netstandard2.0/Microsoft.Extensions.Logging.Abstractions.dll": { + "related": ".xml" + } + } + }, + "Microsoft.NETCore.Platforms/5.0.0": { + "type": "package", + "compile": { + "lib/netstandard1.0/_._": {} + }, + "runtime": { + "lib/netstandard1.0/_._": {} + } + }, + "Microsoft.Win32.Registry/5.0.0": { + "type": "package", + "dependencies": { + "System.Security.AccessControl": "5.0.0", + "System.Security.Principal.Windows": "5.0.0" + }, + "compile": { + "ref/netstandard2.0/Microsoft.Win32.Registry.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netstandard2.0/Microsoft.Win32.Registry.dll": { + "related": ".xml" + } + }, + "runtimeTargets": { + "runtimes/win/lib/netstandard2.0/Microsoft.Win32.Registry.dll": { + "assetType": "runtime", + "rid": "win" + } + } + }, + "MongoDB.Bson/3.1.0": { + "type": "package", + "dependencies": { + "System.Memory": "4.5.5", + "System.Runtime.CompilerServices.Unsafe": "5.0.0" + }, + "compile": { + "lib/net6.0/MongoDB.Bson.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net6.0/MongoDB.Bson.dll": { + "related": ".xml" + } + } + }, + "MongoDB.Driver/3.1.0": { + "type": "package", + "dependencies": { + "DnsClient": "1.6.1", + "Microsoft.Extensions.Logging.Abstractions": "2.0.0", + "MongoDB.Bson": "3.1.0", + "SharpCompress": "0.30.1", + "Snappier": "1.0.0", + "System.Buffers": "4.5.1", + "ZstdSharp.Port": "0.7.3" + }, + "compile": { + "lib/net6.0/MongoDB.Driver.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net6.0/MongoDB.Driver.dll": { + "related": ".xml" + } + } + }, + "Newtonsoft.Json/13.0.3": { + "type": "package", + "compile": { + "lib/net6.0/Newtonsoft.Json.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net6.0/Newtonsoft.Json.dll": { + "related": ".xml" + } + } + }, + "protobuf-net/3.2.45": { + "type": "package", + "dependencies": { + "protobuf-net.Core": "3.2.45" + }, + "compile": { + "lib/net6.0/protobuf-net.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net6.0/protobuf-net.dll": { + "related": ".xml" + } + } + }, + "protobuf-net.Core/3.2.45": { + "type": "package", + "dependencies": { + "System.Collections.Immutable": "7.0.0" + }, + "compile": { + "lib/net6.0/protobuf-net.Core.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net6.0/protobuf-net.Core.dll": { + "related": ".xml" + } + } + }, + "SharpCompress/0.30.1": { + "type": "package", + "compile": { + "lib/net5.0/SharpCompress.dll": {} + }, + "runtime": { + "lib/net5.0/SharpCompress.dll": {} + } + }, + "Snappier/1.0.0": { + "type": "package", + "compile": { + "lib/net5.0/Snappier.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net5.0/Snappier.dll": { + "related": ".xml" + } + } + }, + "System.Buffers/4.5.1": { + "type": "package", + "compile": { + "ref/netcoreapp2.0/_._": {} + }, + "runtime": { + "lib/netcoreapp2.0/_._": {} + } + }, + "System.Collections.Immutable/7.0.0": { + "type": "package", + "compile": { + "lib/net7.0/System.Collections.Immutable.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net7.0/System.Collections.Immutable.dll": { + "related": ".xml" + } + }, + "build": { + "buildTransitive/net6.0/_._": {} + } + }, + "System.IO.Pipelines/9.0.0": { + "type": "package", + "compile": { + "lib/net8.0/System.IO.Pipelines.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net8.0/System.IO.Pipelines.dll": { + "related": ".xml" + } + }, + "build": { + "buildTransitive/net8.0/_._": {} + } + }, + "System.Memory/4.5.5": { + "type": "package", + "compile": { + "ref/netcoreapp2.1/_._": {} + }, + "runtime": { + "lib/netcoreapp2.1/_._": {} + } + }, + "System.Runtime.CompilerServices.Unsafe/5.0.0": { + "type": "package", + "compile": { + "ref/netstandard2.1/System.Runtime.CompilerServices.Unsafe.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netcoreapp2.0/System.Runtime.CompilerServices.Unsafe.dll": { + "related": ".xml" + } + } + }, + "System.Security.AccessControl/5.0.0": { + "type": "package", + "dependencies": { + "Microsoft.NETCore.Platforms": "5.0.0", + "System.Security.Principal.Windows": "5.0.0" + }, + "compile": { + "ref/netstandard2.0/System.Security.AccessControl.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netstandard2.0/System.Security.AccessControl.dll": { + "related": ".xml" + } + }, + "runtimeTargets": { + "runtimes/win/lib/netcoreapp2.0/System.Security.AccessControl.dll": { + "assetType": "runtime", + "rid": "win" + } + } + }, + "System.Security.Principal.Windows/5.0.0": { + "type": "package", + "compile": { + "ref/netcoreapp3.0/System.Security.Principal.Windows.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/netstandard2.0/System.Security.Principal.Windows.dll": { + "related": ".xml" + } + }, + "runtimeTargets": { + "runtimes/unix/lib/netcoreapp2.1/System.Security.Principal.Windows.dll": { + "assetType": "runtime", + "rid": "unix" + }, + "runtimes/win/lib/netcoreapp2.1/System.Security.Principal.Windows.dll": { + "assetType": "runtime", + "rid": "win" + } + } + }, + "ZstdSharp.Port/0.7.3": { + "type": "package", + "compile": { + "lib/net7.0/ZstdSharp.dll": {} + }, + "runtime": { + "lib/net7.0/ZstdSharp.dll": {} + } + }, + "Entity/1.0.0": { + "type": "project", + "framework": ".NETCoreApp,Version=v8.0", + "dependencies": { + "Fantasy-Net": "2024.2.22" + }, + "compile": { + "bin/placeholder/Entity.dll": {} + }, + "runtime": { + "bin/placeholder/Entity.dll": {} + } + } + } + }, + "libraries": { + "CommandLineParser/2.9.1": { + "sha512": "OE0sl1/sQ37bjVsPKKtwQlWDgqaxWgtme3xZz7JssWUzg5JpMIyHgCTY9MVMxOg48fJ1AgGT3tgdH5m/kQ5xhA==", + "type": "package", + "path": "commandlineparser/2.9.1", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "CommandLine20.png", + "License.md", + "README.md", + "commandlineparser.2.9.1.nupkg.sha512", + "commandlineparser.nuspec", + "lib/net40/CommandLine.dll", + "lib/net40/CommandLine.xml", + "lib/net45/CommandLine.dll", + "lib/net45/CommandLine.xml", + "lib/net461/CommandLine.dll", + "lib/net461/CommandLine.xml", + "lib/netstandard2.0/CommandLine.dll", + "lib/netstandard2.0/CommandLine.xml" + ] + }, + "DnsClient/1.6.1": { + "sha512": "4H/f2uYJOZ+YObZjpY9ABrKZI+JNw3uizp6oMzTXwDw6F+2qIPhpRl/1t68O/6e98+vqNiYGu+lswmwdYUy3gg==", + "type": "package", + "path": "dnsclient/1.6.1", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "dnsclient.1.6.1.nupkg.sha512", + "dnsclient.nuspec", + "icon.png", + "lib/net45/DnsClient.dll", + "lib/net45/DnsClient.xml", + "lib/net471/DnsClient.dll", + "lib/net471/DnsClient.xml", + "lib/net5.0/DnsClient.dll", + "lib/net5.0/DnsClient.xml", + "lib/netstandard1.3/DnsClient.dll", + "lib/netstandard1.3/DnsClient.xml", + "lib/netstandard2.0/DnsClient.dll", + "lib/netstandard2.0/DnsClient.xml", + "lib/netstandard2.1/DnsClient.dll", + "lib/netstandard2.1/DnsClient.xml" + ] + }, + "Fantasy-Net/2024.2.22": { + "sha512": "cT6B0YJ5JmbPHBLYgLeVgg2WbXYxxa1tudoIase88uMzAuqU9t7EQ7dFZGSWjP41c5JOQ/0f1q9lzGWTh/hskw==", + "type": "package", + "path": "fantasy-net/2024.2.22", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "LICENSE", + "README.md", + "buildTransitive/Fantasy-Net.targets", + "fantasy-net.2024.2.22.nupkg.sha512", + "fantasy-net.nuspec", + "icon.png", + "lib/net8.0/Fantasy-Net.dll", + "lib/net9.0/Fantasy-Net.dll" + ] + }, + "Microsoft.Extensions.Logging.Abstractions/2.0.0": { + "sha512": "6ZCllUYGFukkymSTx3Yr0G/ajRxoNJp7/FqSxSB4fGISST54ifBhgu4Nc0ItGi3i6DqwuNd8SUyObmiC++AO2Q==", + "type": "package", + "path": "microsoft.extensions.logging.abstractions/2.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "lib/netstandard2.0/Microsoft.Extensions.Logging.Abstractions.dll", + "lib/netstandard2.0/Microsoft.Extensions.Logging.Abstractions.xml", + "microsoft.extensions.logging.abstractions.2.0.0.nupkg.sha512", + "microsoft.extensions.logging.abstractions.nuspec" + ] + }, + "Microsoft.NETCore.Platforms/5.0.0": { + "sha512": "VyPlqzH2wavqquTcYpkIIAQ6WdenuKoFN0BdYBbCWsclXacSOHNQn66Gt4z5NBqEYW0FAPm5rlvki9ZiCij5xQ==", + "type": "package", + "path": "microsoft.netcore.platforms/5.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "LICENSE.TXT", + "THIRD-PARTY-NOTICES.TXT", + "lib/netstandard1.0/_._", + "microsoft.netcore.platforms.5.0.0.nupkg.sha512", + "microsoft.netcore.platforms.nuspec", + "runtime.json", + "useSharedDesignerContext.txt", + "version.txt" + ] + }, + "Microsoft.Win32.Registry/5.0.0": { + "sha512": "dDoKi0PnDz31yAyETfRntsLArTlVAVzUzCIvvEDsDsucrl33Dl8pIJG06ePTJTI3tGpeyHS9Cq7Foc/s4EeKcg==", + "type": "package", + "path": "microsoft.win32.registry/5.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "LICENSE.TXT", + "THIRD-PARTY-NOTICES.TXT", + "lib/net46/Microsoft.Win32.Registry.dll", + "lib/net461/Microsoft.Win32.Registry.dll", + "lib/net461/Microsoft.Win32.Registry.xml", + "lib/netstandard1.3/Microsoft.Win32.Registry.dll", + "lib/netstandard2.0/Microsoft.Win32.Registry.dll", + "lib/netstandard2.0/Microsoft.Win32.Registry.xml", + "microsoft.win32.registry.5.0.0.nupkg.sha512", + "microsoft.win32.registry.nuspec", + "ref/net46/Microsoft.Win32.Registry.dll", + "ref/net461/Microsoft.Win32.Registry.dll", + "ref/net461/Microsoft.Win32.Registry.xml", + "ref/netstandard1.3/Microsoft.Win32.Registry.dll", + "ref/netstandard1.3/Microsoft.Win32.Registry.xml", + "ref/netstandard1.3/de/Microsoft.Win32.Registry.xml", + "ref/netstandard1.3/es/Microsoft.Win32.Registry.xml", + "ref/netstandard1.3/fr/Microsoft.Win32.Registry.xml", + "ref/netstandard1.3/it/Microsoft.Win32.Registry.xml", + "ref/netstandard1.3/ja/Microsoft.Win32.Registry.xml", + "ref/netstandard1.3/ko/Microsoft.Win32.Registry.xml", + "ref/netstandard1.3/ru/Microsoft.Win32.Registry.xml", + "ref/netstandard1.3/zh-hans/Microsoft.Win32.Registry.xml", + "ref/netstandard1.3/zh-hant/Microsoft.Win32.Registry.xml", + "ref/netstandard2.0/Microsoft.Win32.Registry.dll", + "ref/netstandard2.0/Microsoft.Win32.Registry.xml", + "runtimes/win/lib/net46/Microsoft.Win32.Registry.dll", + "runtimes/win/lib/net461/Microsoft.Win32.Registry.dll", + "runtimes/win/lib/net461/Microsoft.Win32.Registry.xml", + "runtimes/win/lib/netstandard1.3/Microsoft.Win32.Registry.dll", + "runtimes/win/lib/netstandard2.0/Microsoft.Win32.Registry.dll", + "runtimes/win/lib/netstandard2.0/Microsoft.Win32.Registry.xml", + "useSharedDesignerContext.txt", + "version.txt" + ] + }, + "MongoDB.Bson/3.1.0": { + "sha512": "3dhaZhz18B5vUoEP13o2j8A6zQfkHdZhwBvLZEjDJum4BTLLv1/Z8bt25UQEtpqvYwLgde4R6ekWZ7XAYUMxuw==", + "type": "package", + "path": "mongodb.bson/3.1.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "README.md", + "lib/net472/MongoDB.Bson.dll", + "lib/net472/MongoDB.Bson.xml", + "lib/net6.0/MongoDB.Bson.dll", + "lib/net6.0/MongoDB.Bson.xml", + "lib/netstandard2.1/MongoDB.Bson.dll", + "lib/netstandard2.1/MongoDB.Bson.xml", + "mongodb.bson.3.1.0.nupkg.sha512", + "mongodb.bson.nuspec", + "packageIcon.png" + ] + }, + "MongoDB.Driver/3.1.0": { + "sha512": "+O7lKaIl7VUHptE0hqTd7UY1G5KDp/o8S4upG7YL4uChMNKD/U6tz9i17nMGHaD/L2AiPLgaJcaDe2XACsegGA==", + "type": "package", + "path": "mongodb.driver/3.1.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "README.md", + "lib/net472/MongoDB.Driver.dll", + "lib/net472/MongoDB.Driver.xml", + "lib/net6.0/MongoDB.Driver.dll", + "lib/net6.0/MongoDB.Driver.xml", + "lib/netstandard2.1/MongoDB.Driver.dll", + "lib/netstandard2.1/MongoDB.Driver.xml", + "mongodb.driver.3.1.0.nupkg.sha512", + "mongodb.driver.nuspec", + "packageIcon.png" + ] + }, + "Newtonsoft.Json/13.0.3": { + "sha512": "HrC5BXdl00IP9zeV+0Z848QWPAoCr9P3bDEZguI+gkLcBKAOxix/tLEAAHC+UvDNPv4a2d18lOReHMOagPa+zQ==", + "type": "package", + "path": "newtonsoft.json/13.0.3", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "LICENSE.md", + "README.md", + "lib/net20/Newtonsoft.Json.dll", + "lib/net20/Newtonsoft.Json.xml", + "lib/net35/Newtonsoft.Json.dll", + "lib/net35/Newtonsoft.Json.xml", + "lib/net40/Newtonsoft.Json.dll", + "lib/net40/Newtonsoft.Json.xml", + "lib/net45/Newtonsoft.Json.dll", + "lib/net45/Newtonsoft.Json.xml", + "lib/net6.0/Newtonsoft.Json.dll", + "lib/net6.0/Newtonsoft.Json.xml", + "lib/netstandard1.0/Newtonsoft.Json.dll", + "lib/netstandard1.0/Newtonsoft.Json.xml", + "lib/netstandard1.3/Newtonsoft.Json.dll", + "lib/netstandard1.3/Newtonsoft.Json.xml", + "lib/netstandard2.0/Newtonsoft.Json.dll", + "lib/netstandard2.0/Newtonsoft.Json.xml", + "newtonsoft.json.13.0.3.nupkg.sha512", + "newtonsoft.json.nuspec", + "packageIcon.png" + ] + }, + "protobuf-net/3.2.45": { + "sha512": "5UZ/ukUHcGbFSl7vNMrHsfjqdxusdd9w7w0fCEXzf3UUtsrGNVCzV5SmF+sCHAbnRV2qPcD1ixiDP7Aj8lX/HA==", + "type": "package", + "path": "protobuf-net/3.2.45", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "lib/net462/protobuf-net.dll", + "lib/net462/protobuf-net.xml", + "lib/net6.0/protobuf-net.dll", + "lib/net6.0/protobuf-net.xml", + "lib/netstandard2.0/protobuf-net.dll", + "lib/netstandard2.0/protobuf-net.xml", + "lib/netstandard2.1/protobuf-net.dll", + "lib/netstandard2.1/protobuf-net.xml", + "protobuf-net.3.2.45.nupkg.sha512", + "protobuf-net.nuspec", + "protobuf-net.png", + "readme.md" + ] + }, + "protobuf-net.Core/3.2.45": { + "sha512": "PMWatW2NrT1uTXD7etJ4VdQ0wWZLFrIfdRGppD2QX7nzZ0+kIzqhq551u6ZiXJHWJgG4hWFEkSnUnt2aB6posg==", + "type": "package", + "path": "protobuf-net.core/3.2.45", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "lib/net462/protobuf-net.Core.dll", + "lib/net462/protobuf-net.Core.xml", + "lib/net6.0/protobuf-net.Core.dll", + "lib/net6.0/protobuf-net.Core.xml", + "lib/netstandard2.0/protobuf-net.Core.dll", + "lib/netstandard2.0/protobuf-net.Core.xml", + "lib/netstandard2.1/protobuf-net.Core.dll", + "lib/netstandard2.1/protobuf-net.Core.xml", + "protobuf-net.core.3.2.45.nupkg.sha512", + "protobuf-net.core.nuspec", + "protobuf-net.png", + "readme.md" + ] + }, + "SharpCompress/0.30.1": { + "sha512": "XqD4TpfyYGa7QTPzaGlMVbcecKnXy4YmYLDWrU+JIj7IuRNl7DH2END+Ll7ekWIY8o3dAMWLFDE1xdhfIWD1nw==", + "type": "package", + "path": "sharpcompress/0.30.1", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "lib/net461/SharpCompress.dll", + "lib/net5.0/SharpCompress.dll", + "lib/netcoreapp3.1/SharpCompress.dll", + "lib/netstandard2.0/SharpCompress.dll", + "lib/netstandard2.1/SharpCompress.dll", + "sharpcompress.0.30.1.nupkg.sha512", + "sharpcompress.nuspec" + ] + }, + "Snappier/1.0.0": { + "sha512": "rFtK2KEI9hIe8gtx3a0YDXdHOpedIf9wYCEYtBEmtlyiWVX3XlCNV03JrmmAi/Cdfn7dxK+k0sjjcLv4fpHnqA==", + "type": "package", + "path": "snappier/1.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "COPYING.txt", + "lib/net5.0/Snappier.dll", + "lib/net5.0/Snappier.xml", + "lib/netcoreapp3.0/Snappier.dll", + "lib/netcoreapp3.0/Snappier.xml", + "lib/netstandard2.0/Snappier.dll", + "lib/netstandard2.0/Snappier.xml", + "lib/netstandard2.1/Snappier.dll", + "lib/netstandard2.1/Snappier.xml", + "snappier.1.0.0.nupkg.sha512", + "snappier.nuspec" + ] + }, + "System.Buffers/4.5.1": { + "sha512": "Rw7ijyl1qqRS0YQD/WycNst8hUUMgrMH4FCn1nNm27M4VxchZ1js3fVjQaANHO5f3sN4isvP4a+Met9Y4YomAg==", + "type": "package", + "path": "system.buffers/4.5.1", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "LICENSE.TXT", + "THIRD-PARTY-NOTICES.TXT", + "lib/net461/System.Buffers.dll", + "lib/net461/System.Buffers.xml", + "lib/netcoreapp2.0/_._", + "lib/netstandard1.1/System.Buffers.dll", + "lib/netstandard1.1/System.Buffers.xml", + "lib/netstandard2.0/System.Buffers.dll", + "lib/netstandard2.0/System.Buffers.xml", + "lib/uap10.0.16299/_._", + "ref/net45/System.Buffers.dll", + "ref/net45/System.Buffers.xml", + "ref/netcoreapp2.0/_._", + "ref/netstandard1.1/System.Buffers.dll", + "ref/netstandard1.1/System.Buffers.xml", + "ref/netstandard2.0/System.Buffers.dll", + "ref/netstandard2.0/System.Buffers.xml", + "ref/uap10.0.16299/_._", + "system.buffers.4.5.1.nupkg.sha512", + "system.buffers.nuspec", + "useSharedDesignerContext.txt", + "version.txt" + ] + }, + "System.Collections.Immutable/7.0.0": { + "sha512": "dQPcs0U1IKnBdRDBkrCTi1FoajSTBzLcVTpjO4MBCMC7f4pDOIPzgBoX8JjG7X6uZRJ8EBxsi8+DR1JuwjnzOQ==", + "type": "package", + "path": "system.collections.immutable/7.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "LICENSE.TXT", + "README.md", + "THIRD-PARTY-NOTICES.TXT", + "buildTransitive/net461/System.Collections.Immutable.targets", + "buildTransitive/net462/_._", + "buildTransitive/net6.0/_._", + "buildTransitive/netcoreapp2.0/System.Collections.Immutable.targets", + "lib/net462/System.Collections.Immutable.dll", + "lib/net462/System.Collections.Immutable.xml", + "lib/net6.0/System.Collections.Immutable.dll", + "lib/net6.0/System.Collections.Immutable.xml", + "lib/net7.0/System.Collections.Immutable.dll", + "lib/net7.0/System.Collections.Immutable.xml", + "lib/netstandard2.0/System.Collections.Immutable.dll", + "lib/netstandard2.0/System.Collections.Immutable.xml", + "system.collections.immutable.7.0.0.nupkg.sha512", + "system.collections.immutable.nuspec", + "useSharedDesignerContext.txt" + ] + }, + "System.IO.Pipelines/9.0.0": { + "sha512": "eA3cinogwaNB4jdjQHOP3Z3EuyiDII7MT35jgtnsA4vkn0LUrrSHsU0nzHTzFzmaFYeKV7MYyMxOocFzsBHpTw==", + "type": "package", + "path": "system.io.pipelines/9.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "LICENSE.TXT", + "PACKAGE.md", + "THIRD-PARTY-NOTICES.TXT", + "buildTransitive/net461/System.IO.Pipelines.targets", + "buildTransitive/net462/_._", + "buildTransitive/net8.0/_._", + "buildTransitive/netcoreapp2.0/System.IO.Pipelines.targets", + "lib/net462/System.IO.Pipelines.dll", + "lib/net462/System.IO.Pipelines.xml", + "lib/net8.0/System.IO.Pipelines.dll", + "lib/net8.0/System.IO.Pipelines.xml", + "lib/net9.0/System.IO.Pipelines.dll", + "lib/net9.0/System.IO.Pipelines.xml", + "lib/netstandard2.0/System.IO.Pipelines.dll", + "lib/netstandard2.0/System.IO.Pipelines.xml", + "system.io.pipelines.9.0.0.nupkg.sha512", + "system.io.pipelines.nuspec", + "useSharedDesignerContext.txt" + ] + }, + "System.Memory/4.5.5": { + "sha512": "XIWiDvKPXaTveaB7HVganDlOCRoj03l+jrwNvcge/t8vhGYKvqV+dMv6G4SAX2NoNmN0wZfVPTAlFwZcZvVOUw==", + "type": "package", + "path": "system.memory/4.5.5", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "LICENSE.TXT", + "THIRD-PARTY-NOTICES.TXT", + "lib/net461/System.Memory.dll", + "lib/net461/System.Memory.xml", + "lib/netcoreapp2.1/_._", + "lib/netstandard1.1/System.Memory.dll", + "lib/netstandard1.1/System.Memory.xml", + "lib/netstandard2.0/System.Memory.dll", + "lib/netstandard2.0/System.Memory.xml", + "ref/netcoreapp2.1/_._", + "system.memory.4.5.5.nupkg.sha512", + "system.memory.nuspec", + "useSharedDesignerContext.txt", + "version.txt" + ] + }, + "System.Runtime.CompilerServices.Unsafe/5.0.0": { + "sha512": "ZD9TMpsmYJLrxbbmdvhwt9YEgG5WntEnZ/d1eH8JBX9LBp+Ju8BSBhUGbZMNVHHomWo2KVImJhTDl2hIgw/6MA==", + "type": "package", + "path": "system.runtime.compilerservices.unsafe/5.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "LICENSE.TXT", + "THIRD-PARTY-NOTICES.TXT", + "lib/net45/System.Runtime.CompilerServices.Unsafe.dll", + "lib/net45/System.Runtime.CompilerServices.Unsafe.xml", + "lib/netcoreapp2.0/System.Runtime.CompilerServices.Unsafe.dll", + "lib/netcoreapp2.0/System.Runtime.CompilerServices.Unsafe.xml", + "lib/netstandard1.0/System.Runtime.CompilerServices.Unsafe.dll", + "lib/netstandard1.0/System.Runtime.CompilerServices.Unsafe.xml", + "lib/netstandard2.0/System.Runtime.CompilerServices.Unsafe.dll", + "lib/netstandard2.0/System.Runtime.CompilerServices.Unsafe.xml", + "ref/net461/System.Runtime.CompilerServices.Unsafe.dll", + "ref/net461/System.Runtime.CompilerServices.Unsafe.xml", + "ref/netstandard1.0/System.Runtime.CompilerServices.Unsafe.dll", + "ref/netstandard1.0/System.Runtime.CompilerServices.Unsafe.xml", + "ref/netstandard2.0/System.Runtime.CompilerServices.Unsafe.dll", + "ref/netstandard2.0/System.Runtime.CompilerServices.Unsafe.xml", + "ref/netstandard2.1/System.Runtime.CompilerServices.Unsafe.dll", + "ref/netstandard2.1/System.Runtime.CompilerServices.Unsafe.xml", + "system.runtime.compilerservices.unsafe.5.0.0.nupkg.sha512", + "system.runtime.compilerservices.unsafe.nuspec", + "useSharedDesignerContext.txt", + "version.txt" + ] + }, + "System.Security.AccessControl/5.0.0": { + "sha512": "dagJ1mHZO3Ani8GH0PHpPEe/oYO+rVdbQjvjJkBRNQkX4t0r1iaeGn8+/ybkSLEan3/slM0t59SVdHzuHf2jmw==", + "type": "package", + "path": "system.security.accesscontrol/5.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "LICENSE.TXT", + "THIRD-PARTY-NOTICES.TXT", + "lib/net46/System.Security.AccessControl.dll", + "lib/net461/System.Security.AccessControl.dll", + "lib/net461/System.Security.AccessControl.xml", + "lib/netstandard1.3/System.Security.AccessControl.dll", + "lib/netstandard2.0/System.Security.AccessControl.dll", + "lib/netstandard2.0/System.Security.AccessControl.xml", + "lib/uap10.0.16299/_._", + "ref/net46/System.Security.AccessControl.dll", + "ref/net461/System.Security.AccessControl.dll", + "ref/net461/System.Security.AccessControl.xml", + "ref/netstandard1.3/System.Security.AccessControl.dll", + "ref/netstandard1.3/System.Security.AccessControl.xml", + "ref/netstandard1.3/de/System.Security.AccessControl.xml", + "ref/netstandard1.3/es/System.Security.AccessControl.xml", + "ref/netstandard1.3/fr/System.Security.AccessControl.xml", + "ref/netstandard1.3/it/System.Security.AccessControl.xml", + "ref/netstandard1.3/ja/System.Security.AccessControl.xml", + "ref/netstandard1.3/ko/System.Security.AccessControl.xml", + "ref/netstandard1.3/ru/System.Security.AccessControl.xml", + "ref/netstandard1.3/zh-hans/System.Security.AccessControl.xml", + "ref/netstandard1.3/zh-hant/System.Security.AccessControl.xml", + "ref/netstandard2.0/System.Security.AccessControl.dll", + "ref/netstandard2.0/System.Security.AccessControl.xml", + "ref/uap10.0.16299/_._", + "runtimes/win/lib/net46/System.Security.AccessControl.dll", + "runtimes/win/lib/net461/System.Security.AccessControl.dll", + "runtimes/win/lib/net461/System.Security.AccessControl.xml", + "runtimes/win/lib/netcoreapp2.0/System.Security.AccessControl.dll", + "runtimes/win/lib/netcoreapp2.0/System.Security.AccessControl.xml", + "runtimes/win/lib/netstandard1.3/System.Security.AccessControl.dll", + "runtimes/win/lib/uap10.0.16299/_._", + "system.security.accesscontrol.5.0.0.nupkg.sha512", + "system.security.accesscontrol.nuspec", + "useSharedDesignerContext.txt", + "version.txt" + ] + }, + "System.Security.Principal.Windows/5.0.0": { + "sha512": "t0MGLukB5WAVU9bO3MGzvlGnyJPgUlcwerXn1kzBRjwLKixT96XV0Uza41W49gVd8zEMFu9vQEFlv0IOrytICA==", + "type": "package", + "path": "system.security.principal.windows/5.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "LICENSE.TXT", + "THIRD-PARTY-NOTICES.TXT", + "lib/net46/System.Security.Principal.Windows.dll", + "lib/net461/System.Security.Principal.Windows.dll", + "lib/net461/System.Security.Principal.Windows.xml", + "lib/netstandard1.3/System.Security.Principal.Windows.dll", + "lib/netstandard2.0/System.Security.Principal.Windows.dll", + "lib/netstandard2.0/System.Security.Principal.Windows.xml", + "lib/uap10.0.16299/_._", + "ref/net46/System.Security.Principal.Windows.dll", + "ref/net461/System.Security.Principal.Windows.dll", + "ref/net461/System.Security.Principal.Windows.xml", + "ref/netcoreapp3.0/System.Security.Principal.Windows.dll", + "ref/netcoreapp3.0/System.Security.Principal.Windows.xml", + "ref/netstandard1.3/System.Security.Principal.Windows.dll", + "ref/netstandard1.3/System.Security.Principal.Windows.xml", + "ref/netstandard1.3/de/System.Security.Principal.Windows.xml", + "ref/netstandard1.3/es/System.Security.Principal.Windows.xml", + "ref/netstandard1.3/fr/System.Security.Principal.Windows.xml", + "ref/netstandard1.3/it/System.Security.Principal.Windows.xml", + "ref/netstandard1.3/ja/System.Security.Principal.Windows.xml", + "ref/netstandard1.3/ko/System.Security.Principal.Windows.xml", + "ref/netstandard1.3/ru/System.Security.Principal.Windows.xml", + "ref/netstandard1.3/zh-hans/System.Security.Principal.Windows.xml", + "ref/netstandard1.3/zh-hant/System.Security.Principal.Windows.xml", + "ref/netstandard2.0/System.Security.Principal.Windows.dll", + "ref/netstandard2.0/System.Security.Principal.Windows.xml", + "ref/uap10.0.16299/_._", + "runtimes/unix/lib/netcoreapp2.0/System.Security.Principal.Windows.dll", + "runtimes/unix/lib/netcoreapp2.0/System.Security.Principal.Windows.xml", + "runtimes/unix/lib/netcoreapp2.1/System.Security.Principal.Windows.dll", + "runtimes/unix/lib/netcoreapp2.1/System.Security.Principal.Windows.xml", + "runtimes/win/lib/net46/System.Security.Principal.Windows.dll", + "runtimes/win/lib/net461/System.Security.Principal.Windows.dll", + "runtimes/win/lib/net461/System.Security.Principal.Windows.xml", + "runtimes/win/lib/netcoreapp2.0/System.Security.Principal.Windows.dll", + "runtimes/win/lib/netcoreapp2.0/System.Security.Principal.Windows.xml", + "runtimes/win/lib/netcoreapp2.1/System.Security.Principal.Windows.dll", + "runtimes/win/lib/netcoreapp2.1/System.Security.Principal.Windows.xml", + "runtimes/win/lib/netstandard1.3/System.Security.Principal.Windows.dll", + "runtimes/win/lib/uap10.0.16299/_._", + "system.security.principal.windows.5.0.0.nupkg.sha512", + "system.security.principal.windows.nuspec", + "useSharedDesignerContext.txt", + "version.txt" + ] + }, + "ZstdSharp.Port/0.7.3": { + "sha512": "U9Ix4l4cl58Kzz1rJzj5hoVTjmbx1qGMwzAcbv1j/d3NzrFaESIurQyg+ow4mivCgkE3S413y+U9k4WdnEIkRA==", + "type": "package", + "path": "zstdsharp.port/0.7.3", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "lib/net461/ZstdSharp.dll", + "lib/net5.0/ZstdSharp.dll", + "lib/net6.0/ZstdSharp.dll", + "lib/net7.0/ZstdSharp.dll", + "lib/netcoreapp3.1/ZstdSharp.dll", + "lib/netstandard2.0/ZstdSharp.dll", + "lib/netstandard2.1/ZstdSharp.dll", + "zstdsharp.port.0.7.3.nupkg.sha512", + "zstdsharp.port.nuspec" + ] + }, + "Entity/1.0.0": { + "type": "project", + "path": "../Entity/Entity.csproj", + "msbuildProject": "../Entity/Entity.csproj" + } + }, + "projectFileDependencyGroups": { + "net8.0": [ + "Entity >= 1.0.0" + ] + }, + "packageFolders": { + "/Users/fantasy/.nuget/packages/": {} + }, + "project": { + "version": "1.0.0", + "restore": { + "projectUniqueName": "/Users/fantasy/Movies/邮件系统/Lession/Server/Hotfix/Hotfix.csproj", + "projectName": "Hotfix", + "projectPath": "/Users/fantasy/Movies/邮件系统/Lession/Server/Hotfix/Hotfix.csproj", + "packagesPath": "/Users/fantasy/.nuget/packages/", + "outputPath": "/Users/fantasy/Movies/邮件系统/Lession/Server/Hotfix/obj/", + "projectStyle": "PackageReference", + "configFilePaths": [ + "/Users/fantasy/.nuget/NuGet/NuGet.Config" + ], + "originalTargetFrameworks": [ + "net8.0" + ], + "sources": { + "/usr/local/share/dotnet/library-packs": {}, + "https://api.nuget.org/v3/index.json": {} + }, + "frameworks": { + "net8.0": { + "targetAlias": "net8.0", + "projectReferences": { + "/Users/fantasy/Movies/邮件系统/Lession/Server/Entity/Entity.csproj": { + "projectPath": "/Users/fantasy/Movies/邮件系统/Lession/Server/Entity/Entity.csproj" + } + } + } + }, + "warningProperties": { + "warnAsError": [ + "NU1605" + ] + }, + "restoreAuditProperties": { + "enableAudit": "true", + "auditLevel": "low", + "auditMode": "all" + }, + "SdkAnalysisLevel": "9.0.100" + }, + "frameworks": { + "net8.0": { + "targetAlias": "net8.0", + "imports": [ + "net461", + "net462", + "net47", + "net471", + "net472", + "net48", + "net481" + ], + "assetTargetFallback": true, + "warn": true, + "frameworkReferences": { + "Microsoft.NETCore.App": { + "privateAssets": "all" + } + }, + "runtimeIdentifierGraphPath": "/usr/local/share/dotnet/sdk/9.0.100/PortableRuntimeIdentifierGraph.json" + } + } + } +} \ No newline at end of file diff --git a/邮件系统课程完整代码/Server/Hotfix/obj/project.nuget.cache b/邮件系统课程完整代码/Server/Hotfix/obj/project.nuget.cache new file mode 100644 index 0000000..7f91a4c --- /dev/null +++ b/邮件系统课程完整代码/Server/Hotfix/obj/project.nuget.cache @@ -0,0 +1,30 @@ +{ + "version": 2, + "dgSpecHash": "K6lNdXXdUo0=", + "success": true, + "projectFilePath": "/Users/fantasy/Movies/邮件系统/Lession/Server/Hotfix/Hotfix.csproj", + "expectedPackageFiles": [ + "/Users/fantasy/.nuget/packages/commandlineparser/2.9.1/commandlineparser.2.9.1.nupkg.sha512", + "/Users/fantasy/.nuget/packages/dnsclient/1.6.1/dnsclient.1.6.1.nupkg.sha512", + "/Users/fantasy/.nuget/packages/fantasy-net/2024.2.22/fantasy-net.2024.2.22.nupkg.sha512", + "/Users/fantasy/.nuget/packages/microsoft.extensions.logging.abstractions/2.0.0/microsoft.extensions.logging.abstractions.2.0.0.nupkg.sha512", + "/Users/fantasy/.nuget/packages/microsoft.netcore.platforms/5.0.0/microsoft.netcore.platforms.5.0.0.nupkg.sha512", + "/Users/fantasy/.nuget/packages/microsoft.win32.registry/5.0.0/microsoft.win32.registry.5.0.0.nupkg.sha512", + "/Users/fantasy/.nuget/packages/mongodb.bson/3.1.0/mongodb.bson.3.1.0.nupkg.sha512", + "/Users/fantasy/.nuget/packages/mongodb.driver/3.1.0/mongodb.driver.3.1.0.nupkg.sha512", + "/Users/fantasy/.nuget/packages/newtonsoft.json/13.0.3/newtonsoft.json.13.0.3.nupkg.sha512", + "/Users/fantasy/.nuget/packages/protobuf-net/3.2.45/protobuf-net.3.2.45.nupkg.sha512", + "/Users/fantasy/.nuget/packages/protobuf-net.core/3.2.45/protobuf-net.core.3.2.45.nupkg.sha512", + "/Users/fantasy/.nuget/packages/sharpcompress/0.30.1/sharpcompress.0.30.1.nupkg.sha512", + "/Users/fantasy/.nuget/packages/snappier/1.0.0/snappier.1.0.0.nupkg.sha512", + "/Users/fantasy/.nuget/packages/system.buffers/4.5.1/system.buffers.4.5.1.nupkg.sha512", + "/Users/fantasy/.nuget/packages/system.collections.immutable/7.0.0/system.collections.immutable.7.0.0.nupkg.sha512", + "/Users/fantasy/.nuget/packages/system.io.pipelines/9.0.0/system.io.pipelines.9.0.0.nupkg.sha512", + "/Users/fantasy/.nuget/packages/system.memory/4.5.5/system.memory.4.5.5.nupkg.sha512", + "/Users/fantasy/.nuget/packages/system.runtime.compilerservices.unsafe/5.0.0/system.runtime.compilerservices.unsafe.5.0.0.nupkg.sha512", + "/Users/fantasy/.nuget/packages/system.security.accesscontrol/5.0.0/system.security.accesscontrol.5.0.0.nupkg.sha512", + "/Users/fantasy/.nuget/packages/system.security.principal.windows/5.0.0/system.security.principal.windows.5.0.0.nupkg.sha512", + "/Users/fantasy/.nuget/packages/zstdsharp.port/0.7.3/zstdsharp.port.0.7.3.nupkg.sha512" + ], + "logs": [] +} \ No newline at end of file diff --git a/邮件系统课程完整代码/Server/Hotfix/obj/project.packagespec.json b/邮件系统课程完整代码/Server/Hotfix/obj/project.packagespec.json new file mode 100644 index 0000000..e4d9f04 --- /dev/null +++ b/邮件系统课程完整代码/Server/Hotfix/obj/project.packagespec.json @@ -0,0 +1 @@ +"restore":{"projectUniqueName":"/Users/fantasy/Movies/邮件系统/Lession/Server/Hotfix/Hotfix.csproj","projectName":"Hotfix","projectPath":"/Users/fantasy/Movies/邮件系统/Lession/Server/Hotfix/Hotfix.csproj","outputPath":"/Users/fantasy/Movies/邮件系统/Lession/Server/Hotfix/obj/","projectStyle":"PackageReference","originalTargetFrameworks":["net8.0"],"sources":{"/usr/local/share/dotnet/library-packs":{},"https://api.nuget.org/v3/index.json":{}},"frameworks":{"net8.0":{"targetAlias":"net8.0","projectReferences":{"/Users/fantasy/Movies/邮件系统/Lession/Server/Entity/Entity.csproj":{"projectPath":"/Users/fantasy/Movies/邮件系统/Lession/Server/Entity/Entity.csproj"}}}},"warningProperties":{"warnAsError":["NU1605"]},"restoreAuditProperties":{"enableAudit":"true","auditLevel":"low","auditMode":"all"},"SdkAnalysisLevel":"9.0.100"}"frameworks":{"net8.0":{"targetAlias":"net8.0","imports":["net461","net462","net47","net471","net472","net48","net481"],"assetTargetFallback":true,"warn":true,"frameworkReferences":{"Microsoft.NETCore.App":{"privateAssets":"all"}},"runtimeIdentifierGraphPath":"/usr/local/share/dotnet/sdk/9.0.100/PortableRuntimeIdentifierGraph.json"}} \ No newline at end of file diff --git a/邮件系统课程完整代码/Server/Hotfix/obj/rider.project.model.nuget.info b/邮件系统课程完整代码/Server/Hotfix/obj/rider.project.model.nuget.info new file mode 100644 index 0000000..90a41f2 --- /dev/null +++ b/邮件系统课程完整代码/Server/Hotfix/obj/rider.project.model.nuget.info @@ -0,0 +1 @@ +17392438089775538 \ No newline at end of file diff --git a/邮件系统课程完整代码/Server/Hotfix/obj/rider.project.restore.info b/邮件系统课程完整代码/Server/Hotfix/obj/rider.project.restore.info new file mode 100644 index 0000000..90a41f2 --- /dev/null +++ b/邮件系统课程完整代码/Server/Hotfix/obj/rider.project.restore.info @@ -0,0 +1 @@ +17392438089775538 \ No newline at end of file diff --git a/邮件系统课程完整代码/Tools/.DS_Store b/邮件系统课程完整代码/Tools/.DS_Store new file mode 100644 index 0000000..5afc148 Binary files /dev/null and b/邮件系统课程完整代码/Tools/.DS_Store differ diff --git a/邮件系统课程完整代码/Tools/ConfigTable/CommandLine.dll b/邮件系统课程完整代码/Tools/ConfigTable/CommandLine.dll new file mode 100644 index 0000000..3eab2be Binary files /dev/null and b/邮件系统课程完整代码/Tools/ConfigTable/CommandLine.dll differ diff --git a/邮件系统课程完整代码/Tools/ConfigTable/EPPlus.Interfaces.dll b/邮件系统课程完整代码/Tools/ConfigTable/EPPlus.Interfaces.dll new file mode 100644 index 0000000..599a767 Binary files /dev/null and b/邮件系统课程完整代码/Tools/ConfigTable/EPPlus.Interfaces.dll differ diff --git a/邮件系统课程完整代码/Tools/ConfigTable/EPPlus.System.Drawing.dll b/邮件系统课程完整代码/Tools/ConfigTable/EPPlus.System.Drawing.dll new file mode 100644 index 0000000..8df125e Binary files /dev/null and b/邮件系统课程完整代码/Tools/ConfigTable/EPPlus.System.Drawing.dll differ diff --git a/邮件系统课程完整代码/Tools/ConfigTable/EPPlus.dll b/邮件系统课程完整代码/Tools/ConfigTable/EPPlus.dll new file mode 100644 index 0000000..b09ea77 Binary files /dev/null and b/邮件系统课程完整代码/Tools/ConfigTable/EPPlus.dll differ diff --git a/邮件系统课程完整代码/Tools/ConfigTable/ExporterSettings.json b/邮件系统课程完整代码/Tools/ConfigTable/ExporterSettings.json new file mode 100644 index 0000000..026e76c --- /dev/null +++ b/邮件系统课程完整代码/Tools/ConfigTable/ExporterSettings.json @@ -0,0 +1,44 @@ +{ + "Export": { + "ExcelProgramPath": { + "Value": "../../Config/Excel/", + "Comment": "Excel文件夹的根目录" + }, + "ExcelVersionFile": { + "Value": "../../Config/Excel/Version.txt", + "Comment": "Excel的Version文件位置、这个文件用于记录每次导出对比是否需要再次导出的文件" + }, + "ExcelServerFileDirectory": { + "Value": "../../Server/Entity/Generate/ConfigTable/Entity/", + "Comment": "Excel生成的代码文件、在服务端文件夹位置" + }, + "ExcelClientFileDirectory": { + "Value": "../../Client/Unity/Assets/Scripts/Hotfix/Generate/ConfigTable/Entity/", + "Comment": "Excel生成的代码文件、在客户端文件夹位置" + }, + "ExcelServerBinaryDirectory": { + "Value": "../../Config/Binary/", + "Comment": "Excel生成服务器二进制数据文件夹位置" + }, + "ExcelClientBinaryDirectory": { + "Value": "../../Client/Unity/Assets/Bundles/Config/", + "Comment": "Excel生成在客户端的二进制数据文件夹位置" + }, + "ExcelServerJsonDirectory": { + "Value": "../../Config/Json/Server/", + "Comment": "Excel生成在服务端的Json数据文件夹位置" + }, + "ExcelClientJsonDirectory": { + "Value": "../../Config/Json/Client/", + "Comment": "Excel生成在客户端的Json数据文件夹位置" + }, + "ServerCustomExportDirectory": { + "Value": "../../Server/Entity/Generate/CustomExport/", + "Comment": "Excel在服务端生成自定义代码的文件夹位置" + }, + "ClientCustomExportDirectory": { + "Value": "../../Client/Unity/Assets/Scripts/Hotfix/Generate/CustomExport", + "Comment": "Excel在客户端端生成自定义代码的文件夹位置" + } + } +} \ No newline at end of file diff --git a/邮件系统课程完整代码/Tools/ConfigTable/Fantasy.Tools.ConfigTable b/邮件系统课程完整代码/Tools/ConfigTable/Fantasy.Tools.ConfigTable new file mode 100644 index 0000000..434496e Binary files /dev/null and b/邮件系统课程完整代码/Tools/ConfigTable/Fantasy.Tools.ConfigTable differ diff --git a/邮件系统课程完整代码/Tools/ConfigTable/Fantasy.Tools.ConfigTable.deps.json b/邮件系统课程完整代码/Tools/ConfigTable/Fantasy.Tools.ConfigTable.deps.json new file mode 100644 index 0000000..b248849 --- /dev/null +++ b/邮件系统课程完整代码/Tools/ConfigTable/Fantasy.Tools.ConfigTable.deps.json @@ -0,0 +1,521 @@ +{ + "runtimeTarget": { + "name": ".NETCoreApp,Version=v8.0", + "signature": "" + }, + "compilationOptions": {}, + "targets": { + ".NETCoreApp,Version=v8.0": { + "Fantasy.Tools.ConfigTable/1.0.0": { + "dependencies": { + "CommandLineParser": "2.9.1", + "EPPlus": "7.3.2", + "Microsoft.CodeAnalysis.CSharp": "4.11.0", + "Microsoft.Extensions.Configuration.Json": "8.0.0", + "Newtonsoft.Json": "13.0.3", + "protobuf-net": "3.2.30" + }, + "runtime": { + "Fantasy.Tools.ConfigTable.dll": {} + } + }, + "CommandLineParser/2.9.1": { + "runtime": { + "lib/netstandard2.0/CommandLine.dll": { + "assemblyVersion": "2.9.1.0", + "fileVersion": "2.9.1.0" + } + } + }, + "EPPlus/7.3.2": { + "dependencies": { + "EPPlus.System.Drawing": "6.1.1", + "Microsoft.Extensions.Configuration.Json": "8.0.0", + "Microsoft.IO.RecyclableMemoryStream": "3.0.1", + "System.ComponentModel.Annotations": "5.0.0", + "System.Formats.Asn1": "8.0.1", + "System.Security.Cryptography.Pkcs": "8.0.0", + "System.Text.Encoding.CodePages": "8.0.0", + "System.Text.Json": "8.0.4" + }, + "runtime": { + "lib/net8.0/EPPlus.dll": { + "assemblyVersion": "7.3.2.0", + "fileVersion": "7.3.2.0" + } + } + }, + "EPPlus.Interfaces/6.1.1": { + "runtime": { + "lib/net7.0/EPPlus.Interfaces.dll": { + "assemblyVersion": "6.1.1.0", + "fileVersion": "6.1.1.0" + } + } + }, + "EPPlus.System.Drawing/6.1.1": { + "dependencies": { + "EPPlus.Interfaces": "6.1.1", + "System.Drawing.Common": "7.0.0" + }, + "runtime": { + "lib/net7.0/EPPlus.System.Drawing.dll": { + "assemblyVersion": "6.1.1.0", + "fileVersion": "6.1.1.0" + } + } + }, + "Microsoft.CodeAnalysis.Analyzers/3.3.4": {}, + "Microsoft.CodeAnalysis.Common/4.11.0": { + "dependencies": { + "Microsoft.CodeAnalysis.Analyzers": "3.3.4", + "System.Collections.Immutable": "8.0.0", + "System.Reflection.Metadata": "8.0.0" + }, + "runtime": { + "lib/net8.0/Microsoft.CodeAnalysis.dll": { + "assemblyVersion": "4.11.0.0", + "fileVersion": "4.1100.24.37604" + } + } + }, + "Microsoft.CodeAnalysis.CSharp/4.11.0": { + "dependencies": { + "Microsoft.CodeAnalysis.Analyzers": "3.3.4", + "Microsoft.CodeAnalysis.Common": "4.11.0", + "System.Collections.Immutable": "8.0.0", + "System.Reflection.Metadata": "8.0.0" + }, + "runtime": { + "lib/net8.0/Microsoft.CodeAnalysis.CSharp.dll": { + "assemblyVersion": "4.11.0.0", + "fileVersion": "4.1100.24.37604" + } + } + }, + "Microsoft.Extensions.Configuration/8.0.0": { + "dependencies": { + "Microsoft.Extensions.Configuration.Abstractions": "8.0.0", + "Microsoft.Extensions.Primitives": "8.0.0" + }, + "runtime": { + "lib/net8.0/Microsoft.Extensions.Configuration.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.23.53103" + } + } + }, + "Microsoft.Extensions.Configuration.Abstractions/8.0.0": { + "dependencies": { + "Microsoft.Extensions.Primitives": "8.0.0" + }, + "runtime": { + "lib/net8.0/Microsoft.Extensions.Configuration.Abstractions.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.23.53103" + } + } + }, + "Microsoft.Extensions.Configuration.FileExtensions/8.0.0": { + "dependencies": { + "Microsoft.Extensions.Configuration": "8.0.0", + "Microsoft.Extensions.Configuration.Abstractions": "8.0.0", + "Microsoft.Extensions.FileProviders.Abstractions": "8.0.0", + "Microsoft.Extensions.FileProviders.Physical": "8.0.0", + "Microsoft.Extensions.Primitives": "8.0.0" + }, + "runtime": { + "lib/net8.0/Microsoft.Extensions.Configuration.FileExtensions.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.23.53103" + } + } + }, + "Microsoft.Extensions.Configuration.Json/8.0.0": { + "dependencies": { + "Microsoft.Extensions.Configuration": "8.0.0", + "Microsoft.Extensions.Configuration.Abstractions": "8.0.0", + "Microsoft.Extensions.Configuration.FileExtensions": "8.0.0", + "Microsoft.Extensions.FileProviders.Abstractions": "8.0.0", + "System.Text.Json": "8.0.4" + }, + "runtime": { + "lib/net8.0/Microsoft.Extensions.Configuration.Json.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.23.53103" + } + } + }, + "Microsoft.Extensions.FileProviders.Abstractions/8.0.0": { + "dependencies": { + "Microsoft.Extensions.Primitives": "8.0.0" + }, + "runtime": { + "lib/net8.0/Microsoft.Extensions.FileProviders.Abstractions.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.23.53103" + } + } + }, + "Microsoft.Extensions.FileProviders.Physical/8.0.0": { + "dependencies": { + "Microsoft.Extensions.FileProviders.Abstractions": "8.0.0", + "Microsoft.Extensions.FileSystemGlobbing": "8.0.0", + "Microsoft.Extensions.Primitives": "8.0.0" + }, + "runtime": { + "lib/net8.0/Microsoft.Extensions.FileProviders.Physical.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.23.53103" + } + } + }, + "Microsoft.Extensions.FileSystemGlobbing/8.0.0": { + "runtime": { + "lib/net8.0/Microsoft.Extensions.FileSystemGlobbing.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.23.53103" + } + } + }, + "Microsoft.Extensions.Primitives/8.0.0": { + "runtime": { + "lib/net8.0/Microsoft.Extensions.Primitives.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.23.53103" + } + } + }, + "Microsoft.IO.RecyclableMemoryStream/3.0.1": { + "runtime": { + "lib/net6.0/Microsoft.IO.RecyclableMemoryStream.dll": { + "assemblyVersion": "3.0.1.0", + "fileVersion": "3.0.1.0" + } + } + }, + "Microsoft.Win32.SystemEvents/7.0.0": { + "runtime": { + "lib/net7.0/Microsoft.Win32.SystemEvents.dll": { + "assemblyVersion": "7.0.0.0", + "fileVersion": "7.0.22.51805" + } + }, + "runtimeTargets": { + "runtimes/win/lib/net7.0/Microsoft.Win32.SystemEvents.dll": { + "rid": "win", + "assetType": "runtime", + "assemblyVersion": "7.0.0.0", + "fileVersion": "7.0.22.51805" + } + } + }, + "Newtonsoft.Json/13.0.3": { + "runtime": { + "lib/net6.0/Newtonsoft.Json.dll": { + "assemblyVersion": "13.0.0.0", + "fileVersion": "13.0.3.27908" + } + } + }, + "protobuf-net/3.2.30": { + "dependencies": { + "protobuf-net.Core": "3.2.30" + }, + "runtime": { + "lib/net6.0/protobuf-net.dll": { + "assemblyVersion": "3.0.0.0", + "fileVersion": "3.2.30.709" + } + } + }, + "protobuf-net.Core/3.2.30": { + "dependencies": { + "System.Collections.Immutable": "8.0.0" + }, + "runtime": { + "lib/net6.0/protobuf-net.Core.dll": { + "assemblyVersion": "3.0.0.0", + "fileVersion": "3.2.30.709" + } + } + }, + "System.Collections.Immutable/8.0.0": {}, + "System.ComponentModel.Annotations/5.0.0": {}, + "System.Drawing.Common/7.0.0": { + "dependencies": { + "Microsoft.Win32.SystemEvents": "7.0.0" + }, + "runtime": { + "lib/net7.0/System.Drawing.Common.dll": { + "assemblyVersion": "7.0.0.0", + "fileVersion": "7.0.22.51805" + } + }, + "runtimeTargets": { + "runtimes/win/lib/net7.0/System.Drawing.Common.dll": { + "rid": "win", + "assetType": "runtime", + "assemblyVersion": "7.0.0.0", + "fileVersion": "7.0.22.51805" + } + } + }, + "System.Formats.Asn1/8.0.1": { + "runtime": { + "lib/net8.0/System.Formats.Asn1.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.724.31311" + } + } + }, + "System.Reflection.Metadata/8.0.0": { + "dependencies": { + "System.Collections.Immutable": "8.0.0" + } + }, + "System.Security.Cryptography.Pkcs/8.0.0": { + "dependencies": { + "System.Formats.Asn1": "8.0.1" + }, + "runtime": { + "lib/net8.0/System.Security.Cryptography.Pkcs.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.23.53103" + } + }, + "runtimeTargets": { + "runtimes/win/lib/net8.0/System.Security.Cryptography.Pkcs.dll": { + "rid": "win", + "assetType": "runtime", + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.23.53103" + } + } + }, + "System.Text.Encoding.CodePages/8.0.0": {}, + "System.Text.Encodings.Web/8.0.0": {}, + "System.Text.Json/8.0.4": { + "dependencies": { + "System.Text.Encodings.Web": "8.0.0" + }, + "runtime": { + "lib/net8.0/System.Text.Json.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.724.31311" + } + } + } + } + }, + "libraries": { + "Fantasy.Tools.ConfigTable/1.0.0": { + "type": "project", + "serviceable": false, + "sha512": "" + }, + "CommandLineParser/2.9.1": { + "type": "package", + "serviceable": true, + "sha512": "sha512-OE0sl1/sQ37bjVsPKKtwQlWDgqaxWgtme3xZz7JssWUzg5JpMIyHgCTY9MVMxOg48fJ1AgGT3tgdH5m/kQ5xhA==", + "path": "commandlineparser/2.9.1", + "hashPath": "commandlineparser.2.9.1.nupkg.sha512" + }, + "EPPlus/7.3.2": { + "type": "package", + "serviceable": true, + "sha512": "sha512-9DShQD2VuDZ7QLHp+map1r2HdI1G325YGkvRG+qs4N2fgeMF1Uq0TONCEL5gKCWMNDVGO0ZELJTAIzwNyOZQug==", + "path": "epplus/7.3.2", + "hashPath": "epplus.7.3.2.nupkg.sha512" + }, + "EPPlus.Interfaces/6.1.1": { + "type": "package", + "serviceable": true, + "sha512": "sha512-y7dkrOoE1ZR9Vgy1Jf2rEIaTf3SHlUjYt01NklP+F5Qh7S2ruPbzTcpYLRWMeXiG8XL8h2jqX4CyIkFt3NQGZw==", + "path": "epplus.interfaces/6.1.1", + "hashPath": "epplus.interfaces.6.1.1.nupkg.sha512" + }, + "EPPlus.System.Drawing/6.1.1": { + "type": "package", + "serviceable": true, + "sha512": "sha512-lRF5gHYrmkHOOiLMI0t6q8zNYjUrzRgAM5BCXumv5xiqXko8fx3AWI+HCNZfhEqVFGOop+42KfR5GiUcCoyoMw==", + "path": "epplus.system.drawing/6.1.1", + "hashPath": "epplus.system.drawing.6.1.1.nupkg.sha512" + }, + "Microsoft.CodeAnalysis.Analyzers/3.3.4": { + "type": "package", + "serviceable": true, + "sha512": "sha512-AxkxcPR+rheX0SmvpLVIGLhOUXAKG56a64kV9VQZ4y9gR9ZmPXnqZvHJnmwLSwzrEP6junUF11vuc+aqo5r68g==", + "path": "microsoft.codeanalysis.analyzers/3.3.4", + "hashPath": "microsoft.codeanalysis.analyzers.3.3.4.nupkg.sha512" + }, + "Microsoft.CodeAnalysis.Common/4.11.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-djf8ujmqYImFgB04UGtcsEhHrzVqzHowS+EEl/Yunc5LdrYrZhGBWUTXoCF0NzYXJxtfuD+UVQarWpvrNc94Qg==", + "path": "microsoft.codeanalysis.common/4.11.0", + "hashPath": "microsoft.codeanalysis.common.4.11.0.nupkg.sha512" + }, + "Microsoft.CodeAnalysis.CSharp/4.11.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-6XYi2EusI8JT4y2l/F3VVVS+ISoIX9nqHsZRaG6W5aFeJ5BEuBosHfT/ABb73FN0RZ1Z3cj2j7cL28SToJPXOw==", + "path": "microsoft.codeanalysis.csharp/4.11.0", + "hashPath": "microsoft.codeanalysis.csharp.4.11.0.nupkg.sha512" + }, + "Microsoft.Extensions.Configuration/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-0J/9YNXTMWSZP2p2+nvl8p71zpSwokZXZuJW+VjdErkegAnFdO1XlqtA62SJtgVYHdKu3uPxJHcMR/r35HwFBA==", + "path": "microsoft.extensions.configuration/8.0.0", + "hashPath": "microsoft.extensions.configuration.8.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.Configuration.Abstractions/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-3lE/iLSutpgX1CC0NOW70FJoGARRHbyKmG7dc0klnUZ9Dd9hS6N/POPWhKhMLCEuNN5nXEY5agmlFtH562vqhQ==", + "path": "microsoft.extensions.configuration.abstractions/8.0.0", + "hashPath": "microsoft.extensions.configuration.abstractions.8.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.Configuration.FileExtensions/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-McP+Lz/EKwvtCv48z0YImw+L1gi1gy5rHhNaNIY2CrjloV+XY8gydT8DjMR6zWeL13AFK+DioVpppwAuO1Gi1w==", + "path": "microsoft.extensions.configuration.fileextensions/8.0.0", + "hashPath": "microsoft.extensions.configuration.fileextensions.8.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.Configuration.Json/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-C2wqUoh9OmRL1akaCcKSTmRU8z0kckfImG7zLNI8uyi47Lp+zd5LWAD17waPQEqCz3ioWOCrFUo+JJuoeZLOBw==", + "path": "microsoft.extensions.configuration.json/8.0.0", + "hashPath": "microsoft.extensions.configuration.json.8.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.FileProviders.Abstractions/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-ZbaMlhJlpisjuWbvXr4LdAst/1XxH3vZ6A0BsgTphZ2L4PGuxRLz7Jr/S7mkAAnOn78Vu0fKhEgNF5JO3zfjqQ==", + "path": "microsoft.extensions.fileproviders.abstractions/8.0.0", + "hashPath": "microsoft.extensions.fileproviders.abstractions.8.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.FileProviders.Physical/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-UboiXxpPUpwulHvIAVE36Knq0VSHaAmfrFkegLyBZeaADuKezJ/AIXYAW8F5GBlGk/VaibN2k/Zn1ca8YAfVdA==", + "path": "microsoft.extensions.fileproviders.physical/8.0.0", + "hashPath": "microsoft.extensions.fileproviders.physical.8.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.FileSystemGlobbing/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-OK+670i7esqlQrPjdIKRbsyMCe9g5kSLpRRQGSr4Q58AOYEe/hCnfLZprh7viNisSUUQZmMrbbuDaIrP+V1ebQ==", + "path": "microsoft.extensions.filesystemglobbing/8.0.0", + "hashPath": "microsoft.extensions.filesystemglobbing.8.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.Primitives/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-bXJEZrW9ny8vjMF1JV253WeLhpEVzFo1lyaZu1vQ4ZxWUlVvknZ/+ftFgVheLubb4eZPSwwxBeqS1JkCOjxd8g==", + "path": "microsoft.extensions.primitives/8.0.0", + "hashPath": "microsoft.extensions.primitives.8.0.0.nupkg.sha512" + }, + "Microsoft.IO.RecyclableMemoryStream/3.0.1": { + "type": "package", + "serviceable": true, + "sha512": "sha512-s/s20YTVY9r9TPfTrN5g8zPF1YhwxyqO6PxUkrYTGI2B+OGPe9AdajWZrLhFqXIvqIW23fnUE4+ztrUWNU1+9g==", + "path": "microsoft.io.recyclablememorystream/3.0.1", + "hashPath": "microsoft.io.recyclablememorystream.3.0.1.nupkg.sha512" + }, + "Microsoft.Win32.SystemEvents/7.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-2nXPrhdAyAzir0gLl8Yy8S5Mnm/uBSQQA7jEsILOS1MTyS7DbmV1NgViMtvV1sfCD1ebITpNwb1NIinKeJgUVQ==", + "path": "microsoft.win32.systemevents/7.0.0", + "hashPath": "microsoft.win32.systemevents.7.0.0.nupkg.sha512" + }, + "Newtonsoft.Json/13.0.3": { + "type": "package", + "serviceable": true, + "sha512": "sha512-HrC5BXdl00IP9zeV+0Z848QWPAoCr9P3bDEZguI+gkLcBKAOxix/tLEAAHC+UvDNPv4a2d18lOReHMOagPa+zQ==", + "path": "newtonsoft.json/13.0.3", + "hashPath": "newtonsoft.json.13.0.3.nupkg.sha512" + }, + "protobuf-net/3.2.30": { + "type": "package", + "serviceable": true, + "sha512": "sha512-C/UTlmxEJHAHpqm8xQK1UyJKaIynVCSNG4mVrbLgnZ7ccH28nN49O8iMJvKEodTgVbnimvy+3mIiAdW6mATwnw==", + "path": "protobuf-net/3.2.30", + "hashPath": "protobuf-net.3.2.30.nupkg.sha512" + }, + "protobuf-net.Core/3.2.30": { + "type": "package", + "serviceable": true, + "sha512": "sha512-v2ZxxYrz+X212ukSx+uqkLuPu414bvmSAnTyf+PBUKR9ENJxO4P/csorA/27456MCp1JNoMssDj/f91RDiwBfQ==", + "path": "protobuf-net.core/3.2.30", + "hashPath": "protobuf-net.core.3.2.30.nupkg.sha512" + }, + "System.Collections.Immutable/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-AurL6Y5BA1WotzlEvVaIDpqzpIPvYnnldxru8oXJU2yFxFUy3+pNXjXd1ymO+RA0rq0+590Q8gaz2l3Sr7fmqg==", + "path": "system.collections.immutable/8.0.0", + "hashPath": "system.collections.immutable.8.0.0.nupkg.sha512" + }, + "System.ComponentModel.Annotations/5.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-dMkqfy2el8A8/I76n2Hi1oBFEbG1SfxD2l5nhwXV3XjlnOmwxJlQbYpJH4W51odnU9sARCSAgv7S3CyAFMkpYg==", + "path": "system.componentmodel.annotations/5.0.0", + "hashPath": "system.componentmodel.annotations.5.0.0.nupkg.sha512" + }, + "System.Drawing.Common/7.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-KIX+oBU38pxkKPxvLcLfIkOV5Ien8ReN78wro7OF5/erwcmortzeFx+iBswlh2Vz6gVne0khocQudGwaO1Ey6A==", + "path": "system.drawing.common/7.0.0", + "hashPath": "system.drawing.common.7.0.0.nupkg.sha512" + }, + "System.Formats.Asn1/8.0.1": { + "type": "package", + "serviceable": true, + "sha512": "sha512-XqKba7Mm/koKSjKMfW82olQdmfbI5yqeoLV/tidRp7fbh5rmHAQ5raDI/7SU0swTzv+jgqtUGkzmFxuUg0it1A==", + "path": "system.formats.asn1/8.0.1", + "hashPath": "system.formats.asn1.8.0.1.nupkg.sha512" + }, + "System.Reflection.Metadata/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-ptvgrFh7PvWI8bcVqG5rsA/weWM09EnthFHR5SCnS6IN+P4mj6rE1lBDC4U8HL9/57htKAqy4KQ3bBj84cfYyQ==", + "path": "system.reflection.metadata/8.0.0", + "hashPath": "system.reflection.metadata.8.0.0.nupkg.sha512" + }, + "System.Security.Cryptography.Pkcs/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-ULmp3xoOwNYjOYp4JZ2NK/6NdTgiN1GQXzVVN1njQ7LOZ0d0B9vyMnhyqbIi9Qw4JXj1JgCsitkTShboHRx7Eg==", + "path": "system.security.cryptography.pkcs/8.0.0", + "hashPath": "system.security.cryptography.pkcs.8.0.0.nupkg.sha512" + }, + "System.Text.Encoding.CodePages/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-OZIsVplFGaVY90G2SbpgU7EnCoOO5pw1t4ic21dBF3/1omrJFpAGoNAVpPyMVOC90/hvgkGG3VFqR13YgZMQfg==", + "path": "system.text.encoding.codepages/8.0.0", + "hashPath": "system.text.encoding.codepages.8.0.0.nupkg.sha512" + }, + "System.Text.Encodings.Web/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-yev/k9GHAEGx2Rg3/tU6MQh4HGBXJs70y7j1LaM1i/ER9po+6nnQ6RRqTJn1E7Xu0fbIFK80Nh5EoODxrbxwBQ==", + "path": "system.text.encodings.web/8.0.0", + "hashPath": "system.text.encodings.web.8.0.0.nupkg.sha512" + }, + "System.Text.Json/8.0.4": { + "type": "package", + "serviceable": true, + "sha512": "sha512-bAkhgDJ88XTsqczoxEMliSrpijKZHhbJQldhAmObj/RbrN3sU5dcokuXmWJWsdQAhiMJ9bTayWsL1C9fbbCRhw==", + "path": "system.text.json/8.0.4", + "hashPath": "system.text.json.8.0.4.nupkg.sha512" + } + } +} \ No newline at end of file diff --git a/邮件系统课程完整代码/Tools/ConfigTable/Fantasy.Tools.ConfigTable.dll b/邮件系统课程完整代码/Tools/ConfigTable/Fantasy.Tools.ConfigTable.dll new file mode 100644 index 0000000..691c3ec Binary files /dev/null and b/邮件系统课程完整代码/Tools/ConfigTable/Fantasy.Tools.ConfigTable.dll differ diff --git a/邮件系统课程完整代码/Tools/ConfigTable/Fantasy.Tools.ConfigTable.pdb b/邮件系统课程完整代码/Tools/ConfigTable/Fantasy.Tools.ConfigTable.pdb new file mode 100644 index 0000000..e28ebf3 Binary files /dev/null and b/邮件系统课程完整代码/Tools/ConfigTable/Fantasy.Tools.ConfigTable.pdb differ diff --git a/邮件系统课程完整代码/Tools/ConfigTable/Fantasy.Tools.ConfigTable.runtimeconfig.json b/邮件系统课程完整代码/Tools/ConfigTable/Fantasy.Tools.ConfigTable.runtimeconfig.json new file mode 100644 index 0000000..becfaea --- /dev/null +++ b/邮件系统课程完整代码/Tools/ConfigTable/Fantasy.Tools.ConfigTable.runtimeconfig.json @@ -0,0 +1,12 @@ +{ + "runtimeOptions": { + "tfm": "net8.0", + "framework": { + "name": "Microsoft.NETCore.App", + "version": "8.0.0" + }, + "configProperties": { + "System.Runtime.Serialization.EnableUnsafeBinaryFormatterSerialization": false + } + } +} \ No newline at end of file diff --git a/邮件系统课程完整代码/Tools/ConfigTable/Microsoft.CodeAnalysis.CSharp.dll b/邮件系统课程完整代码/Tools/ConfigTable/Microsoft.CodeAnalysis.CSharp.dll new file mode 100644 index 0000000..c23db48 Binary files /dev/null and b/邮件系统课程完整代码/Tools/ConfigTable/Microsoft.CodeAnalysis.CSharp.dll differ diff --git a/邮件系统课程完整代码/Tools/ConfigTable/Microsoft.CodeAnalysis.dll b/邮件系统课程完整代码/Tools/ConfigTable/Microsoft.CodeAnalysis.dll new file mode 100644 index 0000000..de7eadd Binary files /dev/null and b/邮件系统课程完整代码/Tools/ConfigTable/Microsoft.CodeAnalysis.dll differ diff --git a/邮件系统课程完整代码/Tools/ConfigTable/Microsoft.Extensions.Configuration.Abstractions.dll b/邮件系统课程完整代码/Tools/ConfigTable/Microsoft.Extensions.Configuration.Abstractions.dll new file mode 100644 index 0000000..a5ab313 Binary files /dev/null and b/邮件系统课程完整代码/Tools/ConfigTable/Microsoft.Extensions.Configuration.Abstractions.dll differ diff --git a/邮件系统课程完整代码/Tools/ConfigTable/Microsoft.Extensions.Configuration.FileExtensions.dll b/邮件系统课程完整代码/Tools/ConfigTable/Microsoft.Extensions.Configuration.FileExtensions.dll new file mode 100644 index 0000000..4efc1a5 Binary files /dev/null and b/邮件系统课程完整代码/Tools/ConfigTable/Microsoft.Extensions.Configuration.FileExtensions.dll differ diff --git a/邮件系统课程完整代码/Tools/ConfigTable/Microsoft.Extensions.Configuration.Json.dll b/邮件系统课程完整代码/Tools/ConfigTable/Microsoft.Extensions.Configuration.Json.dll new file mode 100644 index 0000000..296db6a Binary files /dev/null and b/邮件系统课程完整代码/Tools/ConfigTable/Microsoft.Extensions.Configuration.Json.dll differ diff --git a/邮件系统课程完整代码/Tools/ConfigTable/Microsoft.Extensions.Configuration.dll b/邮件系统课程完整代码/Tools/ConfigTable/Microsoft.Extensions.Configuration.dll new file mode 100644 index 0000000..d3e5c22 Binary files /dev/null and b/邮件系统课程完整代码/Tools/ConfigTable/Microsoft.Extensions.Configuration.dll differ diff --git a/邮件系统课程完整代码/Tools/ConfigTable/Microsoft.Extensions.FileProviders.Abstractions.dll b/邮件系统课程完整代码/Tools/ConfigTable/Microsoft.Extensions.FileProviders.Abstractions.dll new file mode 100644 index 0000000..f907206 Binary files /dev/null and b/邮件系统课程完整代码/Tools/ConfigTable/Microsoft.Extensions.FileProviders.Abstractions.dll differ diff --git a/邮件系统课程完整代码/Tools/ConfigTable/Microsoft.Extensions.FileProviders.Physical.dll b/邮件系统课程完整代码/Tools/ConfigTable/Microsoft.Extensions.FileProviders.Physical.dll new file mode 100644 index 0000000..6fb7f47 Binary files /dev/null and b/邮件系统课程完整代码/Tools/ConfigTable/Microsoft.Extensions.FileProviders.Physical.dll differ diff --git a/邮件系统课程完整代码/Tools/ConfigTable/Microsoft.Extensions.FileSystemGlobbing.dll b/邮件系统课程完整代码/Tools/ConfigTable/Microsoft.Extensions.FileSystemGlobbing.dll new file mode 100644 index 0000000..e590735 Binary files /dev/null and b/邮件系统课程完整代码/Tools/ConfigTable/Microsoft.Extensions.FileSystemGlobbing.dll differ diff --git a/邮件系统课程完整代码/Tools/ConfigTable/Microsoft.Extensions.Primitives.dll b/邮件系统课程完整代码/Tools/ConfigTable/Microsoft.Extensions.Primitives.dll new file mode 100644 index 0000000..c24f2a0 Binary files /dev/null and b/邮件系统课程完整代码/Tools/ConfigTable/Microsoft.Extensions.Primitives.dll differ diff --git a/邮件系统课程完整代码/Tools/ConfigTable/Microsoft.IO.RecyclableMemoryStream.dll b/邮件系统课程完整代码/Tools/ConfigTable/Microsoft.IO.RecyclableMemoryStream.dll new file mode 100644 index 0000000..6e0ea40 Binary files /dev/null and b/邮件系统课程完整代码/Tools/ConfigTable/Microsoft.IO.RecyclableMemoryStream.dll differ diff --git a/邮件系统课程完整代码/Tools/ConfigTable/Microsoft.Win32.SystemEvents.dll b/邮件系统课程完整代码/Tools/ConfigTable/Microsoft.Win32.SystemEvents.dll new file mode 100644 index 0000000..d40a926 Binary files /dev/null and b/邮件系统课程完整代码/Tools/ConfigTable/Microsoft.Win32.SystemEvents.dll differ diff --git a/邮件系统课程完整代码/Tools/ConfigTable/Newtonsoft.Json.dll b/邮件系统课程完整代码/Tools/ConfigTable/Newtonsoft.Json.dll new file mode 100644 index 0000000..d035c38 Binary files /dev/null and b/邮件系统课程完整代码/Tools/ConfigTable/Newtonsoft.Json.dll differ diff --git a/邮件系统课程完整代码/Tools/ConfigTable/Run.bat b/邮件系统课程完整代码/Tools/ConfigTable/Run.bat new file mode 100644 index 0000000..e166f0e --- /dev/null +++ b/邮件系统课程完整代码/Tools/ConfigTable/Run.bat @@ -0,0 +1,21 @@ +@echo off + +echo Please select an option: +echo 1. Client +echo 2. Server +echo 3. All + +set /p choice=Please select an option: + +if "%choice%"=="1" ( + echo Client + dotnet Fantasy.Tools.ConfigTable.dll --ExportPlatform 1 +) else if "%choice%"=="2" ( + echo Server + dotnet Fantasy.Tools.ConfigTable.dll --ExportPlatform 2 +) else if "%choice%"=="3" ( + echo All + dotnet Fantasy.Tools.ConfigTable.dll --ExportPlatform 3 +) else ( + echo Invalid option +) diff --git a/邮件系统课程完整代码/Tools/ConfigTable/Run.sh b/邮件系统课程完整代码/Tools/ConfigTable/Run.sh new file mode 100644 index 0000000..491d8d9 --- /dev/null +++ b/邮件系统课程完整代码/Tools/ConfigTable/Run.sh @@ -0,0 +1,23 @@ +#!/bin/bash + +echo "1. Client" +echo "2. Server" +echo "3. All" + +read -n 1 -p "Please select an option:" choice +echo "" +echo "" +case $choice in + 1) + dotnet Fantasy.Tools.ConfigTable.dll --ExportPlatform 1 + ;; + 2) + dotnet Fantasy.Tools.ConfigTable.dll --ExportPlatform 2 + ;; + 3) + dotnet Fantasy.Tools.ConfigTable.dll --ExportPlatform 3 + ;; + *) + echo "Invalid option" + ;; +esac diff --git a/邮件系统课程完整代码/Tools/ConfigTable/System.Drawing.Common.dll b/邮件系统课程完整代码/Tools/ConfigTable/System.Drawing.Common.dll new file mode 100644 index 0000000..310d5e8 Binary files /dev/null and b/邮件系统课程完整代码/Tools/ConfigTable/System.Drawing.Common.dll differ diff --git a/邮件系统课程完整代码/Tools/ConfigTable/System.Formats.Asn1.dll b/邮件系统课程完整代码/Tools/ConfigTable/System.Formats.Asn1.dll new file mode 100644 index 0000000..16cc849 Binary files /dev/null and b/邮件系统课程完整代码/Tools/ConfigTable/System.Formats.Asn1.dll differ diff --git a/邮件系统课程完整代码/Tools/ConfigTable/System.Security.Cryptography.Pkcs.dll b/邮件系统课程完整代码/Tools/ConfigTable/System.Security.Cryptography.Pkcs.dll new file mode 100644 index 0000000..a76a14a Binary files /dev/null and b/邮件系统课程完整代码/Tools/ConfigTable/System.Security.Cryptography.Pkcs.dll differ diff --git a/邮件系统课程完整代码/Tools/ConfigTable/System.Text.Json.dll b/邮件系统课程完整代码/Tools/ConfigTable/System.Text.Json.dll new file mode 100644 index 0000000..0c6d406 Binary files /dev/null and b/邮件系统课程完整代码/Tools/ConfigTable/System.Text.Json.dll differ diff --git a/邮件系统课程完整代码/Tools/ConfigTable/protobuf-net.Core.dll b/邮件系统课程完整代码/Tools/ConfigTable/protobuf-net.Core.dll new file mode 100644 index 0000000..845a840 Binary files /dev/null and b/邮件系统课程完整代码/Tools/ConfigTable/protobuf-net.Core.dll differ diff --git a/邮件系统课程完整代码/Tools/ConfigTable/protobuf-net.dll b/邮件系统课程完整代码/Tools/ConfigTable/protobuf-net.dll new file mode 100644 index 0000000..e4b6839 Binary files /dev/null and b/邮件系统课程完整代码/Tools/ConfigTable/protobuf-net.dll differ diff --git a/邮件系统课程完整代码/Tools/NetworkProtocol/CommandLine.dll b/邮件系统课程完整代码/Tools/NetworkProtocol/CommandLine.dll new file mode 100644 index 0000000..3eab2be Binary files /dev/null and b/邮件系统课程完整代码/Tools/NetworkProtocol/CommandLine.dll differ diff --git a/邮件系统课程完整代码/Tools/NetworkProtocol/ExporterSettings.json b/邮件系统课程完整代码/Tools/NetworkProtocol/ExporterSettings.json new file mode 100644 index 0000000..41cb0e4 --- /dev/null +++ b/邮件系统课程完整代码/Tools/NetworkProtocol/ExporterSettings.json @@ -0,0 +1,29 @@ +{ + "Export": { + "NetworkProtocolDirectory": { + "Value": "../../Config/NetworkProtocol/", + "Comment": "ProtoBuf文件所在的文件夹位置" + }, + "NetworkProtocolServerDirectory": { + "Value": "../../Server/Entity/Generate/NetworkProtocol/", + "Comment": "ProtoBuf生成到服务端的文件夹位置" + }, + "NetworkProtocolClientDirectory": { + "Value": "../../Client/Unity/Assets/Scripts/Hotfix/Generate/NetworkProtocol/", + "Comment": "ProtoBuf生成到客户端的文件夹位置" + }, + "Serializes": { + "Value": [ +// { +// "KeyIndex": 0, +// "NameSpace" : "MemoryPack", +// "SerializeName": "MemoryPack", +// "Attribute": "\t[MemoryPackable]", +// "Ignore": "\t\t[MemoryPackIgnore]", +// "Member": "MemoryPackOrder" +// } + ], + "Comment": "自定义序列化器" + } + } +} \ No newline at end of file diff --git a/邮件系统课程完整代码/Tools/NetworkProtocol/Fantasy.Tools.NetworkProtocol b/邮件系统课程完整代码/Tools/NetworkProtocol/Fantasy.Tools.NetworkProtocol new file mode 100644 index 0000000..25ceaf1 Binary files /dev/null and b/邮件系统课程完整代码/Tools/NetworkProtocol/Fantasy.Tools.NetworkProtocol differ diff --git a/邮件系统课程完整代码/Tools/NetworkProtocol/Fantasy.Tools.NetworkProtocol.deps.json b/邮件系统课程完整代码/Tools/NetworkProtocol/Fantasy.Tools.NetworkProtocol.deps.json new file mode 100644 index 0000000..3c053cb --- /dev/null +++ b/邮件系统课程完整代码/Tools/NetworkProtocol/Fantasy.Tools.NetworkProtocol.deps.json @@ -0,0 +1,227 @@ +{ + "runtimeTarget": { + "name": ".NETCoreApp,Version=v8.0", + "signature": "" + }, + "compilationOptions": {}, + "targets": { + ".NETCoreApp,Version=v8.0": { + "Fantasy.Tools.NetworkProtocol/1.0.0": { + "dependencies": { + "CommandLineParser": "2.9.1", + "Microsoft.Extensions.Configuration.Json": "8.0.0", + "Newtonsoft.Json": "13.0.3" + }, + "runtime": { + "Fantasy.Tools.NetworkProtocol.dll": {} + } + }, + "CommandLineParser/2.9.1": { + "runtime": { + "lib/netstandard2.0/CommandLine.dll": { + "assemblyVersion": "2.9.1.0", + "fileVersion": "2.9.1.0" + } + } + }, + "Microsoft.Extensions.Configuration/8.0.0": { + "dependencies": { + "Microsoft.Extensions.Configuration.Abstractions": "8.0.0", + "Microsoft.Extensions.Primitives": "8.0.0" + }, + "runtime": { + "lib/net8.0/Microsoft.Extensions.Configuration.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.23.53103" + } + } + }, + "Microsoft.Extensions.Configuration.Abstractions/8.0.0": { + "dependencies": { + "Microsoft.Extensions.Primitives": "8.0.0" + }, + "runtime": { + "lib/net8.0/Microsoft.Extensions.Configuration.Abstractions.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.23.53103" + } + } + }, + "Microsoft.Extensions.Configuration.FileExtensions/8.0.0": { + "dependencies": { + "Microsoft.Extensions.Configuration": "8.0.0", + "Microsoft.Extensions.Configuration.Abstractions": "8.0.0", + "Microsoft.Extensions.FileProviders.Abstractions": "8.0.0", + "Microsoft.Extensions.FileProviders.Physical": "8.0.0", + "Microsoft.Extensions.Primitives": "8.0.0" + }, + "runtime": { + "lib/net8.0/Microsoft.Extensions.Configuration.FileExtensions.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.23.53103" + } + } + }, + "Microsoft.Extensions.Configuration.Json/8.0.0": { + "dependencies": { + "Microsoft.Extensions.Configuration": "8.0.0", + "Microsoft.Extensions.Configuration.Abstractions": "8.0.0", + "Microsoft.Extensions.Configuration.FileExtensions": "8.0.0", + "Microsoft.Extensions.FileProviders.Abstractions": "8.0.0", + "System.Text.Json": "8.0.0" + }, + "runtime": { + "lib/net8.0/Microsoft.Extensions.Configuration.Json.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.23.53103" + } + } + }, + "Microsoft.Extensions.FileProviders.Abstractions/8.0.0": { + "dependencies": { + "Microsoft.Extensions.Primitives": "8.0.0" + }, + "runtime": { + "lib/net8.0/Microsoft.Extensions.FileProviders.Abstractions.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.23.53103" + } + } + }, + "Microsoft.Extensions.FileProviders.Physical/8.0.0": { + "dependencies": { + "Microsoft.Extensions.FileProviders.Abstractions": "8.0.0", + "Microsoft.Extensions.FileSystemGlobbing": "8.0.0", + "Microsoft.Extensions.Primitives": "8.0.0" + }, + "runtime": { + "lib/net8.0/Microsoft.Extensions.FileProviders.Physical.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.23.53103" + } + } + }, + "Microsoft.Extensions.FileSystemGlobbing/8.0.0": { + "runtime": { + "lib/net8.0/Microsoft.Extensions.FileSystemGlobbing.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.23.53103" + } + } + }, + "Microsoft.Extensions.Primitives/8.0.0": { + "runtime": { + "lib/net8.0/Microsoft.Extensions.Primitives.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.23.53103" + } + } + }, + "Newtonsoft.Json/13.0.3": { + "runtime": { + "lib/net6.0/Newtonsoft.Json.dll": { + "assemblyVersion": "13.0.0.0", + "fileVersion": "13.0.3.27908" + } + } + }, + "System.Text.Encodings.Web/8.0.0": {}, + "System.Text.Json/8.0.0": { + "dependencies": { + "System.Text.Encodings.Web": "8.0.0" + } + } + } + }, + "libraries": { + "Fantasy.Tools.NetworkProtocol/1.0.0": { + "type": "project", + "serviceable": false, + "sha512": "" + }, + "CommandLineParser/2.9.1": { + "type": "package", + "serviceable": true, + "sha512": "sha512-OE0sl1/sQ37bjVsPKKtwQlWDgqaxWgtme3xZz7JssWUzg5JpMIyHgCTY9MVMxOg48fJ1AgGT3tgdH5m/kQ5xhA==", + "path": "commandlineparser/2.9.1", + "hashPath": "commandlineparser.2.9.1.nupkg.sha512" + }, + "Microsoft.Extensions.Configuration/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-0J/9YNXTMWSZP2p2+nvl8p71zpSwokZXZuJW+VjdErkegAnFdO1XlqtA62SJtgVYHdKu3uPxJHcMR/r35HwFBA==", + "path": "microsoft.extensions.configuration/8.0.0", + "hashPath": "microsoft.extensions.configuration.8.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.Configuration.Abstractions/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-3lE/iLSutpgX1CC0NOW70FJoGARRHbyKmG7dc0klnUZ9Dd9hS6N/POPWhKhMLCEuNN5nXEY5agmlFtH562vqhQ==", + "path": "microsoft.extensions.configuration.abstractions/8.0.0", + "hashPath": "microsoft.extensions.configuration.abstractions.8.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.Configuration.FileExtensions/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-McP+Lz/EKwvtCv48z0YImw+L1gi1gy5rHhNaNIY2CrjloV+XY8gydT8DjMR6zWeL13AFK+DioVpppwAuO1Gi1w==", + "path": "microsoft.extensions.configuration.fileextensions/8.0.0", + "hashPath": "microsoft.extensions.configuration.fileextensions.8.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.Configuration.Json/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-C2wqUoh9OmRL1akaCcKSTmRU8z0kckfImG7zLNI8uyi47Lp+zd5LWAD17waPQEqCz3ioWOCrFUo+JJuoeZLOBw==", + "path": "microsoft.extensions.configuration.json/8.0.0", + "hashPath": "microsoft.extensions.configuration.json.8.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.FileProviders.Abstractions/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-ZbaMlhJlpisjuWbvXr4LdAst/1XxH3vZ6A0BsgTphZ2L4PGuxRLz7Jr/S7mkAAnOn78Vu0fKhEgNF5JO3zfjqQ==", + "path": "microsoft.extensions.fileproviders.abstractions/8.0.0", + "hashPath": "microsoft.extensions.fileproviders.abstractions.8.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.FileProviders.Physical/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-UboiXxpPUpwulHvIAVE36Knq0VSHaAmfrFkegLyBZeaADuKezJ/AIXYAW8F5GBlGk/VaibN2k/Zn1ca8YAfVdA==", + "path": "microsoft.extensions.fileproviders.physical/8.0.0", + "hashPath": "microsoft.extensions.fileproviders.physical.8.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.FileSystemGlobbing/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-OK+670i7esqlQrPjdIKRbsyMCe9g5kSLpRRQGSr4Q58AOYEe/hCnfLZprh7viNisSUUQZmMrbbuDaIrP+V1ebQ==", + "path": "microsoft.extensions.filesystemglobbing/8.0.0", + "hashPath": "microsoft.extensions.filesystemglobbing.8.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.Primitives/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-bXJEZrW9ny8vjMF1JV253WeLhpEVzFo1lyaZu1vQ4ZxWUlVvknZ/+ftFgVheLubb4eZPSwwxBeqS1JkCOjxd8g==", + "path": "microsoft.extensions.primitives/8.0.0", + "hashPath": "microsoft.extensions.primitives.8.0.0.nupkg.sha512" + }, + "Newtonsoft.Json/13.0.3": { + "type": "package", + "serviceable": true, + "sha512": "sha512-HrC5BXdl00IP9zeV+0Z848QWPAoCr9P3bDEZguI+gkLcBKAOxix/tLEAAHC+UvDNPv4a2d18lOReHMOagPa+zQ==", + "path": "newtonsoft.json/13.0.3", + "hashPath": "newtonsoft.json.13.0.3.nupkg.sha512" + }, + "System.Text.Encodings.Web/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-yev/k9GHAEGx2Rg3/tU6MQh4HGBXJs70y7j1LaM1i/ER9po+6nnQ6RRqTJn1E7Xu0fbIFK80Nh5EoODxrbxwBQ==", + "path": "system.text.encodings.web/8.0.0", + "hashPath": "system.text.encodings.web.8.0.0.nupkg.sha512" + }, + "System.Text.Json/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-OdrZO2WjkiEG6ajEFRABTRCi/wuXQPxeV6g8xvUJqdxMvvuCCEk86zPla8UiIQJz3durtUEbNyY/3lIhS0yZvQ==", + "path": "system.text.json/8.0.0", + "hashPath": "system.text.json.8.0.0.nupkg.sha512" + } + } +} \ No newline at end of file diff --git a/邮件系统课程完整代码/Tools/NetworkProtocol/Fantasy.Tools.NetworkProtocol.dll b/邮件系统课程完整代码/Tools/NetworkProtocol/Fantasy.Tools.NetworkProtocol.dll new file mode 100644 index 0000000..f9219d9 Binary files /dev/null and b/邮件系统课程完整代码/Tools/NetworkProtocol/Fantasy.Tools.NetworkProtocol.dll differ diff --git a/邮件系统课程完整代码/Tools/NetworkProtocol/Fantasy.Tools.NetworkProtocol.pdb b/邮件系统课程完整代码/Tools/NetworkProtocol/Fantasy.Tools.NetworkProtocol.pdb new file mode 100644 index 0000000..91a7531 Binary files /dev/null and b/邮件系统课程完整代码/Tools/NetworkProtocol/Fantasy.Tools.NetworkProtocol.pdb differ diff --git a/邮件系统课程完整代码/Tools/NetworkProtocol/Fantasy.Tools.NetworkProtocol.runtimeconfig.json b/邮件系统课程完整代码/Tools/NetworkProtocol/Fantasy.Tools.NetworkProtocol.runtimeconfig.json new file mode 100644 index 0000000..becfaea --- /dev/null +++ b/邮件系统课程完整代码/Tools/NetworkProtocol/Fantasy.Tools.NetworkProtocol.runtimeconfig.json @@ -0,0 +1,12 @@ +{ + "runtimeOptions": { + "tfm": "net8.0", + "framework": { + "name": "Microsoft.NETCore.App", + "version": "8.0.0" + }, + "configProperties": { + "System.Runtime.Serialization.EnableUnsafeBinaryFormatterSerialization": false + } + } +} \ No newline at end of file diff --git a/邮件系统课程完整代码/Tools/NetworkProtocol/Microsoft.Extensions.Configuration.Abstractions.dll b/邮件系统课程完整代码/Tools/NetworkProtocol/Microsoft.Extensions.Configuration.Abstractions.dll new file mode 100644 index 0000000..a5ab313 Binary files /dev/null and b/邮件系统课程完整代码/Tools/NetworkProtocol/Microsoft.Extensions.Configuration.Abstractions.dll differ diff --git a/邮件系统课程完整代码/Tools/NetworkProtocol/Microsoft.Extensions.Configuration.FileExtensions.dll b/邮件系统课程完整代码/Tools/NetworkProtocol/Microsoft.Extensions.Configuration.FileExtensions.dll new file mode 100644 index 0000000..4efc1a5 Binary files /dev/null and b/邮件系统课程完整代码/Tools/NetworkProtocol/Microsoft.Extensions.Configuration.FileExtensions.dll differ diff --git a/邮件系统课程完整代码/Tools/NetworkProtocol/Microsoft.Extensions.Configuration.Json.dll b/邮件系统课程完整代码/Tools/NetworkProtocol/Microsoft.Extensions.Configuration.Json.dll new file mode 100644 index 0000000..296db6a Binary files /dev/null and b/邮件系统课程完整代码/Tools/NetworkProtocol/Microsoft.Extensions.Configuration.Json.dll differ diff --git a/邮件系统课程完整代码/Tools/NetworkProtocol/Microsoft.Extensions.Configuration.dll b/邮件系统课程完整代码/Tools/NetworkProtocol/Microsoft.Extensions.Configuration.dll new file mode 100644 index 0000000..d3e5c22 Binary files /dev/null and b/邮件系统课程完整代码/Tools/NetworkProtocol/Microsoft.Extensions.Configuration.dll differ diff --git a/邮件系统课程完整代码/Tools/NetworkProtocol/Microsoft.Extensions.FileProviders.Abstractions.dll b/邮件系统课程完整代码/Tools/NetworkProtocol/Microsoft.Extensions.FileProviders.Abstractions.dll new file mode 100644 index 0000000..f907206 Binary files /dev/null and b/邮件系统课程完整代码/Tools/NetworkProtocol/Microsoft.Extensions.FileProviders.Abstractions.dll differ diff --git a/邮件系统课程完整代码/Tools/NetworkProtocol/Microsoft.Extensions.FileProviders.Physical.dll b/邮件系统课程完整代码/Tools/NetworkProtocol/Microsoft.Extensions.FileProviders.Physical.dll new file mode 100644 index 0000000..6fb7f47 Binary files /dev/null and b/邮件系统课程完整代码/Tools/NetworkProtocol/Microsoft.Extensions.FileProviders.Physical.dll differ diff --git a/邮件系统课程完整代码/Tools/NetworkProtocol/Microsoft.Extensions.FileSystemGlobbing.dll b/邮件系统课程完整代码/Tools/NetworkProtocol/Microsoft.Extensions.FileSystemGlobbing.dll new file mode 100644 index 0000000..e590735 Binary files /dev/null and b/邮件系统课程完整代码/Tools/NetworkProtocol/Microsoft.Extensions.FileSystemGlobbing.dll differ diff --git a/邮件系统课程完整代码/Tools/NetworkProtocol/Microsoft.Extensions.Primitives.dll b/邮件系统课程完整代码/Tools/NetworkProtocol/Microsoft.Extensions.Primitives.dll new file mode 100644 index 0000000..c24f2a0 Binary files /dev/null and b/邮件系统课程完整代码/Tools/NetworkProtocol/Microsoft.Extensions.Primitives.dll differ diff --git a/邮件系统课程完整代码/Tools/NetworkProtocol/Newtonsoft.Json.dll b/邮件系统课程完整代码/Tools/NetworkProtocol/Newtonsoft.Json.dll new file mode 100644 index 0000000..d035c38 Binary files /dev/null and b/邮件系统课程完整代码/Tools/NetworkProtocol/Newtonsoft.Json.dll differ diff --git a/邮件系统课程完整代码/Tools/NetworkProtocol/Run.bat b/邮件系统课程完整代码/Tools/NetworkProtocol/Run.bat new file mode 100644 index 0000000..8551afc --- /dev/null +++ b/邮件系统课程完整代码/Tools/NetworkProtocol/Run.bat @@ -0,0 +1,21 @@ +@echo off + +echo Please select an option: +echo 1. Client +echo 2. Server +echo 3. All + +set /p choice=Please select an option: + +if "%choice%"=="1" ( + echo Client + dotnet Fantasy.Tools.NetworkProtocol.dll --ExportPlatform 1 +) else if "%choice%"=="2" ( + echo Server + dotnet Fantasy.Tools.NetworkProtocol.dll --ExportPlatform 2 +) else if "%choice%"=="3" ( + echo All + dotnet Fantasy.Tools.NetworkProtocol.dll --ExportPlatform 3 +) else ( + echo Invalid option +) diff --git a/邮件系统课程完整代码/Tools/NetworkProtocol/Run.sh b/邮件系统课程完整代码/Tools/NetworkProtocol/Run.sh new file mode 100644 index 0000000..763ce02 --- /dev/null +++ b/邮件系统课程完整代码/Tools/NetworkProtocol/Run.sh @@ -0,0 +1,23 @@ +#!/bin/bash + +echo "1. Client" +echo "2. Server" +echo "3. All" + +read -n 1 -p "Please select an option:" choice +echo "" +echo "" +case $choice in + 1) + dotnet Fantasy.Tools.NetworkProtocol.dll --ExportPlatform 1 + ;; + 2) + dotnet Fantasy.Tools.NetworkProtocol.dll --ExportPlatform 2 + ;; + 3) + dotnet Fantasy.Tools.NetworkProtocol.dll --ExportPlatform 3 + ;; + *) + echo "Invalid option" + ;; +esac