hexiaojie 9 ماه پیش
والد
کامیت
491576d033
49فایلهای تغییر یافته به همراه5440 افزوده شده و 3 حذف شده
  1. 2 3
      GameClient/Assets/Game/HotUpdate/Game.HotUpdate.asmdef
  2. 8 0
      GameClient/Assets/Plugins/luban_unity.meta
  3. 397 0
      GameClient/Assets/Plugins/luban_unity/.gitignore
  4. 8 0
      GameClient/Assets/Plugins/luban_unity/Editor.meta
  5. 28 0
      GameClient/Assets/Plugins/luban_unity/Editor/EditorBeanBase.cs
  6. 11 0
      GameClient/Assets/Plugins/luban_unity/Editor/EditorBeanBase.cs.meta
  7. 27 0
      GameClient/Assets/Plugins/luban_unity/Editor/EditorEnumItemInfo.cs
  8. 11 0
      GameClient/Assets/Plugins/luban_unity/Editor/EditorEnumItemInfo.cs.meta
  9. 18 0
      GameClient/Assets/Plugins/luban_unity/Editor/Luban.Editor.asmdef
  10. 7 0
      GameClient/Assets/Plugins/luban_unity/Editor/Luban.Editor.asmdef.meta
  11. 21 0
      GameClient/Assets/Plugins/luban_unity/LICENSE
  12. 7 0
      GameClient/Assets/Plugins/luban_unity/LICENSE.meta
  13. 49 0
      GameClient/Assets/Plugins/luban_unity/README.md
  14. 7 0
      GameClient/Assets/Plugins/luban_unity/README.md.meta
  15. 49 0
      GameClient/Assets/Plugins/luban_unity/README_zh.md
  16. 7 0
      GameClient/Assets/Plugins/luban_unity/README_zh.md.meta
  17. 8 0
      GameClient/Assets/Plugins/luban_unity/Runtime.meta
  18. 8 0
      GameClient/Assets/Plugins/luban_unity/Runtime/BeanBase.cs
  19. 11 0
      GameClient/Assets/Plugins/luban_unity/Runtime/BeanBase.cs.meta
  20. 1568 0
      GameClient/Assets/Plugins/luban_unity/Runtime/ByteBuf.cs
  21. 11 0
      GameClient/Assets/Plugins/luban_unity/Runtime/ByteBuf.cs.meta
  22. 14 0
      GameClient/Assets/Plugins/luban_unity/Runtime/Luban.Runtime.asmdef
  23. 7 0
      GameClient/Assets/Plugins/luban_unity/Runtime/Luban.Runtime.asmdef.meta
  24. 8 0
      GameClient/Assets/Plugins/luban_unity/Runtime/SimpleJSON.meta
  25. 111 0
      GameClient/Assets/Plugins/luban_unity/Runtime/SimpleJSON/Changelog.txt
  26. 7 0
      GameClient/Assets/Plugins/luban_unity/Runtime/SimpleJSON/Changelog.txt.meta
  27. 21 0
      GameClient/Assets/Plugins/luban_unity/Runtime/SimpleJSON/LICENSE
  28. 7 0
      GameClient/Assets/Plugins/luban_unity/Runtime/SimpleJSON/LICENSE.meta
  29. 0 0
      GameClient/Assets/Plugins/luban_unity/Runtime/SimpleJSON/README
  30. 7 0
      GameClient/Assets/Plugins/luban_unity/Runtime/SimpleJSON/README.meta
  31. 1434 0
      GameClient/Assets/Plugins/luban_unity/Runtime/SimpleJSON/SimpleJSON.cs
  32. 11 0
      GameClient/Assets/Plugins/luban_unity/Runtime/SimpleJSON/SimpleJSON.cs.meta
  33. 301 0
      GameClient/Assets/Plugins/luban_unity/Runtime/SimpleJSON/SimpleJSONBinary.cs
  34. 11 0
      GameClient/Assets/Plugins/luban_unity/Runtime/SimpleJSON/SimpleJSONBinary.cs.meta
  35. 516 0
      GameClient/Assets/Plugins/luban_unity/Runtime/SimpleJSON/SimpleJSONDotNetTypes.cs
  36. 11 0
      GameClient/Assets/Plugins/luban_unity/Runtime/SimpleJSON/SimpleJSONDotNetTypes.cs.meta
  37. 462 0
      GameClient/Assets/Plugins/luban_unity/Runtime/SimpleJSON/SimpleJSONUnity.cs
  38. 11 0
      GameClient/Assets/Plugins/luban_unity/Runtime/SimpleJSON/SimpleJSONUnity.cs.meta
  39. 53 0
      GameClient/Assets/Plugins/luban_unity/Runtime/StringUtil.cs
  40. 11 0
      GameClient/Assets/Plugins/luban_unity/Runtime/StringUtil.cs.meta
  41. 8 0
      GameClient/Assets/Plugins/luban_unity/docs.meta
  42. 1 0
      GameClient/Assets/Plugins/luban_unity/docs/_config.yml
  43. 7 0
      GameClient/Assets/Plugins/luban_unity/docs/_config.yml.meta
  44. 8 0
      GameClient/Assets/Plugins/luban_unity/docs/images.meta
  45. BIN
      GameClient/Assets/Plugins/luban_unity/docs/images/logo.png
  46. 121 0
      GameClient/Assets/Plugins/luban_unity/docs/images/logo.png.meta
  47. 19 0
      GameClient/Assets/Plugins/luban_unity/package.json
  48. 7 0
      GameClient/Assets/Plugins/luban_unity/package.json.meta
  49. 3 0
      GameClient/GameClient.sln.DotSettings.user

+ 2 - 3
GameClient/Assets/Game/HotUpdate/Game.HotUpdate.asmdef

@@ -7,9 +7,8 @@
         "GUID:e34a5702dd353724aa315fb8011f08c3",
         "GUID:b0a84d582f6a6fa4185f67ce934d99c2",
         "GUID:6e5063adab271564ba0098a06a8cebda",
-        "GUID:d9a5d47c553a04a28a7d21a3f3fc8dc3",
-        "GUID:9b1c19877f4294a9cb33ff38fc9f1c83",
-        "GUID:f22fac247a56d2d41b687bb0d900e54e"
+        "GUID:f22fac247a56d2d41b687bb0d900e54e",
+        "Luban.Runtime"
     ],
     "includePlatforms": [],
     "excludePlatforms": [],

+ 8 - 0
GameClient/Assets/Plugins/luban_unity.meta

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

+ 397 - 0
GameClient/Assets/Plugins/luban_unity/.gitignore

@@ -0,0 +1,397 @@
+## Ignore Visual Studio temporary files, build results, and
+## files generated by popular Visual Studio add-ons.
+##
+## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore
+
+# User-specific files
+*.rsuser
+*.suo
+*.user
+*.userosscache
+*.sln.docstates
+
+# User-specific files (MonoDevelop/Xamarin Studio)
+*.userprefs
+
+# Mono auto generated files
+mono_crash.*
+
+# Build results
+[Dd]ebug/
+[Dd]ebugPublic/
+[Rr]elease/
+[Rr]eleases/
+x64/
+x86/
+[Ww][Ii][Nn]32/
+[Aa][Rr][Mm]/
+[Aa][Rr][Mm]64/
+bld/
+[Bb]in/
+[Oo]bj/
+[Ll]og/
+[Ll]ogs/
+
+# Visual Studio 2015/2017 cache/options directory
+.vs/
+# Uncomment if you have tasks that create the project's static files in wwwroot
+#wwwroot/
+
+# Visual Studio 2017 auto generated files
+Generated\ Files/
+
+# MSTest test Results
+[Tt]est[Rr]esult*/
+[Bb]uild[Ll]og.*
+
+# NUnit
+*.VisualState.xml
+TestResult.xml
+nunit-*.xml
+
+# Build Results of an ATL Project
+[Dd]ebugPS/
+[Rr]eleasePS/
+dlldata.c
+
+# Benchmark Results
+BenchmarkDotNet.Artifacts/
+
+# .NET Core
+project.lock.json
+project.fragment.lock.json
+artifacts/
+
+# ASP.NET Scaffolding
+ScaffoldingReadMe.txt
+
+# StyleCop
+StyleCopReport.xml
+
+# Files built by Visual Studio
+*_i.c
+*_p.c
+*_h.h
+*.ilk
+*.obj
+*.iobj
+*.pch
+*.pdb
+*.ipdb
+*.pgc
+*.pgd
+*.rsp
+*.sbr
+*.tlb
+*.tli
+*.tlh
+*.tmp
+*.tmp_proj
+*_wpftmp.csproj
+*.log
+*.tlog
+*.vspscc
+*.vssscc
+.builds
+*.pidb
+*.svclog
+*.scc
+
+# Chutzpah Test files
+_Chutzpah*
+
+# Visual C++ cache files
+ipch/
+*.aps
+*.ncb
+*.opendb
+*.opensdf
+*.sdf
+*.cachefile
+*.VC.db
+*.VC.VC.opendb
+
+# Visual Studio profiler
+*.psess
+*.vsp
+*.vspx
+*.sap
+
+# Visual Studio Trace Files
+*.e2e
+
+# TFS 2012 Local Workspace
+$tf/
+
+# Guidance Automation Toolkit
+*.gpState
+
+# ReSharper is a .NET coding add-in
+_ReSharper*/
+*.[Rr]e[Ss]harper
+*.DotSettings.user
+
+# TeamCity is a build add-in
+_TeamCity*
+
+# DotCover is a Code Coverage Tool
+*.dotCover
+
+# AxoCover is a Code Coverage Tool
+.axoCover/*
+!.axoCover/settings.json
+
+# Coverlet is a free, cross platform Code Coverage Tool
+coverage*.json
+coverage*.xml
+coverage*.info
+
+# Visual Studio code coverage results
+*.coverage
+*.coveragexml
+
+# NCrunch
+_NCrunch_*
+.*crunch*.local.xml
+nCrunchTemp_*
+
+# MightyMoose
+*.mm.*
+AutoTest.Net/
+
+# Web workbench (sass)
+.sass-cache/
+
+# Installshield output folder
+[Ee]xpress/
+
+# DocProject is a documentation generator add-in
+DocProject/buildhelp/
+DocProject/Help/*.HxT
+DocProject/Help/*.HxC
+DocProject/Help/*.hhc
+DocProject/Help/*.hhk
+DocProject/Help/*.hhp
+DocProject/Help/Html2
+DocProject/Help/html
+
+# Click-Once directory
+publish/
+
+# Publish Web Output
+*.[Pp]ublish.xml
+*.azurePubxml
+# Note: Comment the next line if you want to checkin your web deploy settings,
+# but database connection strings (with potential passwords) will be unencrypted
+*.pubxml
+*.publishproj
+
+# Microsoft Azure Web App publish settings. Comment the next line if you want to
+# checkin your Azure Web App publish settings, but sensitive information contained
+# in these scripts will be unencrypted
+PublishScripts/
+
+# NuGet Packages
+*.nupkg
+# NuGet Symbol Packages
+*.snupkg
+# The packages folder can be ignored because of Package Restore
+**/[Pp]ackages/*
+# except build/, which is used as an MSBuild target.
+!**/[Pp]ackages/build/
+# Uncomment if necessary however generally it will be regenerated when needed
+#!**/[Pp]ackages/repositories.config
+# NuGet v3's project.json files produces more ignorable files
+*.nuget.props
+*.nuget.targets
+
+# Microsoft Azure Build Output
+csx/
+*.build.csdef
+
+# Microsoft Azure Emulator
+ecf/
+rcf/
+
+# Windows Store app package directories and files
+AppPackages/
+BundleArtifacts/
+Package.StoreAssociation.xml
+_pkginfo.txt
+*.appx
+*.appxbundle
+*.appxupload
+
+# Visual Studio cache files
+# files ending in .cache can be ignored
+*.[Cc]ache
+# but keep track of directories ending in .cache
+!?*.[Cc]ache/
+
+# Others
+ClientBin/
+~$*
+*~
+*.dbmdl
+*.dbproj.schemaview
+*.jfm
+*.pfx
+*.publishsettings
+orleans.codegen.cs
+
+# Including strong name files can present a security risk
+# (https://github.com/github/gitignore/pull/2483#issue-259490424)
+#*.snk
+
+# Since there are multiple workflows, uncomment next line to ignore bower_components
+# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
+#bower_components/
+
+# RIA/Silverlight projects
+Generated_Code/
+
+# Backup & report files from converting an old project file
+# to a newer Visual Studio version. Backup files are not needed,
+# because we have git ;-)
+_UpgradeReport_Files/
+Backup*/
+UpgradeLog*.XML
+UpgradeLog*.htm
+ServiceFabricBackup/
+*.rptproj.bak
+
+# SQL Server files
+*.mdf
+*.ldf
+*.ndf
+
+# Business Intelligence projects
+*.rdl.data
+*.bim.layout
+*.bim_*.settings
+*.rptproj.rsuser
+*- [Bb]ackup.rdl
+*- [Bb]ackup ([0-9]).rdl
+*- [Bb]ackup ([0-9][0-9]).rdl
+
+# Microsoft Fakes
+FakesAssemblies/
+
+# GhostDoc plugin setting file
+*.GhostDoc.xml
+
+# Node.js Tools for Visual Studio
+.ntvs_analysis.dat
+node_modules/
+
+# Visual Studio 6 build log
+*.plg
+
+# Visual Studio 6 workspace options file
+*.opt
+
+# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
+*.vbw
+
+# Visual Studio 6 auto-generated project file (contains which files were open etc.)
+*.vbp
+
+# Visual Studio 6 workspace and project file (working project files containing files to include in project)
+*.dsw
+*.dsp
+
+# Visual Studio 6 technical files
+*.ncb
+*.aps
+
+# Visual Studio LightSwitch build output
+**/*.HTMLClient/GeneratedArtifacts
+**/*.DesktopClient/GeneratedArtifacts
+**/*.DesktopClient/ModelManifest.xml
+**/*.Server/GeneratedArtifacts
+**/*.Server/ModelManifest.xml
+_Pvt_Extensions
+
+# Paket dependency manager
+.paket/paket.exe
+paket-files/
+
+# FAKE - F# Make
+.fake/
+
+# CodeRush personal settings
+.cr/personal
+
+# Python Tools for Visual Studio (PTVS)
+__pycache__/
+*.pyc
+
+# Cake - Uncomment if you are using it
+# tools/**
+# !tools/packages.config
+
+# Tabs Studio
+*.tss
+
+# Telerik's JustMock configuration file
+*.jmconfig
+
+# BizTalk build output
+*.btp.cs
+*.btm.cs
+*.odx.cs
+*.xsd.cs
+
+# OpenCover UI analysis results
+OpenCover/
+
+# Azure Stream Analytics local run output
+ASALocalRun/
+
+# MSBuild Binary and Structured Log
+*.binlog
+
+# NVidia Nsight GPU debugger configuration file
+*.nvuser
+
+# MFractors (Xamarin productivity tool) working folder
+.mfractor/
+
+# Local History for Visual Studio
+.localhistory/
+
+# Visual Studio History (VSHistory) files
+.vshistory/
+
+# BeatPulse healthcheck temp database
+healthchecksdb
+
+# Backup folder for Package Reference Convert tool in Visual Studio 2017
+MigrationBackup/
+
+# Ionide (cross platform F# VS Code tools) working folder
+.ionide/
+
+# Fody - auto-generated XML schema
+FodyWeavers.xsd
+
+# VS Code files for those working on multiple tools
+.vscode/*
+!.vscode/settings.json
+!.vscode/tasks.json
+!.vscode/launch.json
+!.vscode/extensions.json
+*.code-workspace
+
+# Local History for Visual Studio Code
+.history/
+
+# Windows Installer files from build outputs
+*.cab
+*.msi
+*.msix
+*.msm
+*.msp
+
+# JetBrains Rider
+*.sln.iml

+ 8 - 0
GameClient/Assets/Plugins/luban_unity/Editor.meta

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

+ 28 - 0
GameClient/Assets/Plugins/luban_unity/Editor/EditorBeanBase.cs

@@ -0,0 +1,28 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Luban
+{
+    public abstract class EditorBeanBase
+    {
+        public abstract void LoadJson(SimpleJSON.JSONObject json);
+
+        public abstract void SaveJson(SimpleJSON.JSONObject json);
+
+        public void LoadJsonFile(string file)
+        {
+            string jsonText = System.IO.File.ReadAllText(file, Encoding.UTF8);
+            LoadJson((SimpleJSON.JSONObject)SimpleJSON.JSON.Parse(jsonText));
+        }
+
+        public void SaveJsonFile(string file)
+        {
+            var json = new SimpleJSON.JSONObject();
+            SaveJson(json);
+            System.IO.File.WriteAllText(file, json.ToString(), System.Text.Encoding.UTF8);
+        }
+    }
+}

+ 11 - 0
GameClient/Assets/Plugins/luban_unity/Editor/EditorBeanBase.cs.meta

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

+ 27 - 0
GameClient/Assets/Plugins/luban_unity/Editor/EditorEnumItemInfo.cs

@@ -0,0 +1,27 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Luban
+{
+    public class EditorEnumItemInfo
+    {
+        public string Name { get; }
+
+        public string Alias { get; }
+
+        public int Value { get; }
+
+        public string Comment { get; }
+
+        public EditorEnumItemInfo(string name, string alias, int value, string comment)
+        {
+            Name = name;
+            Alias = alias;
+            Value = value;
+            Comment = comment;
+        }
+    }
+}

+ 11 - 0
GameClient/Assets/Plugins/luban_unity/Editor/EditorEnumItemInfo.cs.meta

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

+ 18 - 0
GameClient/Assets/Plugins/luban_unity/Editor/Luban.Editor.asmdef

@@ -0,0 +1,18 @@
+{
+    "name": "Luban.Editor",
+    "rootNamespace": "",
+    "references": [
+        "Luban.Runtime"
+    ],
+    "includePlatforms": [
+        "Editor"
+    ],
+    "excludePlatforms": [],
+    "allowUnsafeCode": true,
+    "overrideReferences": false,
+    "precompiledReferences": [],
+    "autoReferenced": true,
+    "defineConstraints": [],
+    "versionDefines": [],
+    "noEngineReferences": false
+}

+ 7 - 0
GameClient/Assets/Plugins/luban_unity/Editor/Luban.Editor.asmdef.meta

@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 5796a4f593192714cbff2c4360722388
+AssemblyDefinitionImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 21 - 0
GameClient/Assets/Plugins/luban_unity/LICENSE

@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2023 Code Philosophy(代码哲学)
+
+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.

+ 7 - 0
GameClient/Assets/Plugins/luban_unity/LICENSE.meta

@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 078e48d5b430a7d4db6745b56c27f8d5
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 49 - 0
GameClient/Assets/Plugins/luban_unity/README.md

@@ -0,0 +1,49 @@
+
+- [README 中文](./README_zh.md)
+- [README English](./README.md)
+
+# Luban
+
+![icon](docs/images/logo.png)
+
+[![license](http://img.shields.io/badge/license-MIT-blue.svg?style=flat-square)](https://opensource.org/licenses/MIT) ![star](https://img.shields.io/github/stars/focus-creative-games/luban?style=flat-square)
+
+
+luban is a powerful, easy-to-use, elegant, and stable game configuration solution. It is designed to meet the needs of simple to complex game configuration workflows from small to very large game projects.
+
+luban can handle a variety of file types, supports mainstream languages, can generate multiple export formats, supports rich data inspection functions, has good cross-platform capabilities, and generates extremely fast.
+Luban has a clear and elegant generation pipeline design, supports good modularization and plug-in, and is convenient for developers to carry out secondary development. Developers can easily adapt luban to their own configuration format, and customize powerful configuration tools that meet project requirements.
+
+Luban standardizes the game configuration development workflow, which can greatly improve the efficiency of planning and programming.
+
+## Core features
+
+- Rich source data format. Support excel family (csv, xls, xlsx, xlsm), json, xml, yaml, lua, etc.
+- Rich export formats. Support generating binary, json, bson, xml, lua, yaml and other format data
+- Enhanced excel format. Simple configurations such as simple lists, substructures, structured lists, and arbitrarily complex deep nested structures can be concisely configured
+- Complete type system. Not only can it express common specification line lists, but it can flexibly and elegantly express complex GamePlay data such as behavior trees, skills, plots, and dungeons because **supports OOP type inheritance**
+- Support multiple languages. Supports generating language codes such as c#, java, go, cpp, lua, python, typescript, etc.
+- Support mainstream message schemes. protobuf(schema + binary + json), flatbuffers(schema + json), msgpack(binary)
+- Powerful data verification capability. ref reference check, path resource path, range range check, etc.
+- Perfect localization support
+- Supports all major game engines and platforms. Support Unity, Unreal, Cocos2x, Godot, WeChat games, etc.
+- Good cross-platform capability. It can run well on Win, Linux, and Mac platforms.
+- Support all mainstream hot update solutions. hybridclr, ilruntime, {x,t,s}lua, puerts, etc.
+- Clear and elegant generation pipeline, it is easy to carry out secondary development on the basis of luban, and customize a configuration tool suitable for your own project style.
+
+## Documentation
+
+- [Luban](https://github.com/focus-creative-games/luban)
+- [Official Documentation](https://luban.doc.code-philosophy.com/)
+- [Quick Start](https://luban.doc.code-philosophy.com/docs/beginner/quickstart)
+- **Example Project** ([github](https://github.com/focus-creative-games/luban_examples)) ([gitee](https://gitee.com/focus-creative-games/luban_examples) )
+
+## Support and Contact
+
+- QQ group: 692890842 (Luban development exchange group)
+- discord: https://discord.gg/dGY4zzGMJ4
+- Email: luban#code-philosophy.com
+
+## license
+
+Luban is licensed under the [MIT](https://github.com/focus-creative-games/luban/blob/main/LICENSE) license

+ 7 - 0
GameClient/Assets/Plugins/luban_unity/README.md.meta

@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 3cefe9933a4e0e44e845f53b784d2fc6
+TextScriptImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 49 - 0
GameClient/Assets/Plugins/luban_unity/README_zh.md

@@ -0,0 +1,49 @@
+
+- [README 中文](./README_zh.md)
+- [README English](./README.md)
+
+# Luban
+
+![icon](docs/images/logo.png)
+
+[![license](http://img.shields.io/badge/license-MIT-blue.svg?style=flat-square)](https://opensource.org/licenses/MIT) ![star](https://img.shields.io/github/stars/focus-creative-games/luban?style=flat-square)
+
+
+luban是一个强大、易用、优雅、稳定的游戏配置解决方案。它设计目标为满足从小型到超大型游戏项目的简单到复杂的游戏配置工作流需求。
+
+luban可以处理丰富的文件类型,支持主流的语言,可以生成多种导出格式,支持丰富的数据检验功能,具有良好的跨平台能力,并且生成极快。
+luban有清晰优雅的生成管线设计,支持良好的模块化和插件化,方便开发者进行二次开发。开发者很容易就能将luban适配到自己的配置格式,定制出满足项目要求的强大的配置工具。
+
+luban标准化了游戏配置开发工作流,可以极大提升策划和程序的工作效率。
+
+## 核心特性
+
+- 丰富的源数据格式。支持excel族(csv,xls,xlsx,xlsm)、json、xml、yaml、lua等
+- 丰富的导出格式。 支持生成binary、json、bson、xml、lua、yaml等格式数据
+- 增强的excel格式。可以简洁地配置出像简单列表、子结构、结构列表,以及任意复杂的深层次的嵌套结构
+- 完备的类型系统。不仅能表达常见的规范行列表,由于**支持OOP类型继承**,能灵活优雅表达行为树、技能、剧情、副本之类复杂GamePlay数据
+- 支持多种的语言。支持生成c#、java、go、cpp、lua、python、typescript 等语言代码
+- 支持主流的消息方案。 protobuf(schema + binary + json)、flatbuffers(schema + json)、msgpack(binary)
+- 强大的数据校验能力。ref引用检查、path资源路径、range范围检查等等
+- 完善的本地化支持
+- 支持所有主流的游戏引擎和平台。支持Unity、Unreal、Cocos2x、Godot、微信小游戏等
+- 良好的跨平台能力。能在Win,Linux,Mac平台良好运行。
+- 支持所有主流的热更新方案。hybridclr、ilruntime、{x,t,s}lua、puerts等
+- 清晰优雅的生成管线,很容易在luban基础上进行二次开发,定制出适合自己项目风格的配置工具。
+
+## 文档
+
+- [Luban](https://github.com/focus-creative-games/luban)
+- [官方文档](https://luban.doc.code-philosophy.com/)
+- [快速上手](https://luban.doc.code-philosophy.com/docs/beginner/quickstart)
+- **示例项目** ([github](https://github.com/focus-creative-games/luban_examples)) ([gitee](https://gitee.com/focus-creative-games/luban_examples))
+
+## 支持与联系
+
+ - QQ群: 692890842 (Luban开发交流群)
+ - discord: https://discord.gg/dGY4zzGMJ4
+ - 邮箱: luban#code-philosophy.com
+
+## license
+
+Luban is licensed under the [MIT](https://github.com/focus-creative-games/luban/blob/main/LICENSE) license

+ 7 - 0
GameClient/Assets/Plugins/luban_unity/README_zh.md.meta

@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: a673262afcffe1d4a920ae8401c26bef
+TextScriptImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 8 - 0
GameClient/Assets/Plugins/luban_unity/Runtime.meta

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

+ 8 - 0
GameClient/Assets/Plugins/luban_unity/Runtime/BeanBase.cs

@@ -0,0 +1,8 @@
+
+namespace Luban
+{
+    public abstract class BeanBase
+    {
+        public abstract int GetTypeId();
+    }
+}

+ 11 - 0
GameClient/Assets/Plugins/luban_unity/Runtime/BeanBase.cs.meta

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

+ 1568 - 0
GameClient/Assets/Plugins/luban_unity/Runtime/ByteBuf.cs

@@ -0,0 +1,1568 @@
+using System;
+using System.Diagnostics.CodeAnalysis;
+using System.Numerics;
+using System.Runtime.CompilerServices;
+using System.Text;
+
+namespace Luban
+{
+
+    public enum EDeserializeError
+    {
+        OK,
+        NOT_ENOUGH,
+        EXCEED_SIZE,
+        // UNMARSHAL_ERR,
+    }
+
+    public class SerializationException : Exception
+    {
+        public SerializationException() { }
+        public SerializationException(string msg) : base(msg) { }
+
+        public SerializationException(string message, Exception innerException) : base(message, innerException)
+        {
+        }
+    }
+
+    public readonly struct SegmentSaveState
+    {
+        public SegmentSaveState(int readerIndex, int writerIndex)
+        {
+            ReaderIndex = readerIndex;
+            WriterIndex = writerIndex;
+        }
+
+        public int ReaderIndex { get; }
+
+        public int WriterIndex { get; }
+    }
+
+    public sealed class ByteBuf : ICloneable, IEquatable<ByteBuf>
+    {
+        public ByteBuf()
+        {
+            Bytes = Array.Empty<byte>();
+            ReaderIndex = WriterIndex = 0;
+        }
+
+        public ByteBuf(int capacity)
+        {
+            Bytes = capacity > 0 ? new byte[capacity] : Array.Empty<byte>();
+            ReaderIndex = 0;
+            WriterIndex = 0;
+        }
+
+        public ByteBuf(byte[] bytes)
+        {
+            Bytes = bytes;
+            ReaderIndex = 0;
+            WriterIndex = Capacity;
+        }
+
+        public ByteBuf(byte[] bytes, int readIndex, int writeIndex)
+        {
+            Bytes = bytes;
+            ReaderIndex = readIndex;
+            WriterIndex = writeIndex;
+        }
+
+        public ByteBuf(int capacity, Action<ByteBuf> releaser) : this(capacity)
+        {
+            _releaser = releaser;
+        }
+
+        public static ByteBuf Wrap(byte[] bytes)
+        {
+            return new ByteBuf(bytes, 0, bytes.Length);
+        }
+
+        public void Replace(byte[] bytes)
+        {
+            Bytes = bytes;
+            ReaderIndex = 0;
+            WriterIndex = Capacity;
+        }
+
+        public void Replace(byte[] bytes, int beginPos, int endPos)
+        {
+            Bytes = bytes;
+            ReaderIndex = beginPos;
+            WriterIndex = endPos;
+        }
+
+        public int ReaderIndex { get; set; }
+
+        public int WriterIndex { get; set; }
+
+        private readonly Action<ByteBuf> _releaser;
+
+        public int Capacity => Bytes.Length;
+
+        public int Size { get { return WriterIndex - ReaderIndex; } }
+
+        public bool Empty => WriterIndex <= ReaderIndex;
+
+        public bool NotEmpty => WriterIndex > ReaderIndex;
+
+
+        public void AddWriteIndex(int add)
+        {
+            WriterIndex += add;
+        }
+
+        public void AddReadIndex(int add)
+        {
+            ReaderIndex += add;
+        }
+
+#pragma warning disable CA1819 // 属性不应返回数组
+        public byte[] Bytes { get; private set; }
+#pragma warning restore CA1819 // 属性不应返回数组
+
+        public byte[] CopyData()
+        {
+            var n = Remaining;
+            if (n > 0)
+            {
+                var arr = new byte[n];
+                Buffer.BlockCopy(Bytes, ReaderIndex, arr, 0, n);
+                return arr;
+            }
+            else
+            {
+                return Array.Empty<byte>();
+            }
+        }
+
+        public int Remaining { get { return WriterIndex - ReaderIndex; } }
+
+        public void DiscardReadBytes()
+        {
+            WriterIndex -= ReaderIndex;
+            Array.Copy(Bytes, ReaderIndex, Bytes, 0, WriterIndex);
+            ReaderIndex = 0;
+        }
+
+        public int NotCompactWritable { get { return Capacity - WriterIndex; } }
+
+        public void WriteBytesWithoutSize(byte[] bs)
+        {
+            WriteBytesWithoutSize(bs, 0, bs.Length);
+        }
+
+        public void WriteBytesWithoutSize(byte[] bs, int offset, int len)
+        {
+            EnsureWrite(len);
+            Buffer.BlockCopy(bs, offset, Bytes, WriterIndex, len);
+            WriterIndex += len;
+        }
+
+        public void Clear()
+        {
+            ReaderIndex = WriterIndex = 0;
+        }
+
+        private const int MIN_CAPACITY = 16;
+
+        private static int PropSize(int initSize, int needSize)
+        {
+            for (int i = Math.Max(initSize, MIN_CAPACITY); ; i <<= 1)
+            {
+                if (i >= needSize)
+                {
+                    return i;
+                }
+            }
+        }
+
+        private void EnsureWrite0(int size)
+        {
+            var needSize = WriterIndex + size - ReaderIndex;
+            if (needSize < Capacity)
+            {
+                WriterIndex -= ReaderIndex;
+                Array.Copy(Bytes, ReaderIndex, Bytes, 0, WriterIndex);
+                ReaderIndex = 0;
+            }
+            else
+            {
+                int newCapacity = PropSize(Capacity, needSize);
+                var newBytes = new byte[newCapacity];
+                WriterIndex -= ReaderIndex;
+                Buffer.BlockCopy(Bytes, ReaderIndex, newBytes, 0, WriterIndex);
+                ReaderIndex = 0;
+                Bytes = newBytes;
+            }
+        }
+
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public void EnsureWrite(int size)
+        {
+            if (WriterIndex + size > Capacity)
+            {
+                EnsureWrite0(size);
+            }
+        }
+
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        private void EnsureRead(int size)
+        {
+            if (ReaderIndex + size > WriterIndex)
+            {
+                throw new SerializationException();
+            }
+        }
+
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        private bool CanRead(int size)
+        {
+            return (ReaderIndex + size <= WriterIndex);
+        }
+
+        public void Append(byte x)
+        {
+            EnsureWrite(1);
+            Bytes[WriterIndex++] = x;
+        }
+
+        public void WriteBool(bool b)
+        {
+            EnsureWrite(1);
+            Bytes[WriterIndex++] = (byte)(b ? 1 : 0);
+        }
+
+        public bool ReadBool()
+        {
+            EnsureRead(1);
+            return Bytes[ReaderIndex++] != 0;
+        }
+
+        public void WriteByte(byte x)
+        {
+            EnsureWrite(1);
+            Bytes[WriterIndex++] = x;
+        }
+
+        public byte ReadByte()
+        {
+            EnsureRead(1);
+            return Bytes[ReaderIndex++];
+        }
+
+
+        public void WriteShort(short x)
+        {
+            if (x >= 0)
+            {
+                if (x < 0x80)
+                {
+                    EnsureWrite(1);
+                    Bytes[WriterIndex++] = (byte)x;
+                    return;
+                }
+                else if (x < 0x4000)
+                {
+                    EnsureWrite(2);
+                    Bytes[WriterIndex + 1] = (byte)x;
+                    Bytes[WriterIndex] = (byte)((x >> 8) | 0x80);
+                    WriterIndex += 2;
+                    return;
+                }
+            }
+            EnsureWrite(3);
+            Bytes[WriterIndex] = 0xff;
+            Bytes[WriterIndex + 2] = (byte)x;
+            Bytes[WriterIndex + 1] = (byte)(x >> 8);
+            WriterIndex += 3;
+        }
+
+        public short ReadShort()
+        {
+            EnsureRead(1);
+            int h = Bytes[ReaderIndex];
+            if (h < 0x80)
+            {
+                ReaderIndex++;
+                return (short)h;
+            }
+            else if (h < 0xc0)
+            {
+                EnsureRead(2);
+                int x = ((h & 0x3f) << 8) | Bytes[ReaderIndex + 1];
+                ReaderIndex += 2;
+                return (short)x;
+            }
+            else if ((h == 0xff))
+            {
+                EnsureRead(3);
+                int x = (Bytes[ReaderIndex + 1] << 8) | Bytes[ReaderIndex + 2];
+                ReaderIndex += 3;
+                return (short)x;
+            }
+            else
+            {
+                throw new SerializationException();
+            }
+        }
+
+        public short ReadFshort()
+        {
+            EnsureRead(2);
+            short x;
+#if CPU_SUPPORT_MEMORY_NOT_ALIGN
+            unsafe
+            {
+                fixed (byte* b = &Bytes[ReaderIndex])
+                {
+                    x = *(short*)b;
+                }
+            }
+#else
+            x = (short)((Bytes[ReaderIndex + 1] << 8) | Bytes[ReaderIndex]);
+
+#endif
+            ReaderIndex += 2;
+            return x;
+        }
+
+        public void WriteFshort(short x)
+        {
+            EnsureWrite(2);
+#if CPU_SUPPORT_MEMORY_NOT_ALIGN
+            unsafe
+            {
+                fixed (byte* b = &Bytes[WriterIndex])
+                {
+                    *(short*)b = x;
+                }
+            }
+#else
+            Bytes[WriterIndex] = (byte)x;
+            Bytes[WriterIndex + 1] = (byte)(x >> 8);
+#endif
+            WriterIndex += 2;
+        }
+
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public void WriteInt(int x)
+        {
+            WriteUint((uint)x);
+        }
+
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public int ReadInt()
+        {
+            return (int)ReadUint();
+        }
+
+
+        public void WriteUint(uint x)
+        {
+            // 如果有修改,记得也把 EndWriteSegment改了
+            // 0 111 1111
+            if (x < 0x80)
+            {
+                EnsureWrite(1);
+                Bytes[WriterIndex++] = (byte)x;
+            }
+            else if (x < 0x4000) // 10 11 1111, -
+            {
+                EnsureWrite(2);
+                Bytes[WriterIndex + 1] = (byte)x;
+                Bytes[WriterIndex] = (byte)((x >> 8) | 0x80);
+                WriterIndex += 2;
+            }
+            else if (x < 0x200000) // 110 1 1111, -,-
+            {
+                EnsureWrite(3);
+                Bytes[WriterIndex + 2] = (byte)x;
+                Bytes[WriterIndex + 1] = (byte)(x >> 8);
+                Bytes[WriterIndex] = (byte)((x >> 16) | 0xc0);
+                WriterIndex += 3;
+            }
+            else if (x < 0x10000000) // 1110 1111,-,-,-
+            {
+                EnsureWrite(4);
+                Bytes[WriterIndex + 3] = (byte)x;
+                Bytes[WriterIndex + 2] = (byte)(x >> 8);
+                Bytes[WriterIndex + 1] = (byte)(x >> 16);
+                Bytes[WriterIndex] = (byte)((x >> 24) | 0xe0);
+                WriterIndex += 4;
+            }
+            else
+            {
+                EnsureWrite(5);
+                Bytes[WriterIndex] = 0xf0;
+                Bytes[WriterIndex + 4] = (byte)x;
+                Bytes[WriterIndex + 3] = (byte)(x >> 8);
+                Bytes[WriterIndex + 2] = (byte)(x >> 16);
+                Bytes[WriterIndex + 1] = (byte)(x >> 24);
+                WriterIndex += 5;
+            }
+        }
+
+        public uint ReadUint()
+        {
+            ///
+            /// 警告! 如有修改,记得调整 TryDeserializeInplaceOctets
+            EnsureRead(1);
+            uint h = Bytes[ReaderIndex];
+            if (h < 0x80)
+            {
+                ReaderIndex++;
+                return h;
+            }
+            else if (h < 0xc0)
+            {
+                EnsureRead(2);
+                uint x = ((h & 0x3f) << 8) | Bytes[ReaderIndex + 1];
+                ReaderIndex += 2;
+                return x;
+            }
+            else if (h < 0xe0)
+            {
+                EnsureRead(3);
+                uint x = ((h & 0x1f) << 16) | ((uint)Bytes[ReaderIndex + 1] << 8) | Bytes[ReaderIndex + 2];
+                ReaderIndex += 3;
+                return x;
+            }
+            else if (h < 0xf0)
+            {
+
+                EnsureRead(4);
+                uint x = ((h & 0x0f) << 24) | ((uint)Bytes[ReaderIndex + 1] << 16) | ((uint)Bytes[ReaderIndex + 2] << 8) | Bytes[ReaderIndex + 3];
+                ReaderIndex += 4;
+                return x;
+            }
+            else
+            {
+                EnsureRead(5);
+                uint x = ((uint)Bytes[ReaderIndex + 1] << 24) | ((uint)(Bytes[ReaderIndex + 2] << 16)) | ((uint)Bytes[ReaderIndex + 3] << 8) | Bytes[ReaderIndex + 4];
+                ReaderIndex += 5;
+                return x;
+            }
+        }
+
+        public unsafe void WriteUint_Unsafe(uint x)
+        {
+            // 0 111 1111
+            if (x < 0x80)
+            {
+                EnsureWrite(1);
+                Bytes[WriterIndex++] = (byte)(x << 1);
+            }
+            else if (x < 0x4000)// 10 11 1111, -
+            {
+                EnsureWrite(2);
+
+                fixed (byte* wb = &Bytes[WriterIndex])
+                {
+                    *(uint*)(wb) = (x << 2 | 0b01);
+                }
+
+                WriterIndex += 2;
+            }
+            else if (x < 0x200000) // 110 1 1111, -,-
+            {
+                EnsureWrite(3);
+
+                fixed (byte* wb = &Bytes[WriterIndex])
+                {
+                    *(uint*)(wb) = (x << 3 | 0b011);
+                }
+                WriterIndex += 3;
+            }
+            else if (x < 0x10000000) // 1110 1111,-,-,-
+            {
+                EnsureWrite(4);
+                fixed (byte* wb = &Bytes[WriterIndex])
+                {
+                    *(uint*)(wb) = (x << 4 | 0b0111);
+                }
+                WriterIndex += 4;
+            }
+            else
+            {
+                EnsureWrite(5);
+                fixed (byte* wb = &Bytes[WriterIndex])
+                {
+                    *(uint*)(wb) = (x << 5 | 0b01111);
+                }
+                WriterIndex += 5;
+            }
+        }
+
+        public unsafe uint ReadUint_Unsafe()
+        {
+            ///
+            /// 警告! 如有修改,记得调整 TryDeserializeInplaceOctets
+            EnsureRead(1);
+            uint h = Bytes[ReaderIndex];
+            if ((h & 0b1) == 0b0)
+            {
+                ReaderIndex++;
+                return (h >> 1);
+            }
+            else if ((h & 0b11) == 0b01)
+            {
+                EnsureRead(2);
+                fixed (byte* rb = &Bytes[ReaderIndex])
+                {
+                    ReaderIndex += 2;
+                    return (*(uint*)rb) >> 2;
+                }
+            }
+            else if ((h & 0b111) == 0b011)
+            {
+                EnsureRead(3);
+                fixed (byte* rb = &Bytes[ReaderIndex])
+                {
+                    ReaderIndex += 3;
+                    return (*(uint*)rb) >> 3;
+                }
+            }
+            else if ((h & 0b1111) == 0b0111)
+            {
+                EnsureRead(4);
+                fixed (byte* rb = &Bytes[ReaderIndex])
+                {
+                    ReaderIndex += 4;
+                    return (*(uint*)rb) >> 4;
+                }
+            }
+            else
+            {
+                EnsureRead(5);
+                fixed (byte* rb = &Bytes[ReaderIndex])
+                {
+                    ReaderIndex += 5;
+                    return (*(uint*)rb) >> 5;
+                }
+            }
+        }
+
+        public int ReadFint()
+        {
+            EnsureRead(4);
+            int x;
+#if CPU_SUPPORT_MEMORY_NOT_ALIGN
+            unsafe
+            {
+                fixed (byte* b = &Bytes[ReaderIndex])
+                {
+                    x = *(int*)b;
+                }
+            }
+#else
+            x = (Bytes[ReaderIndex + 3] << 24) | (Bytes[ReaderIndex + 2] << 16) | (Bytes[ReaderIndex + 1] << 8) | (Bytes[ReaderIndex]);
+
+#endif
+            ReaderIndex += 4;
+            return x;
+        }
+
+
+        public void WriteFint(int x)
+        {
+            EnsureWrite(4);
+#if CPU_SUPPORT_MEMORY_NOT_ALIGN
+            unsafe
+            {
+                fixed (byte* b = &Bytes[WriterIndex])
+                {
+                    *(int*)b = x;
+                }
+            }
+#else
+            Bytes[WriterIndex] = (byte)x;
+            Bytes[WriterIndex + 1] = (byte)(x >> 8);
+            Bytes[WriterIndex + 2] = (byte)(x >> 16);
+            Bytes[WriterIndex + 3] = (byte)(x >> 24);
+#endif
+            WriterIndex += 4;
+        }
+
+        public int ReadFint_Safe()
+        {
+            EnsureRead(4);
+            int x;
+
+            x = (Bytes[ReaderIndex + 3] << 24) | (Bytes[ReaderIndex + 2] << 16) | (Bytes[ReaderIndex + 1] << 8) | (Bytes[ReaderIndex]);
+
+            ReaderIndex += 4;
+            return x;
+        }
+
+
+        public void WriteFint_Safe(int x)
+        {
+            EnsureWrite(4);
+            Bytes[WriterIndex] = (byte)x;
+            Bytes[WriterIndex + 1] = (byte)(x >> 8);
+            Bytes[WriterIndex + 2] = (byte)(x >> 16);
+            Bytes[WriterIndex + 3] = (byte)(x >> 24);
+            WriterIndex += 4;
+        }
+
+        public void WriteLong(long x)
+        {
+            WriteUlong((ulong)x);
+        }
+
+        public long ReadLong()
+        {
+            return (long)ReadUlong();
+        }
+
+        public void WriteNumberAsLong(double x)
+        {
+            WriteLong((long)x);
+        }
+
+        public double ReadLongAsNumber()
+        {
+            return ReadLong();
+        }
+
+        private void WriteUlong(ulong x)
+        {
+            // 0 111 1111
+            if (x < 0x80)
+            {
+                EnsureWrite(1);
+                Bytes[WriterIndex++] = (byte)x;
+            }
+            else if (x < 0x4000) // 10 11 1111, -
+            {
+                EnsureWrite(2);
+                Bytes[WriterIndex + 1] = (byte)x;
+                Bytes[WriterIndex] = (byte)((x >> 8) | 0x80);
+                WriterIndex += 2;
+            }
+            else if (x < 0x200000) // 110 1 1111, -,-
+            {
+                EnsureWrite(3);
+                Bytes[WriterIndex + 2] = (byte)x;
+                Bytes[WriterIndex + 1] = (byte)(x >> 8);
+                Bytes[WriterIndex] = (byte)((x >> 16) | 0xc0);
+                WriterIndex += 3;
+            }
+            else if (x < 0x10000000) // 1110 1111,-,-,-
+            {
+                EnsureWrite(4);
+                Bytes[WriterIndex + 3] = (byte)x;
+                Bytes[WriterIndex + 2] = (byte)(x >> 8);
+                Bytes[WriterIndex + 1] = (byte)(x >> 16);
+                Bytes[WriterIndex] = (byte)((x >> 24) | 0xe0);
+                WriterIndex += 4;
+            }
+            else if (x < 0x800000000L) // 1111 0xxx,-,-,-,-
+            {
+                EnsureWrite(5);
+                Bytes[WriterIndex + 4] = (byte)x;
+                Bytes[WriterIndex + 3] = (byte)(x >> 8);
+                Bytes[WriterIndex + 2] = (byte)(x >> 16);
+                Bytes[WriterIndex + 1] = (byte)(x >> 24);
+                Bytes[WriterIndex] = (byte)((x >> 32) | 0xf0);
+                WriterIndex += 5;
+            }
+            else if (x < 0x40000000000L) // 1111 10xx, 
+            {
+                EnsureWrite(6);
+                Bytes[WriterIndex + 5] = (byte)x;
+                Bytes[WriterIndex + 4] = (byte)(x >> 8);
+                Bytes[WriterIndex + 3] = (byte)(x >> 16);
+                Bytes[WriterIndex + 2] = (byte)(x >> 24);
+                Bytes[WriterIndex + 1] = (byte)(x >> 32);
+                Bytes[WriterIndex] = (byte)((x >> 40) | 0xf8);
+                WriterIndex += 6;
+            }
+            else if (x < 0x200000000000L) // 1111 110x,
+            {
+                EnsureWrite(7);
+                Bytes[WriterIndex + 6] = (byte)x;
+                Bytes[WriterIndex + 5] = (byte)(x >> 8);
+                Bytes[WriterIndex + 4] = (byte)(x >> 16);
+                Bytes[WriterIndex + 3] = (byte)(x >> 24);
+                Bytes[WriterIndex + 2] = (byte)(x >> 32);
+                Bytes[WriterIndex + 1] = (byte)(x >> 40);
+                Bytes[WriterIndex] = (byte)((x >> 48) | 0xfc);
+                WriterIndex += 7;
+            }
+            else if (x < 0x100000000000000L) // 1111 1110
+            {
+                EnsureWrite(8);
+                Bytes[WriterIndex + 7] = (byte)x;
+                Bytes[WriterIndex + 6] = (byte)(x >> 8);
+                Bytes[WriterIndex + 5] = (byte)(x >> 16);
+                Bytes[WriterIndex + 4] = (byte)(x >> 24);
+                Bytes[WriterIndex + 3] = (byte)(x >> 32);
+                Bytes[WriterIndex + 2] = (byte)(x >> 40);
+                Bytes[WriterIndex + 1] = (byte)(x >> 48);
+                Bytes[WriterIndex] = 0xfe;
+                WriterIndex += 8;
+            }
+            else // 1111 1111
+            {
+                EnsureWrite(9);
+                Bytes[WriterIndex] = 0xff;
+                Bytes[WriterIndex + 8] = (byte)x;
+                Bytes[WriterIndex + 7] = (byte)(x >> 8);
+                Bytes[WriterIndex + 6] = (byte)(x >> 16);
+                Bytes[WriterIndex + 5] = (byte)(x >> 24);
+                Bytes[WriterIndex + 4] = (byte)(x >> 32);
+                Bytes[WriterIndex + 3] = (byte)(x >> 40);
+                Bytes[WriterIndex + 2] = (byte)(x >> 48);
+                Bytes[WriterIndex + 1] = (byte)(x >> 56);
+                WriterIndex += 9;
+            }
+        }
+
+        public ulong ReadUlong()
+        {
+            EnsureRead(1);
+            uint h = Bytes[ReaderIndex];
+            if (h < 0x80)
+            {
+                ReaderIndex++;
+                return h;
+            }
+            else if (h < 0xc0)
+            {
+                EnsureRead(2);
+                uint x = ((h & 0x3f) << 8) | Bytes[ReaderIndex + 1];
+                ReaderIndex += 2;
+                return x;
+            }
+            else if (h < 0xe0)
+            {
+                EnsureRead(3);
+                uint x = ((h & 0x1f) << 16) | ((uint)Bytes[ReaderIndex + 1] << 8) | Bytes[ReaderIndex + 2];
+                ReaderIndex += 3;
+                return x;
+            }
+            else if (h < 0xf0)
+            {
+                EnsureRead(4);
+                uint x = ((h & 0x0f) << 24) | ((uint)Bytes[ReaderIndex + 1] << 16) | ((uint)Bytes[ReaderIndex + 2] << 8) | Bytes[ReaderIndex + 3];
+                ReaderIndex += 4;
+                return x;
+            }
+            else if (h < 0xf8)
+            {
+                EnsureRead(5);
+                uint xl = ((uint)Bytes[ReaderIndex + 1] << 24) | ((uint)(Bytes[ReaderIndex + 2] << 16)) | ((uint)Bytes[ReaderIndex + 3] << 8) | (Bytes[ReaderIndex + 4]);
+                uint xh = h & 0x07;
+                ReaderIndex += 5;
+                return ((ulong)xh << 32) | xl;
+            }
+            else if (h < 0xfc)
+            {
+                EnsureRead(6);
+                uint xl = ((uint)Bytes[ReaderIndex + 2] << 24) | ((uint)(Bytes[ReaderIndex + 3] << 16)) | ((uint)Bytes[ReaderIndex + 4] << 8) | (Bytes[ReaderIndex + 5]);
+                uint xh = ((h & 0x03) << 8) | Bytes[ReaderIndex + 1];
+                ReaderIndex += 6;
+                return ((ulong)xh << 32) | xl;
+            }
+            else if (h < 0xfe)
+            {
+                EnsureRead(7);
+                uint xl = ((uint)Bytes[ReaderIndex + 3] << 24) | ((uint)(Bytes[ReaderIndex + 4] << 16)) | ((uint)Bytes[ReaderIndex + 5] << 8) | (Bytes[ReaderIndex + 6]);
+                uint xh = ((h & 0x01) << 16) | ((uint)Bytes[ReaderIndex + 1] << 8) | Bytes[ReaderIndex + 2];
+                ReaderIndex += 7;
+                return ((ulong)xh << 32) | xl;
+            }
+            else if (h < 0xff)
+            {
+                EnsureRead(8);
+                uint xl = ((uint)Bytes[ReaderIndex + 4] << 24) | ((uint)(Bytes[ReaderIndex + 5] << 16)) | ((uint)Bytes[ReaderIndex + 6] << 8) | (Bytes[ReaderIndex + 7]);
+                uint xh = /*((h & 0x01) << 24) |*/ ((uint)Bytes[ReaderIndex + 1] << 16) | ((uint)Bytes[ReaderIndex + 2] << 8) | Bytes[ReaderIndex + 3];
+                ReaderIndex += 8;
+                return ((ulong)xh << 32) | xl;
+            }
+            else
+            {
+                EnsureRead(9);
+                uint xl = ((uint)Bytes[ReaderIndex + 5] << 24) | ((uint)(Bytes[ReaderIndex + 6] << 16)) | ((uint)Bytes[ReaderIndex + 7] << 8) | (Bytes[ReaderIndex + 8]);
+                uint xh = ((uint)Bytes[ReaderIndex + 1] << 24) | ((uint)Bytes[ReaderIndex + 2] << 16) | ((uint)Bytes[ReaderIndex + 3] << 8) | Bytes[ReaderIndex + 4];
+                ReaderIndex += 9;
+                return ((ulong)xh << 32) | xl;
+            }
+        }
+
+
+        public void WriteFlong(long x)
+        {
+            EnsureWrite(8);
+#if CPU_SUPPORT_MEMORY_NOT_ALIGN
+            unsafe
+            {
+                fixed (byte* b = &Bytes[WriterIndex])
+                {
+                    *(long*)b = x;
+                }
+            }
+#else
+
+            Bytes[WriterIndex] = (byte)x;
+            Bytes[WriterIndex + 1] = (byte)(x >> 8);
+            Bytes[WriterIndex + 2] = (byte)(x >> 16);
+            Bytes[WriterIndex + 3] = (byte)(x >> 24);
+            Bytes[WriterIndex + 4] = (byte)(x >> 32);
+            Bytes[WriterIndex + 5] = (byte)(x >> 40);
+            Bytes[WriterIndex + 6] = (byte)(x >> 48);
+            Bytes[WriterIndex + 7] = (byte)(x >> 56);
+#endif
+            WriterIndex += 8;
+        }
+
+        public long ReadFlong()
+        {
+            EnsureRead(8);
+            long x;
+#if CPU_SUPPORT_MEMORY_NOT_ALIGN
+            unsafe
+            {
+                fixed (byte* b = &Bytes[ReaderIndex])
+                {
+                    x = *(long*)b;
+                }
+            }
+#else
+            int xl = (Bytes[ReaderIndex + 3] << 24) | ((Bytes[ReaderIndex + 2] << 16)) | (Bytes[ReaderIndex + 1] << 8) | (Bytes[ReaderIndex]);
+            int xh = (Bytes[ReaderIndex + 7] << 24) | (Bytes[ReaderIndex + 6] << 16) | (Bytes[ReaderIndex + 5] << 8) | Bytes[ReaderIndex + 4];
+            x = ((long)xh << 32) | (long)xl;
+#endif
+            ReaderIndex += 8;
+            return x;
+        }
+
+        private static unsafe void Copy8(byte* dst, byte* src)
+        {
+            dst[0] = src[0];
+            dst[1] = src[1];
+            dst[2] = src[2];
+            dst[3] = src[3];
+            dst[4] = src[4];
+            dst[5] = src[5];
+            dst[6] = src[6];
+            dst[7] = src[7];
+        }
+
+        private static unsafe void Copy4(byte* dst, byte* src)
+        {
+            dst[0] = src[0];
+            dst[1] = src[1];
+            dst[2] = src[2];
+            dst[3] = src[3];
+        }
+
+
+        //const bool isLittleEndian = true;
+        public void WriteFloat(float x)
+        {
+            EnsureWrite(4);
+            unsafe
+            {
+                fixed (byte* b = &Bytes[WriterIndex])
+                {
+#if !CPU_SUPPORT_MEMORY_NOT_ALIGN
+                    if ((long)b % 4 == 0)
+                    {
+                        *(float*)b = x;
+                    }
+                    else
+                    {
+                        Copy4(b, (byte*)&x);
+                    }
+#else
+                    *(float*)b = x;
+#endif
+                }
+            }
+
+            //if (!BitConverter.IsLittleEndian)
+            //{
+            //    Array.Reverse(data, endPos, 4);
+            //}
+            WriterIndex += 4;
+        }
+
+        public float ReadFloat()
+        {
+            EnsureRead(4);
+            //if (!BitConverter.IsLittleEndian)
+            //{
+            //    Array.Reverse(data, beginPos, 4);
+            //}
+            float x;
+            unsafe
+            {
+                fixed (byte* b = &Bytes[ReaderIndex])
+                {
+#if !CPU_SUPPORT_MEMORY_NOT_ALIGN
+                    if ((long)b % 4 == 0)
+                    {
+                        x = *(float*)b;
+                    }
+                    else
+                    {
+                        *((int*)&x) = (b[0]) | (b[1] << 8) | (b[2] << 16) | (b[3] << 24);
+                    }
+#else
+                    x = *(float*)b;
+#endif
+                }
+            }
+
+            ReaderIndex += 4;
+            return x;
+        }
+
+        public void WriteDouble(double x)
+        {
+            EnsureWrite(8);
+            unsafe
+            {
+                fixed (byte* b = &Bytes[WriterIndex])
+                {
+#if !CPU_SUPPORT_MEMORY_NOT_ALIGN
+                    if ((long)b % 8 == 0)
+                    {
+                        *(double*)b = x;
+                    }
+                    else
+                    {
+                        Copy8(b, (byte*)&x);
+                    }
+#else
+                    *(double*)b = x;
+#endif
+                }
+                //if (!BitConverter.IsLittleEndian)
+                //{
+                //    Array.Reverse(data, endPos, 8);
+                //}
+            }
+
+            WriterIndex += 8;
+        }
+
+        public double ReadDouble()
+        {
+            EnsureRead(8);
+            //if (!BitConverter.IsLittleEndian)
+            //{
+            //    Array.Reverse(data, beginPos, 8);
+            //}
+            double x;
+            unsafe
+            {
+                fixed (byte* b = &Bytes[ReaderIndex])
+                {
+#if !CPU_SUPPORT_MEMORY_NOT_ALIGN
+                    if ((long)b % 8 == 0)
+                    {
+                        x = *(double*)b;
+                    }
+                    else
+                    {
+                        int low = (b[0]) | (b[1] << 8) | (b[2] << 16) | (b[3] << 24);
+                        int high = (b[4]) | (b[5] << 8) | (b[6] << 16) | (b[7] << 24);
+                        *((long*)&x) = ((long)high << 32) | (uint)low;
+                    }
+#else
+                    x = *(double*)b;
+#endif
+                }
+            }
+
+            ReaderIndex += 8;
+            return x;
+        }
+
+        public void WriteSize(int n)
+        {
+            WriteUint((uint)n);
+        }
+
+        public int ReadSize()
+        {
+            return (int)ReadUint();
+        }
+
+        // marshal int 
+        // n -> (n << 1) ^ (n >> 31)
+        // Read
+        // (x >>> 1) ^ ((x << 31) >> 31)
+        // (x >>> 1) ^ -(n&1)
+        public void WriteSint(int x)
+        {
+            WriteUint(((uint)x << 1) ^ ((uint)x >> 31));
+        }
+
+        public int ReadSint()
+        {
+            uint x = ReadUint();
+            return (int)((x >> 1) ^ ((x & 1) << 31));
+        }
+
+
+        // marshal long
+        // n -> (n << 1) ^ (n >> 63)
+        // Read
+        // (x >>> 1) ^((x << 63) >> 63)
+        // (x >>> 1) ^ -(n&1L)
+        public void WriteSlong(long x)
+        {
+            WriteUlong(((ulong)x << 1) ^ ((ulong)x >> 63));
+        }
+
+        public long ReadSlong()
+        {
+            long x = ReadLong();
+            return ((long)((ulong)x >> 1) ^ ((x & 1) << 63));
+        }
+
+        public void WriteString(string x)
+        {
+            var n = x != null ? Encoding.UTF8.GetByteCount(x) : 0;
+            WriteSize(n);
+            if (n > 0)
+            {
+                EnsureWrite(n);
+                Encoding.UTF8.GetBytes(x, 0, x.Length, Bytes, WriterIndex);
+                WriterIndex += n;
+            }
+        }
+
+        // byte[], [start, end)
+        public static Func<byte[], int, int, string> StringCacheFinder { get; set; }
+
+        public string ReadString()
+        {
+            var n = ReadSize();
+            if (n > 0)
+            {
+                EnsureRead(n);
+                string s;
+
+                if (StringCacheFinder == null)
+                {
+                    s = Encoding.UTF8.GetString(Bytes, ReaderIndex, n);
+                }
+                else
+                {
+                    // 只缓存比较小的字符串
+                    s = StringCacheFinder(Bytes, ReaderIndex, n);
+                }
+                ReaderIndex += n;
+                return s;
+            }
+            else
+            {
+                return string.Empty;
+            }
+        }
+
+        public void WriteBytes(byte[] x)
+        {
+            var n = x != null ? x.Length : 0;
+            WriteSize(n);
+            if (n > 0)
+            {
+                EnsureWrite(n);
+                x.CopyTo(Bytes, WriterIndex);
+                WriterIndex += n;
+            }
+        }
+
+        public byte[] ReadBytes()
+        {
+            var n = ReadSize();
+            if (n > 0)
+            {
+                EnsureRead(n);
+                var x = new byte[n];
+                Buffer.BlockCopy(Bytes, ReaderIndex, x, 0, n);
+                ReaderIndex += n;
+                return x;
+            }
+            else
+            {
+                return Array.Empty<byte>();
+            }
+        }
+
+        // 以下是一些特殊类型
+
+        public void WriteComplex(Complex x)
+        {
+            WriteDouble(x.Real);
+            WriteDouble(x.Imaginary);
+        }
+
+        public Complex ReadComplex()
+        {
+            var x = ReadDouble();
+            var y = ReadDouble();
+            return new Complex(x, y);
+        }
+
+        public void WriteVector2(Vector2 x)
+        {
+            WriteFloat(x.X);
+            WriteFloat(x.Y);
+        }
+
+        public Vector2 ReadVector2()
+        {
+            float x = ReadFloat();
+            float y = ReadFloat();
+            return new Vector2(x, y);
+        }
+
+        public void WriteVector3(Vector3 x)
+        {
+            WriteFloat(x.X);
+            WriteFloat(x.Y);
+            WriteFloat(x.Z);
+        }
+
+        public Vector3 ReadVector3()
+        {
+            float x = ReadFloat();
+            float y = ReadFloat();
+            float z = ReadFloat();
+            return new Vector3(x, y, z);
+        }
+
+        public void WriteVector4(Vector4 x)
+        {
+            WriteFloat(x.X);
+            WriteFloat(x.Y);
+            WriteFloat(x.Z);
+            WriteFloat(x.W);
+        }
+
+        public Vector4 ReadVector4()
+        {
+            float x = ReadFloat();
+            float y = ReadFloat();
+            float z = ReadFloat();
+            float w = ReadFloat();
+            return new Vector4(x, y, z, w);
+        }
+
+
+        public void WriteQuaternion(Quaternion x)
+        {
+            WriteFloat(x.X);
+            WriteFloat(x.Y);
+            WriteFloat(x.Z);
+            WriteFloat(x.W);
+        }
+
+        public Quaternion ReadQuaternion()
+        {
+            float x = ReadFloat();
+            float y = ReadFloat();
+            float z = ReadFloat();
+            float w = ReadFloat();
+            return new Quaternion(x, y, z, w);
+        }
+
+
+        public void WriteMatrix4x4(Matrix4x4 x)
+        {
+            WriteFloat(x.M11);
+            WriteFloat(x.M12);
+            WriteFloat(x.M13);
+            WriteFloat(x.M14);
+            WriteFloat(x.M21);
+            WriteFloat(x.M22);
+            WriteFloat(x.M23);
+            WriteFloat(x.M24);
+            WriteFloat(x.M31);
+            WriteFloat(x.M32);
+            WriteFloat(x.M33);
+            WriteFloat(x.M34);
+            WriteFloat(x.M41);
+            WriteFloat(x.M42);
+            WriteFloat(x.M43);
+            WriteFloat(x.M44);
+        }
+
+        public Matrix4x4 ReadMatrix4x4()
+        {
+            float m11 = ReadFloat();
+            float m12 = ReadFloat();
+            float m13 = ReadFloat();
+            float m14 = ReadFloat();
+            float m21 = ReadFloat();
+            float m22 = ReadFloat();
+            float m23 = ReadFloat();
+            float m24 = ReadFloat();
+            float m31 = ReadFloat();
+            float m32 = ReadFloat();
+            float m33 = ReadFloat();
+            float m34 = ReadFloat();
+            float m41 = ReadFloat();
+            float m42 = ReadFloat();
+            float m43 = ReadFloat();
+            float m44 = ReadFloat();
+            return new Matrix4x4(m11, m12, m13, m14,
+                m21, m22, m23, m24,
+                m31, m32, m33, m34,
+                m41, m42, m43, m44);
+        }
+
+        internal void SkipBytes()
+        {
+            int n = ReadSize();
+            EnsureRead(n);
+            ReaderIndex += n;
+        }
+
+
+        public void WriteByteBufWithSize(ByteBuf o)
+        {
+            int n = o.Size;
+            if (n > 0)
+            {
+                WriteSize(n);
+                WriteBytesWithoutSize(o.Bytes, o.ReaderIndex, n);
+            }
+            else
+            {
+                WriteByte(0);
+            }
+        }
+
+        public void WriteByteBufWithoutSize(ByteBuf o)
+        {
+            int n = o.Size;
+            if (n > 0)
+            {
+                WriteBytesWithoutSize(o.Bytes, o.ReaderIndex, n);
+            }
+        }
+
+        public bool TryReadByte(out byte x)
+        {
+            if (CanRead(1))
+            {
+                x = Bytes[ReaderIndex++];
+                return true;
+            }
+            else
+            {
+                x = 0;
+                return false;
+            }
+        }
+
+        public EDeserializeError TryDeserializeInplaceByteBuf(int maxSize, ByteBuf inplaceTempBody)
+        {
+            //if (!CanRead(1)) { return EDeserializeError.NOT_ENOUGH; }
+            int oldReadIndex = ReaderIndex;
+            bool commit = false;
+            try
+            {
+                int n;
+                int h = Bytes[ReaderIndex];
+                if (h < 0x80)
+                {
+                    ReaderIndex++;
+                    n = h;
+                }
+                else if (h < 0xc0)
+                {
+                    if (!CanRead(2)) { return EDeserializeError.NOT_ENOUGH; }
+                    n = ((h & 0x3f) << 8) | Bytes[ReaderIndex + 1];
+                    ReaderIndex += 2;
+                }
+                else if (h < 0xe0)
+                {
+                    if (!CanRead(3)) { return EDeserializeError.NOT_ENOUGH; }
+                    n = ((h & 0x1f) << 16) | (Bytes[ReaderIndex + 1] << 8) | Bytes[ReaderIndex + 2];
+                    ReaderIndex += 3;
+                }
+                else if (h < 0xf0)
+                {
+                    if (!CanRead(4)) { return EDeserializeError.NOT_ENOUGH; }
+                    n = ((h & 0x0f) << 24) | (Bytes[ReaderIndex + 1] << 16) | (Bytes[ReaderIndex + 2] << 8) | Bytes[ReaderIndex + 3];
+                    ReaderIndex += 4;
+                }
+                else
+                {
+                    return EDeserializeError.EXCEED_SIZE;
+                }
+
+                if (n > maxSize)
+                {
+                    return EDeserializeError.EXCEED_SIZE;
+                }
+                if (Remaining < n)
+                {
+                    return EDeserializeError.NOT_ENOUGH;
+                }
+
+                int inplaceReadIndex = ReaderIndex;
+                ReaderIndex += n;
+
+                inplaceTempBody.Replace(Bytes, inplaceReadIndex, ReaderIndex);
+                commit = true;
+            }
+            finally
+            {
+                if (!commit)
+                {
+                    ReaderIndex = oldReadIndex;
+                }
+            }
+
+            return EDeserializeError.OK;
+        }
+
+        public void WriteRawTag(byte b1)
+        {
+            EnsureWrite(1);
+            Bytes[WriterIndex++] = b1;
+        }
+
+        public void WriteRawTag(byte b1, byte b2)
+        {
+            EnsureWrite(2);
+            Bytes[WriterIndex] = b1;
+            Bytes[WriterIndex + 1] = b2;
+            WriterIndex += 2;
+        }
+
+        public void WriteRawTag(byte b1, byte b2, byte b3)
+        {
+            EnsureWrite(3);
+            Bytes[WriterIndex] = b1;
+            Bytes[WriterIndex + 1] = b2;
+            Bytes[WriterIndex + 2] = b3;
+            WriterIndex += 3;
+        }
+
+        #region segment
+
+
+        public void BeginWriteSegment(out int oldSize)
+        {
+            oldSize = Size;
+            EnsureWrite(1);
+            WriterIndex += 1;
+        }
+
+        public void EndWriteSegment(int oldSize)
+        {
+            int startPos = ReaderIndex + oldSize;
+            int segmentSize = WriterIndex - startPos - 1;
+
+            // 0 111 1111
+            if (segmentSize < 0x80)
+            {
+                Bytes[startPos] = (byte)segmentSize;
+            }
+            else if (segmentSize < 0x4000) // 10 11 1111, -
+            {
+                EnsureWrite(1);
+                Bytes[WriterIndex] = Bytes[startPos + 1];
+                Bytes[startPos + 1] = (byte)segmentSize;
+
+                Bytes[startPos] = (byte)((segmentSize >> 8) | 0x80);
+                WriterIndex += 1;
+            }
+            else if (segmentSize < 0x200000) // 110 1 1111, -,-
+            {
+                EnsureWrite(2);
+                Bytes[WriterIndex + 1] = Bytes[startPos + 2];
+                Bytes[startPos + 2] = (byte)segmentSize;
+
+                Bytes[WriterIndex] = Bytes[startPos + 1];
+                Bytes[startPos + 1] = (byte)(segmentSize >> 8);
+
+                Bytes[startPos] = (byte)((segmentSize >> 16) | 0xc0);
+                WriterIndex += 2;
+            }
+            else if (segmentSize < 0x10000000) // 1110 1111,-,-,-
+            {
+                EnsureWrite(3);
+                Bytes[WriterIndex + 2] = Bytes[startPos + 3];
+                Bytes[startPos + 3] = (byte)segmentSize;
+
+                Bytes[WriterIndex + 1] = Bytes[startPos + 2];
+                Bytes[startPos + 2] = (byte)(segmentSize >> 8);
+
+                Bytes[WriterIndex] = Bytes[startPos + 1];
+                Bytes[startPos + 1] = (byte)(segmentSize >> 16);
+
+                Bytes[startPos] = (byte)((segmentSize >> 24) | 0xe0);
+                WriterIndex += 3;
+            }
+            else
+            {
+                throw new SerializationException("exceed max segment size");
+            }
+        }
+
+        public void ReadSegment(out int startIndex, out int segmentSize)
+        {
+            EnsureRead(1);
+            int h = Bytes[ReaderIndex++];
+
+            startIndex = ReaderIndex;
+
+            if (h < 0x80)
+            {
+                segmentSize = h;
+                ReaderIndex += segmentSize;
+            }
+            else if (h < 0xc0)
+            {
+                EnsureRead(1);
+                segmentSize = ((h & 0x3f) << 8) | Bytes[ReaderIndex];
+                int endPos = ReaderIndex + segmentSize;
+                Bytes[ReaderIndex] = Bytes[endPos];
+                ReaderIndex += segmentSize + 1;
+            }
+            else if (h < 0xe0)
+            {
+                EnsureRead(2);
+                segmentSize = ((h & 0x1f) << 16) | ((int)Bytes[ReaderIndex] << 8) | Bytes[ReaderIndex + 1];
+                int endPos = ReaderIndex + segmentSize;
+                Bytes[ReaderIndex] = Bytes[endPos];
+                Bytes[ReaderIndex + 1] = Bytes[endPos + 1];
+                ReaderIndex += segmentSize + 2;
+            }
+            else if (h < 0xf0)
+            {
+                EnsureRead(3);
+                segmentSize = ((h & 0x0f) << 24) | ((int)Bytes[ReaderIndex] << 16) | ((int)Bytes[ReaderIndex + 1] << 8) | Bytes[ReaderIndex + 2];
+                int endPos = ReaderIndex + segmentSize;
+                Bytes[ReaderIndex] = Bytes[endPos];
+                Bytes[ReaderIndex + 1] = Bytes[endPos + 1];
+                Bytes[ReaderIndex + 2] = Bytes[endPos + 2];
+                ReaderIndex += segmentSize + 3;
+            }
+            else
+            {
+                throw new SerializationException("exceed max size");
+            }
+            if (ReaderIndex > WriterIndex)
+            {
+                throw new SerializationException("segment data not enough");
+            }
+        }
+
+        public void ReadSegment(ByteBuf buf)
+        {
+            ReadSegment(out int startPos, out var size);
+            buf.Bytes = Bytes;
+            buf.ReaderIndex = startPos;
+            buf.WriterIndex = startPos + size;
+        }
+
+        public void EnterSegment(out SegmentSaveState saveState)
+        {
+            ReadSegment(out int startPos, out int size);
+
+            saveState = new SegmentSaveState(ReaderIndex, WriterIndex);
+            ReaderIndex = startPos;
+            WriterIndex = startPos + size;
+        }
+
+        public void LeaveSegment(SegmentSaveState saveState)
+        {
+            ReaderIndex = saveState.ReaderIndex;
+            WriterIndex = saveState.WriterIndex;
+        }
+
+        #endregion
+
+        public override string ToString()
+        {
+            string[] datas = new string[WriterIndex - ReaderIndex];
+            for (var i = ReaderIndex; i < WriterIndex; i++)
+            {
+                datas[i - ReaderIndex] = Bytes[i].ToString("X2");
+            }
+            return string.Join(".", datas);
+        }
+
+        public override bool Equals(object obj)
+        {
+            return (obj is ByteBuf other) && Equals(other);
+        }
+
+        public bool Equals(ByteBuf other)
+        {
+            if (other == null)
+            {
+                return false;
+            }
+            if (Size != other.Size)
+            {
+                return false;
+            }
+            for (int i = 0, n = Size; i < n; i++)
+            {
+                if (Bytes[ReaderIndex + i] != other.Bytes[other.ReaderIndex + i])
+                {
+                    return false;
+                }
+            }
+            return true;
+        }
+
+        public object Clone()
+        {
+            return new ByteBuf(CopyData());
+        }
+
+
+        public static ByteBuf FromString(string value)
+        {
+            var ss = value.Split(',');
+            byte[] data = new byte[ss.Length];
+            for (int i = 0; i < data.Length; i++)
+            {
+                data[i] = byte.Parse(ss[i]);
+            }
+            return new ByteBuf(data);
+        }
+
+        public override int GetHashCode()
+        {
+            int hash = 17;
+            for (int i = ReaderIndex; i < WriterIndex; i++)
+            {
+                hash = hash * 23 + Bytes[i];
+            }
+            return hash;
+        }
+
+        public void Release()
+        {
+            _releaser?.Invoke(this);
+        }
+
+#if SUPPORT_PUERTS_ARRAYBUF
+        // -- add for puerts
+        public Puerts.ArrayBuffer ReadArrayBuffer()
+        {
+            return new Puerts.ArrayBuffer(ReadBytes());
+        }
+
+        public void WriteArrayBuffer(Puerts.ArrayBuffer bytes)
+        {
+            WriteBytes(bytes.Bytes);
+        }
+#endif
+    }
+}

+ 11 - 0
GameClient/Assets/Plugins/luban_unity/Runtime/ByteBuf.cs.meta

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

+ 14 - 0
GameClient/Assets/Plugins/luban_unity/Runtime/Luban.Runtime.asmdef

@@ -0,0 +1,14 @@
+{
+    "name": "Luban.Runtime",
+    "rootNamespace": "",
+    "references": [],
+    "includePlatforms": [],
+    "excludePlatforms": [],
+    "allowUnsafeCode": true,
+    "overrideReferences": false,
+    "precompiledReferences": [],
+    "autoReferenced": true,
+    "defineConstraints": [],
+    "versionDefines": [],
+    "noEngineReferences": false
+}

+ 7 - 0
GameClient/Assets/Plugins/luban_unity/Runtime/Luban.Runtime.asmdef.meta

@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 2a81c6962524d424a8ef5072bd3b0fa0
+AssemblyDefinitionImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 8 - 0
GameClient/Assets/Plugins/luban_unity/Runtime/SimpleJSON.meta

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

+ 111 - 0
GameClient/Assets/Plugins/luban_unity/Runtime/SimpleJSON/Changelog.txt

@@ -0,0 +1,111 @@
+/*
+ * [2012-06-09 First Version]
+ * - provides strongly typed node classes and lists / dictionaries
+ * - provides easy access to class members / array items / data values
+ * - the parser now properly identifies types. So generating JSON with this framework should work.
+ * - only double quotes (") are used for quoting strings.
+ * - provides "casting" properties to easily convert to / from those types:
+ *   int / float / double / bool
+ * - provides a common interface for each node so no explicit casting is required.
+ * - the parser tries to avoid errors, but if malformed JSON is parsed the result is more or less undefined
+ * - It can serialize/deserialize a node tree into/from an experimental compact binary format. It might
+ *   be handy if you want to store things in a file and don't want it to be easily modifiable
+ * 
+ * [2012-12-17 Update]
+ * - Added internal JSONLazyCreator class which simplifies the construction of a JSON tree
+ *   Now you can simple reference any item that doesn't exist yet and it will return a JSONLazyCreator
+ *   The class determines the required type by it's further use, creates the type and removes itself.
+ * - Added binary serialization / deserialization.
+ * - Added support for BZip2 zipped binary format. Requires the SharpZipLib ( http://www.icsharpcode.net/opensource/sharpziplib/ )
+ *   The usage of the SharpZipLib library can be disabled by removing or commenting out the USE_SharpZipLib define at the top
+ * - The serializer uses different types when it comes to store the values. Since my data values
+ *   are all of type string, the serializer will "try" which format fits best. The order is: int, float, double, bool, string.
+ *   It's not the most efficient way but for a moderate amount of data it should work on all platforms.
+ * 
+ * [2017-03-08 Update]
+ * - Optimised parsing by using a StringBuilder for token. This prevents performance issues when large
+ *   string data fields are contained in the json data.
+ * - Finally refactored the badly named JSONClass into JSONObject.
+ * - Replaced the old JSONData class by distict typed classes ( JSONString, JSONNumber, JSONBool, JSONNull ) this
+ *   allows to propertly convert the node tree back to json without type information loss. The actual value
+ *   parsing now happens at parsing time and not when you actually access one of the casting properties.
+ * 
+ * [2017-04-11 Update]
+ * - Fixed parsing bug where empty string values have been ignored.
+ * - Optimised "ToString" by using a StringBuilder internally. This should heavily improve performance for large files
+ * - Changed the overload of "ToString(string aIndent)" to "ToString(int aIndent)"
+ * 
+ * [2017-11-29 Update]
+ * - Removed the IEnumerator implementations on JSONArray & JSONObject and replaced it with a common
+ *   struct Enumerator in JSONNode that should avoid garbage generation. The enumerator always works
+ *   on KeyValuePair<string, JSONNode>, even for JSONArray.
+ * - Added two wrapper Enumerators that allows for easy key or value enumeration. A JSONNode now has
+ *   a "Keys" and a "Values" enumerable property. Those are also struct enumerators / enumerables
+ * - A KeyValuePair<string, JSONNode> can now be implicitly converted into a JSONNode. This allows
+ *   a foreach loop over a JSONNode to directly access the values only. Since KeyValuePair as well as
+ *   all the Enumerators are structs, no garbage is allocated.
+ * - To add Linq support another "LinqEnumerator" is available through the "Linq" property. This
+ *   enumerator does implement the generic IEnumerable interface so most Linq extensions can be used
+ *   on this enumerable object. This one does allocate memory as it's a wrapper class.
+ * - The Escape method now escapes all control characters (# < 32) in strings as uncode characters
+ *   (\uXXXX) and if the static bool JSONNode.forceASCII is set to true it will also escape all
+ *   characters # > 127. This might be useful if you require an ASCII output. Though keep in mind
+ *   when your strings contain many non-ascii characters the strings become much longer (x6) and are
+ *   no longer human readable.
+ * - The node types JSONObject and JSONArray now have an "Inline" boolean switch which will default to
+ *   false. It can be used to serialize this element inline even you serialize with an indented format
+ *   This is useful for arrays containing numbers so it doesn't place every number on a new line
+ * - Extracted the binary serialization code into a seperate extension file. All classes are now declared
+ *   as "partial" so an extension file can even add a new virtual or abstract method / interface to
+ *   JSONNode and override it in the concrete type classes. It's of course a hacky approach which is
+ *   generally not recommended, but i wanted to keep everything tightly packed.
+ * - Added a static CreateOrGet method to the JSONNull class. Since this class is immutable it could
+ *   be reused without major problems. If you have a lot null fields in your data it will help reduce
+ *   the memory / garbage overhead. I also added a static setting (reuseSameInstance) to JSONNull
+ *   (default is true) which will change the behaviour of "CreateOrGet". If you set this to false
+ *   CreateOrGet will not reuse the cached instance but instead create a new JSONNull instance each time.
+ *   I made the JSONNull constructor private so if you need to create an instance manually use
+ *   JSONNull.CreateOrGet()
+ * 
+ * [2018-01-09 Update]
+ * - Changed all double.TryParse and double.ToString uses to use the invariant culture to avoid problems
+ *   on systems with a culture that uses a comma as decimal point.
+ * 
+ * [2018-01-26 Update]
+ * - Added AsLong. Note that a JSONNumber is stored as double and can't represent all long values. However
+ *   storing it as string would work.
+ * - Added static setting "JSONNode.longAsString" which controls the default type that is used by the
+ *   LazyCreator when using AsLong
+ * 
+ * [2018-04-25 Update]
+ *  - Added support for parsing single values (JSONBool, JSONString, JSONNumber, JSONNull) as top level value.
+ * 
+ * [2019-02-18 Update]
+ *  - Added HasKey(key) and GetValueOrDefault(key, default) to the JSONNode class to provide way to read
+ *    values conditionally without creating a LazyCreator
+ * 
+ * [2019-03-25 Update]
+ *  - Added static setting "allowLineComments" to the JSONNode class which is true by default. This allows
+ *    "//" line comments when parsing json text as long as it's not within quoted text. All text after // up
+ *    to the end of the line is completely ignored / skipped. This makes it easier to create human readable
+ *    and editable files. Note that stripped comments are not read, processed or preserved in any way. So
+ *    this feature is only relevant for human created files.
+ *  - Explicitly strip BOM (Byte Order Mark) when parsing to avoid getting it leaked into a single primitive
+ *    value. That's a rare case but better safe than sorry.
+ *  - Allowing adding the empty string as key
+ *  
+ * [2019-12-10 Update]
+ *  - Added Clone() method to JSONNode to allow cloning of a whole node tree.
+ * 
+ * [2020-09-19 Update]
+ *  - Added Clear() method to JSONNode.
+ *  - The parser will now automatically mark arrays or objects as inline when it doesn't contain any
+ *    new line characters. This should more or less preserve the layout.
+ *  - Added new extension file "SimpleJSONDotNetTypes.cs" to provide support for some basic .NET types
+ *    like decimal, char, byte, sbyte, short, ushort, uint, DateTime, TimeSpan and Guid as well as some
+ *    nullable types.
+ *  - Fixed an error in the Unity extension file. The Color component order was wrong (it was argb, now it's rgba)
+ *  - There are now two static float variables (ColorDefaultAlpha and Color32DefaultAlpha) to specify the default
+ *    alpha values when reading UnityEngine.Color / Color32 values where the alpha value is absent. The default
+ *    values are 1.0f and 255 respectively.
+ */

+ 7 - 0
GameClient/Assets/Plugins/luban_unity/Runtime/SimpleJSON/Changelog.txt.meta

@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 35336dcb5aad4cf45b523dbf1482a514
+TextScriptImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 21 - 0
GameClient/Assets/Plugins/luban_unity/Runtime/SimpleJSON/LICENSE

@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2012-2017 Markus Göbel (Bunny83)
+
+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.

+ 7 - 0
GameClient/Assets/Plugins/luban_unity/Runtime/SimpleJSON/LICENSE.meta

@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 4615d3ebbd0d7ae4fa8c107f727bbab4
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 0 - 0
GameClient/Assets/Plugins/luban_unity/Runtime/SimpleJSON/README


+ 7 - 0
GameClient/Assets/Plugins/luban_unity/Runtime/SimpleJSON/README.meta

@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 0b3e755f11799b5458a47d6b897a9393
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 1434 - 0
GameClient/Assets/Plugins/luban_unity/Runtime/SimpleJSON/SimpleJSON.cs

@@ -0,0 +1,1434 @@
+/* * * * *
+ * A simple JSON Parser / builder
+ * ------------------------------
+ * 
+ * It mainly has been written as a simple JSON parser. It can build a JSON string
+ * from the node-tree, or generate a node tree from any valid JSON string.
+ * 
+ * Written by Bunny83 
+ * 2012-06-09
+ * 
+ * Changelog now external. See Changelog.txt
+ * 
+ * The MIT License (MIT)
+ * 
+ * Copyright (c) 2012-2019 Markus Göbel (Bunny83)
+ * 
+ * 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.
+ * 
+ * * * * */
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+using System.Text;
+
+namespace SimpleJSON
+{
+    public enum JSONNodeType
+    {
+        Array = 1,
+        Object = 2,
+        String = 3,
+        Number = 4,
+        NullValue = 5,
+        Boolean = 6,
+        None = 7,
+        Custom = 0xFF,
+    }
+    public enum JSONTextMode
+    {
+        Compact,
+        Indent
+    }
+
+    public abstract partial class JSONNode
+    {
+        #region Enumerators
+        public struct Enumerator
+        {
+            private enum Type { None, Array, Object }
+            private Type type;
+            private Dictionary<string, JSONNode>.Enumerator m_Object;
+            private List<JSONNode>.Enumerator m_Array;
+            public bool IsValid { get { return type != Type.None; } }
+            public Enumerator(List<JSONNode>.Enumerator aArrayEnum)
+            {
+                type = Type.Array;
+                m_Object = default(Dictionary<string, JSONNode>.Enumerator);
+                m_Array = aArrayEnum;
+            }
+            public Enumerator(Dictionary<string, JSONNode>.Enumerator aDictEnum)
+            {
+                type = Type.Object;
+                m_Object = aDictEnum;
+                m_Array = default(List<JSONNode>.Enumerator);
+            }
+            public KeyValuePair<string, JSONNode> Current
+            {
+                get
+                {
+                    if (type == Type.Array)
+                        return new KeyValuePair<string, JSONNode>(string.Empty, m_Array.Current);
+                    else if (type == Type.Object)
+                        return m_Object.Current;
+                    return new KeyValuePair<string, JSONNode>(string.Empty, null);
+                }
+            }
+            public bool MoveNext()
+            {
+                if (type == Type.Array)
+                    return m_Array.MoveNext();
+                else if (type == Type.Object)
+                    return m_Object.MoveNext();
+                return false;
+            }
+        }
+        public struct ValueEnumerator
+        {
+            private Enumerator m_Enumerator;
+            public ValueEnumerator(List<JSONNode>.Enumerator aArrayEnum) : this(new Enumerator(aArrayEnum)) { }
+            public ValueEnumerator(Dictionary<string, JSONNode>.Enumerator aDictEnum) : this(new Enumerator(aDictEnum)) { }
+            public ValueEnumerator(Enumerator aEnumerator) { m_Enumerator = aEnumerator; }
+            public JSONNode Current { get { return m_Enumerator.Current.Value; } }
+            public bool MoveNext() { return m_Enumerator.MoveNext(); }
+            public ValueEnumerator GetEnumerator() { return this; }
+        }
+        public struct KeyEnumerator
+        {
+            private Enumerator m_Enumerator;
+            public KeyEnumerator(List<JSONNode>.Enumerator aArrayEnum) : this(new Enumerator(aArrayEnum)) { }
+            public KeyEnumerator(Dictionary<string, JSONNode>.Enumerator aDictEnum) : this(new Enumerator(aDictEnum)) { }
+            public KeyEnumerator(Enumerator aEnumerator) { m_Enumerator = aEnumerator; }
+            public string Current { get { return m_Enumerator.Current.Key; } }
+            public bool MoveNext() { return m_Enumerator.MoveNext(); }
+            public KeyEnumerator GetEnumerator() { return this; }
+        }
+
+        public class LinqEnumerator : IEnumerator<KeyValuePair<string, JSONNode>>, IEnumerable<KeyValuePair<string, JSONNode>>
+        {
+            private JSONNode m_Node;
+            private Enumerator m_Enumerator;
+            internal LinqEnumerator(JSONNode aNode)
+            {
+                m_Node = aNode;
+                if (m_Node != null)
+                    m_Enumerator = m_Node.GetEnumerator();
+            }
+            public KeyValuePair<string, JSONNode> Current { get { return m_Enumerator.Current; } }
+            object IEnumerator.Current { get { return m_Enumerator.Current; } }
+            public bool MoveNext() { return m_Enumerator.MoveNext(); }
+
+            public void Dispose()
+            {
+                m_Node = null;
+                m_Enumerator = new Enumerator();
+            }
+
+            public IEnumerator<KeyValuePair<string, JSONNode>> GetEnumerator()
+            {
+                return new LinqEnumerator(m_Node);
+            }
+
+            public void Reset()
+            {
+                if (m_Node != null)
+                    m_Enumerator = m_Node.GetEnumerator();
+            }
+
+            IEnumerator IEnumerable.GetEnumerator()
+            {
+                return new LinqEnumerator(m_Node);
+            }
+        }
+
+        #endregion Enumerators
+
+        #region common interface
+
+        public static bool forceASCII = false; // Use Unicode by default
+        public static bool longAsString = false; // lazy creator creates a JSONString instead of JSONNumber
+        public static bool allowLineComments = true; // allow "//"-style comments at the end of a line
+
+        public abstract JSONNodeType Tag { get; }
+
+        public virtual JSONNode this[int aIndex] { get { return null; } set { } }
+
+        public virtual JSONNode this[string aKey] { get { return null; } set { } }
+
+        public virtual string Value { get { return ""; } set { } }
+
+        public virtual int Count { get { return 0; } }
+
+        public virtual bool IsNumber { get { return false; } }
+        public virtual bool IsString { get { return false; } }
+        public virtual bool IsBoolean { get { return false; } }
+        public virtual bool IsNull { get { return false; } }
+        public virtual bool IsArray { get { return false; } }
+        public virtual bool IsObject { get { return false; } }
+
+        public virtual bool Inline { get { return false; } set { } }
+
+        public virtual void Add(string aKey, JSONNode aItem)
+        {
+        }
+        public virtual void Add(JSONNode aItem)
+        {
+            Add("", aItem);
+        }
+
+        public virtual JSONNode Remove(string aKey)
+        {
+            return null;
+        }
+
+        public virtual JSONNode Remove(int aIndex)
+        {
+            return null;
+        }
+
+        public virtual JSONNode Remove(JSONNode aNode)
+        {
+            return aNode;
+        }
+        public virtual void Clear() { }
+
+        public virtual JSONNode Clone()
+        {
+            return null;
+        }
+
+        public virtual IEnumerable<JSONNode> Children
+        {
+            get
+            {
+                yield break;
+            }
+        }
+
+        public IEnumerable<JSONNode> DeepChildren
+        {
+            get
+            {
+                foreach (var C in Children)
+                    foreach (var D in C.DeepChildren)
+                        yield return D;
+            }
+        }
+
+        public virtual bool HasKey(string aKey)
+        {
+            return false;
+        }
+
+        public virtual JSONNode GetValueOrDefault(string aKey, JSONNode aDefault)
+        {
+            return aDefault;
+        }
+
+        public override string ToString()
+        {
+            StringBuilder sb = new StringBuilder();
+            WriteToStringBuilder(sb, 0, 0, JSONTextMode.Compact);
+            return sb.ToString();
+        }
+
+        public virtual string ToString(int aIndent)
+        {
+            StringBuilder sb = new StringBuilder();
+            WriteToStringBuilder(sb, 0, aIndent, JSONTextMode.Indent);
+            return sb.ToString();
+        }
+        internal abstract void WriteToStringBuilder(StringBuilder aSB, int aIndent, int aIndentInc, JSONTextMode aMode);
+
+        public abstract Enumerator GetEnumerator();
+        public IEnumerable<KeyValuePair<string, JSONNode>> Linq { get { return new LinqEnumerator(this); } }
+        public KeyEnumerator Keys { get { return new KeyEnumerator(GetEnumerator()); } }
+        public ValueEnumerator Values { get { return new ValueEnumerator(GetEnumerator()); } }
+
+        #endregion common interface
+
+        #region typecasting properties
+
+
+        public virtual double AsDouble
+        {
+            get
+            {
+                double v = 0.0;
+                if (double.TryParse(Value, NumberStyles.Float, CultureInfo.InvariantCulture, out v))
+                    return v;
+                return 0.0;
+            }
+            set
+            {
+                Value = value.ToString(CultureInfo.InvariantCulture);
+            }
+        }
+
+        public virtual int AsInt
+        {
+            get { return (int)AsDouble; }
+            set { AsDouble = value; }
+        }
+
+        public virtual float AsFloat
+        {
+            get { return (float)AsDouble; }
+            set { AsDouble = value; }
+        }
+
+        public virtual bool AsBool
+        {
+            get
+            {
+                bool v = false;
+                if (bool.TryParse(Value, out v))
+                    return v;
+                return !string.IsNullOrEmpty(Value);
+            }
+            set
+            {
+                Value = (value) ? "true" : "false";
+            }
+        }
+
+        public virtual long AsLong
+        {
+            get
+            {
+                long val = 0;
+                if (long.TryParse(Value, out val))
+                    return val;
+                return 0L;
+            }
+            set
+            {
+                Value = value.ToString();
+            }
+        }
+
+        public virtual ulong AsULong
+        {
+            get
+            {
+                ulong val = 0;
+                if (ulong.TryParse(Value, out val))
+                    return val;
+                return 0;
+            }
+            set
+            {
+                Value = value.ToString();
+            }
+        }
+
+        public virtual JSONArray AsArray
+        {
+            get
+            {
+                return this as JSONArray;
+            }
+        }
+
+        public virtual JSONObject AsObject
+        {
+            get
+            {
+                return this as JSONObject;
+            }
+        }
+
+
+        #endregion typecasting properties
+
+        #region operators
+
+        public static implicit operator JSONNode(string s)
+        {
+            return (s == null) ? (JSONNode) JSONNull.CreateOrGet() : new JSONString(s);
+        }
+        public static implicit operator string(JSONNode d)
+        {
+            return (d == null) ? null : d.Value;
+        }
+
+        public static implicit operator JSONNode(double n)
+        {
+            return new JSONNumber(n);
+        }
+        public static implicit operator double(JSONNode d)
+        {
+            return (d == null) ? 0 : d.AsDouble;
+        }
+
+        public static implicit operator JSONNode(float n)
+        {
+            return new JSONNumber(n);
+        }
+        public static implicit operator float(JSONNode d)
+        {
+            return (d == null) ? 0 : d.AsFloat;
+        }
+
+        public static implicit operator JSONNode(int n)
+        {
+            return new JSONNumber(n);
+        }
+        public static implicit operator int(JSONNode d)
+        {
+            return (d == null) ? 0 : d.AsInt;
+        }
+
+        public static implicit operator JSONNode(long n)
+        {
+            if (longAsString)
+                return new JSONString(n.ToString());
+            return new JSONNumber(n);
+        }
+        public static implicit operator long(JSONNode d)
+        {
+            return (d == null) ? 0L : d.AsLong;
+        }
+
+        public static implicit operator JSONNode(ulong n)
+        {
+            if (longAsString)
+                return new JSONString(n.ToString());
+            return new JSONNumber(n);
+        }
+        public static implicit operator ulong(JSONNode d)
+        {
+            return (d == null) ? 0 : d.AsULong;
+        }
+
+        public static implicit operator JSONNode(bool b)
+        {
+            return new JSONBool(b);
+        }
+        public static implicit operator bool(JSONNode d)
+        {
+            return (d == null) ? false : d.AsBool;
+        }
+
+        public static implicit operator JSONNode(KeyValuePair<string, JSONNode> aKeyValue)
+        {
+            return aKeyValue.Value;
+        }
+
+        public static bool operator ==(JSONNode a, object b)
+        {
+            if (ReferenceEquals(a, b))
+                return true;
+            bool aIsNull = a is JSONNull || ReferenceEquals(a, null) || a is JSONLazyCreator;
+            bool bIsNull = b is JSONNull || ReferenceEquals(b, null) || b is JSONLazyCreator;
+            if (aIsNull && bIsNull)
+                return true;
+            return !aIsNull && a.Equals(b);
+        }
+
+        public static bool operator !=(JSONNode a, object b)
+        {
+            return !(a == b);
+        }
+
+        public override bool Equals(object obj)
+        {
+            return ReferenceEquals(this, obj);
+        }
+
+        public override int GetHashCode()
+        {
+            return base.GetHashCode();
+        }
+
+        #endregion operators
+
+        [ThreadStatic]
+        private static StringBuilder m_EscapeBuilder;
+        internal static StringBuilder EscapeBuilder
+        {
+            get
+            {
+                if (m_EscapeBuilder == null)
+                    m_EscapeBuilder = new StringBuilder();
+                return m_EscapeBuilder;
+            }
+        }
+        internal static string Escape(string aText)
+        {
+            var sb = EscapeBuilder;
+            sb.Length = 0;
+            if (sb.Capacity < aText.Length + aText.Length / 10)
+                sb.Capacity = aText.Length + aText.Length / 10;
+            foreach (char c in aText)
+            {
+                switch (c)
+                {
+                    case '\\':
+                        sb.Append("\\\\");
+                        break;
+                    case '\"':
+                        sb.Append("\\\"");
+                        break;
+                    case '\n':
+                        sb.Append("\\n");
+                        break;
+                    case '\r':
+                        sb.Append("\\r");
+                        break;
+                    case '\t':
+                        sb.Append("\\t");
+                        break;
+                    case '\b':
+                        sb.Append("\\b");
+                        break;
+                    case '\f':
+                        sb.Append("\\f");
+                        break;
+                    default:
+                        if (c < ' ' || (forceASCII && c > 127))
+                        {
+                            ushort val = c;
+                            sb.Append("\\u").Append(val.ToString("X4"));
+                        }
+                        else
+                            sb.Append(c);
+                        break;
+                }
+            }
+            string result = sb.ToString();
+            sb.Length = 0;
+            return result;
+        }
+
+        private static JSONNode ParseElement(string token, bool quoted)
+        {
+            if (quoted)
+                return token;
+            if (token.Length <= 5)
+            {
+                string tmp = token.ToLower();
+                if (tmp == "false" || tmp == "true")
+                    return tmp == "true";
+                if (tmp == "null")
+                    return JSONNull.CreateOrGet();
+            }
+            double val;
+            if (double.TryParse(token, NumberStyles.Float, CultureInfo.InvariantCulture, out val))
+                return val;
+            else
+                return token;
+        }
+
+        public static JSONNode Parse(string aJSON)
+        {
+            Stack<JSONNode> stack = new Stack<JSONNode>();
+            JSONNode ctx = null;
+            int i = 0;
+            StringBuilder Token = new StringBuilder();
+            string TokenName = "";
+            bool QuoteMode = false;
+            bool TokenIsQuoted = false;
+            bool HasNewlineChar = false;
+            while (i < aJSON.Length)
+            {
+                switch (aJSON[i])
+                {
+                    case '{':
+                        if (QuoteMode)
+                        {
+                            Token.Append(aJSON[i]);
+                            break;
+                        }
+                        stack.Push(new JSONObject());
+                        if (ctx != null)
+                        {
+                            ctx.Add(TokenName, stack.Peek());
+                        }
+                        TokenName = "";
+                        Token.Length = 0;
+                        ctx = stack.Peek();
+                        HasNewlineChar = false;
+                        break;
+
+                    case '[':
+                        if (QuoteMode)
+                        {
+                            Token.Append(aJSON[i]);
+                            break;
+                        }
+
+                        stack.Push(new JSONArray());
+                        if (ctx != null)
+                        {
+                            ctx.Add(TokenName, stack.Peek());
+                        }
+                        TokenName = "";
+                        Token.Length = 0;
+                        ctx = stack.Peek();
+                        HasNewlineChar = false;
+                        break;
+
+                    case '}':
+                    case ']':
+                        if (QuoteMode)
+                        {
+
+                            Token.Append(aJSON[i]);
+                            break;
+                        }
+                        if (stack.Count == 0)
+                            throw new Exception("JSON Parse: Too many closing brackets");
+
+                        stack.Pop();
+                        if (Token.Length > 0 || TokenIsQuoted)
+                            ctx.Add(TokenName, ParseElement(Token.ToString(), TokenIsQuoted));
+                        if (ctx != null)
+                            ctx.Inline = !HasNewlineChar;
+                        TokenIsQuoted = false;
+                        TokenName = "";
+                        Token.Length = 0;
+                        if (stack.Count > 0)
+                            ctx = stack.Peek();
+                        break;
+
+                    case ':':
+                        if (QuoteMode)
+                        {
+                            Token.Append(aJSON[i]);
+                            break;
+                        }
+                        TokenName = Token.ToString();
+                        Token.Length = 0;
+                        TokenIsQuoted = false;
+                        break;
+
+                    case '"':
+                        QuoteMode ^= true;
+                        TokenIsQuoted |= QuoteMode;
+                        break;
+
+                    case ',':
+                        if (QuoteMode)
+                        {
+                            Token.Append(aJSON[i]);
+                            break;
+                        }
+                        if (Token.Length > 0 || TokenIsQuoted)
+                            ctx.Add(TokenName, ParseElement(Token.ToString(), TokenIsQuoted));
+                        TokenIsQuoted = false;
+                        TokenName = "";
+                        Token.Length = 0;
+                        TokenIsQuoted = false;
+                        break;
+
+                    case '\r':
+                    case '\n':
+                        HasNewlineChar = true;
+                        break;
+
+                    case ' ':
+                    case '\t':
+                        if (QuoteMode)
+                            Token.Append(aJSON[i]);
+                        break;
+
+                    case '\\':
+                        ++i;
+                        if (QuoteMode)
+                        {
+                            char C = aJSON[i];
+                            switch (C)
+                            {
+                                case 't':
+                                    Token.Append('\t');
+                                    break;
+                                case 'r':
+                                    Token.Append('\r');
+                                    break;
+                                case 'n':
+                                    Token.Append('\n');
+                                    break;
+                                case 'b':
+                                    Token.Append('\b');
+                                    break;
+                                case 'f':
+                                    Token.Append('\f');
+                                    break;
+                                case 'u':
+                                    {
+                                        string s = aJSON.Substring(i + 1, 4);
+                                        Token.Append((char)int.Parse(
+                                            s,
+                                            System.Globalization.NumberStyles.AllowHexSpecifier));
+                                        i += 4;
+                                        break;
+                                    }
+                                default:
+                                    Token.Append(C);
+                                    break;
+                            }
+                        }
+                        break;
+                    case '/':
+                        if (allowLineComments && !QuoteMode && i + 1 < aJSON.Length && aJSON[i + 1] == '/')
+                        {
+                            while (++i < aJSON.Length && aJSON[i] != '\n' && aJSON[i] != '\r') ;
+                            break;
+                        }
+                        Token.Append(aJSON[i]);
+                        break;
+                    case '\uFEFF': // remove / ignore BOM (Byte Order Mark)
+                        break;
+
+                    default:
+                        Token.Append(aJSON[i]);
+                        break;
+                }
+                ++i;
+            }
+            if (QuoteMode)
+            {
+                throw new Exception("JSON Parse: Quotation marks seems to be messed up.");
+            }
+            if (ctx == null)
+                return ParseElement(Token.ToString(), TokenIsQuoted);
+            return ctx;
+        }
+
+    }
+    // End of JSONNode
+
+    public partial class JSONArray : JSONNode
+    {
+        private List<JSONNode> m_List = new List<JSONNode>();
+        private bool inline = false;
+        public override bool Inline
+        {
+            get { return inline; }
+            set { inline = value; }
+        }
+
+        public override JSONNodeType Tag { get { return JSONNodeType.Array; } }
+        public override bool IsArray { get { return true; } }
+        public override Enumerator GetEnumerator() { return new Enumerator(m_List.GetEnumerator()); }
+
+        public override JSONNode this[int aIndex]
+        {
+            get
+            {
+                if (aIndex < 0 || aIndex >= m_List.Count)
+                    return new JSONLazyCreator(this);
+                return m_List[aIndex];
+            }
+            set
+            {
+                if (value == null)
+                    value = JSONNull.CreateOrGet();
+                if (aIndex < 0 || aIndex >= m_List.Count)
+                    m_List.Add(value);
+                else
+                    m_List[aIndex] = value;
+            }
+        }
+
+        public override JSONNode this[string aKey]
+        {
+            get { return new JSONLazyCreator(this); }
+            set
+            {
+                if (value == null)
+                    value = JSONNull.CreateOrGet();
+                m_List.Add(value);
+            }
+        }
+
+        public override int Count
+        {
+            get { return m_List.Count; }
+        }
+
+        public override void Add(string aKey, JSONNode aItem)
+        {
+            if (aItem == null)
+                aItem = JSONNull.CreateOrGet();
+            m_List.Add(aItem);
+        }
+
+        public override JSONNode Remove(int aIndex)
+        {
+            if (aIndex < 0 || aIndex >= m_List.Count)
+                return null;
+            JSONNode tmp = m_List[aIndex];
+            m_List.RemoveAt(aIndex);
+            return tmp;
+        }
+
+        public override JSONNode Remove(JSONNode aNode)
+        {
+            m_List.Remove(aNode);
+            return aNode;
+        }
+
+        public override void Clear()
+        {
+            m_List.Clear();
+        }
+
+        public override JSONNode Clone()
+        {
+            var node = new JSONArray();
+            node.m_List.Capacity = m_List.Capacity;
+            foreach(var n in m_List)
+            {
+                if (n != null)
+                    node.Add(n.Clone());
+                else
+                    node.Add(null);
+            }
+            return node;
+        }
+
+        public override IEnumerable<JSONNode> Children
+        {
+            get
+            {
+                foreach (JSONNode N in m_List)
+                    yield return N;
+            }
+        }
+
+
+        internal override void WriteToStringBuilder(StringBuilder aSB, int aIndent, int aIndentInc, JSONTextMode aMode)
+        {
+            aSB.Append('[');
+            int count = m_List.Count;
+            if (inline)
+                aMode = JSONTextMode.Compact;
+            for (int i = 0; i < count; i++)
+            {
+                if (i > 0)
+                    aSB.Append(',');
+                if (aMode == JSONTextMode.Indent)
+                    aSB.AppendLine();
+
+                if (aMode == JSONTextMode.Indent)
+                    aSB.Append(' ', aIndent + aIndentInc);
+                m_List[i].WriteToStringBuilder(aSB, aIndent + aIndentInc, aIndentInc, aMode);
+            }
+            if (aMode == JSONTextMode.Indent)
+                aSB.AppendLine().Append(' ', aIndent);
+            aSB.Append(']');
+        }
+    }
+    // End of JSONArray
+
+    public partial class JSONObject : JSONNode
+    {
+        private Dictionary<string, JSONNode> m_Dict = new Dictionary<string, JSONNode>();
+
+        private bool inline = false;
+        public override bool Inline
+        {
+            get { return inline; }
+            set { inline = value; }
+        }
+
+        public override JSONNodeType Tag { get { return JSONNodeType.Object; } }
+        public override bool IsObject { get { return true; } }
+
+        public override Enumerator GetEnumerator() { return new Enumerator(m_Dict.GetEnumerator()); }
+
+
+        public override JSONNode this[string aKey]
+        {
+            get
+            {
+                if (m_Dict.ContainsKey(aKey))
+                    return m_Dict[aKey];
+                else
+                    return new JSONLazyCreator(this, aKey);
+            }
+            set
+            {
+                if (value == null)
+                    value = JSONNull.CreateOrGet();
+                if (m_Dict.ContainsKey(aKey))
+                    m_Dict[aKey] = value;
+                else
+                    m_Dict.Add(aKey, value);
+            }
+        }
+
+        public override JSONNode this[int aIndex]
+        {
+            get
+            {
+                if (aIndex < 0 || aIndex >= m_Dict.Count)
+                    return null;
+                return m_Dict.ElementAt(aIndex).Value;
+            }
+            set
+            {
+                if (value == null)
+                    value = JSONNull.CreateOrGet();
+                if (aIndex < 0 || aIndex >= m_Dict.Count)
+                    return;
+                string key = m_Dict.ElementAt(aIndex).Key;
+                m_Dict[key] = value;
+            }
+        }
+
+        public override int Count
+        {
+            get { return m_Dict.Count; }
+        }
+
+        public override void Add(string aKey, JSONNode aItem)
+        {
+            if (aItem == null)
+                aItem = JSONNull.CreateOrGet();
+
+            if (aKey != null)
+            {
+                if (m_Dict.ContainsKey(aKey))
+                    m_Dict[aKey] = aItem;
+                else
+                    m_Dict.Add(aKey, aItem);
+            }
+            else
+                m_Dict.Add(Guid.NewGuid().ToString(), aItem);
+        }
+
+        public override JSONNode Remove(string aKey)
+        {
+            if (!m_Dict.ContainsKey(aKey))
+                return null;
+            JSONNode tmp = m_Dict[aKey];
+            m_Dict.Remove(aKey);
+            return tmp;
+        }
+
+        public override JSONNode Remove(int aIndex)
+        {
+            if (aIndex < 0 || aIndex >= m_Dict.Count)
+                return null;
+            var item = m_Dict.ElementAt(aIndex);
+            m_Dict.Remove(item.Key);
+            return item.Value;
+        }
+
+        public override JSONNode Remove(JSONNode aNode)
+        {
+            try
+            {
+                var item = m_Dict.Where(k => k.Value == aNode).First();
+                m_Dict.Remove(item.Key);
+                return aNode;
+            }
+            catch
+            {
+                return null;
+            }
+        }
+
+        public override void Clear()
+        {
+            m_Dict.Clear();
+        }
+
+        public override JSONNode Clone()
+        {
+            var node = new JSONObject();
+            foreach (var n in m_Dict)
+            {
+                node.Add(n.Key, n.Value.Clone());
+            }
+            return node;
+        }
+
+        public override bool HasKey(string aKey)
+        {
+            return m_Dict.ContainsKey(aKey);
+        }
+
+        public override JSONNode GetValueOrDefault(string aKey, JSONNode aDefault)
+        {
+            JSONNode res;
+            if (m_Dict.TryGetValue(aKey, out res))
+                return res;
+            return aDefault;
+        }
+
+        public override IEnumerable<JSONNode> Children
+        {
+            get
+            {
+                foreach (KeyValuePair<string, JSONNode> N in m_Dict)
+                    yield return N.Value;
+            }
+        }
+
+        internal override void WriteToStringBuilder(StringBuilder aSB, int aIndent, int aIndentInc, JSONTextMode aMode)
+        {
+            aSB.Append('{');
+            bool first = true;
+            if (inline)
+                aMode = JSONTextMode.Compact;
+            foreach (var k in m_Dict)
+            {
+                if (!first)
+                    aSB.Append(',');
+                first = false;
+                if (aMode == JSONTextMode.Indent)
+                    aSB.AppendLine();
+                if (aMode == JSONTextMode.Indent)
+                    aSB.Append(' ', aIndent + aIndentInc);
+                aSB.Append('\"').Append(Escape(k.Key)).Append('\"');
+                if (aMode == JSONTextMode.Compact)
+                    aSB.Append(':');
+                else
+                    aSB.Append(" : ");
+                k.Value.WriteToStringBuilder(aSB, aIndent + aIndentInc, aIndentInc, aMode);
+            }
+            if (aMode == JSONTextMode.Indent)
+                aSB.AppendLine().Append(' ', aIndent);
+            aSB.Append('}');
+        }
+
+    }
+    // End of JSONObject
+
+    public partial class JSONString : JSONNode
+    {
+        private string m_Data;
+
+        public override JSONNodeType Tag { get { return JSONNodeType.String; } }
+        public override bool IsString { get { return true; } }
+
+        public override Enumerator GetEnumerator() { return new Enumerator(); }
+
+
+        public override string Value
+        {
+            get { return m_Data; }
+            set
+            {
+                m_Data = value;
+            }
+        }
+
+        public JSONString(string aData)
+        {
+            m_Data = aData;
+        }
+        public override JSONNode Clone()
+        {
+            return new JSONString(m_Data);
+        }
+
+        internal override void WriteToStringBuilder(StringBuilder aSB, int aIndent, int aIndentInc, JSONTextMode aMode)
+        {
+            aSB.Append('\"').Append(Escape(m_Data)).Append('\"');
+        }
+        public override bool Equals(object obj)
+        {
+            if (base.Equals(obj))
+                return true;
+            string s = obj as string;
+            if (s != null)
+                return m_Data == s;
+            JSONString s2 = obj as JSONString;
+            if (s2 != null)
+                return m_Data == s2.m_Data;
+            return false;
+        }
+        public override int GetHashCode()
+        {
+            return m_Data.GetHashCode();
+        }
+        public override void Clear()
+        {
+            m_Data = "";
+        }
+    }
+    // End of JSONString
+
+    public partial class JSONNumber : JSONNode
+    {
+        private double m_Data;
+
+        public override JSONNodeType Tag { get { return JSONNodeType.Number; } }
+        public override bool IsNumber { get { return true; } }
+        public override Enumerator GetEnumerator() { return new Enumerator(); }
+
+        public override string Value
+        {
+            get { return m_Data.ToString(CultureInfo.InvariantCulture); }
+            set
+            {
+                double v;
+                if (double.TryParse(value, NumberStyles.Float, CultureInfo.InvariantCulture, out v))
+                    m_Data = v;
+            }
+        }
+
+        public override double AsDouble
+        {
+            get { return m_Data; }
+            set { m_Data = value; }
+        }
+        public override long AsLong
+        {
+            get { return (long)m_Data; }
+            set { m_Data = value; }
+        }
+        public override ulong AsULong
+        {
+            get { return (ulong)m_Data; }
+            set { m_Data = value; }
+        }
+
+        public JSONNumber(double aData)
+        {
+            m_Data = aData;
+        }
+
+        public JSONNumber(string aData)
+        {
+            Value = aData;
+        }
+
+        public override JSONNode Clone()
+        {
+            return new JSONNumber(m_Data);
+        }
+
+        internal override void WriteToStringBuilder(StringBuilder aSB, int aIndent, int aIndentInc, JSONTextMode aMode)
+        {
+            aSB.Append(Value);
+        }
+        private static bool IsNumeric(object value)
+        {
+            return value is int || value is uint
+                || value is float || value is double
+                || value is decimal
+                || value is long || value is ulong
+                || value is short || value is ushort
+                || value is sbyte || value is byte;
+        }
+        public override bool Equals(object obj)
+        {
+            if (obj == null)
+                return false;
+            if (base.Equals(obj))
+                return true;
+            JSONNumber s2 = obj as JSONNumber;
+            if (s2 != null)
+                return m_Data == s2.m_Data;
+            if (IsNumeric(obj))
+                return Convert.ToDouble(obj) == m_Data;
+            return false;
+        }
+        public override int GetHashCode()
+        {
+            return m_Data.GetHashCode();
+        }
+        public override void Clear()
+        {
+            m_Data = 0;
+        }
+    }
+    // End of JSONNumber
+
+    public partial class JSONBool : JSONNode
+    {
+        private bool m_Data;
+
+        public override JSONNodeType Tag { get { return JSONNodeType.Boolean; } }
+        public override bool IsBoolean { get { return true; } }
+        public override Enumerator GetEnumerator() { return new Enumerator(); }
+
+        public override string Value
+        {
+            get { return m_Data.ToString(); }
+            set
+            {
+                bool v;
+                if (bool.TryParse(value, out v))
+                    m_Data = v;
+            }
+        }
+        public override bool AsBool
+        {
+            get { return m_Data; }
+            set { m_Data = value; }
+        }
+
+        public JSONBool(bool aData)
+        {
+            m_Data = aData;
+        }
+
+        public JSONBool(string aData)
+        {
+            Value = aData;
+        }
+
+        public override JSONNode Clone()
+        {
+            return new JSONBool(m_Data);
+        }
+
+        internal override void WriteToStringBuilder(StringBuilder aSB, int aIndent, int aIndentInc, JSONTextMode aMode)
+        {
+            aSB.Append((m_Data) ? "true" : "false");
+        }
+        public override bool Equals(object obj)
+        {
+            if (obj == null)
+                return false;
+            if (obj is bool)
+                return m_Data == (bool)obj;
+            return false;
+        }
+        public override int GetHashCode()
+        {
+            return m_Data.GetHashCode();
+        }
+        public override void Clear()
+        {
+            m_Data = false;
+        }
+    }
+    // End of JSONBool
+
+    public partial class JSONNull : JSONNode
+    {
+        static JSONNull m_StaticInstance = new JSONNull();
+        public static bool reuseSameInstance = true;
+        public static JSONNull CreateOrGet()
+        {
+            if (reuseSameInstance)
+                return m_StaticInstance;
+            return new JSONNull();
+        }
+        private JSONNull() { }
+
+        public override JSONNodeType Tag { get { return JSONNodeType.NullValue; } }
+        public override bool IsNull { get { return true; } }
+        public override Enumerator GetEnumerator() { return new Enumerator(); }
+
+        public override string Value
+        {
+            get { return "null"; }
+            set { }
+        }
+        public override bool AsBool
+        {
+            get { return false; }
+            set { }
+        }
+
+        public override JSONNode Clone()
+        {
+            return CreateOrGet();
+        }
+
+        public override bool Equals(object obj)
+        {
+            if (object.ReferenceEquals(this, obj))
+                return true;
+            return (obj is JSONNull);
+        }
+        public override int GetHashCode()
+        {
+            return 0;
+        }
+
+        internal override void WriteToStringBuilder(StringBuilder aSB, int aIndent, int aIndentInc, JSONTextMode aMode)
+        {
+            aSB.Append("null");
+        }
+    }
+    // End of JSONNull
+
+    internal partial class JSONLazyCreator : JSONNode
+    {
+        private JSONNode m_Node = null;
+        private string m_Key = null;
+        public override JSONNodeType Tag { get { return JSONNodeType.None; } }
+        public override Enumerator GetEnumerator() { return new Enumerator(); }
+
+        public JSONLazyCreator(JSONNode aNode)
+        {
+            m_Node = aNode;
+            m_Key = null;
+        }
+
+        public JSONLazyCreator(JSONNode aNode, string aKey)
+        {
+            m_Node = aNode;
+            m_Key = aKey;
+        }
+
+        private T Set<T>(T aVal) where T : JSONNode
+        {
+            if (m_Key == null)
+                m_Node.Add(aVal);
+            else
+                m_Node.Add(m_Key, aVal);
+            m_Node = null; // Be GC friendly.
+            return aVal;
+        }
+
+        public override JSONNode this[int aIndex]
+        {
+            get { return new JSONLazyCreator(this); }
+            set { Set(new JSONArray()).Add(value); }
+        }
+
+        public override JSONNode this[string aKey]
+        {
+            get { return new JSONLazyCreator(this, aKey); }
+            set { Set(new JSONObject()).Add(aKey, value); }
+        }
+
+        public override void Add(JSONNode aItem)
+        {
+            Set(new JSONArray()).Add(aItem);
+        }
+
+        public override void Add(string aKey, JSONNode aItem)
+        {
+            Set(new JSONObject()).Add(aKey, aItem);
+        }
+
+        public static bool operator ==(JSONLazyCreator a, object b)
+        {
+            if (b == null)
+                return true;
+            return System.Object.ReferenceEquals(a, b);
+        }
+
+        public static bool operator !=(JSONLazyCreator a, object b)
+        {
+            return !(a == b);
+        }
+
+        public override bool Equals(object obj)
+        {
+            if (obj == null)
+                return true;
+            return System.Object.ReferenceEquals(this, obj);
+        }
+
+        public override int GetHashCode()
+        {
+            return 0;
+        }
+
+        public override int AsInt
+        {
+            get { Set(new JSONNumber(0)); return 0; }
+            set { Set(new JSONNumber(value)); }
+        }
+
+        public override float AsFloat
+        {
+            get { Set(new JSONNumber(0.0f)); return 0.0f; }
+            set { Set(new JSONNumber(value)); }
+        }
+
+        public override double AsDouble
+        {
+            get { Set(new JSONNumber(0.0)); return 0.0; }
+            set { Set(new JSONNumber(value)); }
+        }
+
+        public override long AsLong
+        {
+            get
+            {
+                if (longAsString)
+                    Set(new JSONString("0"));
+                else
+                    Set(new JSONNumber(0.0));
+                return 0L;
+            }
+            set
+            {
+                if (longAsString)
+                    Set(new JSONString(value.ToString()));
+                else
+                    Set(new JSONNumber(value));
+            }
+        }
+
+        public override ulong AsULong
+        {
+            get
+            {
+                if (longAsString)
+                    Set(new JSONString("0"));
+                else
+                    Set(new JSONNumber(0.0));
+                return 0L;
+            }
+            set
+            {
+                if (longAsString)
+                    Set(new JSONString(value.ToString()));
+                else
+                    Set(new JSONNumber(value));
+            }
+        }
+
+        public override bool AsBool
+        {
+            get { Set(new JSONBool(false)); return false; }
+            set { Set(new JSONBool(value)); }
+        }
+
+        public override JSONArray AsArray
+        {
+            get { return Set(new JSONArray()); }
+        }
+
+        public override JSONObject AsObject
+        {
+            get { return Set(new JSONObject()); }
+        }
+        internal override void WriteToStringBuilder(StringBuilder aSB, int aIndent, int aIndentInc, JSONTextMode aMode)
+        {
+            aSB.Append("null");
+        }
+    }
+    // End of JSONLazyCreator
+
+    public static class JSON
+    {
+        public static JSONNode Parse(string aJSON)
+        {
+            return JSONNode.Parse(aJSON);
+        }
+    }
+}

+ 11 - 0
GameClient/Assets/Plugins/luban_unity/Runtime/SimpleJSON/SimpleJSON.cs.meta

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

+ 301 - 0
GameClient/Assets/Plugins/luban_unity/Runtime/SimpleJSON/SimpleJSONBinary.cs

@@ -0,0 +1,301 @@
+//#define USE_SharpZipLib
+/* * * * *
+ * This is an extension of the SimpleJSON framework to provide methods to
+ * serialize a JSON object tree into a compact binary format. Optionally the
+ * binary stream can be compressed with the SharpZipLib when using the define
+ * "USE_SharpZipLib"
+ * 
+ * Those methods where originally part of the framework but since it's rarely
+ * used I've extracted this part into this seperate module file.
+ * 
+ * You can use the define "SimpleJSON_ExcludeBinary" to selectively disable
+ * this extension without the need to remove the file from the project.
+ * 
+ * If you want to use compression when saving to file / stream / B64 you have to include
+ * SharpZipLib ( http://www.icsharpcode.net/opensource/sharpziplib/ ) in your project and
+ * define "USE_SharpZipLib" at the top of the file
+ * 
+ * 
+ * The MIT License (MIT)
+ * 
+ * Copyright (c) 2012-2017 Markus Göbel (Bunny83)
+ * 
+ * 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.
+ * 
+ * * * * */
+using System;
+
+namespace SimpleJSON
+{
+#if !SimpleJSON_ExcludeBinary
+    public abstract partial class JSONNode
+    {
+        public abstract void SerializeBinary(System.IO.BinaryWriter aWriter);
+
+        public void SaveToBinaryStream(System.IO.Stream aData)
+        {
+            var W = new System.IO.BinaryWriter(aData);
+            SerializeBinary(W);
+        }
+
+#if USE_SharpZipLib
+		public void SaveToCompressedStream(System.IO.Stream aData)
+		{
+			using (var gzipOut = new ICSharpCode.SharpZipLib.BZip2.BZip2OutputStream(aData))
+			{
+				gzipOut.IsStreamOwner = false;
+				SaveToBinaryStream(gzipOut);
+				gzipOut.Close();
+			}
+		}
+ 
+		public void SaveToCompressedFile(string aFileName)
+		{
+ 
+			System.IO.Directory.CreateDirectory((new System.IO.FileInfo(aFileName)).Directory.FullName);
+			using(var F = System.IO.File.OpenWrite(aFileName))
+			{
+				SaveToCompressedStream(F);
+			}
+		}
+		public string SaveToCompressedBase64()
+		{
+			using (var stream = new System.IO.MemoryStream())
+			{
+				SaveToCompressedStream(stream);
+				stream.Position = 0;
+				return System.Convert.ToBase64String(stream.ToArray());
+			}
+		}
+ 
+#else
+        public void SaveToCompressedStream(System.IO.Stream aData)
+        {
+            throw new Exception("Can't use compressed functions. You need include the SharpZipLib and uncomment the define at the top of SimpleJSON");
+        }
+
+        public void SaveToCompressedFile(string aFileName)
+        {
+            throw new Exception("Can't use compressed functions. You need include the SharpZipLib and uncomment the define at the top of SimpleJSON");
+        }
+
+        public string SaveToCompressedBase64()
+        {
+            throw new Exception("Can't use compressed functions. You need include the SharpZipLib and uncomment the define at the top of SimpleJSON");
+        }
+#endif
+
+        public void SaveToBinaryFile(string aFileName)
+        {
+            System.IO.Directory.CreateDirectory((new System.IO.FileInfo(aFileName)).Directory.FullName);
+            using (var F = System.IO.File.OpenWrite(aFileName))
+            {
+                SaveToBinaryStream(F);
+            }
+        }
+
+        public string SaveToBinaryBase64()
+        {
+            using (var stream = new System.IO.MemoryStream())
+            {
+                SaveToBinaryStream(stream);
+                stream.Position = 0;
+                return System.Convert.ToBase64String(stream.ToArray());
+            }
+        }
+
+        public static JSONNode DeserializeBinary(System.IO.BinaryReader aReader)
+        {
+            JSONNodeType type = (JSONNodeType)aReader.ReadByte();
+            switch (type)
+            {
+                case JSONNodeType.Array:
+                    {
+                        int count = aReader.ReadInt32();
+                        JSONArray tmp = new JSONArray();
+                        for (int i = 0; i < count; i++)
+                            tmp.Add(DeserializeBinary(aReader));
+                        return tmp;
+                    }
+                case JSONNodeType.Object:
+                    {
+                        int count = aReader.ReadInt32();
+                        JSONObject tmp = new JSONObject();
+                        for (int i = 0; i < count; i++)
+                        {
+                            string key = aReader.ReadString();
+                            var val = DeserializeBinary(aReader);
+                            tmp.Add(key, val);
+                        }
+                        return tmp;
+                    }
+                case JSONNodeType.String:
+                    {
+                        return new JSONString(aReader.ReadString());
+                    }
+                case JSONNodeType.Number:
+                    {
+                        return new JSONNumber(aReader.ReadDouble());
+                    }
+                case JSONNodeType.Boolean:
+                    {
+                        return new JSONBool(aReader.ReadBoolean());
+                    }
+                case JSONNodeType.NullValue:
+                    {
+                        return JSONNull.CreateOrGet();
+                    }
+                default:
+                    {
+                        throw new Exception("Error deserializing JSON. Unknown tag: " + type);
+                    }
+            }
+        }
+
+#if USE_SharpZipLib
+		public static JSONNode LoadFromCompressedStream(System.IO.Stream aData)
+		{
+			var zin = new ICSharpCode.SharpZipLib.BZip2.BZip2InputStream(aData);
+			return LoadFromBinaryStream(zin);
+		}
+		public static JSONNode LoadFromCompressedFile(string aFileName)
+		{
+			using(var F = System.IO.File.OpenRead(aFileName))
+			{
+				return LoadFromCompressedStream(F);
+			}
+		}
+		public static JSONNode LoadFromCompressedBase64(string aBase64)
+		{
+			var tmp = System.Convert.FromBase64String(aBase64);
+			var stream = new System.IO.MemoryStream(tmp);
+			stream.Position = 0;
+			return LoadFromCompressedStream(stream);
+		}
+#else
+        public static JSONNode LoadFromCompressedFile(string aFileName)
+        {
+            throw new Exception("Can't use compressed functions. You need include the SharpZipLib and uncomment the define at the top of SimpleJSON");
+        }
+
+        public static JSONNode LoadFromCompressedStream(System.IO.Stream aData)
+        {
+            throw new Exception("Can't use compressed functions. You need include the SharpZipLib and uncomment the define at the top of SimpleJSON");
+        }
+
+        public static JSONNode LoadFromCompressedBase64(string aBase64)
+        {
+            throw new Exception("Can't use compressed functions. You need include the SharpZipLib and uncomment the define at the top of SimpleJSON");
+        }
+#endif
+
+        public static JSONNode LoadFromBinaryStream(System.IO.Stream aData)
+        {
+            using (var R = new System.IO.BinaryReader(aData))
+            {
+                return DeserializeBinary(R);
+            }
+        }
+
+        public static JSONNode LoadFromBinaryFile(string aFileName)
+        {
+            using (var F = System.IO.File.OpenRead(aFileName))
+            {
+                return LoadFromBinaryStream(F);
+            }
+        }
+
+        public static JSONNode LoadFromBinaryBase64(string aBase64)
+        {
+            var tmp = System.Convert.FromBase64String(aBase64);
+            var stream = new System.IO.MemoryStream(tmp);
+            stream.Position = 0;
+            return LoadFromBinaryStream(stream);
+        }
+    }
+
+    public partial class JSONArray : JSONNode
+    {
+        public override void SerializeBinary(System.IO.BinaryWriter aWriter)
+        {
+            aWriter.Write((byte)JSONNodeType.Array);
+            aWriter.Write(m_List.Count);
+            for (int i = 0; i < m_List.Count; i++)
+            {
+                m_List[i].SerializeBinary(aWriter);
+            }
+        }
+    }
+
+    public partial class JSONObject : JSONNode
+    {
+        public override void SerializeBinary(System.IO.BinaryWriter aWriter)
+        {
+            aWriter.Write((byte)JSONNodeType.Object);
+            aWriter.Write(m_Dict.Count);
+            foreach (string K in m_Dict.Keys)
+            {
+                aWriter.Write(K);
+                m_Dict[K].SerializeBinary(aWriter);
+            }
+        }
+    }
+
+    public partial class JSONString : JSONNode
+    {
+        public override void SerializeBinary(System.IO.BinaryWriter aWriter)
+        {
+            aWriter.Write((byte)JSONNodeType.String);
+            aWriter.Write(m_Data);
+        }
+    }
+
+    public partial class JSONNumber : JSONNode
+    {
+        public override void SerializeBinary(System.IO.BinaryWriter aWriter)
+        {
+            aWriter.Write((byte)JSONNodeType.Number);
+            aWriter.Write(m_Data);
+        }
+    }
+
+    public partial class JSONBool : JSONNode
+    {
+        public override void SerializeBinary(System.IO.BinaryWriter aWriter)
+        {
+            aWriter.Write((byte)JSONNodeType.Boolean);
+            aWriter.Write(m_Data);
+        }
+    }
+    public partial class JSONNull : JSONNode
+    {
+        public override void SerializeBinary(System.IO.BinaryWriter aWriter)
+        {
+            aWriter.Write((byte)JSONNodeType.NullValue);
+        }
+    }
+    internal partial class JSONLazyCreator : JSONNode
+    {
+        public override void SerializeBinary(System.IO.BinaryWriter aWriter)
+        {
+
+        }
+    }
+#endif
+}

+ 11 - 0
GameClient/Assets/Plugins/luban_unity/Runtime/SimpleJSON/SimpleJSONBinary.cs.meta

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

+ 516 - 0
GameClient/Assets/Plugins/luban_unity/Runtime/SimpleJSON/SimpleJSONDotNetTypes.cs

@@ -0,0 +1,516 @@
+#region License and information
+/* * * * *
+ * 
+ * Extension file for the SimpleJSON framework for better support of some common
+ * .NET types. It does only work together with the SimpleJSON.cs
+ * It provides direct conversion support for types like decimal, char, byte,
+ * sbyte, short, ushort, uint, DateTime, TimeSpan and Guid. In addition there
+ * are conversion helpers for converting an array of number values into a byte[]
+ * or a List<byte> as well as converting an array of string values into a string[]
+ * or List<string>.
+ * Finally there are some additional type conversion operators for some nullable
+ * types like short?, int?, float?, double?, long? and bool?. They will actually
+ * assign a JSONNull value when it's null or a JSONNumber when it's not.
+ * 
+ * The MIT License (MIT)
+ * 
+ * Copyright (c) 2020 Markus Göbel (Bunny83)
+ * 
+ * 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.
+ * 
+ * * * * */
+
+#endregion License and information
+
+namespace SimpleJSON
+{
+    using System.Globalization;
+    using System.Collections.Generic;
+    public partial class JSONNode
+    {
+        #region Decimal
+        public virtual decimal AsDecimal
+        {
+            get
+            {
+                decimal result;
+                if (!decimal.TryParse(Value, out result))
+                    result = 0;
+                return result;
+            }
+            set
+            {
+                Value = value.ToString();
+            }
+        }
+
+        public static implicit operator JSONNode(decimal aDecimal)
+        {
+            return new JSONString(aDecimal.ToString());
+        }
+
+        public static implicit operator decimal(JSONNode aNode)
+        {
+            return aNode.AsDecimal;
+        }
+        #endregion Decimal
+
+        #region Char
+        public virtual char AsChar
+        {
+            get
+            {
+                if (IsString && Value.Length > 0)
+                    return Value[0];
+                if (IsNumber)
+                    return (char)AsInt;
+                return '\0';
+            }
+            set
+            {
+                if (IsString)
+                    Value = value.ToString();
+                else if (IsNumber)
+                    AsInt = (int)value;
+            }
+        }
+
+        public static implicit operator JSONNode(char aChar)
+        {
+            return new JSONString(aChar.ToString());
+        }
+
+        public static implicit operator char(JSONNode aNode)
+        {
+            return aNode.AsChar;
+        }
+        #endregion Decimal
+
+        #region UInt
+        public virtual uint AsUInt
+        {
+            get
+            {
+                return (uint)AsDouble;
+            }
+            set
+            {
+                AsDouble = value;
+            }
+        }
+
+        public static implicit operator JSONNode(uint aUInt)
+        {
+            return new JSONNumber(aUInt);
+        }
+
+        public static implicit operator uint(JSONNode aNode)
+        {
+            return aNode.AsUInt;
+        }
+        #endregion UInt
+
+        #region Byte
+        public virtual byte AsByte
+        {
+            get
+            {
+                return (byte)AsInt;
+            }
+            set
+            {
+                AsInt = value;
+            }
+        }
+
+        public static implicit operator JSONNode(byte aByte)
+        {
+            return new JSONNumber(aByte);
+        }
+
+        public static implicit operator byte(JSONNode aNode)
+        {
+            return aNode.AsByte;
+        }
+        #endregion Byte
+        #region SByte
+        public virtual sbyte AsSByte
+        {
+            get
+            {
+                return (sbyte)AsInt;
+            }
+            set
+            {
+                AsInt = value;
+            }
+        }
+
+        public static implicit operator JSONNode(sbyte aSByte)
+        {
+            return new JSONNumber(aSByte);
+        }
+
+        public static implicit operator sbyte(JSONNode aNode)
+        {
+            return aNode.AsSByte;
+        }
+        #endregion SByte
+
+        #region Short
+        public virtual short AsShort
+        {
+            get
+            {
+                return (short)AsInt;
+            }
+            set
+            {
+                AsInt = value;
+            }
+        }
+
+        public static implicit operator JSONNode(short aShort)
+        {
+            return new JSONNumber(aShort);
+        }
+
+        public static implicit operator short(JSONNode aNode)
+        {
+            return aNode.AsShort;
+        }
+        #endregion Short
+        #region UShort
+        public virtual ushort AsUShort
+        {
+            get
+            {
+                return (ushort)AsInt;
+            }
+            set
+            {
+                AsInt = value;
+            }
+        }
+
+        public static implicit operator JSONNode(ushort aUShort)
+        {
+            return new JSONNumber(aUShort);
+        }
+
+        public static implicit operator ushort(JSONNode aNode)
+        {
+            return aNode.AsUShort;
+        }
+        #endregion UShort
+
+        #region DateTime
+        public virtual System.DateTime AsDateTime
+        {
+            get
+            {
+                System.DateTime result;
+                if (!System.DateTime.TryParse(Value, CultureInfo.InvariantCulture, DateTimeStyles.None, out result))
+                    result = new System.DateTime(0);
+                return result;
+            }
+            set
+            {
+                Value = value.ToString(CultureInfo.InvariantCulture);
+            }
+        }
+
+        public static implicit operator JSONNode(System.DateTime aDateTime)
+        {
+            return new JSONString(aDateTime.ToString(CultureInfo.InvariantCulture));
+        }
+
+        public static implicit operator System.DateTime(JSONNode aNode)
+        {
+            return aNode.AsDateTime;
+        }
+        #endregion DateTime
+        #region TimeSpan
+        public virtual System.TimeSpan AsTimeSpan
+        {
+            get
+            {
+                System.TimeSpan result;
+                if (!System.TimeSpan.TryParse(Value, CultureInfo.InvariantCulture, out result))
+                    result = new System.TimeSpan(0);
+                return result;
+            }
+            set
+            {
+                Value = value.ToString();
+            }
+        }
+
+        public static implicit operator JSONNode(System.TimeSpan aTimeSpan)
+        {
+            return new JSONString(aTimeSpan.ToString());
+        }
+
+        public static implicit operator System.TimeSpan(JSONNode aNode)
+        {
+            return aNode.AsTimeSpan;
+        }
+        #endregion TimeSpan
+
+        #region Guid
+        public virtual System.Guid AsGuid
+        {
+            get
+            {
+                System.Guid result;
+                System.Guid.TryParse(Value, out result);
+                return result;
+            }
+            set
+            {
+                Value = value.ToString();
+            }
+        }
+
+        public static implicit operator JSONNode(System.Guid aGuid)
+        {
+            return new JSONString(aGuid.ToString());
+        }
+
+        public static implicit operator System.Guid(JSONNode aNode)
+        {
+            return aNode.AsGuid;
+        }
+        #endregion Guid
+
+        #region ByteArray
+        public virtual byte[] AsByteArray
+        {
+            get
+            {
+                if (this.IsNull || !this.IsArray)
+                    return null;
+                int count = Count;
+                byte[] result = new byte[count];
+                for (int i = 0; i < count; i++)
+                    result[i] = this[i].AsByte;
+                return result;
+            }
+            set
+            {
+                if (!IsArray || value == null)
+                    return;
+                Clear();
+                for (int i = 0; i < value.Length; i++)
+                    Add(value[i]);
+            }
+        }
+
+        public static implicit operator JSONNode(byte[] aByteArray)
+        {
+            return new JSONArray { AsByteArray = aByteArray };
+        }
+
+        public static implicit operator byte[](JSONNode aNode)
+        {
+            return aNode.AsByteArray;
+        }
+        #endregion ByteArray
+        #region ByteList
+        public virtual List<byte> AsByteList
+        {
+            get
+            {
+                if (this.IsNull || !this.IsArray)
+                    return null;
+                int count = Count;
+                List<byte> result = new List<byte>(count);
+                for (int i = 0; i < count; i++)
+                    result.Add(this[i].AsByte);
+                return result;
+            }
+            set
+            {
+                if (!IsArray || value == null)
+                    return;
+                Clear();
+                for (int i = 0; i < value.Count; i++)
+                    Add(value[i]);
+            }
+        }
+
+        public static implicit operator JSONNode(List<byte> aByteList)
+        {
+            return new JSONArray { AsByteList = aByteList };
+        }
+
+        public static implicit operator List<byte> (JSONNode aNode)
+        {
+            return aNode.AsByteList;
+        }
+        #endregion ByteList
+
+        #region StringArray
+        public virtual string[] AsStringArray
+        {
+            get
+            {
+                if (this.IsNull || !this.IsArray)
+                    return null;
+                int count = Count;
+                string[] result = new string[count];
+                for (int i = 0; i < count; i++)
+                    result[i] = this[i].Value;
+                return result;
+            }
+            set
+            {
+                if (!IsArray || value == null)
+                    return;
+                Clear();
+                for (int i = 0; i < value.Length; i++)
+                    Add(value[i]);
+            }
+        }
+
+        public static implicit operator JSONNode(string[] aStringArray)
+        {
+            return new JSONArray { AsStringArray = aStringArray };
+        }
+
+        public static implicit operator string[] (JSONNode aNode)
+        {
+            return aNode.AsStringArray;
+        }
+        #endregion StringArray
+        #region StringList
+        public virtual List<string> AsStringList
+        {
+            get
+            {
+                if (this.IsNull || !this.IsArray)
+                    return null;
+                int count = Count;
+                List<string> result = new List<string>(count);
+                for (int i = 0; i < count; i++)
+                    result.Add(this[i].Value);
+                return result;
+            }
+            set
+            {
+                if (!IsArray || value == null)
+                    return;
+                Clear();
+                for (int i = 0; i < value.Count; i++)
+                    Add(value[i]);
+            }
+        }
+
+        public static implicit operator JSONNode(List<string> aStringList)
+        {
+            return new JSONArray { AsStringList = aStringList };
+        }
+
+        public static implicit operator List<string> (JSONNode aNode)
+        {
+            return aNode.AsStringList;
+        }
+        #endregion StringList
+
+        #region NullableTypes
+        public static implicit operator JSONNode(int? aValue)
+        {
+            if (aValue == null)
+                return JSONNull.CreateOrGet();
+            return new JSONNumber((int)aValue);
+        }
+        public static implicit operator int?(JSONNode aNode)
+        {
+            if (aNode == null || aNode.IsNull)
+                return null;
+            return aNode.AsInt;
+        }
+
+        public static implicit operator JSONNode(float? aValue)
+        {
+            if (aValue == null)
+                return JSONNull.CreateOrGet();
+            return new JSONNumber((float)aValue);
+        }
+        public static implicit operator float? (JSONNode aNode)
+        {
+            if (aNode == null || aNode.IsNull)
+                return null;
+            return aNode.AsFloat;
+        }
+
+        public static implicit operator JSONNode(double? aValue)
+        {
+            if (aValue == null)
+                return JSONNull.CreateOrGet();
+            return new JSONNumber((double)aValue);
+        }
+        public static implicit operator double? (JSONNode aNode)
+        {
+            if (aNode == null || aNode.IsNull)
+                return null;
+            return aNode.AsDouble;
+        }
+
+        public static implicit operator JSONNode(bool? aValue)
+        {
+            if (aValue == null)
+                return JSONNull.CreateOrGet();
+            return new JSONBool((bool)aValue);
+        }
+        public static implicit operator bool? (JSONNode aNode)
+        {
+            if (aNode == null || aNode.IsNull)
+                return null;
+            return aNode.AsBool;
+        }
+
+        public static implicit operator JSONNode(long? aValue)
+        {
+            if (aValue == null)
+                return JSONNull.CreateOrGet();
+            return new JSONNumber((long)aValue);
+        }
+        public static implicit operator long? (JSONNode aNode)
+        {
+            if (aNode == null || aNode.IsNull)
+                return null;
+            return aNode.AsLong;
+        }
+
+        public static implicit operator JSONNode(short? aValue)
+        {
+            if (aValue == null)
+                return JSONNull.CreateOrGet();
+            return new JSONNumber((short)aValue);
+        }
+        public static implicit operator short? (JSONNode aNode)
+        {
+            if (aNode == null || aNode.IsNull)
+                return null;
+            return aNode.AsShort;
+        }
+        #endregion NullableTypes
+    }
+}

+ 11 - 0
GameClient/Assets/Plugins/luban_unity/Runtime/SimpleJSON/SimpleJSONDotNetTypes.cs.meta

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

+ 462 - 0
GameClient/Assets/Plugins/luban_unity/Runtime/SimpleJSON/SimpleJSONUnity.cs

@@ -0,0 +1,462 @@
+#if UNITY_5_3_OR_NEWER
+#region License and information
+/* * * * *
+ * 
+ * Unity extension for the SimpleJSON framework. It does only work together with
+ * the SimpleJSON.cs
+ * It provides several helpers and conversion operators to serialize/deserialize
+ * common Unity types such as Vector2/3/4, Rect, RectOffset, Quaternion and
+ * Matrix4x4 as JSONObject or JSONArray.
+ * This extension will add 3 static settings to the JSONNode class:
+ * ( VectorContainerType, QuaternionContainerType, RectContainerType ) which
+ * control what node type should be used for serializing the given type. So a
+ * Vector3 as array would look like [12,32,24] and {"x":12, "y":32, "z":24} as
+ * object.
+ * 
+ * 
+ * The MIT License (MIT)
+ * 
+ * Copyright (c) 2012-2017 Markus Göbel (Bunny83)
+ * 
+ * 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.
+ * 
+ * * * * */
+
+#endregion License and information
+using UnityEngine;
+
+namespace SimpleJSON
+{
+    public enum JSONContainerType { Array, Object }
+	public partial class JSONNode
+	{
+        public static byte Color32DefaultAlpha = 255;
+        public static float ColorDefaultAlpha = 1f;
+        public static JSONContainerType VectorContainerType = JSONContainerType.Array;
+        public static JSONContainerType QuaternionContainerType = JSONContainerType.Array;
+        public static JSONContainerType RectContainerType = JSONContainerType.Array;
+        public static JSONContainerType ColorContainerType = JSONContainerType.Array;
+        private static JSONNode GetContainer(JSONContainerType aType)
+        {
+            if (aType == JSONContainerType.Array)
+                return new JSONArray();
+            return new JSONObject();
+        }
+
+        #region implicit conversion operators
+        public static implicit operator JSONNode(Vector2 aVec)
+		{
+            JSONNode n = GetContainer(VectorContainerType);
+            n.WriteVector2(aVec);
+			return n;
+		}
+		public static implicit operator JSONNode(Vector3 aVec)
+		{
+            JSONNode n = GetContainer(VectorContainerType);
+            n.WriteVector3(aVec);
+            return n;
+        }
+        public static implicit operator JSONNode(Vector4 aVec)
+		{
+            JSONNode n = GetContainer(VectorContainerType);
+            n.WriteVector4(aVec);
+            return n;
+        }
+        public static implicit operator JSONNode(Color aCol)
+        {
+            JSONNode n = GetContainer(ColorContainerType);
+            n.WriteColor(aCol);
+            return n;
+        }
+        public static implicit operator JSONNode(Color32 aCol)
+        {
+            JSONNode n = GetContainer(ColorContainerType);
+            n.WriteColor32(aCol);
+            return n;
+        }
+        public static implicit operator JSONNode(Quaternion aRot)
+		{
+            JSONNode n = GetContainer(QuaternionContainerType);
+            n.WriteQuaternion(aRot);
+            return n;
+        }
+        public static implicit operator JSONNode(Rect aRect)
+		{
+            JSONNode n = GetContainer(RectContainerType);
+            n.WriteRect(aRect);
+            return n;
+        }
+        public static implicit operator JSONNode(RectOffset aRect)
+		{
+            JSONNode n = GetContainer(RectContainerType);
+            n.WriteRectOffset(aRect);
+            return n;
+        }
+
+        public static implicit operator Vector2(JSONNode aNode)
+        {
+            return aNode.ReadVector2();
+        }
+        public static implicit operator Vector3(JSONNode aNode)
+        {
+            return aNode.ReadVector3();
+        }
+        public static implicit operator Vector4(JSONNode aNode)
+        {
+            return aNode.ReadVector4();
+        }
+        public static implicit operator Color(JSONNode aNode)
+        {
+            return aNode.ReadColor();
+        }
+        public static implicit operator Color32(JSONNode aNode)
+        {
+            return aNode.ReadColor32();
+        }
+        public static implicit operator Quaternion(JSONNode aNode)
+        {
+            return aNode.ReadQuaternion();
+        }
+        public static implicit operator Rect(JSONNode aNode)
+        {
+            return aNode.ReadRect();
+        }
+        public static implicit operator RectOffset(JSONNode aNode)
+        {
+            return aNode.ReadRectOffset();
+        }
+        #endregion implicit conversion operators
+
+        #region Vector2
+        public Vector2 ReadVector2(Vector2 aDefault)
+        {
+            if (IsObject)
+                return new Vector2(this["x"].AsFloat, this["y"].AsFloat);
+            if (IsArray)
+                return new Vector2(this[0].AsFloat, this[1].AsFloat);
+            return aDefault;
+        }
+        public Vector2 ReadVector2(string aXName, string aYName)
+        {
+            if (IsObject)
+            {
+                return new Vector2(this[aXName].AsFloat, this[aYName].AsFloat);
+            }
+            return Vector2.zero;
+        }
+
+        public Vector2 ReadVector2()
+        {
+            return ReadVector2(Vector2.zero);
+        }
+        public JSONNode WriteVector2(Vector2 aVec, string aXName = "x", string aYName = "y")
+        {
+            if (IsObject)
+            {
+                Inline = true;
+                this[aXName].AsFloat = aVec.x;
+                this[aYName].AsFloat = aVec.y;
+            }
+            else if (IsArray)
+            {
+                Inline = true;
+                this[0].AsFloat = aVec.x;
+                this[1].AsFloat = aVec.y;
+            }
+            return this;
+        }
+        #endregion Vector2
+
+        #region Vector3
+        public Vector3 ReadVector3(Vector3 aDefault)
+        {
+            if (IsObject)
+                return new Vector3(this["x"].AsFloat, this["y"].AsFloat, this["z"].AsFloat);
+            if (IsArray)
+                return new Vector3(this[0].AsFloat, this[1].AsFloat, this[2].AsFloat);
+            return aDefault;
+        }
+        public Vector3 ReadVector3(string aXName, string aYName, string aZName)
+        {
+            if (IsObject)
+                return new Vector3(this[aXName].AsFloat, this[aYName].AsFloat, this[aZName].AsFloat);
+            return Vector3.zero;
+        }
+        public Vector3 ReadVector3()
+        {
+            return ReadVector3(Vector3.zero);
+        }
+        public JSONNode WriteVector3(Vector3 aVec, string aXName = "x", string aYName = "y", string aZName = "z")
+        {
+            if (IsObject)
+            {
+                Inline = true;
+                this[aXName].AsFloat = aVec.x;
+                this[aYName].AsFloat = aVec.y;
+                this[aZName].AsFloat = aVec.z;
+            }
+            else if (IsArray)
+            {
+                Inline = true;
+                this[0].AsFloat = aVec.x;
+                this[1].AsFloat = aVec.y;
+                this[2].AsFloat = aVec.z;
+            }
+            return this;
+        }
+        #endregion Vector3
+
+        #region Vector4
+        public Vector4 ReadVector4(Vector4 aDefault)
+        {
+            if (IsObject)
+                return new Vector4(this["x"].AsFloat, this["y"].AsFloat, this["z"].AsFloat, this["w"].AsFloat);
+            if (IsArray)
+                return new Vector4(this[0].AsFloat, this[1].AsFloat, this[2].AsFloat, this[3].AsFloat);
+            return aDefault;
+        }
+        public Vector4 ReadVector4()
+        {
+            return ReadVector4(Vector4.zero);
+        }
+        public JSONNode WriteVector4(Vector4 aVec)
+        {
+            if (IsObject)
+            {
+                Inline = true;
+                this["x"].AsFloat = aVec.x;
+                this["y"].AsFloat = aVec.y;
+                this["z"].AsFloat = aVec.z;
+                this["w"].AsFloat = aVec.w;
+            }
+            else if (IsArray)
+            {
+                Inline = true;
+                this[0].AsFloat = aVec.x;
+                this[1].AsFloat = aVec.y;
+                this[2].AsFloat = aVec.z;
+                this[3].AsFloat = aVec.w;
+            }
+            return this;
+        }
+        #endregion Vector4
+
+        #region Color / Color32
+        public Color ReadColor(Color aDefault)
+        {
+            if (IsObject)
+                return new Color(this["r"].AsFloat, this["g"].AsFloat, this["b"].AsFloat, HasKey("a")?this["a"].AsFloat:ColorDefaultAlpha);
+            if (IsArray)
+                return new Color(this[0].AsFloat, this[1].AsFloat, this[2].AsFloat, (Count>3)?this[3].AsFloat:ColorDefaultAlpha);
+            return aDefault;
+        }
+        public Color ReadColor()
+        {
+            return ReadColor(Color.clear);
+        }
+        public JSONNode WriteColor(Color aCol)
+        {
+            if (IsObject)
+            {
+                Inline = true;
+                this["r"].AsFloat = aCol.r;
+                this["g"].AsFloat = aCol.g;
+                this["b"].AsFloat = aCol.b;
+                this["a"].AsFloat = aCol.a;
+            }
+            else if (IsArray)
+            {
+                Inline = true;
+                this[0].AsFloat = aCol.r;
+                this[1].AsFloat = aCol.g;
+                this[2].AsFloat = aCol.b;
+                this[3].AsFloat = aCol.a;
+            }
+            return this;
+        }
+
+        public Color32 ReadColor32(Color32 aDefault)
+        {
+            if (IsObject)
+                return new Color32((byte)this["r"].AsInt, (byte)this["g"].AsInt, (byte)this["b"].AsInt, (byte)(HasKey("a")?this["a"].AsInt:Color32DefaultAlpha));
+            if (IsArray)
+                return new Color32((byte)this[0].AsInt, (byte)this[1].AsInt, (byte)this[2].AsInt, (byte)((Count>3)?this[3].AsInt:Color32DefaultAlpha));
+            return aDefault;
+        }
+        public Color32 ReadColor32()
+        {
+            return ReadColor32(new Color32());
+        }
+        public JSONNode WriteColor32(Color32 aCol)
+        {
+            if (IsObject)
+            {
+                Inline = true;
+                this["r"].AsInt = aCol.r;
+                this["g"].AsInt = aCol.g;
+                this["b"].AsInt = aCol.b;
+                this["a"].AsInt = aCol.a;
+            }
+            else if (IsArray)
+            {
+                Inline = true;
+                this[0].AsInt = aCol.r;
+                this[1].AsInt = aCol.g;
+                this[2].AsInt = aCol.b;
+                this[3].AsInt = aCol.a;
+            }
+            return this;
+        }
+
+        #endregion Color / Color32
+
+        #region Quaternion
+        public Quaternion ReadQuaternion(Quaternion aDefault)
+        {
+            if (IsObject)
+                return new Quaternion(this["x"].AsFloat, this["y"].AsFloat, this["z"].AsFloat, this["w"].AsFloat);
+            if (IsArray)
+                return new Quaternion(this[0].AsFloat, this[1].AsFloat, this[2].AsFloat, this[3].AsFloat);
+            return aDefault;
+        }
+        public Quaternion ReadQuaternion()
+        {
+            return ReadQuaternion(Quaternion.identity);
+        }
+        public JSONNode WriteQuaternion(Quaternion aRot)
+        {
+            if (IsObject)
+            {
+                Inline = true;
+                this["x"].AsFloat = aRot.x;
+                this["y"].AsFloat = aRot.y;
+                this["z"].AsFloat = aRot.z;
+                this["w"].AsFloat = aRot.w;
+            }
+            else if (IsArray)
+            {
+                Inline = true;
+                this[0].AsFloat = aRot.x;
+                this[1].AsFloat = aRot.y;
+                this[2].AsFloat = aRot.z;
+                this[3].AsFloat = aRot.w;
+            }
+            return this;
+        }
+        #endregion Quaternion
+
+        #region Rect
+        public Rect ReadRect(Rect aDefault)
+        {
+            if (IsObject)
+                return new Rect(this["x"].AsFloat, this["y"].AsFloat, this["width"].AsFloat, this["height"].AsFloat);
+            if (IsArray)
+                return new Rect(this[0].AsFloat, this[1].AsFloat, this[2].AsFloat, this[3].AsFloat);
+            return aDefault;
+        }
+        public Rect ReadRect()
+        {
+            return ReadRect(new Rect());
+        }
+        public JSONNode WriteRect(Rect aRect)
+        {
+            if (IsObject)
+            {
+                Inline = true;
+                this["x"].AsFloat = aRect.x;
+                this["y"].AsFloat = aRect.y;
+                this["width"].AsFloat = aRect.width;
+                this["height"].AsFloat = aRect.height;
+            }
+            else if (IsArray)
+            {
+                Inline = true;
+                this[0].AsFloat = aRect.x;
+                this[1].AsFloat = aRect.y;
+                this[2].AsFloat = aRect.width;
+                this[3].AsFloat = aRect.height;
+            }
+            return this;
+        }
+        #endregion Rect
+
+        #region RectOffset
+        public RectOffset ReadRectOffset(RectOffset aDefault)
+        {
+            if (this is JSONObject)
+                return new RectOffset(this["left"].AsInt, this["right"].AsInt, this["top"].AsInt, this["bottom"].AsInt);
+            if (this is JSONArray)
+                return new RectOffset(this[0].AsInt, this[1].AsInt, this[2].AsInt, this[3].AsInt);
+            return aDefault;
+        }
+        public RectOffset ReadRectOffset()
+        {
+            return ReadRectOffset(new RectOffset());
+        }
+        public JSONNode WriteRectOffset(RectOffset aRect)
+        {
+            if (IsObject)
+            {
+                Inline = true;
+                this["left"].AsInt = aRect.left;
+                this["right"].AsInt = aRect.right;
+                this["top"].AsInt = aRect.top;
+                this["bottom"].AsInt = aRect.bottom;
+            }
+            else if (IsArray)
+            {
+                Inline = true;
+                this[0].AsInt = aRect.left;
+                this[1].AsInt = aRect.right;
+                this[2].AsInt = aRect.top;
+                this[3].AsInt = aRect.bottom;
+            }
+            return this;
+        }
+        #endregion RectOffset
+
+        #region Matrix4x4
+        public Matrix4x4 ReadMatrix()
+        {
+            Matrix4x4 result = Matrix4x4.identity;
+            if (IsArray)
+            {
+                for (int i = 0; i < 16; i++)
+                {
+                    result[i] = this[i].AsFloat;
+                }
+            }
+            return result;
+        }
+        public JSONNode WriteMatrix(Matrix4x4 aMatrix)
+        {
+            if (IsArray)
+            {
+                Inline = true;
+                for (int i = 0; i < 16; i++)
+                {
+                    this[i].AsFloat = aMatrix[i];
+                }
+            }
+            return this;
+        }
+        #endregion Matrix4x4
+    }
+}
+#endif

+ 11 - 0
GameClient/Assets/Plugins/luban_unity/Runtime/SimpleJSON/SimpleJSONUnity.cs.meta

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

+ 53 - 0
GameClient/Assets/Plugins/luban_unity/Runtime/StringUtil.cs

@@ -0,0 +1,53 @@
+using System.Collections.Generic;
+using System.Text;
+
+namespace Luban
+{
+    public static class StringUtil
+    {
+        public static string ToStr(object o)
+        {
+            return ToStr(o, new StringBuilder());
+        }
+
+        public static string ToStr(object o, StringBuilder sb)
+        {
+            foreach (var p in o.GetType().GetFields())
+            {
+
+                sb.Append($"{p.Name} = {p.GetValue(o)},");
+            }
+
+            foreach (var p in o.GetType().GetProperties())
+            {
+                sb.Append($"{p.Name} = {p.GetValue(o)},");
+            }
+            return sb.ToString();
+        }
+
+        public static string ArrayToString<T>(T[] arr)
+        {
+            return "[" + string.Join(",", arr) + "]";
+        }
+
+
+        public static string CollectionToString<T>(IEnumerable<T> arr)
+        {
+            return "[" + string.Join(",", arr) + "]";
+        }
+
+
+        public static string CollectionToString<TK, TV>(IDictionary<TK, TV> dic)
+        {
+            var sb = new StringBuilder();
+            sb.Append('{');
+            foreach (var e in dic)
+            {
+                sb.Append(e.Key).Append(':');
+                sb.Append(e.Value).Append(',');
+            }
+            sb.Append('}');
+            return sb.ToString();
+        }
+    }
+}

+ 11 - 0
GameClient/Assets/Plugins/luban_unity/Runtime/StringUtil.cs.meta

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

+ 8 - 0
GameClient/Assets/Plugins/luban_unity/docs.meta

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

+ 1 - 0
GameClient/Assets/Plugins/luban_unity/docs/_config.yml

@@ -0,0 +1 @@
+theme: jekyll-theme-slate

+ 7 - 0
GameClient/Assets/Plugins/luban_unity/docs/_config.yml.meta

@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: b1e71d5853b6a0f4ea338a9604f4d5be
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 8 - 0
GameClient/Assets/Plugins/luban_unity/docs/images.meta

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

BIN
GameClient/Assets/Plugins/luban_unity/docs/images/logo.png


+ 121 - 0
GameClient/Assets/Plugins/luban_unity/docs/images/logo.png.meta

@@ -0,0 +1,121 @@
+fileFormatVersion: 2
+guid: 2adf4f0248a87f14d9a286c4368a502f
+TextureImporter:
+  internalIDToNameTable: []
+  externalObjects: {}
+  serializedVersion: 12
+  mipmaps:
+    mipMapMode: 0
+    enableMipMap: 1
+    sRGBTexture: 1
+    linearTexture: 0
+    fadeOut: 0
+    borderMipMap: 0
+    mipMapsPreserveCoverage: 0
+    alphaTestReferenceValue: 0.5
+    mipMapFadeDistanceStart: 1
+    mipMapFadeDistanceEnd: 3
+  bumpmap:
+    convertToNormalMap: 0
+    externalNormalMap: 0
+    heightScale: 0.25
+    normalMapFilter: 0
+  isReadable: 0
+  streamingMipmaps: 0
+  streamingMipmapsPriority: 0
+  vTOnly: 0
+  grayScaleToAlpha: 0
+  generateCubemap: 6
+  cubemapConvolution: 0
+  seamlessCubemap: 0
+  textureFormat: 1
+  maxTextureSize: 2048
+  textureSettings:
+    serializedVersion: 2
+    filterMode: 1
+    aniso: 1
+    mipBias: 0
+    wrapU: 0
+    wrapV: 0
+    wrapW: 0
+  nPOTScale: 1
+  lightmap: 0
+  compressionQuality: 50
+  spriteMode: 0
+  spriteExtrude: 1
+  spriteMeshType: 1
+  alignment: 0
+  spritePivot: {x: 0.5, y: 0.5}
+  spritePixelsToUnits: 100
+  spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+  spriteGenerateFallbackPhysicsShape: 1
+  alphaUsage: 1
+  alphaIsTransparency: 0
+  spriteTessellationDetail: -1
+  textureType: 0
+  textureShape: 1
+  singleChannelComponent: 0
+  flipbookRows: 1
+  flipbookColumns: 1
+  maxTextureSizeSet: 0
+  compressionQualitySet: 0
+  textureFormatSet: 0
+  ignorePngGamma: 0
+  applyGammaDecoding: 0
+  cookieLightType: 0
+  platformSettings:
+  - serializedVersion: 3
+    buildTarget: DefaultTexturePlatform
+    maxTextureSize: 2048
+    resizeAlgorithm: 0
+    textureFormat: -1
+    textureCompression: 1
+    compressionQuality: 50
+    crunchedCompression: 0
+    allowsAlphaSplitting: 0
+    overridden: 0
+    androidETC2FallbackOverride: 0
+    forceMaximumCompressionQuality_BC6H_BC7: 0
+  - serializedVersion: 3
+    buildTarget: Standalone
+    maxTextureSize: 2048
+    resizeAlgorithm: 0
+    textureFormat: -1
+    textureCompression: 1
+    compressionQuality: 50
+    crunchedCompression: 0
+    allowsAlphaSplitting: 0
+    overridden: 0
+    androidETC2FallbackOverride: 0
+    forceMaximumCompressionQuality_BC6H_BC7: 0
+  - serializedVersion: 3
+    buildTarget: Android
+    maxTextureSize: 2048
+    resizeAlgorithm: 0
+    textureFormat: -1
+    textureCompression: 1
+    compressionQuality: 50
+    crunchedCompression: 0
+    allowsAlphaSplitting: 0
+    overridden: 0
+    androidETC2FallbackOverride: 0
+    forceMaximumCompressionQuality_BC6H_BC7: 0
+  spriteSheet:
+    serializedVersion: 2
+    sprites: []
+    outline: []
+    physicsShape: []
+    bones: []
+    spriteID: 
+    internalID: 0
+    vertices: []
+    indices: 
+    edges: []
+    weights: []
+    secondaryTextures: []
+  spritePackingTag: 
+  pSDRemoveMatte: 0
+  pSDShowRemoveMatteOption: 0
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 19 - 0
GameClient/Assets/Plugins/luban_unity/package.json

@@ -0,0 +1,19 @@
+{
+  "name": "com.code-philosophy.luban",
+  "version": "1.1.1",
+  "displayName": "Luban",
+  "description": "luban is a powerful, easy-to-use, elegant and stable game configuration solution.",
+  "category": "Runtime",
+  "documentationUrl": "https://luban.doc.code-philosophy.com/docs/intro",
+  "licensesUrl": "https://github.com/focus-creative-games/luban_unity/blob/main/LICENSE",
+  "keywords": [
+    "luban",
+    "focus-creative-games",
+    "code-philosophy"
+  ],
+  "author": {
+    "name": "Code Philosophy",
+    "email": "luban@code-philosophy.com",
+    "url": "https://code-philosophy.com"
+  }
+}

+ 7 - 0
GameClient/Assets/Plugins/luban_unity/package.json.meta

@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: ff12bd64e92ccc647b703701cc341095
+TextScriptImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 3 - 0
GameClient/GameClient.sln.DotSettings.user

@@ -1,10 +1,13 @@
 <wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
+	<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AApplication_002Ecs_002Fl_003AC_0021_003FUsers_003Fadmin_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F683a2b31bf9142429c44f02c75dbc6c913ce00_003Ffe_003F0927df71_003FApplication_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
 	<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ABuildResult_002Ecs_002Fl_003AC_0021_003FUsers_003Fadmin_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F8d4895b259be41298a685a0c9b42357576b400_003Fa9_003Fbef924de_003FBuildResult_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
 	<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AEditorUtility_002Ecs_002Fl_003AC_0021_003FUsers_003Fss510_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F8d4895b259be41298a685a0c9b42357576b400_003F3f_003Fa805acc1_003FEditorUtility_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
 	<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AMemberInfo_002Ecs_002Fl_003AC_0021_003FUsers_003Fss510_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F9c2967a135e648bdb993c5397a44991b573620_003F69_003F4bdfd6bb_003FMemberInfo_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
 	<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AMethodInfo_002Ecs_002Fl_003AC_0021_003FUsers_003Fss510_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fb18a8b3398e74bca86895881dd02956c573648_003F94_003Fb7912d02_003FMethodInfo_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
 	<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AMonoBehaviour_002Ecs_002Fl_003AC_0021_003FUsers_003Fss510_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F683a2b31bf9142429c44f02c75dbc6c913ce00_003F2e_003F343a2d95_003FMonoBehaviour_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
+	<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AObject_002Ecs_002Fl_003AC_0021_003FUsers_003Fadmin_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F683a2b31bf9142429c44f02c75dbc6c913ce00_003F91_003F9360fc50_003FObject_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
 	<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AOptionAttribute_002Ecs_002Fl_003AC_0021_003FUsers_003Fss510_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F16134578226e4e409ecbdd10473cf8f235000_003F4e_003Fb8b5740c_003FOptionAttribute_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
 	<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AResources_002Ecs_002Fl_003AC_0021_003FUsers_003Fadmin_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F683a2b31bf9142429c44f02c75dbc6c913ce00_003Fe5_003F66fcfb7a_003FResources_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
+	<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ASceneManager_002Ecs_002Fl_003AC_0021_003FUsers_003Fadmin_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F683a2b31bf9142429c44f02c75dbc6c913ce00_003F21_003Fadcf2169_003FSceneManager_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
 	<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AScriptableObject_002Ecs_002Fl_003AC_0021_003FUsers_003Fss510_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F683a2b31bf9142429c44f02c75dbc6c913ce00_003F1f_003F8a732769_003FScriptableObject_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
 	</wpf:ResourceDictionary>