Repository: AlianBlank/GameFrameX Branch: main Commit: a6edd582a08e Files: 140 Total size: 272.1 KB Directory structure: gitextract_k8aqoslt/ ├── .github/ │ ├── ISSUE_TEMPLATE/ │ │ ├── bug_report.md │ │ └── feature_request.md │ └── workflows/ │ ├── contributors-readme-action.yml │ └── sync.yml ├── .gitignore ├── Config/ │ ├── Defines/ │ │ └── builtin.xml │ ├── Excels/ │ │ ├── Local/ │ │ │ ├── L-Localization-UI.xlsx │ │ │ ├── L-Localization-成就.xlsx │ │ │ └── L-Localization-文本.xlsx │ │ ├── Tables/ │ │ │ ├── C-AchievementConfig-成就表.xlsx │ │ │ ├── D-ItemConfig-道具表-道具-1001.xlsx │ │ │ └── S-SoundsConfig-声音表.xlsx │ │ ├── __beans__.xlsx │ │ ├── __enums__.xlsx │ │ └── __tables__.xlsx │ ├── Tools/ │ │ ├── Luban.CSharp.pdb │ │ ├── Luban.Core.pdb │ │ ├── Luban.DataLoader.Builtin.pdb │ │ ├── Luban.DataTarget.Builtin.pdb │ │ ├── Luban.DataValidator.Builtin.pdb │ │ ├── Luban.L10N.pdb │ │ ├── Luban.Schema.Builtin.pdb │ │ ├── Luban.deps.json │ │ ├── Luban.pdb │ │ ├── Luban.runtimeconfig.json │ │ ├── Templates/ │ │ │ ├── common/ │ │ │ │ ├── cs/ │ │ │ │ │ └── enum.sbn │ │ │ │ └── ts/ │ │ │ │ └── enum.sbn │ │ │ ├── cs-bin/ │ │ │ │ ├── bean.sbn │ │ │ │ ├── table.sbn │ │ │ │ └── tables.sbn │ │ │ ├── cs-code/ │ │ │ │ ├── bean.sbn │ │ │ │ ├── table.sbn │ │ │ │ ├── tabledata.sbn │ │ │ │ └── tables.sbn │ │ │ ├── cs-dotnet-bin/ │ │ │ │ ├── bean.sbn │ │ │ │ ├── table.sbn │ │ │ │ └── tables.sbn │ │ │ ├── cs-dotnet-json/ │ │ │ │ ├── bean.sbn │ │ │ │ ├── table.sbn │ │ │ │ └── tables.sbn │ │ │ └── cs-simple-json/ │ │ │ ├── bean.sbn │ │ │ ├── table.sbn │ │ │ └── tables.sbn │ │ └── nlog.xml │ ├── gen-client-bin.bat │ ├── gen-client-bin.sh │ ├── gen-client-json.bat │ ├── gen-client-json.sh │ ├── gen-server-bin.bat │ ├── gen-server-bin.sh │ ├── gen-server-json.bat │ ├── gen-server-json.sh │ └── luban.conf ├── Docs/ │ ├── 1.Actor模型.md │ ├── 2.Actor&Component&State.md │ ├── Actor入队.md │ ├── 事件Event-timer.md │ ├── 关于协议.md │ ├── 十分钟.md │ ├── 定时器&计划任务Timer.md │ ├── 最后补充.md │ ├── 热更hotfix.md │ └── 网络Net(tcp&http).md ├── FairyGUIProject/ │ ├── Game.fairy │ ├── assets/ │ │ ├── UIBag/ │ │ │ ├── UIBag.xml │ │ │ ├── UIBagContent.xml │ │ │ ├── UIBagItemInfo.xml │ │ │ ├── package.xml │ │ │ └── 组件/ │ │ │ ├── UIBagItem.xml │ │ │ └── UIBagTypeItem.xml │ │ ├── UICommon/ │ │ │ ├── package.xml │ │ │ ├── 字体/ │ │ │ │ ├── RedNumberFont.fnt │ │ │ │ └── YellowNumberFont.fnt │ │ │ └── 组件/ │ │ │ ├── Dialog/ │ │ │ │ ├── UIDialogMessageBox.xml │ │ │ │ └── UIDialogWithoutButton.xml │ │ │ ├── Goods/ │ │ │ │ └── UIGoodItem.xml │ │ │ ├── UIYellowProgresssBar.xml │ │ │ └── button/ │ │ │ ├── UIBackButton.xml │ │ │ ├── UIBlueCheckButton.xml │ │ │ ├── UIBlueNormalButton.xml │ │ │ ├── UIBlueSingleButton.xml │ │ │ ├── UICloseButton.xml │ │ │ ├── UIWhiteCheckButton.xml │ │ │ ├── UIWhiteNormalButton.xml │ │ │ ├── UIWhiteSingleButton.xml │ │ │ ├── UIYellowCheckButton.xml │ │ │ ├── UIYellowNormalButton.xml │ │ │ ├── UIYellowSingleButton.xml │ │ │ └── switch_btn.xml │ │ ├── UICommonAvatar/ │ │ │ └── package.xml │ │ ├── UILauncher/ │ │ │ ├── Scene/ │ │ │ │ ├── UILauncher.xml │ │ │ │ ├── UILauncherUpgrade.xml │ │ │ │ └── UILauncherUpgradeContent.xml │ │ │ ├── Widget/ │ │ │ │ ├── UILauncherEnterButton.xml │ │ │ │ └── UILoadingMainProgressBar.xml │ │ │ └── package.xml │ │ ├── UILoading/ │ │ │ ├── Scene/ │ │ │ │ └── UILoadingScene.xml │ │ │ ├── Widget/ │ │ │ │ └── UILoadingCenterBox.xml │ │ │ └── package.xml │ │ ├── UILogin/ │ │ │ ├── Scene/ │ │ │ │ ├── UIAnnouncement.xml │ │ │ │ ├── UIAnnouncementContent.xml │ │ │ │ ├── UILogin.xml │ │ │ │ ├── UIPlayerCreate.xml │ │ │ │ ├── UIPlayerList.xml │ │ │ │ ├── UIPlayerListItem.xml │ │ │ │ └── UIPlayerListItemLoginButton.xml │ │ │ ├── Widget/ │ │ │ │ └── UILoginButton.xml │ │ │ └── package.xml │ │ ├── UIMain/ │ │ │ ├── BagButton.xml │ │ │ ├── UIMain.xml │ │ │ └── package.xml │ │ └── UIPlayer/ │ │ └── package.xml │ ├── plugins/ │ │ ├── gencode/ │ │ │ ├── GenCode_CSharp.lua │ │ │ ├── main.lua │ │ │ └── package.json │ │ └── plugins.iml │ └── settings/ │ ├── Adaptation.json │ ├── Common.json │ ├── CustomProperties.json │ ├── PackageGroup.json │ ├── Publish.json │ └── i18n.json ├── LICENSE.md ├── Protobuf/ │ ├── Bag_100.proto │ ├── Basic_10.proto │ ├── Common_20.proto │ ├── Inner_Basic_2.proto │ ├── Proto2CsExport-All.bat │ ├── Proto2CsExport_Client.bat │ ├── Proto2CsExport_Client.sh │ ├── Proto2CsExport_Server.bat │ ├── Proto2CsExport_Server.sh │ ├── User_300.proto │ ├── _-120_InnerSocial_s.proto │ ├── _120_Social.proto │ └── readme.txt ├── README.md └── docker/ ├── mongo/ │ └── docker-compose.yml └── redis/ ├── docker-compose.yml └── redis.conf ================================================ FILE CONTENTS ================================================ ================================================ FILE: .github/ISSUE_TEMPLATE/bug_report.md ================================================ --- name: Bug report about: Create a report to help us improve title: '' labels: '' assignees: '' --- **Describe the bug** A clear and concise description of what the bug is. **To Reproduce** Steps to reproduce the behavior: 1. Go to '...' 2. Click on '....' 3. Scroll down to '....' 4. See error **Expected behavior** A clear and concise description of what you expected to happen. **Screenshots** If applicable, add screenshots to help explain your problem. **Desktop (please complete the following information):** - OS: [e.g. iOS] - Browser [e.g. chrome, safari] - Version [e.g. 22] **Smartphone (please complete the following information):** - Device: [e.g. iPhone6] - OS: [e.g. iOS8.1] - Browser [e.g. stock browser, safari] - Version [e.g. 22] **Additional context** Add any other context about the problem here. ================================================ FILE: .github/ISSUE_TEMPLATE/feature_request.md ================================================ --- name: Feature request about: Suggest an idea for this project title: '' labels: '' assignees: '' --- **Is your feature request related to a problem? Please describe.** A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] **Describe the solution you'd like** A clear and concise description of what you want to happen. **Describe alternatives you've considered** A clear and concise description of any alternative solutions or features you've considered. **Additional context** Add any other context or screenshots about the feature request here. ================================================ FILE: .github/workflows/contributors-readme-action.yml ================================================ # This is a basic workflow to help you get started with Actions # https://github.com/akhilmhdh/contributors-readme-action name: contributors # Controls when the workflow will run on: # Triggers the workflow on push or pull request events but only for the "main" branch push: branches: [ "main" ] pull_request: branches: [ "main" ] jobs: contrib-readme-job: runs-on: ubuntu-latest name: A job to automate contrib in readme permissions: contents: write pull-requests: write steps: - name: Contribute List uses: akhilmhdh/contributors-readme-action@v2.3.10 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} ================================================ FILE: .github/workflows/sync.yml ================================================ name: Sync Github To Image on: push: branches: [main] #schedule: # 定时任务,每天 UTC 时间 0 点运行 #- cron: "0 0 * * *" #workflow_dispatch: jobs: sync-gitlink: runs-on: ubuntu-latest steps: - name: Checkout code uses: actions/checkout@v4 with: fetch-depth: 0 # 为了 git pull --unshallow,我们需要获取所有的提交历史 - name: Set up Git user run: | git config --global user.email "wangfj11@foxmail.com" git config --global user.name "AlianBlank" - name: Set SSH run: | mkdir -p ~/.ssh echo "${{ secrets.GITLINK_ID_RSA }}" >> ~/.ssh/id_rsa chmod 600 ~/.ssh/id_rsa eval $(ssh-agent -s) && ssh-add ~/.ssh/id_rsa # 信任域名 ssh-keyscan -H code.gitlink.org.cn >> ~/.ssh/known_hosts # 查看当前分支 - name: Check current branch run: echo 当前分支:${{ github.ref_name }} ${{ github.Repository }} # 查看远端 地址 - name: echo git url run: echo git@code.gitlink.org.cn:${{ github.Repository }}.git # 添加远端 - name: add remote url run: git remote add gitlink "git@code.gitlink.org.cn:${{ github.Repository }}.git" # 获取 - name: fetch run: git fetch --prune gitlink --tags --verbose # 拉取 - name: pull and push run: | if [ "${{ github.ref_name }}" ]; then git checkout ${{ github.ref_name }} git pull --progress -v --no-rebase gitlink ${{ github.ref_name }} --tags --verbose || echo 远端不存在${{ github.ref_name }}分支; git push -u gitlink ${{ github.ref_name }} --tags --verbose fi sync-gitlab: runs-on: ubuntu-latest steps: - name: Checkout code uses: actions/checkout@v4 with: fetch-depth: 0 # 为了 git pull --unshallow,我们需要获取所有的提交历史 - name: Set up Git user run: | git config --global user.email "wangfj11@foxmail.com" git config --global user.name "AlianBlank" - name: Set SSH run: | mkdir -p ~/.ssh echo "${{ secrets.GITLAB_ID_RSA }}" >> ~/.ssh/id_rsa chmod 600 ~/.ssh/id_rsa eval $(ssh-agent -s) && ssh-add ~/.ssh/id_rsa # 信任域名 ssh-keyscan -H gitlab.com >> ~/.ssh/known_hosts # 查看当前分支 - name: Check current branch run: echo 当前分支:${{ github.ref_name }} ${{ github.Repository }} # 查看远端 地址 - name: echo git url run: echo git@gitlab.com:${{ github.Repository }}.git # 添加远端 - name: add remote url run: git remote add gitlab "git@gitlab.com:${{ github.Repository }}.git" # 获取 - name: fetch run: git fetch --prune gitlab --tags --verbose # 拉取 - name: pull and push run: | if [ "${{ github.ref_name }}" ]; then git checkout ${{ github.ref_name }} git pull --progress -v --no-rebase gitlab ${{ github.ref_name }} --tags --verbose || echo 远端不存在${{ github.ref_name }}分支; git push -u gitlab ${{ github.ref_name }} --tags --verbose fi sync-gitee: runs-on: ubuntu-latest steps: - name: Checkout code uses: actions/checkout@v4 with: fetch-depth: 0 # 为了 git pull --unshallow,我们需要获取所有的提交历史 - name: Set up Git user run: | git config --global user.email "wangfj11@foxmail.com" git config --global user.name "AlianBlank" - name: Set SSH run: | mkdir -p ~/.ssh echo "${{ secrets.GITEE_ID_RSA }}" >> ~/.ssh/id_rsa chmod 600 ~/.ssh/id_rsa eval $(ssh-agent -s) && ssh-add ~/.ssh/id_rsa # 信任域名 ssh-keyscan -H gitee.com >> ~/.ssh/known_hosts # 查看当前分支 - name: Check current branch run: echo 当前分支:${{ github.ref_name }} ${{ github.Repository }} # 查看远端 地址 - name: echo git url run: echo git@gitee.com:${{ github.Repository }}.git # 添加远端 - name: add remote url run: git remote add gitee "git@gitee.com:${{ github.Repository }}.git" # 获取 - name: fetch run: git fetch --prune gitee --tags --verbose # 拉取 - name: pull and push run: | if [ "${{ github.ref_name }}" ]; then git checkout ${{ github.ref_name }} git pull --progress -v --no-rebase gitee ${{ github.ref_name }} --tags --verbose || echo 远端不存在${{ github.ref_name }}分支; git push -u gitee ${{ github.ref_name }} --tags --verbose fi sync-atomgit: runs-on: ubuntu-latest steps: - name: Checkout code uses: actions/checkout@v4 with: fetch-depth: 0 # 为了 git pull --unshallow,我们需要获取所有的提交历史 - name: Set up Git user run: | git config --global user.email "wangfj11@foxmail.com" git config --global user.name "AlianBlank" - name: Set SSH run: | mkdir -p ~/.ssh echo "${{ secrets.ATOMGIT_ID_RSA }}" >> ~/.ssh/id_rsa chmod 600 ~/.ssh/id_rsa eval $(ssh-agent -s) && ssh-add ~/.ssh/id_rsa # 信任域名 ssh-keyscan -H atomgit.com >> ~/.ssh/known_hosts # 查看当前分支 - name: Check current branch run: echo 当前分支:${{ github.ref_name }} ${{ github.Repository }} # 查看远端 地址 - name: echo git url run: echo git@atomgit.com:${{ github.Repository }}.git # 添加远端 - name: add remote url run: git remote add atomgit "git@atomgit.com:${{ github.Repository }}.git" # 获取 - name: fetch run: git fetch --prune atomgit --tags --verbose # 拉取 - name: pull and push run: | if [ "${{ github.ref_name }}" ]; then git checkout ${{ github.ref_name }} git pull --progress -v --no-rebase atomgit ${{ github.ref_name }} --tags --verbose || echo 远端不存在${{ github.ref_name }}分支; git push -u atomgit ${{ github.ref_name }} --tags --verbose fi sync-gitcode: runs-on: ubuntu-latest steps: - name: Checkout code uses: actions/checkout@v4 with: fetch-depth: 0 # 为了 git pull --unshallow,我们需要获取所有的提交历史 - name: Set up Git user run: | git config --global user.email "wangfj11@foxmail.com" git config --global user.name "AlianBlank" - name: Set SSH run: | mkdir -p ~/.ssh echo "${{ secrets.GITCODE_ID_RSA }}" >> ~/.ssh/id_rsa chmod 600 ~/.ssh/id_rsa eval $(ssh-agent -s) && ssh-add ~/.ssh/id_rsa # 信任域名 ssh-keyscan -H gitcode.net >> ~/.ssh/known_hosts # 查看当前分支 - name: Check current branch run: echo 当前分支:${{ github.ref_name }} ${{ github.Repository }} # 查看远端 地址 - name: echo git url run: echo git@gitcode.net:${{ github.Repository }}.git # 添加远端 - name: add remote url run: git remote add gitcode "git@gitcode.net:${{ github.Repository }}.git" # 获取 - name: fetch run: git fetch --prune gitcode --tags --verbose # 拉取 - name: pull and push run: | if [ "${{ github.ref_name }}" ]; then git checkout ${{ github.ref_name }} git pull --progress -v --no-rebase gitcode ${{ github.ref_name }} --tags --verbose || echo 远端不存在${{ github.ref_name }}分支; git push -u gitcode ${{ github.ref_name }} --tags --verbose fi sync-framagit: runs-on: ubuntu-latest steps: - name: Checkout code uses: actions/checkout@v4 with: fetch-depth: 0 # 为了 git pull --unshallow,我们需要获取所有的提交历史 - name: Set up Git user run: | git config --global user.email "wangfj11@foxmail.com" git config --global user.name "AlianBlank" - name: Set SSH run: | mkdir -p ~/.ssh echo "${{ secrets.FRAMAGIT_ID_RSA }}" >> ~/.ssh/id_rsa chmod 600 ~/.ssh/id_rsa eval $(ssh-agent -s) && ssh-add ~/.ssh/id_rsa # 信任域名 ssh-keyscan -H framagit.org >> ~/.ssh/known_hosts # 查看当前分支 - name: Check current branch run: echo 当前分支:${{ github.ref_name }} ${{ github.Repository }} # 查看远端 地址 - name: echo git url run: echo git@framagit.org:${{ github.Repository }}.git # 添加远端 - name: add remote url run: git remote add framagit "git@framagit.org:${{ github.Repository }}.git" # 获取 - name: fetch run: git fetch --prune framagit --tags --verbose # 拉取 - name: pull and push run: | if [ "${{ github.ref_name }}" ]; then git checkout ${{ github.ref_name }} git pull --progress -v --no-rebase framagit ${{ github.ref_name }} --tags --verbose || echo 远端不存在${{ github.ref_name }}分支; git push -u framagit ${{ github.ref_name }} --tags --verbose fi ================================================ FILE: .gitignore ================================================ Unity/.idea Unity/Bundles Unity/Library Unity/obj GeekConfig/.idea GeekConfig/Test Server/.idea Server/database Server/bin Server/**/obj Unity/*.csproj FairyGUIProject/.objs FairyGUIProject/plugins/.idea Unity/Sandbox Unity/Temp Unity/Assets/Bundles/Code Unity/HybridCLRData/HotUpdateDlls Unity/HybridCLRData/LocalIl2CppData-WindowsEditor Unity/HybridCLRData/hybridclr_repo Unity/HybridCLRData/il2cpp_plus_repo Tools/Geek.MsgPackTool-src/.idea Server/**/bin Unity/.cache.meta docker/mongo/database Unity/Packages/packages-lock.json Unity/Unity.sln.DotSettings.user Unity/Unity.sln docker/redis/apps/datadir .DS_Store Unity/HybridCLRData Unity/Builds Unity/Logs Unity/Android_Symbols Proto2CSApp/.idea Proto2CSApp/obj Proto2CSApp/bin ================================================ FILE: Config/Defines/builtin.xml ================================================ ================================================ FILE: Config/Tools/Luban.deps.json ================================================ { "runtimeTarget": { "name": ".NETCoreApp,Version=v8.0", "signature": "" }, "compilationOptions": {}, "targets": { ".NETCoreApp,Version=v8.0": { "Luban/3.12.0": { "dependencies": { "CommandLineParser": "2.9.1", "Luban.Bson": "1.0.0", "Luban.CSharp": "1.0.0", "Luban.Core": "1.0.0", "Luban.Cpp": "1.0.0", "Luban.DataLoader.Builtin": "1.0.0", "Luban.DataTarget.Builtin": "1.0.0", "Luban.DataValidator.Builtin": "1.0.0", "Luban.FlatBuffers": "1.0.0", "Luban.Gdscript": "1.0.0", "Luban.Golang": "1.0.0", "Luban.Java": "1.0.0", "Luban.L10N": "1.0.0", "Luban.Lua": "1.0.0", "Luban.MsgPack": "1.0.0", "Luban.PHP": "1.0.0", "Luban.Protobuf": "1.0.0", "Luban.Python": "1.0.0", "Luban.Rust": "1.0.0", "Luban.Schema.Builtin": "1.0.0", "Luban.Typescript": "1.0.0", "YamlDotNet.NetCore": "1.0.0" }, "runtime": { "Luban.dll": {} } }, "CommandLineParser/2.9.1": { "runtime": { "lib/netstandard2.0/CommandLine.dll": { "assemblyVersion": "2.9.1.0", "fileVersion": "2.9.1.0" } } }, "ExcelDataReader/3.7.0": { "runtime": { "lib/netstandard2.1/ExcelDataReader.dll": { "assemblyVersion": "3.7.0.0", "fileVersion": "3.7.0.0" } } }, "Google.Protobuf/3.29.0": { "runtime": { "lib/net5.0/Google.Protobuf.dll": { "assemblyVersion": "3.29.0.0", "fileVersion": "3.29.0.0" } } }, "MessagePack/2.5.192": { "dependencies": { "MessagePack.Annotations": "2.5.192", "Microsoft.NET.StringTools": "17.6.3" }, "runtime": { "lib/net6.0/MessagePack.dll": { "assemblyVersion": "2.5.0.0", "fileVersion": "2.5.192.54228" } } }, "MessagePack.Annotations/2.5.192": { "runtime": { "lib/netstandard2.0/MessagePack.Annotations.dll": { "assemblyVersion": "2.5.0.0", "fileVersion": "2.5.192.54228" } } }, "Microsoft.CSharp/4.5.0": {}, "Microsoft.NET.StringTools/17.6.3": { "runtime": { "lib/net7.0/Microsoft.NET.StringTools.dll": { "assemblyVersion": "1.0.0.0", "fileVersion": "17.6.3.22601" } } }, "Microsoft.NETCore.Platforms/1.0.1": {}, "Microsoft.NETCore.Targets/1.0.1": {}, "NeoLua/1.3.14": { "dependencies": { "Microsoft.CSharp": "4.5.0" }, "runtime": { "lib/net5.0/Neo.Lua.dll": { "assemblyVersion": "5.3.0.0", "fileVersion": "1.3.14.0" } }, "resources": { "lib/net5.0/de/Neo.Lua.resources.dll": { "locale": "de" } } }, "Newtonsoft.Json/13.0.1": { "runtime": { "lib/netstandard2.0/Newtonsoft.Json.dll": { "assemblyVersion": "13.0.0.0", "fileVersion": "13.0.1.25517" } } }, "Newtonsoft.Json.Bson/1.0.3": { "dependencies": { "Newtonsoft.Json": "13.0.1" }, "runtime": { "lib/netstandard2.0/Newtonsoft.Json.Bson.dll": { "assemblyVersion": "1.0.0.0", "fileVersion": "1.0.3.29904" } } }, "NLog/5.3.4": { "runtime": { "lib/netstandard2.0/NLog.dll": { "assemblyVersion": "5.0.0.0", "fileVersion": "5.3.4.2778" } } }, "Scriban/5.12.0": { "runtime": { "lib/net7.0/Scriban.dll": { "assemblyVersion": "5.0.0.0", "fileVersion": "5.12.0.0" } } }, "System.Collections/4.0.11": { "dependencies": { "Microsoft.NETCore.Platforms": "1.0.1", "Microsoft.NETCore.Targets": "1.0.1", "System.Runtime": "4.1.0" } }, "System.Diagnostics.Debug/4.0.11": { "dependencies": { "Microsoft.NETCore.Platforms": "1.0.1", "Microsoft.NETCore.Targets": "1.0.1", "System.Runtime": "4.1.0" } }, "System.Diagnostics.Tools/4.0.1": { "dependencies": { "Microsoft.NETCore.Platforms": "1.0.1", "Microsoft.NETCore.Targets": "1.0.1", "System.Runtime": "4.1.0" } }, "System.Globalization/4.0.11": { "dependencies": { "Microsoft.NETCore.Platforms": "1.0.1", "Microsoft.NETCore.Targets": "1.0.1", "System.Runtime": "4.1.0" } }, "System.IO/4.1.0": { "dependencies": { "Microsoft.NETCore.Platforms": "1.0.1", "Microsoft.NETCore.Targets": "1.0.1", "System.Runtime": "4.1.0", "System.Text.Encoding": "4.0.11", "System.Threading.Tasks": "4.0.11" } }, "System.Linq/4.1.0": { "dependencies": { "System.Collections": "4.0.11", "System.Diagnostics.Debug": "4.0.11", "System.Resources.ResourceManager": "4.0.1", "System.Runtime": "4.1.0", "System.Runtime.Extensions": "4.1.0" } }, "System.Linq.Expressions/4.1.0": { "dependencies": { "System.Collections": "4.0.11", "System.Diagnostics.Debug": "4.0.11", "System.Globalization": "4.0.11", "System.IO": "4.1.0", "System.Linq": "4.1.0", "System.ObjectModel": "4.0.12", "System.Reflection": "4.1.0", "System.Reflection.Emit": "4.0.1", "System.Reflection.Emit.ILGeneration": "4.0.1", "System.Reflection.Emit.Lightweight": "4.0.1", "System.Reflection.Extensions": "4.0.1", "System.Reflection.Primitives": "4.0.1", "System.Reflection.TypeExtensions": "4.1.0", "System.Resources.ResourceManager": "4.0.1", "System.Runtime": "4.1.0", "System.Runtime.Extensions": "4.1.0", "System.Threading": "4.0.11" } }, "System.ObjectModel/4.0.12": { "dependencies": { "System.Collections": "4.0.11", "System.Diagnostics.Debug": "4.0.11", "System.Resources.ResourceManager": "4.0.1", "System.Runtime": "4.1.0", "System.Threading": "4.0.11" } }, "System.Reflection/4.1.0": { "dependencies": { "Microsoft.NETCore.Platforms": "1.0.1", "Microsoft.NETCore.Targets": "1.0.1", "System.IO": "4.1.0", "System.Reflection.Primitives": "4.0.1", "System.Runtime": "4.1.0" } }, "System.Reflection.Emit/4.0.1": { "dependencies": { "System.IO": "4.1.0", "System.Reflection": "4.1.0", "System.Reflection.Emit.ILGeneration": "4.0.1", "System.Reflection.Primitives": "4.0.1", "System.Runtime": "4.1.0" } }, "System.Reflection.Emit.ILGeneration/4.0.1": { "dependencies": { "System.Reflection": "4.1.0", "System.Reflection.Primitives": "4.0.1", "System.Runtime": "4.1.0" } }, "System.Reflection.Emit.Lightweight/4.0.1": { "dependencies": { "System.Reflection": "4.1.0", "System.Reflection.Emit.ILGeneration": "4.0.1", "System.Reflection.Primitives": "4.0.1", "System.Runtime": "4.1.0" } }, "System.Reflection.Extensions/4.0.1": { "dependencies": { "Microsoft.NETCore.Platforms": "1.0.1", "Microsoft.NETCore.Targets": "1.0.1", "System.Reflection": "4.1.0", "System.Runtime": "4.1.0" } }, "System.Reflection.Primitives/4.0.1": { "dependencies": { "Microsoft.NETCore.Platforms": "1.0.1", "Microsoft.NETCore.Targets": "1.0.1", "System.Runtime": "4.1.0" } }, "System.Reflection.TypeExtensions/4.1.0": { "dependencies": { "System.Reflection": "4.1.0", "System.Runtime": "4.1.0" } }, "System.Resources.ResourceManager/4.0.1": { "dependencies": { "Microsoft.NETCore.Platforms": "1.0.1", "Microsoft.NETCore.Targets": "1.0.1", "System.Globalization": "4.0.11", "System.Reflection": "4.1.0", "System.Runtime": "4.1.0" } }, "System.Runtime/4.1.0": { "dependencies": { "Microsoft.NETCore.Platforms": "1.0.1", "Microsoft.NETCore.Targets": "1.0.1" } }, "System.Runtime.Extensions/4.1.0": { "dependencies": { "Microsoft.NETCore.Platforms": "1.0.1", "Microsoft.NETCore.Targets": "1.0.1", "System.Runtime": "4.1.0" } }, "System.Runtime.Serialization.Primitives/4.1.1": { "dependencies": { "System.Resources.ResourceManager": "4.0.1", "System.Runtime": "4.1.0" } }, "System.Text.Encoding/4.0.11": { "dependencies": { "Microsoft.NETCore.Platforms": "1.0.1", "Microsoft.NETCore.Targets": "1.0.1", "System.Runtime": "4.1.0" } }, "System.Text.Encoding.Extensions/4.0.11": { "dependencies": { "Microsoft.NETCore.Platforms": "1.0.1", "Microsoft.NETCore.Targets": "1.0.1", "System.Runtime": "4.1.0", "System.Text.Encoding": "4.0.11" } }, "System.Text.RegularExpressions/4.1.0": { "dependencies": { "System.Collections": "4.0.11", "System.Globalization": "4.0.11", "System.Resources.ResourceManager": "4.0.1", "System.Runtime": "4.1.0", "System.Runtime.Extensions": "4.1.0", "System.Threading": "4.0.11" } }, "System.Threading/4.0.11": { "dependencies": { "System.Runtime": "4.1.0", "System.Threading.Tasks": "4.0.11" } }, "System.Threading.Tasks/4.0.11": { "dependencies": { "Microsoft.NETCore.Platforms": "1.0.1", "Microsoft.NETCore.Targets": "1.0.1", "System.Runtime": "4.1.0" } }, "Ude.NetStandard/1.2.0": { "runtime": { "lib/netstandard2.0/Ude.NetStandard.dll": { "assemblyVersion": "1.0.2.0", "fileVersion": "1.0.2.0" } } }, "YamlDotNet.NetCore/1.0.0": { "dependencies": { "System.Collections": "4.0.11", "System.Diagnostics.Debug": "4.0.11", "System.Diagnostics.Tools": "4.0.1", "System.Globalization": "4.0.11", "System.Linq": "4.1.0", "System.Linq.Expressions": "4.1.0", "System.ObjectModel": "4.0.12", "System.Reflection.Extensions": "4.0.1", "System.Runtime.Extensions": "4.1.0", "System.Runtime.Serialization.Primitives": "4.1.1", "System.Text.Encoding.Extensions": "4.0.11", "System.Text.RegularExpressions": "4.1.0" }, "runtime": { "lib/netstandard1.0/YamlDotNet.NetCore.dll": { "assemblyVersion": "0.0.1.0", "fileVersion": "0.0.0.0" } } }, "Luban.Bson/1.0.0": { "dependencies": { "Luban.Core": "1.0.0", "Newtonsoft.Json.Bson": "1.0.3" }, "runtime": { "Luban.Bson.dll": { "assemblyVersion": "1.0.0.0", "fileVersion": "1.0.0.0" } } }, "Luban.Core/1.0.0": { "dependencies": { "NLog": "5.3.4", "Scriban": "5.12.0" }, "runtime": { "Luban.Core.dll": { "assemblyVersion": "1.0.0.0", "fileVersion": "1.0.0.0" } } }, "Luban.Cpp/1.0.0": { "dependencies": { "Luban.Core": "1.0.0" }, "runtime": { "Luban.Cpp.dll": { "assemblyVersion": "1.0.0.0", "fileVersion": "1.0.0.0" } } }, "Luban.CSharp/1.0.0": { "dependencies": { "Luban.Core": "1.0.0", "Luban.DataValidator.Builtin": "1.0.0" }, "runtime": { "Luban.CSharp.dll": { "assemblyVersion": "1.0.0.0", "fileVersion": "1.0.0.0" } } }, "Luban.DataLoader.Builtin/1.0.0": { "dependencies": { "ExcelDataReader": "3.7.0", "Luban.Core": "1.0.0", "NeoLua": "1.3.14", "Ude.NetStandard": "1.2.0", "YamlDotNet.NetCore": "1.0.0" }, "runtime": { "Luban.DataLoader.Builtin.dll": { "assemblyVersion": "1.0.0.0", "fileVersion": "1.0.0.0" } } }, "Luban.DataTarget.Builtin/1.0.0": { "dependencies": { "Luban.Core": "1.0.0", "Luban.DataLoader.Builtin": "1.0.0" }, "runtime": { "Luban.DataTarget.Builtin.dll": { "assemblyVersion": "1.0.0.0", "fileVersion": "1.0.0.0" } } }, "Luban.DataValidator.Builtin/1.0.0": { "dependencies": { "Luban.Core": "1.0.0" }, "runtime": { "Luban.DataValidator.Builtin.dll": { "assemblyVersion": "1.0.0.0", "fileVersion": "1.0.0.0" } } }, "Luban.FlatBuffers/1.0.0": { "dependencies": { "Luban.Core": "1.0.0", "Luban.DataTarget.Builtin": "1.0.0" }, "runtime": { "Luban.FlatBuffers.dll": { "assemblyVersion": "1.0.0.0", "fileVersion": "1.0.0.0" } } }, "Luban.Gdscript/1.0.0": { "dependencies": { "Luban.Core": "1.0.0", "Luban.DataTarget.Builtin": "1.0.0" }, "runtime": { "Luban.Gdscript.dll": { "assemblyVersion": "1.0.0.0", "fileVersion": "1.0.0.0" } } }, "Luban.Golang/1.0.0": { "dependencies": { "Luban.Core": "1.0.0" }, "runtime": { "Luban.Golang.dll": { "assemblyVersion": "1.0.0.0", "fileVersion": "1.0.0.0" } } }, "Luban.Java/1.0.0": { "dependencies": { "Luban.Core": "1.0.0" }, "runtime": { "Luban.Java.dll": { "assemblyVersion": "1.0.0.0", "fileVersion": "1.0.0.0" } } }, "Luban.L10N/1.0.0": { "dependencies": { "Luban.Core": "1.0.0", "Luban.DataLoader.Builtin": "1.0.0" }, "runtime": { "Luban.L10N.dll": { "assemblyVersion": "1.0.0.0", "fileVersion": "1.0.0.0" } } }, "Luban.Lua/1.0.0": { "dependencies": { "Luban.Core": "1.0.0" }, "runtime": { "Luban.Lua.dll": { "assemblyVersion": "1.0.0.0", "fileVersion": "1.0.0.0" } } }, "Luban.MsgPack/1.0.0": { "dependencies": { "Luban.Core": "1.0.0", "MessagePack": "2.5.192" }, "runtime": { "Luban.MsgPack.dll": { "assemblyVersion": "1.0.0.0", "fileVersion": "1.0.0.0" } } }, "Luban.PHP/1.0.0": { "dependencies": { "Luban.Core": "1.0.0", "Luban.DataTarget.Builtin": "1.0.0" }, "runtime": { "Luban.PHP.dll": { "assemblyVersion": "1.0.0.0", "fileVersion": "1.0.0.0" } } }, "Luban.Protobuf/1.0.0": { "dependencies": { "Google.Protobuf": "3.29.0", "Luban.Core": "1.0.0", "Luban.DataTarget.Builtin": "1.0.0" }, "runtime": { "Luban.Protobuf.dll": { "assemblyVersion": "1.0.0.0", "fileVersion": "1.0.0.0" } } }, "Luban.Python/1.0.0": { "dependencies": { "Luban.Core": "1.0.0", "Luban.DataTarget.Builtin": "1.0.0" }, "runtime": { "Luban.Python.dll": { "assemblyVersion": "1.0.0.0", "fileVersion": "1.0.0.0" } } }, "Luban.Rust/1.0.0": { "dependencies": { "Luban.Core": "1.0.0" }, "runtime": { "Luban.Rust.dll": { "assemblyVersion": "1.0.0.0", "fileVersion": "1.0.0.0" } } }, "Luban.Schema.Builtin/1.0.0": { "dependencies": { "Luban.Core": "1.0.0", "Luban.DataLoader.Builtin": "1.0.0" }, "runtime": { "Luban.Schema.Builtin.dll": { "assemblyVersion": "1.0.0.0", "fileVersion": "1.0.0.0" } } }, "Luban.Typescript/1.0.0": { "dependencies": { "Luban.CSharp": "1.0.0", "Luban.Core": "1.0.0", "Luban.DataTarget.Builtin": "1.0.0" }, "runtime": { "Luban.Typescript.dll": { "assemblyVersion": "1.0.0.0", "fileVersion": "1.0.0.0" } } } } }, "libraries": { "Luban/3.12.0": { "type": "project", "serviceable": false, "sha512": "" }, "CommandLineParser/2.9.1": { "type": "package", "serviceable": true, "sha512": "sha512-OE0sl1/sQ37bjVsPKKtwQlWDgqaxWgtme3xZz7JssWUzg5JpMIyHgCTY9MVMxOg48fJ1AgGT3tgdH5m/kQ5xhA==", "path": "commandlineparser/2.9.1", "hashPath": "commandlineparser.2.9.1.nupkg.sha512" }, "ExcelDataReader/3.7.0": { "type": "package", "serviceable": true, "sha512": "sha512-AMv3oDETRHSRyXC17rBtKH45qIfFyo433LMeaMB3u4RNr/c9Luuc0Z+JMP6+3Cx9n4wXqFqcrEIVxrf/GgYnZg==", "path": "exceldatareader/3.7.0", "hashPath": "exceldatareader.3.7.0.nupkg.sha512" }, "Google.Protobuf/3.29.0": { "type": "package", "serviceable": true, "sha512": "sha512-l1012jd1Y2XsLQ+h9cXE7Bo3WruXql3Xc3KP/z+yZDJMSkfb2guslHCxwFsqd2ScHB0h2J7Yuy255RrBD/DGBw==", "path": "google.protobuf/3.29.0", "hashPath": "google.protobuf.3.29.0.nupkg.sha512" }, "MessagePack/2.5.192": { "type": "package", "serviceable": true, "sha512": "sha512-Jtle5MaFeIFkdXtxQeL9Tu2Y3HsAQGoSntOzrn6Br/jrl6c8QmG22GEioT5HBtZJR0zw0s46OnKU8ei2M3QifA==", "path": "messagepack/2.5.192", "hashPath": "messagepack.2.5.192.nupkg.sha512" }, "MessagePack.Annotations/2.5.192": { "type": "package", "serviceable": true, "sha512": "sha512-jaJuwcgovWIZ8Zysdyf3b7b34/BrADw4v82GaEZymUhDd3ScMPrYd/cttekeDteJJPXseJxp04yTIcxiVUjTWg==", "path": "messagepack.annotations/2.5.192", "hashPath": "messagepack.annotations.2.5.192.nupkg.sha512" }, "Microsoft.CSharp/4.5.0": { "type": "package", "serviceable": true, "sha512": "sha512-kaj6Wb4qoMuH3HySFJhxwQfe8R/sJsNJnANrvv8WdFPMoNbKY5htfNscv+LHCu5ipz+49m2e+WQXpLXr9XYemQ==", "path": "microsoft.csharp/4.5.0", "hashPath": "microsoft.csharp.4.5.0.nupkg.sha512" }, "Microsoft.NET.StringTools/17.6.3": { "type": "package", "serviceable": true, "sha512": "sha512-N0ZIanl1QCgvUumEL1laasU0a7sOE5ZwLZVTn0pAePnfhq8P7SvTjF8Axq+CnavuQkmdQpGNXQ1efZtu5kDFbA==", "path": "microsoft.net.stringtools/17.6.3", "hashPath": "microsoft.net.stringtools.17.6.3.nupkg.sha512" }, "Microsoft.NETCore.Platforms/1.0.1": { "type": "package", "serviceable": true, "sha512": "sha512-2G6OjjJzwBfNOO8myRV/nFrbTw5iA+DEm0N+qUqhrOmaVtn4pC77h38I1jsXGw5VH55+dPfQsqHD0We9sCl9FQ==", "path": "microsoft.netcore.platforms/1.0.1", "hashPath": "microsoft.netcore.platforms.1.0.1.nupkg.sha512" }, "Microsoft.NETCore.Targets/1.0.1": { "type": "package", "serviceable": true, "sha512": "sha512-rkn+fKobF/cbWfnnfBOQHKVKIOpxMZBvlSHkqDWgBpwGDcLRduvs3D9OLGeV6GWGvVwNlVi2CBbTjuPmtHvyNw==", "path": "microsoft.netcore.targets/1.0.1", "hashPath": "microsoft.netcore.targets.1.0.1.nupkg.sha512" }, "NeoLua/1.3.14": { "type": "package", "serviceable": true, "sha512": "sha512-BXIUN+ePY2wx3ZGiSmR8KZKD85s01pXI690orrB3u/biB8R0nalziGw+iGbPBq1Cuz8Upggpw2ERF84POXWTCQ==", "path": "neolua/1.3.14", "hashPath": "neolua.1.3.14.nupkg.sha512" }, "Newtonsoft.Json/13.0.1": { "type": "package", "serviceable": true, "sha512": "sha512-ppPFpBcvxdsfUonNcvITKqLl3bqxWbDCZIzDWHzjpdAHRFfZe0Dw9HmA0+za13IdyrgJwpkDTDA9fHaxOrt20A==", "path": "newtonsoft.json/13.0.1", "hashPath": "newtonsoft.json.13.0.1.nupkg.sha512" }, "Newtonsoft.Json.Bson/1.0.3": { "type": "package", "serviceable": true, "sha512": "sha512-bCcwagnHfYnhwQfY1criEcn6Hy9PtBuVnZu0pA8hmRhuR3jI/8WxVgoVAdNw9BJ3JHkxmWJzpj/AQy+PMMLqxg==", "path": "newtonsoft.json.bson/1.0.3", "hashPath": "newtonsoft.json.bson.1.0.3.nupkg.sha512" }, "NLog/5.3.4": { "type": "package", "serviceable": true, "sha512": "sha512-gLy7+O1hEYJXIlcTr1/VWjGXrZTQFZzYNO18IWasD64pNwz0BreV+nHLxWKXWZzERRzoKnsk2XYtwLkTVk7J1A==", "path": "nlog/5.3.4", "hashPath": "nlog.5.3.4.nupkg.sha512" }, "Scriban/5.12.0": { "type": "package", "serviceable": true, "sha512": "sha512-/YTTCxjBIpfwX3MKMT4JMFVl1jX4IHW7zih+Bg3cTIkzGnbFt+B3l/k90ILDw6DRiFE7T+VxEyls7zk4p029ng==", "path": "scriban/5.12.0", "hashPath": "scriban.5.12.0.nupkg.sha512" }, "System.Collections/4.0.11": { "type": "package", "serviceable": true, "sha512": "sha512-YUJGz6eFKqS0V//mLt25vFGrrCvOnsXjlvFQs+KimpwNxug9x0Pzy4PlFMU3Q2IzqAa9G2L4LsK3+9vCBK7oTg==", "path": "system.collections/4.0.11", "hashPath": "system.collections.4.0.11.nupkg.sha512" }, "System.Diagnostics.Debug/4.0.11": { "type": "package", "serviceable": true, "sha512": "sha512-w5U95fVKHY4G8ASs/K5iK3J5LY+/dLFd4vKejsnI/ZhBsWS9hQakfx3Zr7lRWKg4tAw9r4iktyvsTagWkqYCiw==", "path": "system.diagnostics.debug/4.0.11", "hashPath": "system.diagnostics.debug.4.0.11.nupkg.sha512" }, "System.Diagnostics.Tools/4.0.1": { "type": "package", "serviceable": true, "sha512": "sha512-xBfJ8pnd4C17dWaC9FM6aShzbJcRNMChUMD42I6772KGGrqaFdumwhn9OdM68erj1ueNo3xdQ1EwiFjK5k8p0g==", "path": "system.diagnostics.tools/4.0.1", "hashPath": "system.diagnostics.tools.4.0.1.nupkg.sha512" }, "System.Globalization/4.0.11": { "type": "package", "serviceable": true, "sha512": "sha512-B95h0YLEL2oSnwF/XjqSWKnwKOy/01VWkNlsCeMTFJLLabflpGV26nK164eRs5GiaRSBGpOxQ3pKoSnnyZN5pg==", "path": "system.globalization/4.0.11", "hashPath": "system.globalization.4.0.11.nupkg.sha512" }, "System.IO/4.1.0": { "type": "package", "serviceable": true, "sha512": "sha512-3KlTJceQc3gnGIaHZ7UBZO26SHL1SHE4ddrmiwumFnId+CEHP+O8r386tZKaE6zlk5/mF8vifMBzHj9SaXN+mQ==", "path": "system.io/4.1.0", "hashPath": "system.io.4.1.0.nupkg.sha512" }, "System.Linq/4.1.0": { "type": "package", "serviceable": true, "sha512": "sha512-bQ0iYFOQI0nuTnt+NQADns6ucV4DUvMdwN6CbkB1yj8i7arTGiTN5eok1kQwdnnNWSDZfIUySQY+J3d5KjWn0g==", "path": "system.linq/4.1.0", "hashPath": "system.linq.4.1.0.nupkg.sha512" }, "System.Linq.Expressions/4.1.0": { "type": "package", "serviceable": true, "sha512": "sha512-I+y02iqkgmCAyfbqOmSDOgqdZQ5tTj80Akm5BPSS8EeB0VGWdy6X1KCoYe8Pk6pwDoAKZUOdLVxnTJcExiv5zw==", "path": "system.linq.expressions/4.1.0", "hashPath": "system.linq.expressions.4.1.0.nupkg.sha512" }, "System.ObjectModel/4.0.12": { "type": "package", "serviceable": true, "sha512": "sha512-tAgJM1xt3ytyMoW4qn4wIqgJYm7L7TShRZG4+Q4Qsi2PCcj96pXN7nRywS9KkB3p/xDUjc2HSwP9SROyPYDYKQ==", "path": "system.objectmodel/4.0.12", "hashPath": "system.objectmodel.4.0.12.nupkg.sha512" }, "System.Reflection/4.1.0": { "type": "package", "serviceable": true, "sha512": "sha512-JCKANJ0TI7kzoQzuwB/OoJANy1Lg338B6+JVacPl4TpUwi3cReg3nMLplMq2uqYfHFQpKIlHAUVAJlImZz/4ng==", "path": "system.reflection/4.1.0", "hashPath": "system.reflection.4.1.0.nupkg.sha512" }, "System.Reflection.Emit/4.0.1": { "type": "package", "serviceable": true, "sha512": "sha512-P2wqAj72fFjpP6wb9nSfDqNBMab+2ovzSDzUZK7MVIm54tBJEPr9jWfSjjoTpPwj1LeKcmX3vr0ttyjSSFM47g==", "path": "system.reflection.emit/4.0.1", "hashPath": "system.reflection.emit.4.0.1.nupkg.sha512" }, "System.Reflection.Emit.ILGeneration/4.0.1": { "type": "package", "serviceable": true, "sha512": "sha512-Ov6dU8Bu15Bc7zuqttgHF12J5lwSWyTf1S+FJouUXVMSqImLZzYaQ+vRr1rQ0OZ0HqsrwWl4dsKHELckQkVpgA==", "path": "system.reflection.emit.ilgeneration/4.0.1", "hashPath": "system.reflection.emit.ilgeneration.4.0.1.nupkg.sha512" }, "System.Reflection.Emit.Lightweight/4.0.1": { "type": "package", "serviceable": true, "sha512": "sha512-sSzHHXueZ5Uh0OLpUQprhr+ZYJrLPA2Cmr4gn0wj9+FftNKXx8RIMKvO9qnjk2ebPYUjZ+F2ulGdPOsvj+MEjA==", "path": "system.reflection.emit.lightweight/4.0.1", "hashPath": "system.reflection.emit.lightweight.4.0.1.nupkg.sha512" }, "System.Reflection.Extensions/4.0.1": { "type": "package", "serviceable": true, "sha512": "sha512-GYrtRsZcMuHF3sbmRHfMYpvxZoIN2bQGrYGerUiWLEkqdEUQZhH3TRSaC/oI4wO0II1RKBPlpIa1TOMxIcOOzQ==", "path": "system.reflection.extensions/4.0.1", "hashPath": "system.reflection.extensions.4.0.1.nupkg.sha512" }, "System.Reflection.Primitives/4.0.1": { "type": "package", "serviceable": true, "sha512": "sha512-4inTox4wTBaDhB7V3mPvp9XlCbeGYWVEM9/fXALd52vNEAVisc1BoVWQPuUuD0Ga//dNbA/WeMy9u9mzLxGTHQ==", "path": "system.reflection.primitives/4.0.1", "hashPath": "system.reflection.primitives.4.0.1.nupkg.sha512" }, "System.Reflection.TypeExtensions/4.1.0": { "type": "package", "serviceable": true, "sha512": "sha512-tsQ/ptQ3H5FYfON8lL4MxRk/8kFyE0A+tGPXmVP967cT/gzLHYxIejIYSxp4JmIeFHVP78g/F2FE1mUUTbDtrg==", "path": "system.reflection.typeextensions/4.1.0", "hashPath": "system.reflection.typeextensions.4.1.0.nupkg.sha512" }, "System.Resources.ResourceManager/4.0.1": { "type": "package", "serviceable": true, "sha512": "sha512-TxwVeUNoTgUOdQ09gfTjvW411MF+w9MBYL7AtNVc+HtBCFlutPLhUCdZjNkjbhj3bNQWMdHboF0KIWEOjJssbA==", "path": "system.resources.resourcemanager/4.0.1", "hashPath": "system.resources.resourcemanager.4.0.1.nupkg.sha512" }, "System.Runtime/4.1.0": { "type": "package", "serviceable": true, "sha512": "sha512-v6c/4Yaa9uWsq+JMhnOFewrYkgdNHNG2eMKuNqRn8P733rNXeRCGvV5FkkjBXn2dbVkPXOsO0xjsEeM1q2zC0g==", "path": "system.runtime/4.1.0", "hashPath": "system.runtime.4.1.0.nupkg.sha512" }, "System.Runtime.Extensions/4.1.0": { "type": "package", "serviceable": true, "sha512": "sha512-CUOHjTT/vgP0qGW22U4/hDlOqXmcPq5YicBaXdUR2UiUoLwBT+olO6we4DVbq57jeX5uXH2uerVZhf0qGj+sVQ==", "path": "system.runtime.extensions/4.1.0", "hashPath": "system.runtime.extensions.4.1.0.nupkg.sha512" }, "System.Runtime.Serialization.Primitives/4.1.1": { "type": "package", "serviceable": true, "sha512": "sha512-HZ6Du5QrTG8MNJbf4e4qMO3JRAkIboGT5Fk804uZtg3Gq516S7hAqTm2UZKUHa7/6HUGdVy3AqMQKbns06G/cg==", "path": "system.runtime.serialization.primitives/4.1.1", "hashPath": "system.runtime.serialization.primitives.4.1.1.nupkg.sha512" }, "System.Text.Encoding/4.0.11": { "type": "package", "serviceable": true, "sha512": "sha512-U3gGeMlDZXxCEiY4DwVLSacg+DFWCvoiX+JThA/rvw37Sqrku7sEFeVBBBMBnfB6FeZHsyDx85HlKL19x0HtZA==", "path": "system.text.encoding/4.0.11", "hashPath": "system.text.encoding.4.0.11.nupkg.sha512" }, "System.Text.Encoding.Extensions/4.0.11": { "type": "package", "serviceable": true, "sha512": "sha512-jtbiTDtvfLYgXn8PTfWI+SiBs51rrmO4AAckx4KR6vFK9Wzf6tI8kcRdsYQNwriUeQ1+CtQbM1W4cMbLXnj/OQ==", "path": "system.text.encoding.extensions/4.0.11", "hashPath": "system.text.encoding.extensions.4.0.11.nupkg.sha512" }, "System.Text.RegularExpressions/4.1.0": { "type": "package", "serviceable": true, "sha512": "sha512-i88YCXpRTjCnoSQZtdlHkAOx4KNNik4hMy83n0+Ftlb7jvV6ZiZWMpnEZHhjBp6hQVh8gWd/iKNPzlPF7iyA2g==", "path": "system.text.regularexpressions/4.1.0", "hashPath": "system.text.regularexpressions.4.1.0.nupkg.sha512" }, "System.Threading/4.0.11": { "type": "package", "serviceable": true, "sha512": "sha512-N+3xqIcg3VDKyjwwCGaZ9HawG9aC6cSDI+s7ROma310GQo8vilFZa86hqKppwTHleR/G0sfOzhvgnUxWCR/DrQ==", "path": "system.threading/4.0.11", "hashPath": "system.threading.4.0.11.nupkg.sha512" }, "System.Threading.Tasks/4.0.11": { "type": "package", "serviceable": true, "sha512": "sha512-k1S4Gc6IGwtHGT8188RSeGaX86Qw/wnrgNLshJvsdNUOPP9etMmo8S07c+UlOAx4K/xLuN9ivA1bD0LVurtIxQ==", "path": "system.threading.tasks/4.0.11", "hashPath": "system.threading.tasks.4.0.11.nupkg.sha512" }, "Ude.NetStandard/1.2.0": { "type": "package", "serviceable": true, "sha512": "sha512-zRWpPAxBg3lNdm4UiKixTe+DFPoNid9CILggTCy/0WR2WKETe17kTWhiiIpLB2k5IEgnvA0QLfKlvd6Tvu0pzA==", "path": "ude.netstandard/1.2.0", "hashPath": "ude.netstandard.1.2.0.nupkg.sha512" }, "YamlDotNet.NetCore/1.0.0": { "type": "package", "serviceable": true, "sha512": "sha512-vPiKF4Yf02MS96Nzwcr8+WrvlhTx+camOgUzxhazU0hCzs2ESetWDCxaIT/MYdAw2oONYem1ow9PXWJjHkRUDw==", "path": "yamldotnet.netcore/1.0.0", "hashPath": "yamldotnet.netcore.1.0.0.nupkg.sha512" }, "Luban.Bson/1.0.0": { "type": "project", "serviceable": false, "sha512": "" }, "Luban.Core/1.0.0": { "type": "project", "serviceable": false, "sha512": "" }, "Luban.Cpp/1.0.0": { "type": "project", "serviceable": false, "sha512": "" }, "Luban.CSharp/1.0.0": { "type": "project", "serviceable": false, "sha512": "" }, "Luban.DataLoader.Builtin/1.0.0": { "type": "project", "serviceable": false, "sha512": "" }, "Luban.DataTarget.Builtin/1.0.0": { "type": "project", "serviceable": false, "sha512": "" }, "Luban.DataValidator.Builtin/1.0.0": { "type": "project", "serviceable": false, "sha512": "" }, "Luban.FlatBuffers/1.0.0": { "type": "project", "serviceable": false, "sha512": "" }, "Luban.Gdscript/1.0.0": { "type": "project", "serviceable": false, "sha512": "" }, "Luban.Golang/1.0.0": { "type": "project", "serviceable": false, "sha512": "" }, "Luban.Java/1.0.0": { "type": "project", "serviceable": false, "sha512": "" }, "Luban.L10N/1.0.0": { "type": "project", "serviceable": false, "sha512": "" }, "Luban.Lua/1.0.0": { "type": "project", "serviceable": false, "sha512": "" }, "Luban.MsgPack/1.0.0": { "type": "project", "serviceable": false, "sha512": "" }, "Luban.PHP/1.0.0": { "type": "project", "serviceable": false, "sha512": "" }, "Luban.Protobuf/1.0.0": { "type": "project", "serviceable": false, "sha512": "" }, "Luban.Python/1.0.0": { "type": "project", "serviceable": false, "sha512": "" }, "Luban.Rust/1.0.0": { "type": "project", "serviceable": false, "sha512": "" }, "Luban.Schema.Builtin/1.0.0": { "type": "project", "serviceable": false, "sha512": "" }, "Luban.Typescript/1.0.0": { "type": "project", "serviceable": false, "sha512": "" } } } ================================================ FILE: Config/Tools/Luban.runtimeconfig.json ================================================ { "runtimeOptions": { "tfm": "net8.0", "framework": { "name": "Microsoft.NETCore.App", "version": "8.0.0" }, "configProperties": { "System.Runtime.Serialization.EnableUnsafeBinaryFormatterSerialization": false } } } ================================================ FILE: Config/Tools/Templates/common/cs/enum.sbn ================================================ {{~ comment = __enum.comment items = __enum.items ~}} {{namespace_with_grace_begin __namespace_with_top_module}} {{~if comment != '' ~}} /// /// {{escape_comment comment}} /// {{~end~}} {{~if __enum.is_flags~}} [System.Flags] {{~end~}} public enum {{__name}} { {{~ for item in items ~}} {{~if item.comment != '' ~}} /// /// {{escape_comment item.comment_or_alias}} /// {{~end~}} {{format_enum_item_name __code_style item.name}} = {{item.value}}, {{~end~}} } {{namespace_with_grace_end __namespace_with_top_module}} ================================================ FILE: Config/Tools/Templates/common/ts/enum.sbn ================================================ ================================================ FILE: Config/Tools/Templates/cs-bin/bean.sbn ================================================ using LuBan.Runtime; using GameFrameX.Config; {{ parent_def_type = __bean.parent_def_type export_fields = __bean.export_fields hierarchy_export_fields = __bean.hierarchy_export_fields }} {{namespace_with_grace_begin __namespace_with_top_module}} {{~if __bean.comment != '' ~}} /// /// {{escape_comment __bean.comment}} /// {{~end~}} {{~ func get_ref_name ret (format_property_name __code_style $0.name) + '_Ref' end func get_index_var_name ret (format_property_name __code_style $0.name) + '_Index' end func generate_resolve_field_ref field = $0 fieldName = format_property_name __code_style field.name refTable = get_ref_table field if can_generate_ref field tableName = format_property_name __code_style refTable.name if field.is_nullable ret (get_ref_name field) + ' = ' + fieldName + '!= null ? tables.' + tableName + '.Get(' + (get_value_of_nullable_type field.ctype fieldName) + ') : null;' else ret (get_ref_name field) + ' = tables.' + tableName + '.Get(' + fieldName + ');' end else if can_generate_collection_ref field collection_ref_table = get_collection_ref_table field tableName = format_property_name __code_style collection_ref_table.name if field.ctype.type_name == 'list' || field.ctype.type_name == 'set' line1 = (get_ref_name field) + ' = new ' + (declaring_collection_ref_name field.ctype) + '();' + '\n' line2 = 'foreach (var _v in ' + fieldName + ') { ' + (get_ref_name field) + '.Add(tables.' + tableName + '.Get(_v)); }' + '\n' ret line1 + line2 else if field.ctype.type_name == 'array' line1 = (get_ref_name field) + ' = new ' + (declaring_type_name collection_ref_table.value_ttype) + '[' + fieldName + '.Length];' + '\n' line2 = 'for (int _i = 0; _i < ' + fieldName + '.Length; _i++) { ' + (get_ref_name field) + '[_i] = tables.' + tableName + '.Get(' + fieldName + '[_i]); }' + '\n' ret line1 + line2 else if field.ctype.type_name == 'map' line1 = (get_ref_name field) + ' = new ' + (declaring_collection_ref_name field.ctype) + '();' + '\n' line2 = 'foreach (var (_k,_v) in ' + fieldName + ') { ' + (get_ref_name field) + '.Add(_k, tables.' + tableName + '.GetOrDefault(_v)); }' + '\n' ret line1 + line2 else ret '' end else if (is_field_bean_need_resolve_ref field) ret fieldName + '?.ResolveRef(tables);' else if (is_field_array_like_need_resolve_ref field) ret 'foreach (var _e in ' + fieldName + ') { _e?.ResolveRef(tables); }' else if (is_field_map_need_resolve_ref field) ret 'foreach (var _e in ' + fieldName + '.Values) { _e?.ResolveRef(tables); }' else ret '' end end end func get_param_def_list(bean) paramList = [] while bean tempList = bean.export_fields |array.each do; ret (declaring_type_name $0.ctype) + ' ' + (format_property_name __code_style $0.name); end paramList = tempList + paramList bean = bean.parent_def_type end ret array.join paramList ', ' end func get_param_name_list(bean) paramList = [] index = 0 while bean tempList = bean.export_fields |array.each do; ret (format_property_name __code_style $0.name); end paramList = tempList + paramList bean = bean.parent_def_type end ret array.join paramList ', ' end ~}} {{~if __bean.is_value_type~}} public partial struct {{__name}} {{~else~}} public {{class_modifier __bean}} partial class {{__name}} : {{if parent_def_type}}{{__bean.parent}}{{else}}LuBan.Runtime.BeanBase{{end}} {{~end~}} { public {{__name}}({{get_param_def_list(__bean)}}) {{if parent_def_type}} : base({{get_param_name_list(__bean.parent_def_type)}}) {{end}} { {{~ for field in export_fields fieldName = format_property_name __code_style field.name ~}} this.{{fieldName}} = {{fieldName}}; {{~if can_generate_ref field~}} this.{{get_ref_name field}} = null; {{~end~}} {{~if has_index field~}} this.{{get_index_var_name field}} = new {{declaring_type_name (get_index_map_type field)}}({{field.size}}); foreach(var _v in {{fieldName}}) { this.{{get_index_var_name field}}.Add(_v.{{format_property_name __code_style (get_index_field field).name}}, _v); } {{~end~}} {{~end~}} PostInit(); } public {{__name}}(ByteBuf _buf) {{if parent_def_type}} : base(_buf) {{end}} { {{~ for field in export_fields this.fieldName = format_property_name __code_style field.name ~}} {{deserialize '_buf' fieldName field.ctype}} {{~if can_generate_ref field~}} {{get_ref_name field}} = null; {{~end~}} {{~if has_index field~}} foreach(var _v in {{fieldName}}) { {{get_index_var_name field}}.Add(_v.{{format_property_name __code_style (get_index_field field).name}}, _v); } {{~end~}} {{~end~}} // Localization Key Begin {{~ for field in export_fields ~}} {{~if field.type =='text'~}} {{format_property_name __code_style field.name}}_Localization_Key = {{format_property_name __code_style field.name}}; {{~end~}} {{~end~}} // Localization Key End PostInit(); } public static {{__name}} Deserialize{{__name}}(ByteBuf _buf) { {{~if __bean.is_abstract_type~}} switch (_buf.ReadInt()) { {{~for child in __bean.hierarchy_not_abstract_children~}} case {{child.full_name}}.__ID__: return new {{child.full_name}}(_buf); {{~end~}} default: throw new SerializationException(); } {{~else~}} return new {{__bean.full_name}}(_buf); {{~end~}} } {{~ for field in export_fields ~}} {{~if field.comment != '' ~}} /// /// {{escape_comment field.comment}} /// {{~end~}} public {{declaring_type_name field.ctype}} {{format_property_name __code_style field.name}} { private set; get; } {{~if field.type =='text'~}} {{~if field.comment != '' ~}} /// /// {{escape_comment field.comment}} 的多语言Key /// {{~end~}} public readonly string {{format_property_name __code_style field.name}}_Localization_Key; {{~end~}} {{~if can_generate_ref field~}} public {{declaring_type_name (get_ref_type field)}} {{get_ref_name field}} { private set; get; } {{~else if can_generate_collection_ref field~}} public {{declaring_collection_ref_name field.ctype}} {{get_ref_name field}} { private set; get; } {{~end~}} {{~if has_index field indexMapType = get_index_map_type field ~}} public readonly {{declaring_type_name indexMapType}} {{get_index_var_name field}} = new {{declaring_type_name indexMapType}}(); {{~end~}} {{~end~}} {{~if !__bean.is_abstract_type && !__bean.is_value_type~}} public const int __ID__ = {{__bean.id}}; public override int GetTypeId() => __ID__; {{~end~}} public {{method_modifier __bean}} void ResolveRef({{__manager_name}} tables) { {{~if parent_def_type~}} base.ResolveRef(tables); {{~end~}} {{~for field in export_fields~}} {{generate_resolve_field_ref field}} {{~end~}} PostResolveRef(); } public void TranslateText(System.Func translator) { {{~if parent_def_type~}} base.TranslateText(translator); {{~end~}} {{~ for field in export_fields ~}} {{~if field.type =='text'~}} {{format_property_name __code_style field.name}} = translator({{format_property_name __code_style field.name}}_Localization_Key, {{format_property_name __code_style field.name}}); {{~end~}} {{~end~}} } public override string ToString() { return "{{full_name}}{ " {{~for field in hierarchy_export_fields ~}} + "{{format_field_name __code_style field.name}}:" + {{to_pretty_string (format_property_name __code_style field.name) field.ctype}} + "," {{~end~}} + "}"; } partial void PostInit(); partial void PostResolveRef(); } {{namespace_with_grace_end __namespace_with_top_module}} ================================================ FILE: Config/Tools/Templates/cs-bin/table.sbn ================================================ using LuBan.Runtime; using GameFrameX.Config.Runtime; {{ key_type = __table.key_ttype value_type = __table.value_ttype func index_type_name ret (declaring_type_name $0.type) end func table_union_map_type_name ret 'System.Collections.Generic.Dictionary<(' + (array.each __table.index_list @index_type_name | array.join ', ') + '), ' + (declaring_type_name value_type) + '>' end func table_key_list varName = $0 indexList = __table.index_list |array.each do; ret varName + '.' + (format_property_name __code_style $0.index_field.name); end; ret array.join indexList ', ' end func table_param_def_list paramList = __table.index_list |array.each do; ret (declaring_type_name $0.type) + ' ' + $0.index_field.name; end ret array.join paramList ', ' end func table_param_name_list paramList = __table.index_list |array.each do; ret $0.index_field.name; end ret array.join paramList ', ' end }} {{namespace_with_grace_begin __namespace_with_top_module}} {{~if __table.comment != '' ~}} /// /// {{escape_comment __table.comment}} /// {{~end~}} public partial class {{__name}} : BaseDataTable<{{declaring_type_name __value_type}}> { {{~if __table.is_map_table ~}} private readonly System.Func> _loadFunc; public {{__name}}(System.Func> loadFunc) { _loadFunc = loadFunc; } public override async System.Threading.Tasks.Task LoadAsync() { ByteBuf _buf = await _loadFunc(); StringDataMaps.Clear(); DataList.Clear(); for(int n = _buf.ReadSize() ; n > 0 ; --n) { {{declaring_type_name value_type}} _v; {{deserialize '_buf' '_v' value_type}} DataList.Add(_v); {{~if __key_type.type_name != 'string' ~}} LongDataMaps.Add(_v.{{format_property_name __code_style __table.index_field.name}}, _v); {{~end~}} StringDataMaps.Add(_v.{{format_property_name __code_style __table.index_field.name}}.ToString(), _v); } PostInit(); } {{~if value_type.is_dynamic~}} //public T GetOrDefaultAs({{declaring_type_name key_type}} key) where T : {{declaring_type_name value_type}} => _dataMap.TryGetValue(key, out var v) ? (T)v : null; //public T GetAs({{declaring_type_name key_type}} key) where T : {{declaring_type_name value_type}} => (T)_dataMap[key]; {{~end~}} public void ResolveRef({{__manager_name}} tables) { foreach(var value in DataList) { value.ResolveRef(tables); } PostResolveRef(); } public void TranslateText(System.Func translator) { foreach(var v in DataList) { v.TranslateText(translator); } } {{~else if __table.is_list_table ~}} {{~if __table.is_union_index~}} private {{table_union_map_type_name}} _dataMapUnion; {{~else if !__table.index_list.empty?~}} {{~for idx in __table.index_list~}} private System.Collections.Generic.Dictionary<{{declaring_type_name idx.type}}, {{declaring_type_name value_type}}> _dataMap_{{idx.index_field.name}}; {{~end~}} {{~end~}} private readonly System.Func> _loadFunc; public {{__name}}(System.Func> loadFunc) { _loadFunc = loadFunc; {{~if __table.is_union_index~}} _dataMapUnion = new {{table_union_map_type_name}}(); {{~else if !__table.index_list.empty?~}} {{~for idx in __table.index_list~}} _dataMap_{{idx.index_field.name}} = new System.Collections.Generic.Dictionary<{{declaring_type_name idx.type}}, {{declaring_type_name value_type}}>(); {{~end~}} {{~end~}} } public override async System.Threading.Tasks.Task LoadAsync() { ByteBuf _buf = await _loadFunc(); DataList.Clear(); for(int n = _buf.ReadSize() ; n > 0 ; --n) { {{declaring_type_name value_type}} _v; {{deserialize '_buf' '_v' value_type}} DataList.Add(_v); } {{~if __table.is_union_index~}} _dataMapUnion.Clear(); foreach(var _v in DataList) { _dataMapUnion.Add(({{table_key_list "_v"}}), _v); } {{~else if !__table.index_list.empty?~}} {{~for idx in __table.index_list~}} _dataMap_{{idx.index_field.name}}.Clear(); {{~end~}} foreach(var _v in DataList) { {{~for idx in __table.index_list~}} _dataMap_{{idx.index_field.name}}.Add(_v.{{format_property_name __code_style idx.index_field.name}}, _v); {{~end~}} } {{~end~}} PostInit(); } {{~if __table.is_union_index~}} public {{declaring_type_name value_type}} Get({{table_param_def_list}}) => _dataMapUnion.TryGetValue(({{table_param_name_list}}), out {{declaring_type_name value_type}} __v) ? __v : null; {{~else if !__table.index_list.empty? ~}} {{~for idx in __table.index_list~}} public {{declaring_type_name value_type}} GetBy{{format_property_name __code_style idx.index_field.name}}({{declaring_type_name idx.type}} key) => _dataMap_{{idx.index_field.name}}.TryGetValue(key, out {{declaring_type_name value_type}} __v) ? __v : null; {{~end~}} {{~end~}} public void ResolveRef({{__manager_name}} tables) { foreach(var _v in DataList) { _v.ResolveRef(tables); } PostResolveRef(); } public void TranslateText(System.Func translator) { foreach(var v in DataList) { v.TranslateText(translator); } } {{~else~}} private {{declaring_type_name value_type}} _data; public {{declaring_type_name value_type}} Data => _data; private readonly System.Func> _loadFunc; public {{__name}}(System.Func> loadFunc) { _loadFunc = loadFunc; } public async System.Threading.Tasks.Task LoadAsync() { ByteBuf _buf = await _loadFunc(); int n = _buf.ReadSize(); if (n != 1) throw new SerializationException("table mode=one, but size != 1"); {{deserialize '_buf' '_data' value_type}} PostInit(); } {{~ for field in value_type.def_bean.hierarchy_export_fields ~}} {{~if field.comment != '' ~}} /// /// {{escape_comment field.comment}} /// {{~end~}} public {{declaring_type_name field.ctype}} {{format_property_name __code_style field.name}} => _data.{{format_property_name __code_style field.name}}; {{~end~}} public void ResolveRef({{__manager_name}} tables) { _data.ResolveRef(tables); PostResolveRef(); } public void TranslateText(System.Func translator) { _data.TranslateText(translator); } {{~end~}} partial void PostInit(); partial void PostResolveRef(); } {{namespace_with_grace_end __namespace_with_top_module}} ================================================ FILE: Config/Tools/Templates/cs-bin/tables.sbn ================================================ using System; using LuBan.Runtime; using GameFrameX.Config.Runtime; {{namespace_with_grace_begin __namespace}} public partial class {{__name}} { {{~for table in __tables ~}} {{~if table.comment != '' ~}} /// /// {{escape_comment table.comment}} /// {{~end~}} internal {{table.full_name}} {{format_property_name __code_style table.name}} { private set; get; } {{~end~}} private ConfigComponent m_ConfigComponent; public void Init(ConfigComponent configComponent) { m_ConfigComponent = configComponent; configComponent.RemoveAllConfigs(); } /// /// 是否加载完成 /// public bool IsLoaded { get; private set; } /// /// 异步加载配置文件 /// /// 加载器 public async System.Threading.Tasks.Task LoadAsync(System.Func> loader) { if (IsLoaded) { return; } IsLoaded = false; m_ConfigComponent.RemoveAllConfigs(); var loadTasks = new System.Collections.Generic.List(); {{~for table in __tables ~}} {{format_property_name __code_style table.name}} = new {{table.full_name}}(() => loader("{{table.output_data_file}}")); loadTasks.Add({{format_property_name __code_style table.name}}.LoadAsync()); m_ConfigComponent.Add(nameof({{table.full_name}}), {{format_property_name __code_style table.name}}); {{~end~}} await System.Threading.Tasks.Task.WhenAll(loadTasks); Refresh(); IsLoaded = true; } /// /// 设置本地化的适配器 /// /// 适配器对象 /// 如果未加载完成将抛出此异常 public void SetTranslateText(System.Func translator) { if (IsLoaded == false) { throw new InvalidOperationException("Table is not loaded!"); } {{~for table in __tables ~}} {{format_property_name __code_style table.name}}.TranslateText(translator); {{~end~}} } private void ResolveRef() { {{~for table in __tables ~}} {{format_property_name __code_style table.name}}.ResolveRef(this); {{~end~}} PostResolveRef(); } public void Refresh() { PostInit(); ResolveRef(); } partial void PostInit(); partial void PostResolveRef(); } {{namespace_with_grace_end __namespace}} ================================================ FILE: Config/Tools/Templates/cs-code/bean.sbn ================================================ using Luban; {{ parent_def_type = __bean.parent_def_type export_fields = __bean.export_fields hierarchy_export_fields = __bean.hierarchy_export_fields }} {{namespace_with_grace_begin __namespace_with_top_module}} {{~if __bean.comment != '' ~}} /// /// {{escape_comment __bean.comment}} /// {{~end~}} {{~ func get_ref_name ret (format_property_name __code_style $0.name) + '_Ref' end func get_index_var_name ret (format_property_name __code_style $0.name) + '_Index' end func generate_resolve_field_ref field = $0 fieldName = format_property_name __code_style field.name refTable = get_ref_table field if can_generate_ref field tableName = format_property_name __code_style refTable.name if field.is_nullable ret (get_ref_name field) + ' = ' + fieldName + '!= null ? tables.' + tableName + '.Get(' + (get_value_of_nullable_type field.ctype fieldName) + ') : null;' else ret (get_ref_name field) + ' = tables.' + tableName + '.Get(' + fieldName + ');' end else if can_generate_collection_ref field collection_ref_table = get_collection_ref_table field tableName = format_property_name __code_style collection_ref_table.name if field.ctype.type_name == 'list' || field.ctype.type_name == 'set' line1 = (get_ref_name field) + ' = new ' + (declaring_collection_ref_name field.ctype) + '();' + '\n' line2 = 'foreach (var _v in ' + fieldName + ') { ' + (get_ref_name field) + '.Add(tables.' + tableName + '.Get(_v)); }' + '\n' ret line1 + line2 else if field.ctype.type_name == 'array' line1 = (get_ref_name field) + ' = new ' + (declaring_type_name collection_ref_table.value_ttype) + '[' + fieldName + '.Length];' + '\n' line2 = 'for (int _i = 0; _i < ' + fieldName + '.Length; _i++) { ' + (get_ref_name field) + '[_i] = tables.' + tableName + '.Get(' + fieldName + '[_i]); }' + '\n' ret line1 + line2 else if field.ctype.type_name == 'map' line1 = (get_ref_name field) + ' = new ' + (declaring_collection_ref_name field.ctype) + '();' + '\n' line2 = 'foreach (var (_k,_v) in ' + fieldName + ') { ' + (get_ref_name field) + '.Add(_k, tables.' + tableName + '.Get(_v)); }' + '\n' ret line1 + line2 else ret '' end else if (is_field_bean_need_resolve_ref field) ret fieldName + '?.ResolveRef(tables);' else if (is_field_array_like_need_resolve_ref field) ret 'foreach (var _e in ' + fieldName + ') { _e?.ResolveRef(tables); }' else if (is_field_map_need_resolve_ref field) ret 'foreach (var _e in ' + fieldName + '.Values) { _e?.ResolveRef(tables); }' else ret '' end end end func get_param_def_list(bean) paramList = [] while bean tempList = bean.export_fields |array.each do; ret (declaring_type_name $0.ctype) + ' ' + (format_property_name __code_style $0.name); end paramList = tempList + paramList bean = bean.parent_def_type end ret array.join paramList ', ' end func get_param_name_list(bean) paramList = [] index = 0 while bean tempList = bean.export_fields |array.each do; ret (format_property_name __code_style $0.name); end paramList = tempList + paramList bean = bean.parent_def_type end ret array.join paramList ', ' end ~}} {{~if __bean.is_value_type~}} public partial struct {{__name}} {{~else~}} public {{class_modifier __bean}} partial class {{__name}} : {{if parent_def_type}}{{__bean.parent}}{{else}}Luban.BeanBase{{end}} {{~end~}} { public {{__name}}({{get_param_def_list(__bean)}}) {{if parent_def_type}} : base({{get_param_name_list(__bean.parent_def_type)}}) {{end}} { {{~ for field in export_fields fieldName = format_property_name __code_style field.name ~}} this.{{fieldName}} = {{fieldName}}; {{~if can_generate_ref field~}} this.{{get_ref_name field}} = null; {{~end~}} {{~if has_index field~}} this.{{get_index_var_name field}} = new {{declaring_type_name (get_index_map_type field)}}({{field.size}}); foreach(var _v in {{fieldName}}) { this.{{get_index_var_name field}}.Add(_v.{{format_property_name __code_style (get_index_field field).name}}, _v); } {{~end~}} {{~end~}} PostInit(); } {{~ for field in export_fields ~}} {{~if field.comment != '' ~}} /// /// {{escape_comment field.comment}} /// {{~end~}} public readonly {{declaring_type_name field.ctype}} {{format_property_name __code_style field.name}}; {{~if can_generate_ref field~}} public {{declaring_type_name (get_ref_type field)}} {{get_ref_name field}} { private set; get; } {{~else if can_generate_collection_ref field~}} public {{declaring_collection_ref_name field.ctype}} {{get_ref_name field}} { private set; get; } {{~end~}} {{~if has_index field indexMapType = get_index_map_type field ~}} public readonly {{declaring_type_name indexMapType}} {{get_index_var_name field}}; {{~end~}} {{~end~}} {{~if !__bean.is_abstract_type && !__bean.is_value_type~}} public const int __ID__ = {{__bean.id}}; public override int GetTypeId() => __ID__; {{~end~}} public {{method_modifier __bean}} void ResolveRef({{__manager_name}} tables) { {{~if parent_def_type~}} base.ResolveRef(tables); {{~end~}} {{~for field in export_fields~}} {{generate_resolve_field_ref field}} {{~end~}} } public override string ToString() { return "{{full_name}}{ " {{~for field in hierarchy_export_fields ~}} + "{{format_field_name __code_style field.name}}:" + {{to_pretty_string (format_property_name __code_style field.name) field.ctype}} + "," {{~end~}} + "}"; } partial void PostInit(); } {{namespace_with_grace_end __namespace_with_top_module}} ================================================ FILE: Config/Tools/Templates/cs-code/table.sbn ================================================ using Luban; {{ key_type = __table.key_ttype value_type = __table.value_ttype func index_type_name ret (declaring_type_name $0.type) end func table_union_map_type_name ret 'System.Collections.Generic.Dictionary<(' + (array.each __table.index_list @index_type_name | array.join ', ') + '), ' + (declaring_type_name value_type) + '>' end func table_key_list varName = $0 indexList = __table.index_list |array.each do; ret varName + '.' + (format_property_name __code_style $0.index_field.name); end; ret array.join indexList ', ' end func table_param_def_list paramList = __table.index_list |array.each do; ret (declaring_type_name $0.type) + ' ' + $0.index_field.name; end ret array.join paramList ', ' end func table_param_name_list paramList = __table.index_list |array.each do; ret $0.index_field.name; end ret array.join paramList ', ' end func table_param_type_list paramList = __table.index_list |array.each do; ret (declaring_type_name $0.type); end ret array.join paramList ', ' end }} {{namespace_with_grace_begin __namespace_with_top_module}} {{~if __table.comment != '' ~}} /// /// {{escape_comment __table.comment}} /// {{~end~}} public partial class {{__name}} { {{~if __table.is_map_table ~}} private readonly System.Collections.Generic.Dictionary<{{declaring_type_name key_type}}, {{declaring_type_name value_type}}> _dataMap; private readonly System.Collections.Generic.List<{{declaring_type_name value_type}}> _dataList; public System.Collections.Generic.Dictionary<{{declaring_type_name key_type}}, {{declaring_type_name value_type}}> DataMap => _dataMap; public System.Collections.Generic.List<{{declaring_type_name value_type}}> DataList => _dataList; {{~if value_type.is_dynamic~}} public T GetOrDefaultAs({{declaring_type_name key_type}} key) where T : {{declaring_type_name value_type}} => _dataMap.TryGetValue(key, out var v) ? (T)v : null; public T GetAs({{declaring_type_name key_type}} key) where T : {{declaring_type_name value_type}} => (T)_dataMap[key]; {{~end~}} public {{declaring_type_name value_type}} GetOrDefault({{declaring_type_name key_type}} key) => _dataMap.TryGetValue(key, out var v) ? v : null; public {{declaring_type_name value_type}} Get({{declaring_type_name key_type}} key) => _dataMap[key]; public {{declaring_type_name value_type}} this[{{declaring_type_name key_type}} key] => _dataMap[key]; public void ResolveRef({{__manager_name}} tables) { foreach(var _v in _dataList) { _v.ResolveRef(tables); } } {{~else if __table.is_list_table ~}} private readonly System.Collections.Generic.List<{{declaring_type_name value_type}}> _dataList; {{~if __table.is_union_index~}} private {{table_union_map_type_name}} _dataMapUnion; {{~else if !__table.index_list.empty?~}} {{~for idx in __table.index_list~}} private System.Collections.Generic.Dictionary<{{declaring_type_name idx.type}}, {{declaring_type_name value_type}}> _dataMap_{{idx.index_field.name}}; {{~end~}} {{~end~}} public System.Collections.Generic.List<{{declaring_type_name value_type}}> DataList => _dataList; {{~if __table.is_union_index~}} public {{declaring_type_name value_type}} Get({{table_param_def_list}}) => _dataMapUnion.TryGetValue(({{table_param_name_list}}), out {{declaring_type_name value_type}} __v) ? __v : null; {{~else if !__table.index_list.empty? ~}} {{~for idx in __table.index_list~}} public {{declaring_type_name value_type}} GetBy{{format_property_name __code_style idx.index_field.name}}({{declaring_type_name idx.type}} key) => _dataMap_{{idx.index_field.name}}.TryGetValue(key, out {{declaring_type_name value_type}} __v) ? __v : null; {{~end~}} {{~end~}} public void ResolveRef({{__manager_name}} tables) { foreach(var _v in _dataList) { _v.ResolveRef(tables); } } {{~else~}} private readonly {{declaring_type_name value_type}} _data; public {{declaring_type_name value_type}} Data => _data; {{~ for field in value_type.def_bean.hierarchy_export_fields ~}} {{~if field.comment != '' ~}} /// /// {{escape_comment field.comment}} /// {{~end~}} public {{declaring_type_name field.ctype}} {{format_property_name __code_style field.name}} => _data.{{format_property_name __code_style field.name}}; {{~end~}} public void ResolveRef({{__manager_name}} tables) { _data.ResolveRef(tables); } {{~end~}} partial void PostInit(); } {{namespace_with_grace_end __namespace_with_top_module}} ================================================ FILE: Config/Tools/Templates/cs-code/tabledata.sbn ================================================ using Luban; {{ key_type = __table.key_ttype value_type = __table.value_ttype func index_type_name ret (declaring_type_name $0.type) end func table_union_map_type_name ret 'System.Collections.Generic.Dictionary<(' + (array.each __table.index_list @index_type_name | array.join ', ') + '), ' + (declaring_type_name value_type) + '>' end func table_key_list varName = $0 indexList = __table.index_list |array.each do; ret varName + '.' + (format_property_name __code_style $0.index_field.name); end; ret array.join indexList ', ' end func table_data_list dataList = __records |array.each do; ret (apply_value $0); end ret array.join dataList ',\n' end }} {{namespace_with_grace_begin __namespace_with_top_module}} {{~if __table.comment != '' ~}} /// /// {{escape_comment __table.comment}} /// {{~end~}} public partial class {{__name}} { {{~if __table.is_map_table ~}} public {{__name}}() { _dataList = new System.Collections.Generic.List<{{declaring_type_name value_type}}> () { {{table_data_list}} }; _dataMap = new System.Collections.Generic.Dictionary<{{declaring_type_name key_type}}, {{declaring_type_name value_type}}> (_dataList.Count); foreach(var _v in _dataList) { _dataMap.Add(_v.{{format_property_name __code_style __table.index_field.name}}, _v); } PostInit(); } {{~else if __table.is_list_table ~}} public {{__name}}() { _dataList = new System.Collections.Generic.List<{{declaring_type_name value_type}}> () { {{table_data_list}} }; {{~if __table.is_union_index~}} _dataMapUnion = new {{table_union_map_type_name}} (_dataList.Count); foreach(var _v in _dataList) { _dataMapUnion.Add(({{table_key_list "_v"}}), _v); } {{~else if !__table.index_list.empty?~}} {{~for idx in __table.index_list~}} _dataMap_{{idx.index_field.name}} = new System.Collections.Generic.Dictionary<{{declaring_type_name idx.type}}, {{declaring_type_name value_type}}> (_dataList.Count); {{~end~}} foreach(var _v in _dataList) { {{~for idx in __table.index_list~}} _dataMap_{{idx.index_field.name}}.Add(_v.{{format_property_name __code_style idx.index_field.name}}, _v); {{~end~}} } {{~end~}} PostInit(); } {{~else~}} public {{__name}}() { _data = {{table_data_list}}; PostInit(); } {{~end~}} } {{namespace_with_grace_end __namespace_with_top_module}} ================================================ FILE: Config/Tools/Templates/cs-code/tables.sbn ================================================ using Luban; {{namespace_with_grace_begin __namespace}} public partial class {{__name}} { {{~for table in __tables ~}} {{~if table.comment != '' ~}} /// /// {{escape_comment table.comment}} /// {{~end~}} internal {{table.full_name}} {{format_property_name __code_style table.name}} { private set; get; } {{~end~}} public {{__name}}() { TablesMemory.BeginRecord(); {{~for table in __tables ~}} {{format_property_name __code_style table.name}} = new {{table.full_name}}(); {{~end~}} PostInit(); ResolveRef(); TablesMemory.EndRecord(); } private void ResolveRef() { {{~for table in __tables ~}} {{format_property_name __code_style table.name}}.ResolveRef(this); {{~end~}} } partial void PostInit(); } {{namespace_with_grace_end __namespace}} ================================================ FILE: Config/Tools/Templates/cs-dotnet-bin/bean.sbn ================================================ using GameFrameX.Core.Config; {{ parent_def_type = __bean.parent_def_type export_fields = __bean.export_fields hierarchy_export_fields = __bean.hierarchy_export_fields }} {{namespace_with_grace_begin __namespace_with_top_module}} {{~if __bean.comment != '' ~}} /// /// {{escape_comment __bean.comment}} /// {{~end~}} {{~ func get_ref_name ret (format_property_name __code_style $0.name) + '_Ref' end func get_index_var_name ret (format_property_name __code_style $0.name) + '_Index' end func generate_resolve_field_ref field = $0 fieldName = format_property_name __code_style field.name refTable = get_ref_table field if can_generate_ref field tableName = format_property_name __code_style refTable.name if field.is_nullable ret (get_ref_name field) + ' = ' + fieldName + '!= null ? tables.' + tableName + '.Get(' + (get_value_of_nullable_type field.ctype fieldName) + ') : null;' else ret (get_ref_name field) + ' = tables.' + tableName + '.Get(' + fieldName + ');' end else if can_generate_collection_ref field collection_ref_table = get_collection_ref_table field tableName = format_property_name __code_style collection_ref_table.name if field.ctype.type_name == 'list' || field.ctype.type_name == 'set' line1 = (get_ref_name field) + ' = new ' + (declaring_collection_ref_name field.ctype) + '();' + '\n' line2 = 'foreach (var _v in ' + fieldName + ') { ' + (get_ref_name field) + '.Add(tables.' + tableName + '.Get(_v)); }' + '\n' ret line1 + line2 else if field.ctype.type_name == 'array' line1 = (get_ref_name field) + ' = new ' + (declaring_type_name collection_ref_table.value_ttype) + '[' + fieldName + '.Length];' + '\n' line2 = 'for (int _i = 0; _i < ' + fieldName + '.Length; _i++) { ' + (get_ref_name field) + '[_i] = tables.' + tableName + '.Get(' + fieldName + '[_i]); }' + '\n' ret line1 + line2 else if field.ctype.type_name == 'map' line1 = (get_ref_name field) + ' = new ' + (declaring_collection_ref_name field.ctype) + '();' + '\n' line2 = 'foreach (var (_k,_v) in ' + fieldName + ') { ' + (get_ref_name field) + '.Add(_k, tables.' + tableName + '.GetOrDefault(_v)); }' + '\n' ret line1 + line2 else ret '' end else if (is_field_bean_need_resolve_ref field) ret fieldName + '?.ResolveRef(tables);' else if (is_field_array_like_need_resolve_ref field) ret 'foreach (var _e in ' + fieldName + ') { _e?.ResolveRef(tables); }' else if (is_field_map_need_resolve_ref field) ret 'foreach (var _e in ' + fieldName + '.Values) { _e?.ResolveRef(tables); }' else ret '' end end end func get_param_def_list(bean) paramList = [] while bean tempList = bean.export_fields |array.each do; ret (declaring_type_name $0.ctype) + ' ' + (format_property_name __code_style $0.name); end paramList = tempList + paramList bean = bean.parent_def_type end ret array.join paramList ', ' end func get_param_name_list(bean) paramList = [] index = 0 while bean tempList = bean.export_fields |array.each do; ret (format_property_name __code_style $0.name); end paramList = tempList + paramList bean = bean.parent_def_type end ret array.join paramList ', ' end ~}} {{~if __bean.is_value_type~}} public partial struct {{__name}} {{~else~}} public {{class_modifier __bean}} partial class {{__name}} : {{if parent_def_type}}{{__bean.parent}}{{else}}BeanBase{{end}} {{~end~}} { public {{__name}}({{get_param_def_list(__bean)}}) {{if parent_def_type}} : base({{get_param_name_list(__bean.parent_def_type)}}) {{end}} { {{~ for field in export_fields fieldName = format_property_name __code_style field.name ~}} this.{{fieldName}} = {{fieldName}}; {{~if can_generate_ref field~}} this.{{get_ref_name field}} = null; {{~end~}} {{~if has_index field~}} this.{{get_index_var_name field}} = new {{declaring_type_name (get_index_map_type field)}}({{field.size}}); foreach(var _v in {{fieldName}}) { this.{{get_index_var_name field}}.Add(_v.{{format_property_name __code_style (get_index_field field).name}}, _v); } {{~end~}} {{~end~}} PostInit(); } public {{__name}}(ByteBuf _buf) {{if parent_def_type}} : base(_buf) {{end}} { {{~ for field in export_fields this.fieldName = format_property_name __code_style field.name ~}} {{deserialize '_buf' fieldName field.ctype}} {{~if can_generate_ref field~}} {{get_ref_name field}} = null; {{~end~}} {{~if has_index field~}} foreach(var _v in {{fieldName}}) { {{get_index_var_name field}}.Add(_v.{{format_property_name __code_style (get_index_field field).name}}, _v); } {{~end~}} {{~end~}} // Localization Key Begin {{~ for field in export_fields ~}} {{~if field.type =='text'~}} {{format_property_name __code_style field.name}}_Localization_Key = {{format_property_name __code_style field.name}}; {{~end~}} {{~end~}} // Localization Key End PostInit(); } public static {{__name}} Deserialize{{__name}}(ByteBuf _buf) { {{~if __bean.is_abstract_type~}} switch (_buf.ReadInt()) { {{~for child in __bean.hierarchy_not_abstract_children~}} case {{child.full_name}}.__ID__: return new {{child.full_name}}(_buf); {{~end~}} default: throw new SerializationException(); } {{~else~}} return new {{__bean.full_name}}(_buf); {{~end~}} } {{~ for field in export_fields ~}} {{~if field.comment != '' ~}} /// /// {{escape_comment field.comment}} /// {{~end~}} public {{declaring_type_name field.ctype}} {{format_property_name __code_style field.name}} { private set; get; } {{~if field.type =='text'~}} {{~if field.comment != '' ~}} /// /// {{escape_comment field.comment}} 的多语言Key /// {{~end~}} public readonly string {{format_property_name __code_style field.name}}_Localization_Key; {{~end~}} {{~if can_generate_ref field~}} public {{declaring_type_name (get_ref_type field)}} {{get_ref_name field}} { private set; get; } {{~else if can_generate_collection_ref field~}} public {{declaring_collection_ref_name field.ctype}} {{get_ref_name field}} { private set; get; } {{~end~}} {{~if has_index field indexMapType = get_index_map_type field ~}} public readonly {{declaring_type_name indexMapType}} {{get_index_var_name field}} = new {{declaring_type_name indexMapType}}(); {{~end~}} {{~end~}} {{~if !__bean.is_abstract_type && !__bean.is_value_type~}} public const int __ID__ = {{__bean.id}}; public override int GetTypeId() => __ID__; {{~end~}} public {{method_modifier __bean}} void ResolveRef({{__manager_name}} tables) { {{~if parent_def_type~}} base.ResolveRef(tables); {{~end~}} {{~for field in export_fields~}} {{generate_resolve_field_ref field}} {{~end~}} PostResolveRef(); } public void TranslateText(System.Func translator) { {{~if parent_def_type~}} base.TranslateText(translator); {{~end~}} {{~ for field in export_fields ~}} {{~if field.type =='text'~}} {{format_property_name __code_style field.name}} = translator({{format_property_name __code_style field.name}}_Localization_Key, {{format_property_name __code_style field.name}}); {{~end~}} {{~end~}} } public override string ToString() { return "{{full_name}}{ " {{~for field in hierarchy_export_fields ~}} + "{{format_field_name __code_style field.name}}:" + {{to_pretty_string (format_property_name __code_style field.name) field.ctype}} + "," {{~end~}} + "}"; } partial void PostInit(); partial void PostResolveRef(); } {{namespace_with_grace_end __namespace_with_top_module}} ================================================ FILE: Config/Tools/Templates/cs-dotnet-bin/table.sbn ================================================ using GameFrameX.Core.Config; {{ key_type = __table.key_ttype value_type = __table.value_ttype func index_type_name ret (declaring_type_name $0.type) end func table_union_map_type_name ret 'System.Collections.Generic.Dictionary<(' + (array.each __table.index_list @index_type_name | array.join ', ') + '), ' + (declaring_type_name value_type) + '>' end func table_key_list varName = $0 indexList = __table.index_list |array.each do; ret varName + '.' + (format_property_name __code_style $0.index_field.name); end; ret array.join indexList ', ' end func table_param_def_list paramList = __table.index_list |array.each do; ret (declaring_type_name $0.type) + ' ' + $0.index_field.name; end ret array.join paramList ', ' end func table_param_name_list paramList = __table.index_list |array.each do; ret $0.index_field.name; end ret array.join paramList ', ' end }} {{namespace_with_grace_begin __namespace_with_top_module}} {{~if __table.comment != '' ~}} /// /// {{escape_comment __table.comment}} /// {{~end~}} public partial class {{__name}} : BaseDataTable<{{declaring_type_name __value_type}}> { {{~if __table.is_map_table ~}} private readonly System.Func> _loadFunc; public {{__name}}(System.Func> loadFunc) { _loadFunc = loadFunc; } public override async System.Threading.Tasks.Task LoadAsync() { ByteBuf _buf = await _loadFunc(); StringDataMaps.Clear(); DataList.Clear(); for(int n = _buf.ReadSize() ; n > 0 ; --n) { {{declaring_type_name value_type}} _v; {{deserialize '_buf' '_v' value_type}} DataList.Add(_v); {{~if __key_type.type_name != 'string' ~}} LongDataMaps.Add(_v.{{format_property_name __code_style __table.index_field.name}}, _v); {{~end~}} StringDataMaps.Add(_v.{{format_property_name __code_style __table.index_field.name}}.ToString(), _v); } PostInit(); } {{~if value_type.is_dynamic~}} //public T GetOrDefaultAs({{declaring_type_name key_type}} key) where T : {{declaring_type_name value_type}} => _dataMap.TryGetValue(key, out var v) ? (T)v : null; //public T GetAs({{declaring_type_name key_type}} key) where T : {{declaring_type_name value_type}} => (T)_dataMap[key]; {{~end~}} public void ResolveRef({{__manager_name}} tables) { foreach(var value in DataList) { value.ResolveRef(tables); } PostResolveRef(); } public void TranslateText(System.Func translator) { foreach(var v in DataList) { v.TranslateText(translator); } } {{~else if __table.is_list_table ~}} private readonly System.Collections.Generic.List<{{declaring_type_name value_type}}> _dataList; {{~if __table.is_union_index~}} private {{table_union_map_type_name}} _dataMapUnion; {{~else if !__table.index_list.empty?~}} {{~for idx in __table.index_list~}} private System.Collections.Generic.Dictionary<{{declaring_type_name idx.type}}, {{declaring_type_name value_type}}> _dataMap_{{idx.index_field.name}}; {{~end~}} {{~end~}} private readonly System.Func> _loadFunc; public {{__name}}(System.Func> loadFunc) { _loadFunc = loadFunc; _dataList = new System.Collections.Generic.List<{{declaring_type_name value_type}}>(); {{~if __table.is_union_index~}} _dataMapUnion = new {{table_union_map_type_name}}(); {{~else if !__table.index_list.empty?~}} {{~for idx in __table.index_list~}} _dataMap_{{idx.index_field.name}} = new System.Collections.Generic.Dictionary<{{declaring_type_name idx.type}}, {{declaring_type_name value_type}}>(); {{~end~}} {{~end~}} } public async System.Threading.Tasks.Task LoadAsync() { ByteBuf _buf = await _loadFunc(); _dataList.Clear(); for(int n = _buf.ReadSize() ; n > 0 ; --n) { {{declaring_type_name value_type}} _v; {{deserialize '_buf' '_v' value_type}} _dataList.Add(_v); } {{~if __table.is_union_index~}} _dataMapUnion.Clear(); foreach(var _v in _dataList) { _dataMapUnion.Add(({{table_key_list "_v"}}), _v); } {{~else if !__table.index_list.empty?~}} {{~for idx in __table.index_list~}} _dataMap_{{idx.index_field.name}}.Clear(); {{~end~}} foreach(var _v in _dataList) { {{~for idx in __table.index_list~}} _dataMap_{{idx.index_field.name}}.Add(_v.{{format_property_name __code_style idx.index_field.name}}, _v); {{~end~}} } {{~end~}} PostInit(); } public System.Collections.Generic.List<{{declaring_type_name value_type}}> DataList => _dataList; {{~if __table.is_union_index~}} public {{declaring_type_name value_type}} Get({{table_param_def_list}}) => _dataMapUnion.TryGetValue(({{table_param_name_list}}), out {{declaring_type_name value_type}} __v) ? __v : null; {{~else if !__table.index_list.empty? ~}} {{~for idx in __table.index_list~}} public {{declaring_type_name value_type}} GetBy{{format_property_name __code_style idx.index_field.name}}({{declaring_type_name idx.type}} key) => _dataMap_{{idx.index_field.name}}.TryGetValue(key, out {{declaring_type_name value_type}} __v) ? __v : null; {{~end~}} {{~end~}} public void ResolveRef({{__manager_name}} tables) { foreach(var _v in _dataList) { _v.ResolveRef(tables); } PostResolveRef(); } public void TranslateText(System.Func translator) { foreach(var v in DataList) { v.TranslateText(translator); } } {{~else~}} private {{declaring_type_name value_type}} _data; public {{declaring_type_name value_type}} Data => _data; private readonly System.Func> _loadFunc; public {{__name}}(System.Func> loadFunc) { _loadFunc = loadFunc; } public async System.Threading.Tasks.Task LoadAsync() { ByteBuf _buf = await _loadFunc(); int n = _buf.ReadSize(); if (n != 1) throw new SerializationException("table mode=one, but size != 1"); {{deserialize '_buf' '_data' value_type}} PostInit(); } {{~ for field in value_type.def_bean.hierarchy_export_fields ~}} {{~if field.comment != '' ~}} /// /// {{escape_comment field.comment}} /// {{~end~}} public {{declaring_type_name field.ctype}} {{format_property_name __code_style field.name}} => _data.{{format_property_name __code_style field.name}}; {{~end~}} public void ResolveRef({{__manager_name}} tables) { _data.ResolveRef(tables); PostResolveRef(); } public void TranslateText(System.Func translator) { _data.TranslateText(translator); } {{~end~}} partial void PostInit(); partial void PostResolveRef(); } {{namespace_with_grace_end __namespace_with_top_module}} ================================================ FILE: Config/Tools/Templates/cs-dotnet-bin/tables.sbn ================================================ using System; using GameFrameX.Core.Config; {{namespace_with_grace_begin __namespace}} public partial class {{__name}} { {{~for table in __tables ~}} {{~if table.comment != '' ~}} /// /// {{escape_comment table.comment}} /// {{~end~}} internal {{table.full_name}} {{format_property_name __code_style table.name}} { private set; get; } {{~end~}} private ConfigComponent m_ConfigComponent; public void Init(ConfigComponent configComponent) { m_ConfigComponent = configComponent; configComponent.RemoveAllConfigs(); } /// /// 是否加载完成 /// public bool IsLoaded { get; private set; } /// /// 异步加载配置文件 /// /// 加载器 public async System.Threading.Tasks.Task LoadAsync(System.Func> loader) { if (IsLoaded) { return; } IsLoaded = false; m_ConfigComponent.RemoveAllConfigs(); var loadTasks = new System.Collections.Generic.List(); {{~for table in __tables ~}} {{format_property_name __code_style table.name}} = new {{table.full_name}}(() => loader("{{table.output_data_file}}", true)); loadTasks.Add({{format_property_name __code_style table.name}}.LoadAsync()); m_ConfigComponent.Add(nameof({{table.full_name}}), {{format_property_name __code_style table.name}}); {{~end~}} await System.Threading.Tasks.Task.WhenAll(loadTasks); Refresh(); IsLoaded = true; } /// /// 设置本地化的适配器 /// /// 适配器对象 /// 如果未加载完成将抛出此异常 public void SetTranslateText(System.Func translator) { if (IsLoaded == false) { throw new InvalidOperationException("Table is not loaded!"); } {{~for table in __tables ~}} {{format_property_name __code_style table.name}}.TranslateText(translator); {{~end~}} } private void ResolveRef() { {{~for table in __tables ~}} {{format_property_name __code_style table.name}}.ResolveRef(this); {{~end~}} PostResolveRef(); } public void Refresh() { PostInit(); ResolveRef(); } partial void PostInit(); partial void PostResolveRef(); } {{namespace_with_grace_end __namespace}} ================================================ FILE: Config/Tools/Templates/cs-dotnet-json/bean.sbn ================================================ using System.Text.Json; using GameFrameX.Core.Config; {{ parent_def_type = __bean.parent_def_type export_fields = __bean.export_fields hierarchy_export_fields = __bean.hierarchy_export_fields }} {{namespace_with_grace_begin __namespace_with_top_module}} {{~if __bean.comment != '' ~}} /// /// {{escape_comment __bean.comment}} /// {{~end~}} {{~ func get_ref_name ret (format_property_name __code_style $0.name) + '_Ref' end func get_index_var_name ret (format_property_name __code_style $0.name) + '_Index' end func generate_resolve_field_ref field = $0 fieldName = format_property_name __code_style field.name refTable = get_ref_table field if can_generate_ref field tableName = format_property_name __code_style refTable.name if field.is_nullable ret (get_ref_name field) + ' = ' + fieldName + '!= null ? tables.' + tableName + '.Get(' + (get_value_of_nullable_type field.ctype fieldName) + ') : null;' else ret (get_ref_name field) + ' = tables.' + tableName + '.Get(' + fieldName + ');' end else if can_generate_collection_ref field collection_ref_table = get_collection_ref_table field tableName = format_property_name __code_style collection_ref_table.name if field.ctype.type_name == 'list' || field.ctype.type_name == 'set' line1 = (get_ref_name field) + ' = new ' + (declaring_collection_ref_name field.ctype) + '();' + '\n' line2 = 'foreach (var _v in ' + fieldName + ') { ' + (get_ref_name field) + '.Add(tables.' + tableName + '.Get(_v)); }' + '\n' ret line1 + line2 else if field.ctype.type_name == 'array' line1 = (get_ref_name field) + ' = new ' + (declaring_type_name collection_ref_table.value_ttype) + '[' + fieldName + '.Length];' + '\n' line2 = 'for (int _i = 0; _i < ' + fieldName + '.Length; _i++) { ' + (get_ref_name field) + '[_i] = tables.' + tableName + '.Get(' + fieldName + '[_i]); }' + '\n' ret line1 + line2 else if field.ctype.type_name == 'map' line1 = (get_ref_name field) + ' = new ' + (declaring_collection_ref_name field.ctype) + '();' + '\n' line2 = 'foreach (var (_k,_v) in ' + fieldName + ') { ' + (get_ref_name field) + '.Add(_k, tables.' + tableName + '.Get(_v)); }' + '\n' ret line1 + line2 else ret '' end else if (is_field_bean_need_resolve_ref field) ret fieldName + '?.ResolveRef(tables);' else if (is_field_array_like_need_resolve_ref field) ret 'foreach (var _e in ' + fieldName + ') { _e?.ResolveRef(tables); }' else if (is_field_map_need_resolve_ref field) ret 'foreach (var _e in ' + fieldName + '.Values) { _e?.ResolveRef(tables); }' else ret '' end end end func get_param_def_list(bean) paramList = [] while bean tempList = bean.export_fields |array.each do; ret (declaring_type_name $0.ctype) + ' ' + (format_property_name __code_style $0.name); end paramList = tempList + paramList bean = bean.parent_def_type end ret array.join paramList ', ' end func get_param_name_list(bean) paramList = [] index = 0 while bean tempList = bean.export_fields |array.each do; ret (format_property_name __code_style $0.name); end paramList = tempList + paramList bean = bean.parent_def_type end ret array.join paramList ', ' end ~}} {{~if __bean.is_value_type~}} public partial struct {{__name}} {{~else~}} public {{class_modifier __bean}} partial class {{__name}} : {{if parent_def_type}}{{__bean.parent}}{{else}}BeanBase{{end}} {{~end~}} { /* public {{__name}}({{get_param_def_list(__bean)}}) {{if parent_def_type}} : base({{get_param_name_list(__bean.parent_def_type)}}) {{end}} { {{~ for field in export_fields fieldName = format_property_name __code_style field.name ~}} this.{{fieldName}} = {{fieldName}}; {{~if can_generate_ref field~}} this.{{get_ref_name field}} = null; {{~end~}} {{~if has_index field~}} this.{{get_index_var_name field}} = new {{declaring_type_name (get_index_map_type field)}}({{field.size}}); foreach(var _v in {{fieldName}}) { this.{{get_index_var_name field}}.Add(_v.{{format_property_name __code_style (get_index_field field).name}}, _v); } {{~end~}} {{~end~}} PostInit(); } */ public {{__name}}(JsonElement _buf) {{if parent_def_type}} : base(_buf) {{end}} { {{~ for field in export_fields fieldName = format_property_name __code_style field.name ~}} {{deserialize_field fieldName '_buf' field.name field.ctype}} {{~if can_generate_ref field~}} {{get_ref_name field}} = null; {{~end~}} {{~if has_index field~}} foreach(var _v in {{fieldName}}) { {{get_index_var_name field}}.Add(_v.{{format_property_name __code_style (get_index_field field).name}}, _v); } {{~end~}} {{~end~}} } public static {{__name}} Deserialize{{__name}}(JsonElement _buf) { {{~if __bean.is_abstract_type~}} switch (_buf.GetProperty("$type").GetString()) { {{~for child in __bean.hierarchy_not_abstract_children~}} case "{{impl_data_type child __bean}}": return new {{child.full_name}}(_buf); {{~end~}} default: throw new SerializationException(); } {{~else~}} return new {{__bean.full_name}}(_buf); {{~end~}} } {{~ for field in export_fields ~}} {{~if field.comment != '' ~}} /// /// {{escape_comment field.comment}} /// {{~end~}} public {{declaring_type_name field.ctype}} {{format_property_name __code_style field.name}} { private set; get; } {{~if can_generate_ref field~}} public {{declaring_type_name (get_ref_type field)}} {{get_ref_name field}} { private set; get; } {{~else if can_generate_collection_ref field~}} public {{declaring_collection_ref_name field.ctype}} {{get_ref_name field}} { private set; get; } {{~end~}} {{~if has_index field indexMapType = get_index_map_type field ~}} public {{declaring_type_name indexMapType}} {{get_index_var_name field}} { private set; get; } = new {{declaring_type_name indexMapType}}(); {{~end~}} {{~end~}} {{~if !__bean.is_abstract_type && !__bean.is_value_type~}} private const int __ID__ = {{__bean.id}}; public override int GetTypeId() => __ID__; {{~end~}} public {{method_modifier __bean}} void ResolveRef({{__manager_name}} tables) { {{~if parent_def_type~}} base.ResolveRef(tables); {{~end~}} {{~for field in export_fields~}} {{generate_resolve_field_ref field}} {{~end~}} } public override string ToString() { return "{{full_name}}{ " {{~for field in hierarchy_export_fields ~}} + "{{format_field_name __code_style field.name}}:" + {{to_pretty_string (format_property_name __code_style field.name) field.ctype}} + "," {{~end~}} + "}"; } partial void PostInit(); } {{namespace_with_grace_end __namespace_with_top_module}} ================================================ FILE: Config/Tools/Templates/cs-dotnet-json/table.sbn ================================================ using System.Text.Json; using GameFrameX.Core.Config; {{ key_type = __table.key_ttype value_type = __table.value_ttype func index_type_name ret (declaring_type_name $0.type) end func table_union_map_type_name ret 'System.Collections.Generic.Dictionary<(' + (array.each __table.index_list @index_type_name | array.join ', ') + '), ' + (declaring_type_name value_type) + '>' end func table_key_list varName = $0 indexList = __table.index_list |array.each do; ret varName + '.' + (format_property_name __code_style $0.index_field.name); end; ret array.join indexList ', ' end func table_param_def_list paramList = __table.index_list |array.each do; ret (declaring_type_name $0.type) + ' ' + $0.index_field.name; end ret array.join paramList ', ' end func table_param_name_list paramList = __table.index_list |array.each do; ret $0.index_field.name; end ret array.join paramList ', ' end func table_param_type_list paramList = __table.index_list |array.each do; ret (declaring_type_name $0.type); end ret array.join paramList ', ' end }} {{namespace_with_grace_begin __namespace_with_top_module}} {{~if __table.comment != '' ~}} /// /// {{escape_comment __table.comment}} /// {{~end~}} public partial class {{__name}} : BaseDataTable<{{declaring_type_name value_type}}> { {{~if __table.is_map_table ~}} //private readonly System.Collections.Generic.Dictionary<{{declaring_type_name key_type}}, {{declaring_type_name value_type}}> _dataMap; //private readonly System.Collections.Generic.List<{{declaring_type_name value_type}}> _dataList; //public System.Collections.Generic.Dictionary<{{declaring_type_name key_type}}, {{declaring_type_name value_type}}> DataMap => _dataMap; //public System.Collections.Generic.List<{{declaring_type_name value_type}}> DataList => _dataList; {{~if value_type.is_dynamic~}} //public T GetOrDefaultAs({{declaring_type_name key_type}} key) where T : {{declaring_type_name value_type}} => _dataMap.TryGetValue(key, out var v) ? (T)v : null; //public T GetAs({{declaring_type_name key_type}} key) where T : {{declaring_type_name value_type}} => (T)_dataMap[key]; {{~end~}} //public {{declaring_type_name value_type}} GetOrDefault({{declaring_type_name key_type}} key) => _dataMap.TryGetValue(key, out var v) ? v : null; //public {{declaring_type_name value_type}} Get({{declaring_type_name key_type}} key) => _dataMap[key]; //public {{declaring_type_name value_type}} this[{{declaring_type_name key_type}} key] => _dataMap[key]; public override async System.Threading.Tasks.Task LoadAsync() { var jsonElement = await _loadFunc(); DataList.Clear(); LongDataMaps.Clear(); StringDataMaps.Clear(); foreach(var element in jsonElement.EnumerateArray()) { {{declaring_type_name __value_type}} _v; {{deserialize '_v' 'element' __value_type}} DataList.Add(_v); {{~if __key_type.type_name != 'string' ~}} LongDataMaps.Add(_v.{{format_property_name __code_style __table.index_field.name}}, _v); {{~end~}} StringDataMaps.Add(_v.{{format_property_name __code_style __table.index_field.name}}.ToString(), _v); } PostInit(); } public void ResolveRef({{__manager_name}} tables) { foreach(var element in DataList) { element.ResolveRef(tables); } } {{~else if __table.is_list_table ~}} //private readonly System.Collections.Generic.List<{{declaring_type_name value_type}}> _dataList; {{~if __table.is_union_index~}} private {{table_union_map_type_name}} _dataMapUnion; {{~else if !__table.index_list.empty?~}} {{~for idx in __table.index_list~}} private System.Collections.Generic.Dictionary<{{declaring_type_name idx.type}}, {{declaring_type_name value_type}}> _dataMap_{{idx.index_field.name}}; {{~end~}} {{~end~}} //public System.Collections.Generic.List<{{declaring_type_name value_type}}> DataList => _dataList; {{~if __table.is_union_index~}} public {{declaring_type_name value_type}} Get({{table_param_def_list}}) => _dataMapUnion.TryGetValue(({{table_param_name_list}}), out {{declaring_type_name value_type}} __v) ? __v : null; {{~else if !__table.index_list.empty? ~}} {{~for idx in __table.index_list~}} public {{declaring_type_name value_type}} GetBy{{format_property_name __code_style idx.index_field.name}}({{declaring_type_name idx.type}} key) => _dataMap_{{idx.index_field.name}}.TryGetValue(key, out {{declaring_type_name value_type}} __v) ? __v : null; {{~end~}} {{~end~}} public override async System.Threading.Tasks.Task LoadAsync() { var jsonElement = await _loadFunc(); DataList.Clear(); LongDataMaps.Clear(); StringDataMaps.Clear(); foreach(var element in jsonElement.EnumerateArray()) { {{declaring_type_name __value_type}} _v; {{deserialize '_v' 'element' __value_type}} DataList.Add(_v); } {{~if __table.is_union_index~}} _dataMapUnion = new {{table_union_map_type_name}}(); _dataMapUnion.Clear(); foreach(var element in DataList) { _dataMapUnion.Add(({{table_key_list "element"}}), element); } {{~else if !__table.index_list.empty?~}} {{~for idx in __table.index_list~}} _dataMap_{{idx.index_field.name}} = new System.Collections.Generic.Dictionary<{{declaring_type_name idx.type}}, {{declaring_type_name __value_type}}>(); {{~end~}} {{~for idx in __table.index_list~}} _dataMap_{{idx.index_field.name}}.Clear(); {{~end~}} foreach(var element in DataList) { {{~for idx in __table.index_list~}} _dataMap_{{idx.index_field.name}}.Add(element.{{format_property_name __code_style idx.index_field.name}}, element); {{~end~}} } {{~end~}} PostInit(); } public void ResolveRef({{__manager_name}} tables) { foreach(var element in DataList) { element.ResolveRef(tables); } } {{~else~}} private {{declaring_type_name value_type}} _data; public {{declaring_type_name value_type}} Data => _data; {{~ for field in value_type.def_bean.hierarchy_export_fields ~}} {{~if field.comment != '' ~}} /// /// {{escape_comment field.comment}} /// {{~end~}} public {{declaring_type_name field.ctype}} {{format_property_name __code_style field.name}} => _data.{{format_property_name __code_style field.name}}; {{~end~}} public override async Task LoadAsync() { var jsonElement = await _loadFunc(); int n = jsonElement.GetArrayLength(); if (n != 1) throw new SerializationException("table mode=one, but size != 1"); {{deserialize '_data' 'jsonElement[0]' __value_type}} } public void ResolveRef({{__manager_name}} tables) { _data.ResolveRef(tables); } {{~end~}} partial void PostInit(); public {{__name}}(Func> loadFunc) : base(loadFunc) { } } {{namespace_with_grace_end __namespace_with_top_module}} ================================================ FILE: Config/Tools/Templates/cs-dotnet-json/tables.sbn ================================================ using System.Text.Json; using GameFrameX.Core.Config; using GameFrameX.Config; {{namespace_with_grace_begin __namespace}} public partial class {{__name}} { {{~for table in __tables ~}} {{~if table.comment != '' ~}} /// /// {{escape_comment table.comment}} /// {{~end~}} internal {{table.full_name}} {{format_property_name __code_style table.name}} { private set; get; } {{~end~}} private ConfigComponent m_ConfigComponent; public void Init(ConfigComponent configComponent) { m_ConfigComponent = configComponent; configComponent.RemoveAllConfigs(); } public async System.Threading.Tasks.Task LoadAsync(System.Func> loader) { //m_ConfigComponent.RemoveAllConfigs(); var loadTasks = new System.Collections.Generic.List(); {{~for table in __tables ~}} {{format_property_name __code_style table.name}} = new {{table.full_name}}(() => loader("{{table.output_data_file}}")); loadTasks.Add({{format_property_name __code_style table.name}}.LoadAsync()); m_ConfigComponent.Add(nameof({{table.full_name}}), {{format_property_name __code_style table.name}}); {{~end~}} await System.Threading.Tasks.Task.WhenAll(loadTasks); Refresh(); } public {{__name}}() { //TablesMemory.BeginRecord(); {{~for table in __tables ~}} // {{format_property_name __code_style table.name}} = new {{table.full_name}}(); {{~end~}} //TablesMemory.EndRecord(); } public void Refresh() { PostInit(); ResolveRef(); } private void ResolveRef() { {{~for table in __tables ~}} {{format_property_name __code_style table.name}}.ResolveRef(this); {{~end~}} } partial void PostInit(); } {{namespace_with_grace_end __namespace}} ================================================ FILE: Config/Tools/Templates/cs-simple-json/bean.sbn ================================================ using LuBan.Runtime; using GameFrameX.Config; using SimpleJSON; {{ parent_def_type = __bean.parent_def_type export_fields = __bean.export_fields hierarchy_export_fields = __bean.hierarchy_export_fields }} {{namespace_with_grace_begin __namespace_with_top_module}} {{~if __bean.comment != '' ~}} /// /// {{escape_comment __bean.comment}} /// {{~end~}} {{~ func get_ref_name ret (format_property_name __code_style $0.name) + '_Ref' end func get_index_var_name ret (format_property_name __code_style $0.name) + '_Index' end func generate_resolve_field_ref field = $0 fieldName = format_property_name __code_style field.name refTable = get_ref_table field if can_generate_ref field tableName = format_property_name __code_style refTable.name if field.is_nullable ret (get_ref_name field) + ' = ' + fieldName + '!= null ? tables.' + tableName + '.Get(' + (get_value_of_nullable_type field.ctype fieldName) + ') : null;' else ret (get_ref_name field) + ' = tables.' + tableName + '.Get(' + fieldName + ');' end else if can_generate_collection_ref field collection_ref_table = get_collection_ref_table field tableName = format_property_name __code_style collection_ref_table.name if field.ctype.type_name == 'list' || field.ctype.type_name == 'set' line1 = (get_ref_name field) + ' = new ' + (declaring_collection_ref_name field.ctype) + '();' + '\n' line2 = 'foreach (var _v in ' + fieldName + ') ' + '\n{\n' line3 = '\t' + (get_ref_name field) + '.Add(tables.' + tableName + '.Get(_v)); ' line3 = line3 + '\n' + '}' + '\n' ret line1 + line2 + line3 else if field.ctype.type_name == 'array' line1 = (get_ref_name field) + ' = new ' + (declaring_type_name collection_ref_table.value_ttype) + '[' + fieldName + '.Length];' + '\n' line2 = 'for (int _i = 0; _i < ' + fieldName + '.Length; _i++) { ' + (get_ref_name field) + '[_i] = tables.' + tableName + '.Get(' + fieldName + '[_i]); }' + '\n' ret line1 + line2 else if field.ctype.type_name == 'map' line1 = (get_ref_name field) + ' = new ' + (declaring_collection_ref_name field.ctype) + '();' + '\n' line2 = 'foreach (var _kv in ' + fieldName + ') { ' + '\n' line3 = ' ' + (get_ref_name field) + '.Add(_kv.Key, tables.' + tableName + '.Get(_kv.Value));' + '\n' line3 = line3 + '}' + '\n' ret line1 + line2 + line3 else ret '' end else if (is_field_bean_need_resolve_ref field) ret fieldName + '?.ResolveRef(tables);' else if (is_field_array_like_need_resolve_ref field) ret 'foreach (var _e in ' + fieldName + ') \n{\n \t_e?.ResolveRef(tables);\n}' else if (is_field_map_need_resolve_ref field) ret 'foreach (var _e in ' + fieldName + '.Values) \n{\n \t_e?.ResolveRef(tables);\n}' else ret '' end end end func get_param_def_list(bean) paramList = [] while bean tempList = bean.export_fields |array.each do; ret (declaring_type_name $0.ctype) + ' ' + (format_property_name __code_style $0.name); end paramList = tempList + paramList bean = bean.parent_def_type end ret array.join paramList ', ' end func get_param_name_list(bean) paramList = [] index = 0 while bean tempList = bean.export_fields |array.each do; ret (format_property_name __code_style $0.name); end paramList = tempList + paramList bean = bean.parent_def_type end ret array.join paramList ', ' end ~}} {{~if __bean.is_value_type~}} public partial struct {{__name}} {{~else~}} public {{class_modifier __bean}} partial class {{__name}} : {{if parent_def_type}}{{__bean.parent}}{{else}}LuBan.Runtime.BeanBase{{end}} {{~end~}} { public {{__name}}({{get_param_def_list(__bean)}}) {{if parent_def_type}} : base({{get_param_name_list(__bean.parent_def_type)}}) {{end}} { {{~ for field in export_fields fieldName = format_property_name __code_style field.name ~}} this.{{fieldName}} = {{fieldName}}; {{~if can_generate_ref field~}} this.{{get_ref_name field}} = null; {{~end~}} {{~if has_index field~}} this.{{get_index_var_name field}} = new {{declaring_type_name (get_index_map_type field)}}({{field.size}}); foreach(var _v in {{fieldName}}) { this.{{get_index_var_name field}}.Add(_v.{{format_property_name __code_style (get_index_field field).name}}, _v); } {{~end~}} {{~end~}} PostInit(); } public {{__name}}(JSONNode _buf){{if parent_def_type}} : base(_buf) {{end}} { {{~ for field in export_fields fieldName = format_property_name __code_style field.name ~}} {{deserialize_field fieldName '_buf' field.name field.ctype}} {{~if can_generate_ref field~}} {{get_ref_name field}} = null; {{~end~}} {{~if has_index field~}} foreach(var _v in {{fieldName}}) { {{get_index_var_name field}}.Add(_v.{{format_property_name __code_style (get_index_field field).name}}, _v); } {{~end~}} {{~end~}} // Localization Key Begin {{~ for field in export_fields ~}} {{~if field.type =='text'~}} {{format_property_name __code_style field.name}}_Localization_Key = {{format_property_name __code_style field.name}}; {{~end~}} {{~end~}} // Localization Key End PostInit(); } public static {{__name}} Deserialize{{__name}}(JSONNode _buf) { {{~if __bean.is_abstract_type~}} switch ((string)_buf["$type"]) { {{~for child in __bean.hierarchy_not_abstract_children~}} case "{{impl_data_type child __bean}}": return new {{child.full_name}}(_buf); {{~end~}} default: throw new SerializationException(); } {{~else~}} return new {{__bean.full_name}}(_buf); {{~end~}} } {{~ for field in export_fields ~}} {{~if field.comment != '' ~}} /// /// {{escape_comment field.comment}} /// {{~end~}} public {{declaring_type_name field.ctype}} {{format_property_name __code_style field.name}} { private set; get; } {{~if field.type =='text'~}} {{~if field.comment != '' ~}} /// /// {{escape_comment field.comment}} 的多语言Key /// {{~end~}} private readonly string {{format_property_name __code_style field.name}}_Localization_Key; {{~end~}} {{~if can_generate_ref field~}} public {{declaring_type_name (get_ref_type field)}} {{get_ref_name field}} { private set; get; } {{~else if can_generate_collection_ref field~}} public {{declaring_collection_ref_name field.ctype}} {{get_ref_name field}} { private set; get; } {{~end~}} {{~if has_index field indexMapType = get_index_map_type field ~}} public readonly {{declaring_type_name indexMapType}} {{get_index_var_name field}} = new {{declaring_type_name indexMapType}}(); {{~end~}} {{~end~}} {{~if !__bean.is_abstract_type && !__bean.is_value_type~}} public const int __ID__ = {{__bean.id}}; public override int GetTypeId() => __ID__; {{~end~}} public {{method_modifier __bean}} void ResolveRef({{__manager_name}} tables) { {{~if parent_def_type~}} base.ResolveRef(tables); {{~end~}} {{~for field in export_fields~}} {{generate_resolve_field_ref field}} {{~end~}} } public void TranslateText(System.Func translator) { {{~if parent_def_type~}} base.TranslateText(translator); {{~end~}} {{~ for field in export_fields ~}} {{~if field.type =='text'~}} {{format_property_name __code_style field.name}} = translator({{format_property_name __code_style field.name}}_Localization_Key, {{format_property_name __code_style field.name}}); {{~end~}} {{~end~}} } public override string ToString() { return "{{full_name}}{ " {{~for field in hierarchy_export_fields ~}} + "{{format_field_name __code_style field.name}}:" + {{to_pretty_string (format_property_name __code_style field.name) field.ctype}} + "," {{~end~}} + "}"; } partial void PostInit(); } {{namespace_with_grace_end __namespace_with_top_module}} ================================================ FILE: Config/Tools/Templates/cs-simple-json/table.sbn ================================================ using LuBan.Runtime; using GameFrameX.Config.Runtime; using SimpleJSON; {{ func index_type_name ret (declaring_type_name $0.type) end func table_union_map_type_name ret 'System.Collections.Generic.Dictionary<(' + (array.each __table.index_list @index_type_name | array.join ', ') + '), ' + (declaring_type_name __value_type) + '>' end func table_key_list varName = $0 indexList = __table.index_list |array.each do; ret varName + '.' + (format_property_name __code_style $0.index_field.name); end; ret array.join indexList ', ' end func table_param_def_list paramList = __table.index_list |array.each do; ret (declaring_type_name $0.type) + ' ' + $0.index_field.name; end ret array.join paramList ', ' end func table_param_name_list paramList = __table.index_list |array.each do; ret $0.index_field.name; end ret array.join paramList ', ' end }} {{namespace_with_grace_begin __namespace_with_top_module}} {{~if __table.comment != '' ~}} /// /// {{escape_comment __table.comment}} /// {{~end~}} public partial class {{__name}} : BaseDataTable<{{declaring_type_name __value_type}}> { {{~if __table.is_map_table ~}} private readonly System.Func> _loadFunc; public {{__name}}(System.Func> loadFunc) { _loadFunc = loadFunc; } public override async System.Threading.Tasks.Task LoadAsync() { var jsonNode = await _loadFunc(); StringDataMaps.Clear(); DataList.Clear(); foreach(var _ele in jsonNode.Children) { {{declaring_type_name __value_type}} _v; {{deserialize '_v' '_ele' __value_type}} DataList.Add(_v); {{~if __key_type.type_name != 'string' ~}} LongDataMaps.Add(_v.{{format_property_name __code_style __table.index_field.name}}, _v); {{~end~}} StringDataMaps.Add(_v.{{format_property_name __code_style __table.index_field.name}}.ToString(), _v); } PostInit(); } {{~if __value_type.is_dynamic~}} //public T GetOrDefaultAs({{declaring_type_name __key_type}} key) where T : {{declaring_type_name __value_type}} => _dataMap.TryGetValue(key, out var v) ? (T)v : null; //public T GetAs({{declaring_type_name __key_type}} key) where T : {{declaring_type_name __value_type}} => (T)_dataMap[key]; {{~end~}} public void ResolveRef({{__manager_name}} tables) { foreach(var value in DataList) { value.ResolveRef(tables); } } public void TranslateText(System.Func translator) { foreach(var v in DataList) { v.TranslateText(translator); } } {{~else if __table.is_list_table ~}} {{~if __table.is_union_index~}} private {{table_union_map_type_name}} _dataMapUnion; {{~else if !__table.index_list.empty?~}} {{~for idx in __table.index_list~}} private System.Collections.Generic.Dictionary<{{declaring_type_name idx.type}}, {{declaring_type_name __value_type}}> _dataMap_{{idx.index_field.name}}; {{~end~}} {{~end~}} private readonly System.Func> _loadFunc; public {{__name}}(System.Func> loadFunc) { _loadFunc = loadFunc; {{~if __table.is_union_index~}} _dataMapUnion = new {{table_union_map_type_name}}(); {{~else if !__table.index_list.empty?~}} {{~for idx in __table.index_list~}} _dataMap_{{idx.index_field.name}} = new System.Collections.Generic.Dictionary<{{declaring_type_name idx.type}}, {{declaring_type_name __value_type}}>(); {{~end~}} {{~end~}} } public override async System.Threading.Tasks.Task LoadAsync() { JSONNode _json = await _loadFunc(); DataList.Clear(); foreach(var _ele in _json.Children) { {{declaring_type_name __value_type}} _v; {{deserialize '_v' '_ele' __value_type}} DataList.Add(_v); } {{~if __table.is_union_index~}} _dataMapUnion.Clear(); foreach(var _v in DataList) { _dataMapUnion.Add(({{table_key_list "_v"}}), _v); } {{~else if !__table.index_list.empty?~}} {{~for idx in __table.index_list~}} _dataMap_{{idx.index_field.name}}.Clear(); {{~end~}} foreach(var _v in DataList) { {{~for idx in __table.index_list~}} _dataMap_{{idx.index_field.name}}.Add(_v.{{format_property_name __code_style idx.index_field.name}}, _v); {{~end~}} } {{~end~}} PostInit(); } //public System.Collections.Generic.List<{{declaring_type_name __value_type}}> DataList => DataList; {{~if __table.is_union_index~}} public {{declaring_type_name __value_type}} Get({{table_param_def_list}}) => _dataMapUnion.TryGetValue(({{table_param_name_list}}), out {{declaring_type_name __value_type}} __v) ? __v : null; {{~else if !__table.index_list.empty? ~}} {{~for idx in __table.index_list~}} public {{declaring_type_name __value_type}} GetBy{{format_property_name __code_style idx.index_field.name}}({{declaring_type_name idx.type}} key) => _dataMap_{{idx.index_field.name}}.TryGetValue(key, out {{declaring_type_name __value_type}} __v) ? __v : null; {{~end~}} {{~end~}} public void ResolveRef({{__manager_name}} tables) { foreach(var _v in DataList) { _v.ResolveRef(tables); } } public void TranslateText(System.Func translator) { foreach(var v in DataList) { v.TranslateText(translator); } } {{~else~}} private {{declaring_type_name __value_type}} _data; public {{declaring_type_name __value_type}} Data => _data; private readonly System.Func> _loadFunc; public {{__name}}(System.Func> loadFunc) { _loadFunc = loadFunc; } public override async System.Threading.Tasks.Task LoadAsync() { JSONNode _json = await _loadFunc(); int n = _json.Count; if (n != 1) throw new SerializationException("table mode=one, but size != 1"); {{deserialize '_data' '_json[0]' __value_type}} } {{~ for field in __value_type.def_bean.hierarchy_export_fields ~}} {{~if field.comment != '' ~}} /// /// {{escape_comment field.comment}} /// {{~end~}} public {{declaring_type_name field.ctype}} {{format_property_name __code_style field.name}} => _data.{{format_property_name __code_style field.name}}; {{~end~}} public void ResolveRef({{__manager_name}} tables) { _data.ResolveRef(tables); } public void TranslateText(System.Func translator) { _data.TranslateText(translator); } {{~end~}} partial void PostInit(); } {{namespace_with_grace_end __namespace_with_top_module}} ================================================ FILE: Config/Tools/Templates/cs-simple-json/tables.sbn ================================================ using System; using LuBan.Runtime; using GameFrameX.Config.Runtime; using SimpleJSON; {{namespace_with_grace_begin __namespace}} public partial class {{__name}} { {{~for table in __tables ~}} {{~if table.comment != '' ~}} /// /// {{escape_comment table.comment}} /// {{~end~}} internal {{table.full_name}} {{format_property_name __code_style table.name}} { private set; get; } {{~end~}} private ConfigComponent m_ConfigComponent; public void Init(ConfigComponent configComponent) { m_ConfigComponent = configComponent; configComponent.RemoveAllConfigs(); } /// /// 是否加载完成 /// public bool IsLoaded { get; private set; } /// /// 异步加载配置文件 /// /// 加载器 public async System.Threading.Tasks.Task LoadAsync(System.Func> loader) { if (IsLoaded) { return; } IsLoaded = false; m_ConfigComponent.RemoveAllConfigs(); var loadTasks = new System.Collections.Generic.List(); {{~for table in __tables ~}} {{format_property_name __code_style table.name}} = new {{table.full_name}}(() => loader("{{table.output_data_file}}")); loadTasks.Add({{format_property_name __code_style table.name}}.LoadAsync()); m_ConfigComponent.Add(nameof({{table.full_name}}), {{format_property_name __code_style table.name}}); {{~end~}} await System.Threading.Tasks.Task.WhenAll(loadTasks); Refresh(); IsLoaded = true; } /// /// 设置本地化的适配器 /// /// 适配器对象 /// 如果未加载完成将抛出此异常 public void SetTranslateText(System.Func translator) { if (IsLoaded == false) { throw new InvalidOperationException("Table is not loaded!"); } {{~for table in __tables ~}} {{format_property_name __code_style table.name}}.TranslateText(translator); {{~end~}} } private void ResolveRef() { {{~for table in __tables ~}} {{format_property_name __code_style table.name}}.ResolveRef(this); {{~end~}} } public void Refresh() { PostInit(); ResolveRef(); } partial void PostInit(); } {{namespace_with_grace_end __namespace}} ================================================ FILE: Config/Tools/nlog.xml ================================================ ================================================ FILE: Config/gen-client-bin.bat ================================================ dotnet.exe ./Tools/Luban.dll --target client --dataTarget bin --codeTarget cs-bin --xargs outputDataDir=../Unity/Assets//Bundles/Config --xargs outputCodeDir=../Unity/Assets//Hotfix/Config/Generate --xargs tableImporter.name=gameframex -x l10n.provider=gameframex -x l10n.textFile.keyFieldName=key -x l10n.textFile.path=./Excels/Local/ --conf ./Luban.conf pause ================================================ FILE: Config/gen-client-bin.sh ================================================ dotnet ./Tools/Luban.dll --target client --dataTarget bin --codeTarget cs-bin --xargs outputDataDir=../Unity/Assets//Bundles/Config --xargs outputCodeDir=../Unity/Assets//Hotfix/Config/Generate --xargs tableImporter.name=gameframex -x l10n.provider=gameframex -x l10n.textFile.keyFieldName=key -x l10n.textFile.path=./Excels/Local/ --conf ./Luban.conf pause ================================================ FILE: Config/gen-client-json.bat ================================================ dotnet.exe ./Tools/Luban.dll --target client --dataTarget json --codeTarget cs-simple-json --xargs outputDataDir=../Unity/Assets//Bundles/Config --xargs outputCodeDir=../Unity/Assets//Hotfix/Config/Generate --xargs tableImporter.name=gameframex -x l10n.provider=gameframex -x l10n.textFile.keyFieldName=key -x l10n.textFile.path=./Excels/Local/ --conf ./Luban.conf pause ================================================ FILE: Config/gen-client-json.sh ================================================ dotnet ./Tools/Luban.dll --target client --dataTarget json --codeTarget cs-simple-json --xargs outputDataDir=../Unity/Assets//Bundles/Config --xargs outputCodeDir=../Unity/Assets//Hotfix/Config/Generate --xargs tableImporter.name=gameframex -x l10n.provider=gameframex -x l10n.textFile.keyFieldName=key -x l10n.textFile.path=./Excels/Local/ --conf ./Luban.conf pause ================================================ FILE: Config/gen-server-bin.bat ================================================ dotnet.exe ./Tools/Luban.dll --target server --dataTarget bin --codeTarget cs-dotnet-bin --xargs outputDataDir=../Server/GameFrameX.Config/Json --xargs tableImporter.name=gameframex --xargs outputCodeDir=../Server/GameFrameX.Config/Config --conf ./Luban.conf pause ================================================ FILE: Config/gen-server-bin.sh ================================================ dotnet ./Tools/Luban.dll --target server --dataTarget bin --codeTarget cs-dotnet-bin --xargs outputDataDir=../Server/GameFrameX.Config/Json --xargs tableImporter.name=gameframex --xargs outputCodeDir=../Server/GameFrameX.Config/Config --conf ./Luban.conf pause ================================================ FILE: Config/gen-server-json.bat ================================================ dotnet.exe ./Tools/Luban.dll --target server --dataTarget json --codeTarget cs-dotnet-json --xargs outputDataDir=../Server/GameFrameX.Config/Json --xargs tableImporter.name=gameframex --xargs outputCodeDir=../Server/GameFrameX.Config/Config --conf ./Luban.conf pause ================================================ FILE: Config/gen-server-json.sh ================================================ dotnet ./Tools/Luban.dll --target server --dataTarget json --codeTarget cs-dotnet-json --xargs outputDataDir=../Server/GameFrameX.Config/Json --xargs tableImporter.name=gameframex --xargs outputCodeDir=../Server/GameFrameX.Config/Config --conf ./Luban.conf pause ================================================ FILE: Config/luban.conf ================================================ { "groups": [ { "names": [ "c" ], "default": true }, { "names": [ "s" ], "default": true } ], "schemaFiles": [ { "fileName": "Defines", "type": "" }, { "fileName": "Excels/__tables__.xlsx", "type": "table" }, { "fileName": "Excels/__beans__.xlsx", "type": "bean" }, { "fileName": "Excels/__enums__.xlsx", "type": "enum" } ], "dataDir": "Excels", "targets": [ { "name": "server", "manager": "TablesComponent", "groups": [ "s" ], "topModule": "GameFrameX.Config" }, { "name": "client", "manager": "TablesComponent", "groups": [ "c" ], "topModule": "Hotfix.Config" }, { "name": "all", "manager": "Tables", "groups": [ "c", "s" ], "topModule": "cfg" } ], "description": "描述备注: toolPath: LuBan 工具目录, UNITY_ASSETS_PATH: Unity Assets 全路径, SERVER_PATH: 服务器全目录, commands: 需要执行的命令列表", "toolPath": "/../Config/Tools/Luban.dll", "UNITY_ASSETS_PATH": "", "SERVER_PATH": "", "commands": [ { "command": "--target server --dataTarget json --codeTarget cs-dotnet-json --xargs outputDataDir=%SERVER_PATH%/Server.Config/Json --xargs outputCodeDir=%SERVER_PATH%/Server.Config/Config", "target": "server", "active": true }, { "localizationFileName": "Localization.xlsx", "command": "--target client --dataTarget json --codeTarget cs-simple-json --xargs outputDataDir=%UNITY_ASSETS_PATH%/Bundles/Config --xargs outputCodeDir=%UNITY_ASSETS_PATH%/Hotfix/Config/Generate ", "target": "client", "active": true }, { "command": "--target server --dataTarget bin --codeTarget cs-bin --validationFailAsError true --xargs outputDataDir=%SERVER_PATH%/Server.Config/Json --xargs outputCodeDir=%SERVER_PATH%/Server.Config/Config", "target": "server", "active": false }, { "localizationFileName": "Localization.xlsx", "command": "--target client --dataTarget bin --codeTarget cs-bin --validationFailAsError true --xargs outputDataDir=%UNITY_ASSETS_PATH%/Bundles/Config --xargs outputCodeDir=%UNITY_ASSETS_PATH%/Hotfix/Config/Generate", "target": "client", "active": false }, { "command": "luban", "target": "all", "active": false } ] } ================================================ FILE: Docs/1.Actor模型.md ================================================ ## Actor模型 ## actor模型是什么可以自行查阅一下相关资料;actor模型在一定程度可以说是解决并发的最佳方案。 GeekServer的actor可以简单理解为一个线程(其实用的是线程池),一个actor的逻辑只需保证在自己的队列里面执行即保证可线程安全,无需关心锁的问题。GeekServer的基础就是actor,一切皆可为actor。GeekServer的actor模型构建于强大的TPL DataFlow之上,底层使用内置线程池。GeekServer同时使用异步变成(async/await),让逻辑代码更加清晰明了,符合人类的思维方式。 ## Actor死锁 ## Actor模型本身是存在死锁的情况,且不容易被发现。GeekServer内部可检测环路死锁(即:A->B->C->A),并采用调用链重入机制消除环路死锁(类似与线程的可重入性)。 还有另外一种情况(多路死锁),比如有2个actor,A和B,一段逻辑A调用B,同时有另外一段逻辑发起了B调用A,就会出现A等B,B再等A,此时发生死锁。同理 [A->B->C,C->D->A] [A->B->C,B->C->A],这样的调用路径都可能会存在死锁。 这种死锁无法解决,而且不确定,因为它和调用时间节点有关系,只能从设计上去规避。 ```csharp class ActorA { Task A1() { await Task.Delay(10); var b = GetActorB(); return b.SendAsync(b.B1); } Task A2() { var b = GetActorB(); return b.SendAsync(b.B1); } } class ActorB { Task B1() { await Task.Delay(5); var a = GetActorA(); return a.SendAsync(a.A2); } } Task Call() { var a = GetActorA(); return a.SendAsync(a.A1);//这里就会触发死锁 } ``` 如果得到打印日志【执行超时】很有可能就是触发了死锁。由于Actor设定了超时时间,在断点调试的时候需要手动将超时时间改长,默认10秒,在BaseActor.TIME_OUT修改。**(或者用一个Debug模式的宏来控制)** ## 多路死锁解决方案 ## 由以上的分析可以看出,多路死锁其实是由于**Await**引起的,如果所有调用都不Await则永远不会有死锁。 这里为大家罗列了几种解决方案:(在GeekServer中可以通过ActorLimit来定制自己的检测规则) 1. **跨Actor调用,不能Await** 优点:规则简单,统一,绝对不会发生死锁 缺点:失去了异步语法的优势,所有需要跨Actor获取返回值的,只能使用回调,代码结构散乱,书写代码不方便。 2. **为Actor分配等级,只允许低等级await调用高等级(如:Role->Server 而Server不能等待调用Role, 推荐使用此方案)** 案例:公民可以去政府部门排队等待办理业务员,但是政府部门不可能去等待某个人去处理完自己的私事,再帮下一个人办理业务,顶多发短信或者打电话通知某个人做什么事情。 在方案1的基础上,给了使用者更多的异步调用空间。 3. **提供一个注册接口,注册哪些Actor可以Await调用哪些Actor,并在注册时候进行检测看是否可能存在死锁** 这是方案2的一个更加灵活的变种。 4. **允许交错执行** [了解更多](https://blog.csdn.net/uddiqpl/article/details/86294520) 如果你的某个组件不会操作数据或者对操作顺序不敏感,交错执行是很有用的。GeekServer中的FuncComponent比较符合这个特点,但不绝对,仍需要开发人员自行判断。 (Orleans中有此方案) 5. **允许存在多路死锁的风险,由开发人员保证不会触发死锁** 优点:规则简单,统一,书写代码很方便,全程异步。 缺点:有可能发生死锁,对编码人员能力要求较高 6. **超时规则** 如果发生多路死锁,选择一条调用路径并终止,保证其中一条调用路径正确。(Orleans中有此方案) 优缺点和方案5一样。 7. **使用线程安全容器以及lock等** 但这与无锁化设计的理念冲突 ================================================ FILE: Docs/2.Actor&Component&State.md ================================================ # Entity和Component和State GeekServer的Entity包含1个/多个Component,Component包含0个/1个State,你可以这样理解:Entity=实体,Component=功能系统,State=功能系统的数据。每个Entity都包含一个Actor成员变量,Entity的所有行为调度都有Actor完成,以保证线程安全。 Entity是GeekServer的基础,一切功能都可以作为单独的Entity(比如一个角色,一个公会,一个玩法系统。。。),Component隶属于Entity,State隶属于Component,Component承载各种逻辑,State承载各种数据。Entity拆分方式根据项目的具体需求可以任意规划。 ### Entity(Actor)拆分 1. 尽可能独立(一个系统或者玩家的操作尽量不阻塞其他玩家的操作) 2. 在独立的前提下尽可能少(节约管理成本) 3. 一个角色,包含若干个功能系统(背包,宠物,任务。。。) 4. 一个公会,包含多个公会基础系统(基础信息,捐赠,工会副本。。。) 比如有2个全局玩法,世界boss和工会战,如果这2个系统归于一个Actor,那么当一个玩家挑战世界boss时,挑战逻辑到Actor线程中执行,此时另一个玩家要去报名工会战,报名逻辑也需要到Actor线程中执行,此时报名公会战的逻辑则需要等待前一个玩家挑战世界boss逻辑完成后才能执行,客户端表现可能就是更长时间的网络连接中,在cpu够用的情况下就产生了多余的等待时间,这就有些不合理了;这种功能之间没有任何交集的情况下我们建议将世界boss和工会战分别拆分为Actor,各自的逻辑便可以更加顺畅的执行,客户端等待的时间也越短。 ### State(对象数据库) GeekServer支持内嵌模式和MongoDB直连模式,其中内嵌数据库目前为Facebook的RocksDB,读写性能都相当强悍。 可以通过app_config.json中 "DBModel"(0:内嵌 1:mongodb)来指定,默认是使用的内嵌模式。 1.单服结构,**强烈推荐使用内嵌模式**,内嵌数据库没有任何读写压力,数据就在本地磁盘,不受网络因素影响。同时由Geek.Server.RemoteBackup进程来异步远程备份,保证数据的安全。 2.Geek.Server.RemoteBackup 启动后会定期扫描,数据库根目录下的数据库文件,异步同步到远程mongodb。由于此进程和游戏逻辑没有仍和关联,所以此进程是可以随时重启的,即便进程崩溃也不会丢失数据,极大的提高了容错性。 3.不管哪种模式,数据库中存放的数据都是经过Messagepack序列化之后的二进制数据,需要使用Tools/GeekDB.GUI来浏览数据 GeekDB.GUI ![](https://github.com/leeveel/GeekServer/blob/main/Docs/imgs/geekdb.png) ================================================ FILE: Docs/Actor入队.md ================================================ ## Actor入队透明 ## GeekServer编译期间会自动注入入队代码(**AgentWeaver**), 开发人员无需入队逻辑, 只需要像调用普通函数一样书写逻辑。 ```c# //编译期间会注入一个继承自xxxCompAgent的wrapper类,来实现自动入队 //同时SendAsync内部自动处理了线程上下文,开发者只需要像调用普通函数一样书写逻辑 public class ServerCompAgentWrapper : ServerCompAgent { public override Task CheckCrossDay() { return base.Actor.SendAsync((Func)base.CheckCrossDay, isAwait: false, 10000); } public override Task GetDaysFromOpenServer() { return base.Actor.SendAsync((Func>)base.GetDaysFromOpenServer, isAwait: true, 10000); } } var serverComp = await EntityMgr.GetCompAgent(ActorType.Server); //使用方式(就像调用普通函数一样,无需关心多线程或入队) _ = serverComp.CheckCrossDay(); ``` ## 线程上下文 ## GeekServer内部会自动处理线程上下文,由RuntimeContext实现,主要用于环路调用检测,以及判断是否需要入队,其内部使用**AsyncLocal**实现 ```c# internal class RuntimeContext { internal static long Current => callCtx.Value; internal static AsyncLocal callCtx = new AsyncLocal(); [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static void SetContext(long callChainId) { callCtx.Value = callChainId; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static void ResetContext() { callCtx.Value = 0; } } ``` ================================================ FILE: Docs/事件Event-timer.md ================================================ # 事件 GeekServer根据热更新设计方案,事件采用接口方式进行监听和回调。监听或者回调事件方法,自定义类型继承EventListener,实现InitListener初始化监听,实现HandleEvent进行回调处理。需要注意的是,EventListener的泛型参数需要是添加事件的Entity对应的Agent,否则会出现类型转换失败。 ```csharp class RoleEH : EventListener { protected override async Task HandleEvent(RoleCompAgent agent, Event evt) { switch (evt.EventId) { case (int)EventID.OnDisconnected: await agent.OnDisconnected(); break; case (int)EventID.OnMsgReceived: await agent.OnMsgReceived(); break; } } public override Task InitListener(long entityId) { GED.AddListener(entityId, EventID.OnDisconnected); GED.AddListener(entityId, EventID.OnMsgReceived); return Task.CompletedTask; } } ``` # Timer或Schedule ```csharp public override async Task Active() { await base.Active(); this.Schedule(ServerComp.CrossDayHour, 0); } class CorssDayTimerHandler : TimerHandler { protected override async Task HandleTimer(ServerCompAgent agent, Param param) { //排除时间精度问题,Quartz可能产生1,2毫秒误差 await Task.Delay(100); _ = agent.CheckCrossDay(); } } ``` ================================================ FILE: Docs/关于协议.md ================================================ # GeekProto ### 特点 基于MessagePack,序列化和反序列化效率极高,同时序列化之后的数据极小,数据传输效率很高。[MessagePack-CSharp](https://github.com/neuecc/MessagePack-CSharp) 【Super Fast Binary Serialization Library】 ### 定义方式 ```csharp /// /// 请求登录 /// [MessagePackObject(true)] public class ReqLogin : Message { public string UserName { get; set; } public string Platform { get; set; } public int SdkType { get; set; } public string SdkToken { get; set; } public string Device { get; set; } } ``` 1.Geek.MsgPackTool为每个可序列化类自动分配唯一ID(FullName的hashcode),如果存在hash冲突(概率很小),工具会提示你进行修改类名。 2.MessagePackObject注解,所有需要序列化的类都要标记,为了更好的兼容性和便捷性messagepack使用map模式,即MessagePackObject(true) 3.仅作为消息头的类需要继承自Message,其他不用 4.**请勿将协议中的类,存入State中(为支持协议的热更新)** ### 限制 兼容限制:不能修改字段类型(如从bool改为long) [了解更多 MessagePack-CSharp](https://github.com/neuecc/MessagePack-CSharp) ### 多态支持 MessagePack对多态支持不友好,Geek.MessagePackTool工具会在代码生成时,生成多态绑定关系来解决此问题! ```csharp public partial class PolymorphicRegister { static PolymorphicRegister() { System.Console.WriteLine("***PolymorphicRegister Init***"); Init(); Register(); } public static void Register() { settings.RegisterType(112001); settings.RegisterType(112002); settings.RegisterType(112003); settings.RegisterType(112004); settings.RegisterType(112005); settings.RegisterType(111112); settings.RegisterType(111001); settings.RegisterType(111002); settings.RegisterType(111003); settings.RegisterType(111004); settings.RegisterType(111005); } } ``` ### 最佳实践 1.可以将Geek.MessagePackTool.exe添加到vs studio的外部工具 ![](https://github.com/leeveel/GeekServer/blob/main/Docs/imgs/vs001.png) ![](https://github.com/leeveel/GeekServer/blob/main/Docs/imgs/vs002.png) 2.Geek.MessagePackTool工作时仅需要依赖GeekServer.Proto工程,所以其他工程编译不过时,不影响导出协议 ================================================ FILE: Docs/十分钟.md ================================================ # 十分钟上手GeekServer # 运行 1. 安装[.NetCore6.0](https://dotnet.microsoft.com/download/dotnet/6.0) 2. 安装[mongodb4.x](https://www.mongodb.com/try/download/community) 3. 打开git clone本项目https://github.com/leeveel/GeekServer.git 4. 运行Tools/ExcelGen/ExcelToCode.exe 点击[服务器-ALL]导出配置表 5. 用VisualStudio2022打开GeekServer.sln 启动GeekServer.App 6. 启动GeekServer.TestPressure (一个1000人登录的demo) 7. 打开UnityDemo工程,打开SampleScene,运行查看日志(**检查Main Camera上是否有脚本丢失,如果有请挂载GameMain.cs**) ## 如何添加新功能 ### 1.规划线程模型 以demo为例,demo中有两个Actor(可以理解为逻辑上的线程),一个是Server,另外一个是Role,Server线程是全局的一个服务器只会存在一个,而Role则是一个玩家一个线程。在demo中Server线程负责了登录以及世界等级相关逻辑(实际开发中规划一个LoginActor比较合理),于是为Server注册了LoginComp和ServerComp两个组件。对于Role来说,一个玩家会存在很多功能系统,如角色模块,背包模块,宠物模块,所有为Role注册RoleComp,BagComp,PetComp。 **也就是说一个功能系统的逻辑是运行在哪个线程上,取决于你把这个功能系统的组件注册在哪个Actor上。** ### 2.如何为Actor注册组件 通过Comp注解为Actor注册组件 [Comp(ActorType.Role)] public class BagComp : StateComp ### 3.如何绑定组件状态(数据) 一个功能系统由两部分组成,1是逻辑代码(xxxCompAgent),2是数据(xxxState),为了实现逻辑代码的热更新,GeekServer使用了代理的方式将逻辑与数据分离。以下代码展示组件和数据的绑定方式: [Comp(ActorType.Role)] public class BagComp : StateComp public class BagCompAgent : StateCompAgent ### 4.如何监听事件 请参见Geek.Server.Role.PetCompAgent ### 5.如何添加定时器 请参见Server.Logic.Logic.ServerCompAgent ### 6.为需给外部提供服务的接口添加[Api]注解 请参见Server.Logic.Logic.ServerCompAgent.GetWorldLevel()接口,此接口是获取服务器世界等级,由于这个接口会对外部提供服务,即其他Actor都有可能访它,所以需要添加[Api]注解 ## 方法注解 **[Api]**:代表此接口需要被其他Actor调用 **[Discard]**:代表在调用此接口的时候,会使用弃元运算符(_ = DoSomething()),**因为弃元运算符会导致执行此异步函数逻辑的线程不可确定,所以GeekServer对标记了[Discard]注解的处理方式是,强制插入队列末端执行。** **[ThreadSafe]**:代表此接口是线程安全的,不是必须的,而且应该尽量少用(1.让逻辑开发人员尽量少关注多线程 2.如果标注的接口逻辑很复杂,再代码多次迭代之后,很容易误判) **[TimeOut(30000)]**:可以自定义接口的超时时间 具体代码请参见Server.Logic.Logic.ServerCompAgent ## 关于Message.Unid 在demo中可以看到客户端的ReqXXX消息,在服务器回包当中,都带上了ReqXXX传过来的Unid。demo中这个设计为了解决自动处理客户端(发送消息->锁屏->收到回包->解锁屏)的逻辑。**如果你有自己的方案或者不需要此设计忽略它**。 ### 至此已经足够你基于GeekServer开发自己的游戏功能 ================================================ FILE: Docs/定时器&计划任务Timer.md ================================================ # 定时器&计划任务 GeekServer中没有使用传统意义中的Update,除MMO项目,其他大部分游戏类型的服务器基本没有必要使用Update,需要Update的模块添加一个Timer也可以实现 根据热更新设计方案,定时器和计划任务采用接口方式进行回调,任务使用扩展方法实现,[源码参考](https://github.com/leeveel/GeekServer/tree/master/GeekServer.Hotfix/Logic/Common/TimerExt.cs) 定时器支持:1次性delay,周期性timer。 计划任务:指定时间1次性任务,每天任务,每周任务,每周几任务,每月任务。 GeekServer中没有对定时器&计划任务做持久化,所以你可能需要在开服后、玩家上线或者Component激活时考虑一下计划任务逻辑是否需要被处理了。 回调函数继承TimerHandler<>,重写HandleTimer,里面处理定时器回调逻辑即可。 需要注意的是定时器是接入的Quartz,由于硬件精度问题(windows时间实际精度为10毫秒左右),回调时间可能会提前1-2毫秒,如果对时间依赖特别大的可能需要特殊处理下,比如在Timer回调后延时50毫秒再执行回调逻辑。 ================================================ FILE: Docs/最后补充.md ================================================ # 补充 ### server_config.json配置 server_config.json中的配置在[Settings](https://github.com/leeveel/GeekServer/tree/master/GeekServer.Core/Utils/Settings.cs) 中解析,每个字段的作用参考[Settings](https://github.com/leeveel/GeekServer/tree/master/GeekServer.Core/Utils/Settings.cs)注释 ### 唯一Id生成 GeekServer提供的[IdGenerator](https://github.com/leeveel/GeekServer/tree/master/GeekServer.Core/Utils/IdGenerator.cs) 可用于全局id生成,比如roleId,公会id等;给定服务器id,保证全局唯一(30年内)。GeekServer为serverId预留了16位,即0-65535有效,我们推荐serverId从10000起。 ### 日志 GeekServer使用NLog采集日志,采集方式包含控制台和文件。由于控制台占用IO,会占用大量资源,只在debug模式下输出。特殊的,LOOGER.DEBUG()只会在debug模式下打印在控制台,不会采集到日志文件。 ### 温馨提示 1. 服务器区别于客户端,服务器在非重大问题的情况下,是不能直接退出的,更不能出现闪退。GeekServer做了异常处理,在监听到没处理的异常时会自动走关服流程(actor回收,回存数据。。。)。理论上开发者应该确保所有的逻辑异常都能被try/catch到,然后视情况判断是丢弃异常还是关服。 ================================================ FILE: Docs/热更hotfix.md ================================================ # 热更新 GeekServer支持不停服热更新逻辑。 #### 热更思路 游戏中的所有状态放在App工程中,始终存在于内存,不能热更。Actor和Component的逻辑使用代理模式(Agent)放到Hotfix工程。热更时载入新的dll(GeekServer.Hotfix.dll),清除所有老的Agent,所有新逻辑重新从Actor/Component获取新的Agent汇入新dll中执行热更后的逻辑,达到热更目的。正在执行老dll逻辑的代码获取的Agent依然来自热更前的老Dll中,等待老dll中的逻辑执行完后清理掉内存中老的dll。底层使用接口驱动热更dll中的逻辑。 需要注意的是,热更时新的dll需要放在新的目录下面,然后再载入内存,因为老的dll可能正在运行,是无法直接覆盖的。参考代码[HotfixModule.Load](https://github.com/leeveel/GeekServer/tree/master/GeekServer.Core/Hotfix/HotfixModule.cs) #### 可以热更部分 可以热更的逻辑都应该放在GeekServer.Hotfix工程中 1. 所有Actor/Component的Agent,Agent中只有逻辑没有状态,状态全部放到Component的State 2. HttpHandler 3. TcpHandler 4. 协议 5. 配置表/配置表代码 #### 热更新流程 1. 游戏后台将新的GeekServer.Hotfix.dll及相关文件(对应pdb,json等)拷贝到游戏服特定目录下 2. 游戏后台向游戏服发送http命令,通知进行热更,并告知dll目录,md5等信息 3. 游戏服中热更HttpHandler根据后台信息,验证热更dll完整性,合法性,修改dllVersion.txt,发起热更调用 ================================================ FILE: Docs/网络Net(tcp&http).md ================================================ # 网络 GeekServer网络层使用kestrel,GeekServer目前只接入了tcp和http,但是kestrel是支持UDP,websocket,Http123,singalr等几乎所有的常见协议的,如有所需请自行接入(工作量很小)。 ### donetty vs kestrel ![](https://github.com/leeveel/GeekServer/blob/main/Docs/imgs/dotnetty.png) ![](https://github.com/leeveel/GeekServer/blob/main/Docs/imgs/kestrel.png) ### http 创建任意脚本名字Handler,继承BaseHttpHandler,使用HttpMsgMapping标记指令,实现Action函数即可使用。Action中调用或者实现对应指令的逻辑,并返回结果给客户端。此外httpHandler还有2个字段可以重写标示是否验证,CheckSign是否验证,Inner是否使用内部验证方式。GeekServer支持post和get方式访问。 ###### 特殊key不要占用 1. cmd:指令,自己定义的任意字符串 2. time:用于安全验证,当前utc时间tick(DateTime.UtcNow.Ticks),同时也做时间校验,客户端时间需要和服务器时间基本一致(超前/延后10秒左右) 3. sign:用于安全验证,安全验证算法后的结果 ###### 安全验证算法 验证算法见[BaseHttpHandler](https://github.com/leeveel/GeekServer/tree/master/GeekServer.Core/Net/Http/BaseHttpHandler.cs) GetStringSign函数 sign = 算法函数(code + time),其中sign和time在客户端发送到服务器的参数里面,code是[server_config.json](https://github.com/leeveel/GeekServer/tree/master/GeekServer.App/Config/server_config.json) 中配置的HttpCode(非inner验证)/HttpInnerCode(inner验证) 注意,上线的商业项目记得修改HttpCode和HttpInnerCode,否则可能被他人利用。 一般的,非Inner验证用于提供给第3放使用(运营/sdk。。。),Inner验证用于内部游戏后台(发邮件,封号。。。) ```csharp //在浏览器中访问地址即可验证:http://localhost:20000/geek/server/logic?cmd=test //带安全验证的url:http://localhost:20000/geek/server/logic?cmd=test&time=637574338045380003&sign=ad762402fc9c5275bbb68464cf30aac888 [HttpMsgMapping("test")] //指令为test public class TestHttpHandler : BaseHttpHandler { //不使用内部验证算法 public override bool Inner => false; //是否验证参数,debug模式下始终不验证(debug模式在server_config.json中修改) public override bool CheckSign => false; public override Task Action(string ip, string url, Dictionary paramMap) { return Task.FromResult((string)HttpResult.Success); } } ``` ### tcp GeekServer的tcp协议为自定义协议,区别于google的protocolBuffer和flatBuffer,但是序列化和反序列化都要优于2者。 ###### tcp使用步骤 1. [协议工具目录](https://github.com/leeveel/GeekServer/tree/master/Tools/GeekProto) 2. 运行Geek.Proto.exe生成协议导 3. 创建任意脚本名字Handler,继承FixedIdEntityHandler/TcpCompHandler,使用MsgMapping标记消息类型,实现ActionAsync函数即可。BaseTcpHandler中的Msg即为解析好的当前类型协议数据 ```csharp [MsgMapping(typeof(ReqBagInfo))] public class ReqBagInfoHandler : TcpCompHandler { public override Task ActionAsync() { var req = (ReqBagInfo)Msg; //your logic here... return Task.CompletedTask; } } ``` ###### [GeekProto协议](https://github.com/leeveel/GeekServer/blob/main/Docs/%E5%85%B3%E4%BA%8E%E5%8D%8F%E8%AE%AE.md) ================================================ FILE: FairyGUIProject/Game.fairy ================================================ ================================================ FILE: FairyGUIProject/assets/UIBag/UIBag.xml ================================================ ================================================ FILE: FairyGUIProject/assets/UIBag/UIBagContent.xml ================================================ ================================================ FILE: FairyGUIProject/assets/UIBag/UIBagItemInfo.xml ================================================