├── .github ├── ISSUE_TEMPLATE │ ├── 1_server_issue.md │ ├── 2_windy_issue.md │ ├── 3_network_issue.md │ ├── 4_skill_issue.md │ ├── 5_optimition_request.md │ ├── 6_other_issues.md │ └── config.yml ├── PULL_REQUEST_TEMPLATE.md └── workflows │ ├── network-pressure.yml │ ├── network-test.yml │ └── pull-request-check.yml ├── .gitignore ├── .gitmodules ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── HandlerGenerator ├── .gitignore ├── CollectionHelper.cs ├── EasyGrpcProtoc │ └── EasyGrpcProtoc.csproj ├── Gencode_Configuration │ ├── afterbuild_task_unix.tmpl.sh │ ├── afterbuild_task_win.tmpl.ps1 │ ├── default_protobuf_branches.txt │ ├── handlerignore.txt │ ├── protobuf_general_license.txt │ └── protobuf_source_git.txt ├── HandlerGenerator.csproj ├── OuterInvoke.cs ├── OuterInvokeConfig.cs ├── Program.cs ├── ProtoFieldNameAnalyze │ ├── Compiled │ │ └── StringPool.cs │ ├── GeneratedProtos │ │ └── StringPool.proto │ ├── README.md │ └── run_test.bat ├── ProtobufManage │ ├── DMCATakenDownException.cs │ ├── GitInvoke.cs │ ├── GitProtobufPromptCLI.cs │ ├── GitProtosManager.cs │ ├── ProtoStatInfo.cs │ └── RunUpdateProtobufConfig.cs ├── ProtoshiftEx │ ├── BasicCode │ │ ├── BasicCodeReader.cs │ │ ├── BasicCodeWriter.cs │ │ └── TxtReader.cs │ ├── CodeGenerate │ │ ├── HandlerCodeWriter.cs │ │ ├── HandlerCommonFieldGenerate.cs │ │ ├── HandlerJitParamters.cs │ │ ├── HandlerMapFieldGenerate.cs │ │ ├── HandlerOneofFieldGenerate.cs │ │ ├── ImportTypesCollection.cs │ │ └── SkillIssueCollection.cs │ ├── CompiledEnumStringPoolManager.cs │ └── OuterDispatchGenerate │ │ ├── CmdIdDataStructure.cs │ │ ├── GenAskCmdId.cs │ │ ├── GenProtoshiftDispatch.cs │ │ ├── GenShiftCmdId.cs │ │ └── GenTemporaryAskCmdId.cs ├── RebuildWatcher.cs ├── RegenOutput │ ├── RegenOutputCommonField.cs │ ├── RegenOutputEnum.cs │ ├── RegenOutputMapField.cs │ ├── RegenOutputMessage.cs │ └── RegenOutputOneofField.cs ├── StartupWorkingDirChanger.cs ├── Tools.cs └── resLoader │ └── ResourcesLoader.cs ├── KCP ├── .github │ └── FUNDING.yml ├── .gitignore ├── Kcp │ ├── FakeKcpIO.cs │ ├── IKcpInterface.cs │ ├── IKcpSegment.cs │ ├── Kcp.cs │ ├── Kcp.csproj │ ├── KcpCore.cs │ ├── KcpIO.cs │ ├── KcpOutputWriter.cs │ ├── KcpSegment.cs │ ├── KcpTrace.cs │ ├── README.md │ ├── SegManager.cs │ ├── SimpleKcpClient.cs │ ├── SingleThreadAssert.cs │ ├── TraceList.cs │ ├── UniqueIDManager.cs │ ├── Utility.cs │ └── miHoMoKCP_Compare │ │ ├── ikcp_master.c │ │ ├── ikcp_master.h │ │ ├── ikcp_mihomo.c │ │ └── ikcp_mihomo.h └── README.md ├── LICENSE ├── NewProtoHandlers ├── .gitignore ├── NewProtoHandlers.csproj ├── ProtoSerializeJson.cs └── QueryJsonSerializer.cs ├── OldProtoHandlers ├── .gitignore ├── OldProtoHandlers.csproj ├── ProtoSerializeJson.cs └── QueryJsonSerializer.cs ├── ProtoshiftHandlers ├── .gitignore ├── Example │ ├── Generated_std │ │ ├── HandlerExampleEnum.cs │ │ ├── HandlerExampleProto.cs │ │ ├── HandlerExampleProto2.cs │ │ ├── HandlerInMessage.cs │ │ └── ProtobufExtension.UnknownFieldSet.cs │ ├── NewProtos │ │ ├── Compiled │ │ │ ├── ExampleEnum.cs │ │ │ ├── ExampleProto.cs │ │ │ └── InMessage.cs │ │ └── Proto │ │ │ ├── ExampleEnum.proto │ │ │ ├── ExampleProto.proto │ │ │ └── InMessage.proto │ ├── OldProtos │ │ ├── Compiled │ │ │ ├── ExampleEnum.cs │ │ │ ├── ExampleProto.cs │ │ │ └── InMessage.cs │ │ └── Proto │ │ │ ├── ExampleEnum.proto │ │ │ ├── ExampleProto.proto │ │ │ └── InMessage.proto │ ├── ProtoshiftDispatch.cs │ ├── ShiftCmdId.cs │ └── compile.sh ├── HandlerBase.cs ├── HotPatchMiddleware.cs ├── ProtoshiftHandlers.csproj └── SpecialHandlers │ ├── CustomHandlers │ └── HandlerUint32PairAndMap.cs │ ├── HandlerAbilityInvokeEntry.cs │ ├── HandlerCombatInvokeEntry.cs │ ├── HandlerGCGAttackCostInfo.cs │ ├── HandlerGCGMsgPhaseChange.cs │ ├── HandlerGCGMsgUpdateController.cs │ ├── HandlerGCGPlayCardCostInfo.cs │ ├── HandlerGCGSelectOnStageCostInfo.cs │ ├── HandlerUnionCmd.cs │ └── README.md ├── README.md ├── Tests ├── .gitignore ├── KcpTests │ ├── KcpPerformanceTest │ │ ├── Analysis │ │ │ ├── AnalysisResults.cs │ │ │ ├── ClientDataChannel.cs │ │ │ ├── MainAnalysis.cs │ │ │ ├── PacketRecordCollection.cs │ │ │ ├── ProxyDataChannel.cs │ │ │ └── ServerDataChannel.cs │ │ ├── Client │ │ │ └── ClientApp.cs │ │ ├── Constants.cs │ │ ├── KcpPerformanceTest.csproj │ │ ├── Program.cs │ │ ├── Protocol │ │ │ └── Mihomonet.cs │ │ ├── Proxy │ │ │ ├── GameSession │ │ │ │ ├── GameSessionDispatch.cs │ │ │ │ └── HandlerSession.cs │ │ │ └── ProxyApp.cs │ │ ├── Server │ │ │ └── ServerApp.cs │ │ ├── Util.cs │ │ ├── resLoader │ │ │ ├── Resources.cs │ │ │ └── ResourcesLoader.cs │ │ └── resources │ │ │ └── xor │ │ │ ├── dispatchKey.bin │ │ │ └── dispatchSeed.bin │ ├── KcpTests.sln │ ├── README.md │ └── SharedLib │ │ ├── Crypto │ │ ├── README.md │ │ └── mt19937 │ │ │ ├── README.md │ │ │ └── csharp │ │ │ ├── mt19937.cs │ │ │ └── mt19937_test.cs │ │ ├── KCP │ │ ├── KcpProxy │ │ │ ├── AnimeGame_KcpProxy.drawio │ │ │ ├── AnimeGame_KcpProxy.png │ │ │ ├── KcpProxyBase.cs │ │ │ ├── KcpProxyClient.cs │ │ │ ├── KcpProxyServer.cs │ │ │ ├── ProxyHandlers.cs │ │ │ └── README.md │ │ ├── MhyKCP │ │ │ ├── Handshake.cs │ │ │ ├── KCPClient.cs │ │ │ ├── KCPServer.cs │ │ │ ├── KcpInnerBuffer.cs │ │ │ ├── KcpPacketAudit.cs │ │ │ ├── MhyKcpBase.cs │ │ │ └── UdpKcpCallback.cs │ │ ├── OldAnimeGameKCP │ │ │ ├── LICENSE │ │ │ ├── README.md │ │ │ └── Util │ │ │ │ ├── ByteArray.cs │ │ │ │ └── MonotonicTime.cs │ │ ├── SingleThreadAssert.cs │ │ └── SpecialUdp │ │ │ ├── Obsoleted │ │ │ └── ConcurrentUdpClient.cs │ │ │ └── SocketUdpClient.cs │ │ └── SharedLib.csproj ├── ProtoshiftBenchmark │ ├── Program.cs │ ├── ProtoshiftBenchmark.csproj │ └── StartupWorkingDirChanger.cs ├── csharp-Protoshift-Replay │ ├── GameSession │ │ └── PacketRecordCollection.cs │ ├── Program.cs │ ├── StartupWorkingDirChanger.cs │ └── csharp-Protoshift-Replay.csproj ├── run-benchmark.ps1 └── run-benchmark.sh ├── csharp-Protoshift.sln ├── csharp-Protoshift ├── .gitignore ├── Commands │ ├── CommandListConfig.cs │ ├── ICommandHandler.cs │ ├── ProtoHotPatchCmd.cs │ ├── ProxyRelated │ │ ├── ForceInjectPacketCmd.cs │ │ ├── KickPlayerCmd.cs │ │ ├── QueryClientCmd.cs │ │ ├── SetVerboseCmd.cs │ │ ├── TargetCmd.cs │ │ ├── TargetManager.cs │ │ └── TargetOptionBase.cs │ ├── README_CN.md │ ├── ServerCommandLine.cs │ ├── StopServerCmd.cs │ ├── Utils │ │ ├── ConvertCmd.cs │ │ ├── Dispatch │ │ │ ├── CurrExtend.cs │ │ │ └── CurrRegionCmd.cs │ │ ├── EasyInput.cs │ │ ├── Ec2b │ │ │ └── Ec2bCmd.cs │ │ ├── MT19937Cmd.cs │ │ ├── Protobuf │ │ │ └── ProtobufCmd.cs │ │ └── UtilCmd.cs │ └── Windy │ │ ├── WindyCommand.cs │ │ ├── WindyCompilerManager.cs │ │ └── WindyLuacManager.cs ├── Config │ ├── ChatGPT Config v1.0.0.md │ ├── Config.cs │ ├── Config_v1.0.0.cs │ └── Config_v1.0.1.cs ├── Crypto │ ├── Containers │ │ └── Blk.cs │ ├── Extensions │ │ └── ByteArrayExtensions.cs │ ├── Formats │ │ └── Ec2b.cs │ ├── Managers │ │ └── FormatManager.cs │ ├── README.md │ └── Utils │ │ ├── AES.cs │ │ ├── EndianReader.cs │ │ ├── EndianType.cs │ │ ├── EndianWriter.cs │ │ └── MT19937_64.cs ├── GameSession │ ├── GameSessionDispatch.cs │ ├── HandlerSession.Common.cs │ ├── PacketNotify │ │ ├── HandlerSession.Notify.Rsa.cs │ │ └── HandlerSession.PacketNotifyDispatch.cs │ ├── Protoshift │ │ ├── HandlerSession.Protoshift.cs │ │ └── PacketRecord.cs │ └── ProxyOnly │ │ ├── HandlerSession.ProxyOnly.cs │ │ └── PacketRecord.cs ├── Images │ └── windy_welcome-to-csharp-Protoshift.jpg ├── KCP │ ├── KcpProxy │ │ ├── AnimeGame_KcpProxy.drawio │ │ ├── AnimeGame_KcpProxy.png │ │ ├── KcpProxyBase.cs │ │ ├── KcpProxyClient.cs │ │ ├── KcpProxyServer.cs │ │ ├── ProxyHandlers.cs │ │ └── README.md │ ├── MhyKCP │ │ ├── Handshake.cs │ │ ├── KCPClient.cs │ │ ├── KCPServer.cs │ │ ├── KcpInnerBuffer.cs │ │ ├── KcpPacketAudit.cs │ │ ├── MhyKcpBase.cs │ │ └── UdpKcpCallback.cs │ ├── OldAnimeGameKCP │ │ ├── LICENSE │ │ ├── README.md │ │ └── Util │ │ │ ├── ByteArray.cs │ │ │ └── MonotonicTime.cs │ ├── SingleThreadAssert.cs │ └── SpecialUdp │ │ └── SocketUdpClient.cs ├── LoggerChannelTraceExtensions.cs ├── Program.cs ├── ProtoHotPatch │ ├── HotPatchCompileCheck.cs │ ├── ProtoHotPatchCompileErrs.cs │ ├── ProtoHotPatchCompiler.cs │ ├── ProtoshiftHotPatchConfig.cs │ ├── README.md │ └── README_CN.md ├── SkillIssue │ └── SkillIssueDetect.cs ├── StartupWorkingDirChanger.cs ├── ThirdPartyLicenses │ ├── Asset │ │ └── LICENSE.txt │ ├── KCP │ │ └── LICENSE │ ├── XC.RSAUtil │ │ └── LICENSE │ ├── csharp-logger │ │ └── LICENSE │ ├── csharp-protoparser │ │ └── LICENSE │ └── xlua │ │ └── LICENSE.TXT ├── Tools.cs ├── config_example.json ├── csharp-Protoshift.csproj ├── protoshift_hotpatch_config.tmpl.json ├── resLoader │ ├── Resources.cs │ └── ResourcesLoader.cs └── resources │ ├── config-schemas │ ├── config_schema_latest.json │ ├── config_schema_v1.0.0.json │ └── config_schema_v1.0.1.json │ ├── luac_bins │ ├── README.md │ ├── luac_unix64 │ ├── luac_win32.exe │ └── luac_win64.exe │ ├── rsakeys │ ├── ClientPri │ │ ├── 2.pem │ │ ├── 3.pem │ │ ├── 4.pem │ │ └── 5.pem │ └── ServerPri │ │ ├── 2-pri.pem │ │ ├── 3-pri.pem │ │ ├── 4-pri.pem │ │ ├── 5-pri.pem │ │ └── README.md │ ├── windy_scripts │ ├── Put your luas here.txt │ └── welcome-to-csharp-Protoshift.lua │ └── xor │ ├── dispatchKey.bin │ └── dispatchSeed.bin ├── docs └── README_CN.md ├── run ├── run.ps1 ├── scripts ├── publish ├── publish.ps1 ├── rebuild ├── rebuild.ps1 ├── run-benchmark ├── run-benchmark-debug ├── run-benchmark-debug.ps1 ├── run-benchmark.ps1 ├── run-rel └── run-rel.ps1 ├── update └── update.ps1 /.github/ISSUE_TEMPLATE/1_server_issue.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Server Running Issue 3 | about: Issues of server running 4 | labels: bug, server 5 | --- 6 | 7 | Note: Asking in English can make your problem more widely known by the community, while asking in Chinese will make it handled more quickly by the repository owner. There is CN template version below, so you can choose one as you like. 8 | 9 | 说明:以英文提问可使你的问题更广泛由社区所了解,而以中文提问可以使仓库所有者更快跟进。下附有中文版模板,可据你的偏好自行选择一种。 10 | 11 | ------------------------------------ 12 | 13 | ## Basic Information 14 | 15 | - Protoshift version: 16 | - Server OS: 17 | - Client OS: 18 | 19 | ## Problem Encountered 20 | 21 | - [ ] Meets a network timeout under certain circumstances (but a KCP connection has been established) 22 | - [ ] The server indicates a fatal error and stops running 23 | - [ ] The effect of Protoshift HotPatch is not as expected, or it sends out wrong warnings/errors 24 | - [ ] Other problems (please specify) 25 | 26 | ## Detailed Description of the Phenomenon 27 | 28 | ## Server Log When the Exception Occurs 29 | 30 | ## Checklist 31 | 32 | - [ ] I have searched for related issues in the issue area but have not resolved them 33 | - [ ] I have browsed various Issue templates and confirmed that the current template is suitable for my problem 34 | - [ ] I confirm that the issue I raised is related to the Protoshift server itself (and not dependent on other factors) 35 | - [ ] I have run the building process properly 36 | - [ ] I have attached necessary log records in the issue (you can also send them to `mihomo-technology@outlook.com`, making it disclosed after removing sensitive information). I also attached the necessary content of `latest.errtrace.log` (if an exception occurs) 37 | - [ ] I confirm that the logs I have included in the body of the issue are not leaking my private information 38 | - [ ] I confirm that the phenomenon is unrelated to the defects of my server (the real game server) 39 | - [ ] **I am not running the server on any version of macOS, nor am I running the game client on iOS** 40 | 41 | ------------------------------------ 42 | 43 | ## 基本信息 44 | 45 | - Protoshift 版本号: 46 | - 服务器使用 OS: 47 | - 客户端 OS: 48 | 49 | ## 遇到的问题 50 | 51 | - [ ] 在特定情况下,网络响应超时(但建立了 KCP 连接) 52 | - [ ] 服务器提示发生了致命错误且停止运行 53 | - [ ] Protoshift HotPatch 效果未达预期,或发出错误的警告/错误 54 | - [ ] 其他问题(请具体说明) 55 | 56 | ## 异常现象的具体说明 57 | 58 | ## 引发异常时的服务器日志 59 | 60 | ## Checklist 61 | 62 | - [ ] 我已在 issue 区寻找过相关的问题但未得到解决 63 | - [ ] 我已浏览过多种 Issue 模板并确认当前模板适合我的问题 64 | - [ ] 我确认提出的 issue 与 Protoshift 服务器本身有关(而不取决于其他因素) 65 | - [ ] 我正确运行了生成 66 | - [ ] 我已在 issue 中附带必要的日志记录(也可发送至 `mihomo-technology@outlook.com`,去除敏感信息后的部分将被公开)。我还附带了 `latest.errtrace.log` 的必要内容(如果有发生异常) 67 | - [ ] 我确认在 issue 主体中附带的日志没有泄露隐私信息 68 | - [ ] 我确认现象与我的服务器(真正的游戏服务器)的本身缺陷无关 69 | - [ ] **我并非在 macOS 的任何版本上运行服务器,也并非在 iOS 上运行游戏客户端** 70 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/3_network_issue.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Network Issue 3 | about: KCP related issue 4 | labels: network, kcp 5 | --- 6 | 7 | Note: Asking in English can make your problem more widely known by the community, while asking in Chinese will make it handled more quickly by the repository owner. There is CN template version below, so you can choose one as you like. 8 | 9 | 说明:以英文提问可使你的问题更广泛由社区所了解,而以中文提问可以使仓库所有者更快跟进。下附有中文版模板,可据你的偏好自行选择一种。 10 | 11 | ------------------------------------ 12 | 13 | ## Basic Information 14 | 15 | - Protoshift version: 16 | 17 | ## Problem Encountered 18 | 19 | - [ ] Under certain circumstances, the server stops responding (and a KCP connection has not been successfully established) 20 | - [ ] I am dissatisfied with the delay, TTL, and network fluctuations of the Network Protocol Stack, and have some optimization schemes 21 | - [ ] There is severe delay or/and network fluctuation when the number of online clients is high 22 | - [ ] I have reason to question that there are problems with the basic KCP implementation (slicing packet into Segment, Segment memory allocation, ordered packet transmission, thread safety, etc.) 23 | - [ ] Other problems (please specify) 24 | 25 | ## Detailed Description of the Phenomenon and Server / `KcpPerformaceTest` Log 26 | 27 | ## Checklist 28 | 29 | - [ ] I have searched for related issues in the issue area but have not resolved them 30 | - [ ] I have browsed various Issue templates and confirmed that the current template is suitable for my problem 31 | - [ ] I confirm that the issue I raised is related to the network protocol stack itself (and not dependent on other factors) 32 | - [ ] I have run the building process properly 33 | - [ ] I tried to run Protoshift and the game server on the same device 34 | - [ ] I have attached necessary log records in the issue (you can also send them to `mihomo-technology@outlook.com`, making it disclosed after removing sensitive information). I also attached the necessary content of `latest.errtrace.log` (if an exception occurs). 35 | - [ ] I confirm that the phenomenon is unrelated to the defects of my server (the real game server) 36 | - [ ] **I am not running the server on any version of macOS, nor am I running the game client on iOS** 37 | 38 | ---------------------------------- 39 | 40 | ## 基本信息 41 | 42 | - Protoshift 版本号: 43 | 44 | ## 遇到的问题 45 | 46 | - [ ] 在特定情况下,服务器停止响应(且未成功建立 KCP 连接) 47 | - [ ] 我对网络协议栈的延迟、TTL、网络波动不满意,并有一些优化方案 48 | - [ ] 在客户端在线数量高时有严重的延迟/网络波动 49 | - [ ] 我有理由质疑基础 KCP 的实现出现了问题(包切片、Segment 内存分配、有序包传输、线程安全等方面) 50 | - [ ] 其他问题(请具体说明) 51 | 52 | ## 异常现象的具体说明与服务器 / `KcpPerformaceTest` 日志 53 | 54 | ## Checklist 55 | 56 | - [ ] 我已在 issue 区寻找过相关的问题但未得到解决 57 | - [ ] 我已浏览过多种 Issue 模板并确认当前模板适合我的问题 58 | - [ ] 我确认提出的 issue 与网络协议栈本身有关(而不取决于其他因素) 59 | - [ ] 我正确运行了生成 60 | - [ ] 我尝试了将 Protoshift 与游戏服务器运行在同一台设备上 61 | - [ ] 我已在 issue 中附带必要的日志记录(也可发送至 `mihomo-technology@outlook.com`,去除敏感信息后的部分将被公开)。我还附带了 `latest.errtrace.log` 的必要内容(如果有发生异常)。 62 | - [ ] 我确认现象与我的服务器(真正的游戏服务器)的本身缺陷无关 63 | - [ ] **我并非在 macOS 的任何版本上运行服务器,也并非在 iOS 上运行游戏客户端** 64 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/6_other_issues.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Other issues 3 | about: Any other types of issues 4 | --- 5 | 6 | Note: Asking in English can make your problem more widely known by the community, while asking in Chinese will make it handled more quickly by the repository owner. Though CN template version is still provided below, this type of issue perfer to be raised in EN version. 7 | 8 | 说明:以英文提问可使你的问题更广泛由社区所了解,而以中文提问可以使仓库所有者更快跟进。尽管下附有中文版模板,本类型的 issue 仍建议以英文提问,可借助 AI 翻译。 9 | 10 | ------------------------------------ 11 | 12 | ## Basic Information 13 | 14 | - Protoshift version: 15 | - Server OS: 16 | - Client OS: 17 | - Server Protobuf version (branch of OldProtos): 18 | - Client Protobuf version (branch of NewProtos): 19 | 20 | ## Problem Encountered 21 | 22 | ## Detailed Description 23 | 24 | ## Game Video / Server Log / Other Necessary Information 25 | 26 | ## Checklist 27 | 28 | - [ ] I have searched for related issues in the issue area but have not resolved them 29 | - [ ] I have browsed various Issue templates and confirmed that the current template is suitable for my problem 30 | - [ ] I am using the default Protobuf source and ran the build correctly 31 | - [ ] I have attached necessary log records in the issue (you can also send them to `mihomo-technology@outlook.com`, making it disclosed after removing sensitive information). I also attached the necessary content of `latest.errtrace.log` (if an exception occurs in the log). 32 | - [ ] I confirm that the logs I have included in the body of the issue are not leaking my private information 33 | - [ ] I confirm that the phenomenon is unrelated to the defects of my server (the real game server) 34 | - [ ] I confirm that the phenomenon can be removed from any external factors (such as Windy, cheats, specific GM commands, or custom server data), or I have publicly disclosed these external and deployment methods in the main body of the issue 35 | - [ ] **I am not running the server on any version of macOS, nor am I running the game client on iOS** 36 | 37 | ---------------------------- 38 | 39 | 40 | ## 基本信息 41 | 42 | - Protoshift 版本号: 43 | - 服务器使用 OS: 44 | - 客户端 OS: 45 | - 服务器 Protobuf 版本(OldProtos 的分支): 46 | - 客户端 Protobuf 版本(NewProtos 的分支): 47 | 48 | ## 遇到的问题 49 | 50 | ## 具体说明 51 | 52 | ## 游戏录像 / 服务器日志 / 其他必要信息 53 | 54 | ## Checklist 55 | 56 | - [ ] 我已在 issue 区寻找过相关的问题但未得到解决 57 | - [ ] 我已浏览过多种 Issue 模板并确认当前模板适合我的问题 58 | - [ ] 我正使用默认提供的 Protobuf 并且正确运行了构建 59 | - [ ] 我已在 issue 中附带必要的日志记录(也可发送至 `mihomo-technology@outlook.com`,去除敏感信息后的部分将被公开)。我还附带了 `latest.errtrace.log` 的必要内容(如果日志中有发生异常)。 60 | - [ ] 我确认在 issue 主体中附带的日志没有泄露隐私信息 61 | - [ ] 我确认现象与我的服务器(真正的游戏服务器)的本身缺陷无关 62 | - [ ] 我确认现象可以在去除任何外置因素(如 Windy、外挂、特定 GM 命令、或定制版服务器等),或我已在 issue 主体中公开这些外置与部署方法 63 | - [ ] **我并非在 macOS 的任何版本上运行服务器,也并非在 iOS 上运行游戏客户端** 64 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | contact_links: 3 | - name: CLI commands input issue 4 | about: Submit a issue to our collaborated repo 5 | url: https://github.com/YYHEggEgg/csharp-logger/issues 6 | - name: Fix Proto skill issue 7 | about: Create a pull request to the outer protos repo 8 | url: https://github.com/YYHEggEgg/mihomo-protos/pulls 9 | - name: Get basic FAQs and Using Practices 10 | about: Visit our official blog 11 | url: https://yyheggegg.github.io/mihomo-gio-blogs/ 12 | - name: Ask for help 13 | about: Join Discord to get more information 14 | url: https://discord.gg/3XkT93zsNy 15 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ## Description 2 | 3 | Please carefully read the [Contributing note](https://github.com/YYHEggEgg/csharp-Protoshift/blob/main/CONTRIBUTING.md) and [Code of conduct](https://github.com/YYHEggEgg/csharp-Protoshift/blob/main/CODE_OF_CONDUCT.md) before making any pull requests. 4 | 5 | ## Issues fixed by this PR 6 | 7 | 8 | ## Type of changes 9 | 10 | 11 | 12 | - [ ] Bug fix 13 | - [ ] New feature 14 | - [ ] Enhancement 15 | - [ ] Documentation 16 | 17 | ## Checklist: 18 | 19 | - [ ] My code follows the style guidelines of this project 20 | - [ ] My pull request is unique and no other pull requests have been opened for these changes 21 | - [ ] I have read the [Contributing note](https://github.com/YYHEggEgg/csharp-Protoshift/blob/main/CONTRIBUTING.md) and [Code of conduct](https://github.com/YYHEggEgg/csharp-Protoshift/blob/main/CODE_OF_CONDUCT.md) 22 | - [ ] I am responsible for any copyright issues with my code if it occurs in the future. -------------------------------------------------------------------------------- /.github/workflows/network-pressure.yml: -------------------------------------------------------------------------------- 1 | name: Network Pressure Test 2 | 3 | on: 4 | pull_request: 5 | branches: 6 | - main 7 | 8 | jobs: 9 | network-pressure-10-clients-ubuntu-rel: 10 | runs-on: ubuntu-latest 11 | 12 | steps: 13 | - name: Checkout code 14 | uses: actions/checkout@v2 15 | 16 | - name: Setup .NET Core 17 | uses: actions/setup-dotnet@v1 18 | with: 19 | dotnet-version: '6.0.x' 20 | 21 | - name: Restore NuGet packages 22 | run: | 23 | dotnet nuget add source https://apiint.nugettest.org/v3/index.json -n "nuget.org (Integration)" 24 | dotnet restore Tests/KcpTests/KcpPerformanceTest/KcpPerformanceTest.csproj 25 | 26 | - name: Run tests 27 | run: cd Tests/KcpTests/KcpPerformanceTest ; dotnet run --configuration Release -- --packet-size 3500 --packet-repeat-time 5000 --packet-interval 50 --github-actions --clients-count 10 28 | 29 | - name: Archive logs 30 | uses: actions/upload-artifact@v2 31 | with: 32 | name: Report & logs (ubuntu-rel-pressure-x10) - ${{ github.sha }} 33 | path: Tests/KcpTests/KcpPerformanceTest/logs 34 | retention-days: 21 35 | 36 | network-pressure-20-clients-ubuntu-rel: 37 | runs-on: ubuntu-latest 38 | 39 | steps: 40 | - name: Checkout code 41 | uses: actions/checkout@v2 42 | 43 | - name: Setup .NET Core 44 | uses: actions/setup-dotnet@v1 45 | with: 46 | dotnet-version: '6.0.x' 47 | 48 | - name: Restore NuGet packages 49 | run: | 50 | dotnet nuget add source https://apiint.nugettest.org/v3/index.json -n "nuget.org (Integration)" 51 | dotnet restore Tests/KcpTests/KcpPerformanceTest/KcpPerformanceTest.csproj 52 | 53 | - name: Run tests 54 | run: cd Tests/KcpTests/KcpPerformanceTest ; dotnet run --configuration Release -- --packet-size 3500 --packet-repeat-time 5000 --packet-interval 50 --github-actions --clients-count 20 55 | 56 | - name: Archive logs 57 | uses: actions/upload-artifact@v2 58 | with: 59 | name: Report & logs (ubuntu-rel-pressure-x20) - ${{ github.sha }} 60 | path: Tests/KcpTests/KcpPerformanceTest/logs 61 | retention-days: 21 -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "docs/wiki"] 2 | path = docs/wiki 3 | url = https://github.com/YYHEggEgg/csharp-Protoshift.wiki.git 4 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | Please note we have a code of conduct, please follow it in all your interactions with the project. If you have any further questions please [create an issue](https://github.com/YYHEggEgg/csharp-Protoshift/issues/new/choose) or ask in [the Discord server](https://discord.gg/3XkT93zsNy). 4 | 5 | - Only fix/add the functionality in question OR address wide-spread whitespace/style issues, not both. 6 | - Address a single concern in the least number of changed lines as possible. 7 | 8 | **Do not make a pull request to merge into branch `main`. Use the development branch instead.** 9 | 10 | ## Pull Request Process 11 | 12 | 1. Ensure any custom dependencies are removed before the end of the layer when doing a build. 13 | 2. Update the README.md and wiki with details of changes to the interface, this includes new environment variables, exposed ports, useful file locations and container parameters. 14 | 3. Write with detail on your pull request description what you have committed, to make it easier for the collaborators to make a changelog. 15 | 16 | ## Code Content 17 | 18 | Your code should follow the standards set below: 19 | 20 | - Your code can be run purely using .NET 6.0 Runtime. 21 | - Code that can be run on a specified platform (e.g. P/Invode) is prohibited, unless code for each platform is provided and they perform the same. 22 | 23 | ## Intellectual Property 24 | 25 | Please avoid adding any direct references to the following, whenever possible: 26 | - Game names; 27 | - Character names; 28 | - Notable weapon names; 29 | - Other potential copyright content. 30 | -------------------------------------------------------------------------------- /HandlerGenerator/.gitignore: -------------------------------------------------------------------------------- 1 | Gencode_Configuration/afterbuild_task_unix.sh 2 | Gencode_Configuration/afterbuild_task_win.ps1 3 | last_build_record.json 4 | proto2json/proto2json_output 5 | Proto2json_Output 6 | -------------------------------------------------------------------------------- /HandlerGenerator/CollectionHelper.cs: -------------------------------------------------------------------------------- 1 | namespace csharp_Protoshift.Enhanced.Handlers.Generator 2 | { 3 | public static class CollectionHelper 4 | { 5 | public static CollectionResult GetCompareResult( 6 | IEnumerable left, IEnumerable right, IEqualityComparer comparer) 7 | where T : notnull 8 | { 9 | 10 | return new CollectionResult(left.InnerIntersect(right, comparer), 11 | left.Except(right, comparer), right.Except(left, comparer)); 12 | } 13 | 14 | private static IEnumerable<(T LeftItem, T RightItem)> InnerIntersect( 15 | this IEnumerable left, IEnumerable right, IEqualityComparer comparer) 16 | where T : notnull 17 | { 18 | var set = new HashSet(right, comparer); 19 | 20 | foreach (T left_element in left) 21 | { 22 | #pragma warning disable CS8600 23 | if (set.TryGetValue(left_element, out T right_element)) 24 | #pragma warning restore CS8600 25 | { 26 | yield return (left_element, right_element); 27 | set.Remove(right_element); 28 | } 29 | } 30 | } 31 | } 32 | 33 | public class CollectionResult where T : notnull 34 | { 35 | public readonly IEnumerable<(T LeftItem, T RightItem)> IntersectItems; 36 | public readonly IEnumerable LeftOnlys, RightOnlys; 37 | 38 | public CollectionResult(IEnumerable<(T LeftItem, T RightItem)> intersectItems, IEnumerable leftOnlys, IEnumerable rightOnlys) 39 | { 40 | IntersectItems = intersectItems; 41 | LeftOnlys = leftOnlys; 42 | RightOnlys = rightOnlys; 43 | } 44 | } 45 | } -------------------------------------------------------------------------------- /HandlerGenerator/EasyGrpcProtoc/EasyGrpcProtoc.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0 5 | Major 6 | enable 7 | enable 8 | 9 | 10 | 11 | 12 | 13 | runtime; build; native; contentfiles; analyzers; buildtransitive 14 | all 15 | 16 | 17 | 18 | 19 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /HandlerGenerator/Gencode_Configuration/afterbuild_task_unix.tmpl.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # This is a script for you to run simple after-build tasks. 4 | # Change its name to 'afterbuild_task_unix.sh' to enable it. 5 | # Notice that it's for unix (macOS & Linux). 6 | 7 | # The script will be given only one param, the full path 8 | # of the generated build, e.g. 9 | # afterbuild_task_unix.sh "/../Builds/output_20231003_f215adf". 10 | 11 | # For example, you can run something like scp to copy the build somewhere else. 12 | 13 | echo "Build completed! New build at: $1" -------------------------------------------------------------------------------- /HandlerGenerator/Gencode_Configuration/afterbuild_task_win.tmpl.ps1: -------------------------------------------------------------------------------- 1 | # This is a script for you to run simple after-build tasks. 2 | # Change its name to 'afterbuild_task_win.ps1' to enable it. 3 | # Notice that it's for unix (macOS & Linux). 4 | 5 | # The script will be given only one param, the full path 6 | # of the generated build, e.g. 7 | # afterbuild_task_win.ps1 "/../Builds/output_20231003_f215adf". 8 | 9 | # For example, you can run something like scp to copy the build somewhere else. 10 | 11 | Write-Host Build completed! New build at: $args[0] -------------------------------------------------------------------------------- /HandlerGenerator/Gencode_Configuration/default_protobuf_branches.txt: -------------------------------------------------------------------------------- 1 | # This file is used to configure the default branches 2 | # of protobuf when there's no protobuf. 3 | # 4 | # The file should only contain two lines that 5 | # indicates the default old / new protobuf branch. 6 | 7 | 3.4_gio 8 | 3.4_live 9 | -------------------------------------------------------------------------------- /HandlerGenerator/Gencode_Configuration/handlerignore.txt: -------------------------------------------------------------------------------- 1 | # This is the Protoshift Handlers ignore file. 2 | # 3 | # If some proto need special work, please add 4 | # them to the file, one name per line. 5 | # 6 | # e.g. Write like this: 7 | # UnionCmd 8 | # 9 | # After running the program, you may write your 10 | # code based on files with the same name 11 | # in ProtoshiftHandlers/SpecialHandlers. 12 | # (e.g. HandlerUnionCmd.cs) 13 | # 14 | # There'll be the generated code, but they won't 15 | # change since the next time running build. 16 | 17 | UnionCmd 18 | AbilityInvokeEntry 19 | CombatInvokeEntry 20 | GCGAttackCostInfo 21 | GCGMsgPhaseChange 22 | GCGMsgUpdateController 23 | GCGPlayCardCostInfo 24 | GCGSelectOnStageCostInfo -------------------------------------------------------------------------------- /HandlerGenerator/Gencode_Configuration/protobuf_general_license.txt: -------------------------------------------------------------------------------- 1 | // mihomo-protos - Public protocol APIs for miHomo software, open-sourced for compatibility. 2 | // Copyright (c) 2023 YYHEggEgg 3 | // 4 | // This program is free software: you can redistribute it and/or modify 5 | // it under the terms of the GNU Affero General Public License as 6 | // published by the Free Software Foundation, either version 3 of the 7 | // License, or (at your option) any later version. 8 | // 9 | // This program is distributed in the hope that it will be useful, 10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | // GNU Affero General Public License for more details. 13 | // 14 | // You should have received a copy of the GNU Affero General Public License 15 | // along with this program. If not, see . -------------------------------------------------------------------------------- /HandlerGenerator/Gencode_Configuration/protobuf_source_git.txt: -------------------------------------------------------------------------------- 1 | # This file is used to configure the git source 2 | # of protobuf. 3 | # 4 | # The file should only contain one line that directs 5 | # the git repository (contains '.git' suffix). e.g.: 6 | # https://github.com/YYHEggEgg/mihomo-protos.git 7 | # Only the first line takes effect. 8 | # 9 | # Notice that it does not need to be enabled if you 10 | # don't have problem accessing GitHub; it'll probably 11 | # affect the build interval. 12 | -------------------------------------------------------------------------------- /HandlerGenerator/HandlerGenerator.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Exe 5 | net6.0 6 | Major 7 | enable 8 | enable 9 | csharp_Protoshift.Enhanced.Handlers.Generator 10 | 1.0.2 11 | YYHEggEgg 12 | csharp-Protoshift.$(AssemblyName) 13 | Copyright (c) 2023 EggEgg 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /HandlerGenerator/OuterInvokeConfig.cs: -------------------------------------------------------------------------------- 1 | namespace csharp_Protoshift.Enhanced.Handlers.Generator 2 | { 3 | /// 4 | /// This class is used for configuring the invoke path of some apps. 5 | /// It's useful if you don't add them to the environment PATH. 6 | /// 7 | internal class OuterInvokeGlobalConfig 8 | { 9 | /// 10 | /// The protobuf compiler from https://github.com/protocolbuffers/protobuf/releases. 11 | /// If protoc isn't in the PATH, you can change it to a definitive path. 12 | /// Not recommend a relative path because the working directory will be changed by the program at the startup. 13 | /// 14 | /// Set the value to not null to specify the path of protobuf compiler. 15 | public const string? protoc_path = null; 16 | /// 17 | /// The dotnet runtime CLI from Microsoft. 18 | /// If dotnet isn't in the PATH, you can change it to a definitive path. 19 | /// Not recommend a relative path because the working directory will be changed by the program at the startup. 20 | /// 21 | public const string dotnet_path = "dotnet"; 22 | /// 23 | /// The git path. In most cases you should make git into PATH instead of changing here. 24 | /// If git isn't in the PATH, you can change it to a definitive path. 25 | /// Not recommend a relative path because the working directory will be changed by the program at the startup. 26 | /// 27 | public const string git_path = "git"; 28 | /// 29 | /// The powershell path in Windows. This constant is here just because it can be here. 30 | /// 31 | public const string windows_powershell_path = "powershell.exe"; 32 | /// 33 | /// The maximum length of creating a process's command line 34 | /// string. The minimum value ever searched is Windows 35 | /// cmd.exe's 8191, but here use 7 * 1024. 36 | /// 37 | public static int maximum_createproc_length => 7 * 1024; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /HandlerGenerator/ProtoFieldNameAnalyze/Compiled/StringPool.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Generated by the protocol buffer compiler. DO NOT EDIT! 3 | // source: StringPool.proto 4 | // 5 | #pragma warning disable 1591, 0612, 3021, 8981 6 | #region Designer generated code 7 | 8 | using pb = global::Google.Protobuf; 9 | using pbc = global::Google.Protobuf.Collections; 10 | using pbr = global::Google.Protobuf.Reflection; 11 | using scg = global::System.Collections.Generic; 12 | /// Holder for reflection information generated from StringPool.proto 13 | public static partial class StringPoolReflection { 14 | 15 | #region Descriptor 16 | /// File descriptor for StringPool.proto 17 | public static pbr::FileDescriptor Descriptor { 18 | get { return descriptor; } 19 | } 20 | private static pbr::FileDescriptor descriptor; 21 | 22 | static StringPoolReflection() { 23 | byte[] descriptorData = global::System.Convert.FromBase64String( 24 | string.Concat( 25 | "ChBTdHJpbmdQb29sLnByb3RvKrUBCgpTdHJpbmdQb29sEg4KCmlkZW50aWZp", 26 | "ZXIQABIbChdjbGllbnRfY29uZmlnX2VuY3J5cHRlZBABEhUKEXNlcnZlcl9z", 27 | "ZWNyZXRfa2V5EAISFQoRY2xpZW50X3NlY3JldF9rZXkQAxIPCgtyRWdpb25f", 28 | "aW5mbxAEEg8KC3JlZ2lvbl9pbmZvEAQSDwoLcmVnaW9uX2luRm8QBBIVChFV", 29 | "bmszMzAwX0hCRlZJSkROShAFGgIQAWIGcHJvdG8z")); 30 | descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData, 31 | new pbr::FileDescriptor[] { }, 32 | new pbr::GeneratedClrTypeInfo(new[] {typeof(global::StringPool), }, null, null)); 33 | } 34 | #endregion 35 | 36 | } 37 | #region Enums 38 | public enum StringPool { 39 | [pbr::OriginalName("identifier")] Identifier = 0, 40 | [pbr::OriginalName("client_config_encrypted")] ClientConfigEncrypted = 1, 41 | [pbr::OriginalName("server_secret_key")] ServerSecretKey = 2, 42 | [pbr::OriginalName("client_secret_key")] ClientSecretKey = 3, 43 | [pbr::OriginalName("rEgion_info")] REgionInfo = 4, 44 | [pbr::OriginalName("region_info", PreferredAlias = false)] RegionInfo = 4, 45 | [pbr::OriginalName("region_inFo", PreferredAlias = false)] RegionInFo = 4, 46 | [pbr::OriginalName("Unk3300_HBFVIJDNJ")] Unk3300Hbfvijdnj = 5, 47 | } 48 | 49 | #endregion 50 | 51 | 52 | #endregion Designer generated code 53 | -------------------------------------------------------------------------------- /HandlerGenerator/ProtoFieldNameAnalyze/GeneratedProtos/StringPool.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | enum StringPool { 3 | option allow_alias = true; 4 | identifier = 0; 5 | client_config_encrypted = 1; 6 | server_secret_key = 2; 7 | client_secret_key = 3; 8 | rEgion_info = 4; 9 | region_info = 4; 10 | region_inFo = 4; 11 | Unk3300_HBFVIJDNJ = 5; 12 | } 13 | 14 | // message AAA { 15 | // string rEgion_info = 1; 16 | // } 17 | 18 | // message BBB { 19 | // string region_info = 2; 20 | // } -------------------------------------------------------------------------------- /HandlerGenerator/ProtoFieldNameAnalyze/README.md: -------------------------------------------------------------------------------- 1 | # 分析 Protobuf 编译后字段的名称 2 | 3 | 众所周知,Protobuf 使用一种类似于驼峰命名法的方法在编译后重命名字段,但它具有很多 corner case。 4 | 5 | 这里为了替代自行推断字段名可能产生的 bug,使用了另一种方法——让 protoc 来处理。 6 | 7 | 先来看一组例子: 8 | 9 | ```proto 10 | syntax = "proto3"; 11 | enum StringPool { 12 | identifier = 0; 13 | client_config_encrypted = 1; 14 | server_secret_key = 2; 15 | client_secret_key = 3; 16 | region_info = 4; 17 | Unk3300_HBFVIJDNJ = 5; 18 | } 19 | ``` 20 | 21 | 将其编译将会得到以下代码: 22 | 23 | ```cs 24 | // 25 | // Generated by the protocol buffer compiler. DO NOT EDIT! 26 | // source: StringPool.proto 27 | // 28 | #pragma warning disable 1591, 0612, 3021, 8981 29 | #region Designer generated code 30 | ... 31 | #region Enums 32 | public enum StringPool { 33 | [pbr::OriginalName("identifier")] Identifier = 0, 34 | [pbr::OriginalName("client_config_encrypted")] ClientConfigEncrypted = 1, 35 | [pbr::OriginalName("server_secret_key")] ServerSecretKey = 2, 36 | [pbr::OriginalName("client_secret_key")] ClientSecretKey = 3, 37 | [pbr::OriginalName("region_info")] RegionInfo = 4, 38 | [pbr::OriginalName("Unk3300_HBFVIJDNJ")] Unk3300Hbfvijdnj = 5, 39 | } 40 | 41 | #endregion 42 | 43 | 44 | #endregion Designer generated code 45 | ``` 46 | 47 | 可以看到,对于每个 enum 字段,protoc 会在其中标识其原来定义的名字(message 生成的代码则不会有)。 48 | 那么可以想到一种极为方便的方式:收集所有 proto 的字段,将其收集入一个“字符串池”proto,然后通过编译生成的代码来获取字段名。 49 | 50 | 但是 protoc 对于 enum 仍会进行特殊处理,可能会导致生成的字段名被影响(比如前半段与 enum 名重合而被省略)。如何解决? 51 | 针对这种情况,易知多个 enum 名不可能为同一个字段名的前缀。因此只需要通过不同的 enum 名生成三份代码,取出现过至少两次的名字即可。 -------------------------------------------------------------------------------- /HandlerGenerator/ProtoFieldNameAnalyze/run_test.bat: -------------------------------------------------------------------------------- 1 | protoc --proto_path="GeneratedProtos" "GeneratedProtos\*.proto" --csharp_out="Compiled" -------------------------------------------------------------------------------- /HandlerGenerator/ProtobufManage/DMCATakenDownException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace csharp_Protoshift.Enhanced.Handlers.Generator.ProtobufManage 8 | { 9 | /// 10 | /// 11 | /// 12 | internal class DMCATakenDownException : Exception 13 | { 14 | public DMCATakenDownException(string message) : base(message) { } 15 | public DMCATakenDownException(string message, Exception? innerException) : base(message, innerException) { } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /HandlerGenerator/ProtobufManage/ProtoStatInfo.cs: -------------------------------------------------------------------------------- 1 | namespace csharp_Protoshift.Enhanced.Handlers.Generator.ProtobufManage; 2 | 3 | internal enum ProtoStat 4 | { 5 | Undefined, 6 | Valid, 7 | Deprecated, 8 | DMCATakenDown 9 | } 10 | 11 | internal class ProtoStatInfo 12 | { 13 | /// 14 | /// The protobuf version's current accessibility. 15 | /// 16 | public ProtoStat CurrentStat { get; set; } 17 | /// 18 | /// The repository that contains proto2json outputs. 19 | /// Only valid when 'CurrentStat' = 'DMCATakenDown'. 20 | /// 21 | public string? RedirectToRepo { get; set; } 22 | /// 23 | /// The release/updated UTC time of this branch. 24 | /// 25 | public DateTime ReleaseTime { get; set; } 26 | } 27 | -------------------------------------------------------------------------------- /HandlerGenerator/ProtobufManage/RunUpdateProtobufConfig.cs: -------------------------------------------------------------------------------- 1 | using CommandLine; 2 | using CommandLine.Text; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | 9 | namespace csharp_Protoshift.Enhanced.Handlers.Generator.ProtobufManage 10 | { 11 | internal class RunUpdateProtobufConfig 12 | { 13 | [Option('c', "clear", Required = false, Default = false, HelpText = "Clear the smart build record to get rid of related issues.")] 14 | public bool ClearWorkspace { get; set; } 15 | [Option('u', "update", Required = false, Default = false, HelpText = "Fetch the newest protobuf.")] 16 | public bool RequestUpdate { get; set; } 17 | [Option("branch-oldprotos", Required = false, Default = null, HelpText = "The branch you would like to choose.")] 18 | public string? OldProtosBranch { get; set; } 19 | [Option("branch-newprotos", Required = false, Default = null, HelpText = "The branch you would like to choose.")] 20 | public string? NewProtosBranch { get; set; } 21 | [Option('y', Required = false, Default = false, HelpText = "Automatically passes every queries in building. Not recommend to enable this because some nasty situations needs human help.")] 22 | public bool AlwaysPassChoices { get; set; } 23 | [Option("fail-on-afterbuild-failure", Required = false, Default = true, HelpText = "Whether the builder should exit with non-zero code when the custom after-build task script failed. Default is Yes.")] 24 | public bool PublishFailOnAfterBuildTasksFailure { get; set; } 25 | 26 | [Usage(ApplicationAlias = "csharp-Protoshift.HandlerGenerator")] 27 | public static IEnumerable Examples 28 | { 29 | get 30 | { 31 | yield return new Example("Update with default/existing protobuf branches.", 32 | new RunUpdateProtobufConfig { RequestUpdate = true }); 33 | yield return new Example("Update with given protobuf branches.", 34 | new RunUpdateProtobufConfig { RequestUpdate = true, OldProtosBranch = "3.4_gio", NewProtosBranch = "3.4_live" }); 35 | yield break; 36 | } 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /HandlerGenerator/ProtoshiftEx/BasicCode/TxtReader.cs: -------------------------------------------------------------------------------- 1 | #region // Generated by ChatGPT 2 | // 请你编写一个静态类 TxtReader,读取具有以下格式的 txt 内容: 3 | 4 | // - 每行代表一个内容,忽略前导/后置空格/缩进。 5 | // - 以 `#` 代表注释符号。 6 | // - 忽略空行。 7 | // - 忽略行末注释。 8 | 9 | // 它需要实现: 10 | 11 | // - `List ReadFrom(string filePath)`:传入文件所在路径,返回每行有效内容的集合。 12 | #endregion 13 | 14 | 15 | using YYHEggEgg.Logger; 16 | 17 | namespace csharp_Protoshift.Enhanced.Handlers.Generator 18 | { 19 | public static class TxtReader 20 | { 21 | public static List ReadFrom(string filePath) 22 | { 23 | var lines = from line in File.ReadAllLines(filePath) 24 | let trimmedLine = line.Trim() 25 | where !string.IsNullOrWhiteSpace(trimmedLine) && !trimmedLine.StartsWith("#") 26 | let index = trimmedLine.IndexOf('#') 27 | select index >= 0 ? trimmedLine.Substring(0, index).TrimEnd() : trimmedLine; 28 | 29 | return lines.ToList(); 30 | } 31 | 32 | /// 33 | /// Read a TXT file with certain count of lines. 34 | /// Throw 35 | /// if there's too few lines, or raise a warning 36 | /// when there's too many lines. 37 | /// 38 | /// A string? array that have a length of . 39 | public static string?[] ReadSpecifiedCount(string filePath, 40 | int minLinesCount, int maxLinesCount, string? logWarnSender = null) 41 | { 42 | var list = ReadFrom(filePath); 43 | if (list.Count < minLinesCount) 44 | { 45 | throw new InvalidOperationException( 46 | $"{filePath} has too few lines (< {minLinesCount}). Please set it back to default."); 47 | } 48 | else if (list.Count > maxLinesCount) 49 | { 50 | Log.Warn($"{filePath} has more than {maxLinesCount} lines. " + 51 | $"Notice that only the first two lines take effect.", logWarnSender); 52 | } 53 | 54 | var rtn = new string[maxLinesCount]; 55 | for (int i = 0; i < list.Count; i++) rtn[i] = list[i]; 56 | return rtn; 57 | } 58 | 59 | /// 60 | /// Read a TXT file with certain count of lines. 61 | /// Throw 62 | /// if there's too few lines, or raise a warning 63 | /// when there's too many lines. 64 | /// 65 | /// 66 | #pragma warning disable CS8619 67 | public static string[] ReadSpecifiedCount(string filePath, 68 | int linesCount, string? logWarnSender = null) => 69 | ReadSpecifiedCount(filePath, linesCount, linesCount, logWarnSender); 70 | #pragma warning restore CS8619 71 | } 72 | } -------------------------------------------------------------------------------- /HandlerGenerator/ProtoshiftEx/CodeGenerate/HandlerJitParamters.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace csharp_Protoshift.Enhanced.Handlers.Generator 8 | { 9 | public partial class HandlerCodeWriter 10 | { 11 | /// 12 | /// Get (code of) a value of 13 | /// to provide for GetNewShiftToOldJitInstance(). 14 | /// 15 | /// 16 | /// 17 | private static string GetTypeJitParamter(string fieldType) 18 | { 19 | return fieldType switch 20 | { 21 | "double" => "4.25", 22 | "float" => "3.4F", 23 | "int32" => "20231024", 24 | "int64" => "202411041200", 25 | "uint32" => "20231024", 26 | "uint64" => "202411041200", 27 | "sint32" => "20231024", 28 | "sint64" => "202411041200", 29 | "fixed32" => "20231024", 30 | "fixed64" => "202411041200", 31 | "sfixed32" => "20231024", 32 | "sfixed64" => "202411041200", 33 | "bool" => "true", 34 | "string" => "\"miHomo Technology Presents\"", 35 | "bytes" => "ByteString.CopyFrom(\"Masquerade of the GIO\", System.Text.Encoding.Default)", 36 | _ => $"handler_{fieldType}.GetNewShiftToOldJitInstance()" 37 | }; 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /HandlerGenerator/ProtoshiftEx/CodeGenerate/SkillIssueCollection.cs: -------------------------------------------------------------------------------- 1 | using YYHEggEgg.ProtoParser; 2 | 3 | namespace csharp_Protoshift.Enhanced.Handlers.Generator 4 | { 5 | internal class SkillIssueCollection 6 | { 7 | public bool HasSkillIssue = false; 8 | public List CommonFields = new(); 9 | public List MapFields = new(); 10 | public List OneofFields = new(); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /HandlerGenerator/RegenOutput/RegenOutputCommonField.cs: -------------------------------------------------------------------------------- 1 | using YYHEggEgg.ProtoParser; 2 | 3 | namespace csharp_Protoshift.Enhanced.Handlers.Generator.RegenOutput 4 | { 5 | static class RegenOutputCommonField 6 | { 7 | public static void OutputCommonField(ref BasicCodeWriter fi, 8 | ref SortedSet imports, CommonResult commonResult) 9 | { 10 | fi.WriteLine($"{(commonResult.IsRepeatedField ? "repeated " : "")}{commonResult.FieldType} {commonResult.FieldName} = {commonResult.FieldNumber};"); 11 | if (commonResult.IsImportType) imports.Add(commonResult.FieldType); 12 | } 13 | } 14 | } -------------------------------------------------------------------------------- /HandlerGenerator/RegenOutput/RegenOutputEnum.cs: -------------------------------------------------------------------------------- 1 | using YYHEggEgg.ProtoParser; 2 | 3 | namespace csharp_Protoshift.Enhanced.Handlers.Generator.RegenOutput 4 | { 5 | static class RegenOutputEnum 6 | { 7 | public static void OutputEnum(ref BasicCodeWriter fi, EnumResult enumResult) 8 | { 9 | var options = from tuple in enumResult.EnumOptions 10 | orderby tuple.name 11 | select tuple; 12 | var positive_nodes = from tuple in enumResult.EnumNodes 13 | where tuple.number > 0 14 | orderby tuple.number 15 | select tuple; 16 | var non_positive_nodes = from tuple in enumResult.EnumNodes 17 | where tuple.number <= 0 18 | orderby tuple.number descending 19 | select tuple; 20 | fi.WriteLine($"enum {enumResult.EnumName}"); 21 | fi.EnterCodeRegion(); 22 | var non_duplicate_nodes_count = 23 | positive_nodes.Concat(non_positive_nodes) 24 | .Distinct(new EnumResult.EnumNodeNumberEqualityComparer()).Count(); 25 | 26 | if (non_duplicate_nodes_count < non_positive_nodes.Count() + positive_nodes.Count()) 27 | fi.WriteLine($"option allow_alias = true;"); 28 | 29 | foreach (var tuple in non_positive_nodes) 30 | { 31 | fi.WriteLine($"{tuple.name} = {tuple.number};"); 32 | } 33 | foreach (var tuple in positive_nodes) 34 | { 35 | fi.WriteLine($"{tuple.name} = {tuple.number};"); 36 | } 37 | fi.ExitCodeRegion(); 38 | } 39 | } 40 | } -------------------------------------------------------------------------------- /HandlerGenerator/RegenOutput/RegenOutputMapField.cs: -------------------------------------------------------------------------------- 1 | using YYHEggEgg.ProtoParser; 2 | 3 | namespace csharp_Protoshift.Enhanced.Handlers.Generator.RegenOutput 4 | { 5 | static class RegenOutputMapField 6 | { 7 | public static void OutputMapField(ref BasicCodeWriter fi, 8 | ref SortedSet imports, MapResult mapResult) 9 | { 10 | fi.WriteLine($"map<{mapResult.KeyType}, {mapResult.ValueType}> {mapResult.FieldName} = {mapResult.FieldNumber};"); 11 | if (mapResult.KeyIsImportType) imports.Add(mapResult.KeyType); 12 | if (mapResult.ValueIsImportType) imports.Add(mapResult.ValueType); 13 | } 14 | } 15 | } -------------------------------------------------------------------------------- /HandlerGenerator/RegenOutput/RegenOutputOneofField.cs: -------------------------------------------------------------------------------- 1 | using YYHEggEgg.ProtoParser; 2 | 3 | namespace csharp_Protoshift.Enhanced.Handlers.Generator.RegenOutput 4 | { 5 | static class RegenOutputOneofField 6 | { 7 | public static void OutputOneofField(ref BasicCodeWriter fi, 8 | ref SortedSet imports, OneofResult oneofResult) 9 | { 10 | fi.WriteLine($"oneof {oneofResult.OneofEntryName}"); 11 | fi.EnterCodeRegion(); 12 | var commonFields = from commonField in oneofResult.OneofInnerFields 13 | orderby commonField.FieldName 14 | select commonField; 15 | foreach (var commonField in commonFields) 16 | { 17 | RegenOutputCommonField.OutputCommonField(ref fi, ref imports, commonField); 18 | } 19 | fi.ExitCodeRegion(); 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /HandlerGenerator/StartupWorkingDirChanger.cs: -------------------------------------------------------------------------------- 1 | using YYHEggEgg.Logger; 2 | 3 | namespace csharp_Protoshift.Enhanced.Handlers.Generator 4 | { 5 | internal static class StartupWorkingDirChanger 6 | { 7 | public const string? Required_file = "./HandlerGenerator.csproj"; 8 | public const string? Required_directory = "./../csharp-Protoshift/resources"; 9 | 10 | public const string Terminating_Note = "Can't find source code path. Please run this program with dotnet run. \n" + 11 | "***********WARNING**********\n" + 12 | "DO NOT USE --project PARAM! USE cd COMMAND INSTEAD!\n" + 13 | "***********WARNING**********"; 14 | 15 | public static void ChangeToDotNetRunPath(LoggerConfig log_init_config) 16 | { 17 | string before_workingdir = Environment.CurrentDirectory; 18 | string after_workingdir; 19 | if (CheckForRequirements()) 20 | { 21 | after_workingdir = before_workingdir; 22 | } 23 | else 24 | { 25 | var program_path = AppDomain.CurrentDomain.BaseDirectory; 26 | after_workingdir = GetParentDirectory(program_path, 4); 27 | } 28 | 29 | if (Directory.Exists(after_workingdir) && CheckForRequirements(after_workingdir)) 30 | { 31 | Environment.CurrentDirectory = after_workingdir; 32 | Log.Initialize(log_init_config); 33 | Log.Dbug($"Startup Current directory is: {before_workingdir}."); 34 | Log.Dbug($"Changed Current directory to: {after_workingdir}."); 35 | } 36 | else 37 | { 38 | Log.Initialize(log_init_config); 39 | Log.Warn($"Startup Current directory is: {before_workingdir}."); 40 | Log.Warn($"Found Current directory is: {after_workingdir}."); 41 | Log.Erro(Terminating_Note, nameof(StartupWorkingDirChanger)); 42 | Log.Erro("Process terminated for false launch. Exit code is 4206.", nameof(StartupWorkingDirChanger)); 43 | // if (log_init_config.Use_Console_Wrapper) 44 | // ConsoleWrapper.ReadLine(); 45 | // else Console.ReadLine(); 46 | Environment.Exit(4206); 47 | } 48 | } 49 | 50 | private static bool CheckForRequirements(string? dir = null) 51 | { 52 | dir ??= Environment.CurrentDirectory; 53 | if (Required_file != null && !File.Exists($"{dir}/{Required_file}")) return false; 54 | if (Required_directory != null && !Directory.Exists($"{dir}/{Required_directory}")) return false; 55 | return true; 56 | } 57 | 58 | private static string GetParentDirectory(string? base_dir, int parent_level) 59 | { 60 | if (base_dir == null) return string.Empty; 61 | if (parent_level == 0) return base_dir; 62 | return GetParentDirectory(Directory.GetParent(base_dir)?.FullName, parent_level - 1); 63 | } 64 | } 65 | } -------------------------------------------------------------------------------- /KCP/.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: #KumoKyaku 2 | custom: ["https://github.com/KumoKyaku/KumoKyaku.github.io/blob/develop/source/_posts/%E5%9B%BE%E5%BA%8A/alipay.png" , "https://paypal.me/kumokyaku?country.x=C2&locale.x=zh_XC"] 3 | -------------------------------------------------------------------------------- /KCP/.gitignore: -------------------------------------------------------------------------------- 1 | ChangeLog.md 2 | Image 3 | KCP.sln 4 | KcpDemo 5 | OpenSource.snk 6 | TestClient 7 | TestServer 8 | UnitTestProject1 9 | UnityIL2CPPTest 10 | 11 | # ------------------------- 12 | 13 | ## Ignore Visual Studio temporary files, build results, and 14 | ## files generated by popular Visual Studio add-ons. 15 | 16 | # User-specific files 17 | *.suo 18 | *.user 19 | *.userosscache 20 | *.sln.docstates 21 | 22 | # User-specific files (MonoDevelop/Xamarin Studio) 23 | *.userprefs 24 | 25 | # Build results 26 | [Dd]ebug/ 27 | [Dd]ebugPublic/ 28 | [Rr]elease/ 29 | [Rr]eleases/ 30 | x64/ 31 | x86/ 32 | bld/ 33 | [Bb]in/ 34 | [Oo]bj/ 35 | [Ll]og/ 36 | 37 | # Visual Studio 2015 cache/options directory 38 | .vs/ 39 | # Uncomment if you have tasks that create the 40 | packages/ 41 | -------------------------------------------------------------------------------- /KCP/Kcp/FakeKcpIO.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Buffers; 3 | using System.Collections.Generic; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace System.Net.Sockets.Kcp 8 | { 9 | /// 10 | /// 用于调试的KCP IO 类,没有Kcp功能 11 | /// 12 | public class FakeKcpIO : IKcpIO 13 | { 14 | QueuePipe recv = new QueuePipe(); 15 | public int Input(ReadOnlySpan span) 16 | { 17 | byte[] buffer = new byte[span.Length]; 18 | span.CopyTo(buffer); 19 | recv.Write(buffer); 20 | return 0; 21 | } 22 | 23 | public int Input(ReadOnlySequence span) 24 | { 25 | byte[] buffer = new byte[span.Length]; 26 | span.CopyTo(buffer); 27 | return Input(buffer); 28 | } 29 | 30 | public async ValueTask RecvAsync(IBufferWriter writer, object options = null) 31 | { 32 | var buffer = await recv.ReadAsync().ConfigureAwait(false); 33 | var target = writer.GetMemory(buffer.Length); 34 | buffer.AsSpan().CopyTo(target.Span); 35 | writer.Advance(buffer.Length); 36 | } 37 | 38 | public async ValueTask RecvAsync(ArraySegment buffer, object options = null) 39 | { 40 | var temp = await recv.ReadAsync().ConfigureAwait(false); 41 | temp.AsSpan().CopyTo(buffer); 42 | return temp.Length; 43 | } 44 | 45 | QueuePipe send = new QueuePipe(); 46 | public int Send(ReadOnlySpan span, object options = null) 47 | { 48 | byte[] buffer = new byte[span.Length]; 49 | span.CopyTo(buffer); 50 | send.Write(buffer); 51 | return 0; 52 | } 53 | 54 | public int Send(ReadOnlySequence span, object options = null) 55 | { 56 | byte[] buffer = new byte[span.Length]; 57 | span.CopyTo(buffer); 58 | return Send(buffer); 59 | } 60 | 61 | public async ValueTask OutputAsync(IBufferWriter writer, object options = null) 62 | { 63 | var buffer = await send.ReadAsync().ConfigureAwait(false); 64 | Write(writer, buffer); 65 | } 66 | 67 | private static void Write(IBufferWriter writer, byte[] buffer) 68 | { 69 | var span = writer.GetSpan(buffer.Length); 70 | buffer.AsSpan().CopyTo(span); 71 | writer.Advance(buffer.Length); 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /KCP/Kcp/IKcpSegment.cs: -------------------------------------------------------------------------------- 1 | namespace System.Net.Sockets.Kcp 2 | { 3 | /// 4 | /// Kcp报头 5 | /// https://zhuanlan.zhihu.com/p/559191428 6 | /// 7 | public interface IKcpHeader 8 | { 9 | /// 10 | /// 会话编号,两方一致才会通信 11 | /// 12 | uint conv { get; set; } 13 | #if MIHOMO_KCP 14 | /// 15 | /// miHoMo KCP modify: IUINT32 token 16 | /// Change line(s) in file compare: ikcp.h, +271 17 | /// 18 | uint token { get; set; } 19 | #endif 20 | /// 21 | /// 指令类型 22 | /// 23 | /// 24 | /// IKCP_CMD_PUSH = 81 // cmd: push data 数据报文 25 | /// IKCP_CMD_ACK = 82 // cmd: ack 确认报文 26 | /// IKCP_CMD_WASK = 83 // cmd: window probe (ask) 窗口探测报文,询问对端剩余接收窗口的大小. 27 | /// IKCP_CMD_WINS = 84 // cmd: window size (tell) 窗口通知报文,通知对端剩余接收窗口的大小. 28 | /// 29 | byte cmd { get; set; } 30 | /// 31 | /// 剩余分片数量,表示随后还有多少个报文属于同一个包。 32 | /// 33 | byte frg { get; set; } 34 | /// 35 | /// 自己可用窗口大小 36 | /// 37 | ushort wnd { get; set; } 38 | /// 39 | /// 发送时的时间戳 40 | /// 41 | uint ts { get; set; } 42 | /// 43 | /// 编号 确认编号或者报文编号 44 | /// 45 | uint sn { get; set; } 46 | /// 47 | /// 代表编号前面的所有报都收到了的标志 48 | /// 49 | uint una { get; set; } 50 | /// 51 | /// 数据内容长度 52 | /// 53 | uint len { get; } 54 | } 55 | public interface IKcpSegment : IKcpHeader 56 | { 57 | /// 58 | /// 重传的时间戳。超过当前时间重发这个包 59 | /// 60 | uint resendts { get; set; } 61 | /// 62 | /// 超时重传时间,根据网络去定 63 | /// 64 | uint rto { get; set; } 65 | /// 66 | /// 快速重传机制,记录被跳过的次数,超过次数进行快速重传 67 | /// 68 | uint fastack { get; set; } 69 | /// 70 | /// 重传次数 71 | /// 72 | uint xmit { get; set; } 73 | 74 | /// 75 | /// 数据内容 76 | /// 77 | Span data { get; } 78 | /// 79 | /// 将IKcpSegment编码成字节数组,并返回总长度(包括Kcp报头) 80 | /// 81 | /// 82 | /// 83 | int Encode(Span buffer); 84 | } 85 | 86 | public interface ISegmentManager where Segment : IKcpSegment 87 | { 88 | Segment Alloc(int appendDateSize); 89 | void Free(Segment seg); 90 | } 91 | 92 | } 93 | 94 | 95 | 96 | -------------------------------------------------------------------------------- /KCP/Kcp/KcpOutputWriter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Buffers; 3 | using System.Collections.Generic; 4 | using System.Text; 5 | 6 | namespace System.Net.Sockets.Kcp 7 | { 8 | public abstract class KcpOutputWriter : IKcpOutputWriter 9 | { 10 | public int UnflushedBytes { get; set; } 11 | public IMemoryOwner MemoryOwner { get; set; } 12 | public void Flush() 13 | { 14 | Output(MemoryOwner, UnflushedBytes); 15 | MemoryOwner = null; 16 | UnflushedBytes = 0; 17 | } 18 | 19 | public void Advance(int count) 20 | { 21 | UnflushedBytes += count; 22 | } 23 | 24 | public Memory GetMemory(int sizeHint = 0) 25 | { 26 | if (MemoryOwner == null) 27 | { 28 | MemoryOwner = MemoryPool.Shared.Rent(2048); 29 | } 30 | return MemoryOwner.Memory.Slice(UnflushedBytes); 31 | } 32 | 33 | public Span GetSpan(int sizeHint = 0) 34 | { 35 | if (MemoryOwner == null) 36 | { 37 | MemoryOwner = MemoryPool.Shared.Rent(2048); 38 | } 39 | return MemoryOwner.Memory.Span.Slice(UnflushedBytes); 40 | } 41 | 42 | /// 43 | /// Socket发送是要pin byte[],为了不阻塞KcpFlush,动态缓存是必须的。 44 | /// 45 | /// 46 | /// 47 | public abstract void Output(IMemoryOwner buffer, int avalidLength); 48 | } 49 | } 50 | 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /KCP/Kcp/KcpTrace.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace System.Net.Sockets.Kcp 6 | { 7 | public partial class KcpCore 8 | { 9 | public KcpLogMask LogMask { get; set; } = KcpLogMask.IKCP_LOG_PARSE_DATA | KcpLogMask.IKCP_LOG_NEED_SEND | KcpLogMask.IKCP_LOG_DEAD_LINK; 10 | 11 | public virtual bool CanLog(KcpLogMask mask) 12 | { 13 | if ((mask & LogMask) == 0) 14 | { 15 | return false; 16 | } 17 | 18 | #if NETSTANDARD2_0_OR_GREATER || NET5_0_OR_GREATER 19 | if (TraceListener != null) 20 | { 21 | return true; 22 | } 23 | #endif 24 | return false; 25 | } 26 | 27 | #if NETSTANDARD2_0_OR_GREATER || NET5_0_OR_GREATER 28 | public System.Diagnostics.TraceListener TraceListener { get; set; } 29 | #endif 30 | 31 | public virtual void LogFail(string message) 32 | { 33 | #if NETSTANDARD2_0_OR_GREATER || NET5_0_OR_GREATER 34 | TraceListener?.Fail(message); 35 | #endif 36 | } 37 | 38 | public virtual void LogWriteLine(string message, string category) 39 | { 40 | #if NETSTANDARD2_0_OR_GREATER || NET5_0_OR_GREATER 41 | TraceListener?.WriteLine(message, category); 42 | #endif 43 | } 44 | 45 | [Obsolete("一定要先判断CanLog 内部判断是否存在TraceListener,避免在没有TraceListener时生成字符串", true)] 46 | public virtual void LogWriteLine(string message, KcpLogMask mask) 47 | { 48 | #if NETSTANDARD2_0_OR_GREATER || NET5_0_OR_GREATER 49 | if (CanLog(mask)) 50 | { 51 | LogWriteLine(message, mask.ToString()); 52 | } 53 | #endif 54 | } 55 | } 56 | 57 | [Flags] 58 | public enum KcpLogMask 59 | { 60 | IKCP_LOG_OUTPUT = 1 << 0, 61 | IKCP_LOG_INPUT = 1 << 1, 62 | IKCP_LOG_SEND = 1 << 2, 63 | IKCP_LOG_RECV = 1 << 3, 64 | IKCP_LOG_IN_DATA = 1 << 4, 65 | IKCP_LOG_IN_ACK = 1 << 5, 66 | IKCP_LOG_IN_PROBE = 1 << 6, 67 | IKCP_LOG_IN_WINS = 1 << 7, 68 | IKCP_LOG_OUT_DATA = 1 << 8, 69 | IKCP_LOG_OUT_ACK = 1 << 9, 70 | IKCP_LOG_OUT_PROBE = 1 << 10, 71 | IKCP_LOG_OUT_WINS = 1 << 11, 72 | 73 | IKCP_LOG_PARSE_DATA = 1 << 12, 74 | IKCP_LOG_NEED_SEND = 1 << 13, 75 | IKCP_LOG_DEAD_LINK = 1 << 14, 76 | } 77 | } 78 | 79 | 80 | -------------------------------------------------------------------------------- /KCP/Kcp/README.md: -------------------------------------------------------------------------------- 1 | # About reference 2 | The code of this program is from [KumoKyaku/KCP](https://github.com/KumoKyaku/KCP). 3 | 4 | The original repository is using [MIT License](https://github.com/KumoKyaku/KCP/blob/master/LICENSE). 5 | 6 | ## Information 7 | 8 | Nuget: v2.6.3(latest [![Nuget](https://img.shields.io/nuget/v/Kcp)](https://www.nuget.org/packages/Kcp/)) 9 | Commit: [b478eed on master (Jul 12, 2023, 8:59 AM GMT+8)](https://github.com/KumoKyaku/KCP/commit/b478eed599b09481f5030dd3ba1c6c5fa3058a7a) 10 | 11 | ## Modifications 12 | Have some modifications for miHoMo KCP support. 13 | There're references in directory `miHoMoKCP_Compare`. 14 | 15 | For more information, search for code `miHoMo KCP modify` in this project. 16 | To see the changes more clearly, compare files in `miHoMoKCP_Compare` with tools (e.g. VSCode). 17 | 18 | **If you want to switch to original KCP, delete define constant `MIHOMO_KCP`.** -------------------------------------------------------------------------------- /KCP/Kcp/SimpleKcpClient.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Buffers; 3 | using System.Collections.Generic; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | #if NETSTANDARD2_0_OR_GREATER || NET5_0_OR_GREATER 8 | 9 | namespace System.Net.Sockets.Kcp.Simple 10 | { 11 | /// 12 | /// 简单例子 13 | /// 14 | public class SimpleKcpClient : IKcpCallback 15 | { 16 | UdpClient client; 17 | 18 | public SimpleKcpClient() 19 | : this(null) 20 | { 21 | 22 | } 23 | 24 | public SimpleKcpClient(IPEndPoint endPoint) 25 | { 26 | client = new UdpClient(); 27 | client.Connect(endPoint); 28 | #if !MIHOMO_KCP 29 | kcp = new SimpleSegManager.Kcp(2001, this); 30 | #else 31 | kcp = new SimpleSegManager.Kcp(2001, 10000, this); 32 | #endif 33 | this.EndPoint = endPoint; 34 | BeginRecv(); 35 | } 36 | 37 | public SimpleSegManager.Kcp kcp { get; } 38 | public IPEndPoint EndPoint { get; set; } 39 | 40 | public void Output(IMemoryOwner buffer, int avalidLength, bool isKcpPacket = true) 41 | { 42 | var s = buffer.Memory.Span.Slice(0, avalidLength).ToArray(); 43 | client.SendAsync(s, s.Length); 44 | buffer.Dispose(); 45 | } 46 | 47 | public async void SendAsync(byte[] datagram, int bytes) 48 | { 49 | kcp.Send(datagram.AsSpan().Slice(0, bytes)); 50 | } 51 | 52 | public async ValueTask ReceiveAsync() 53 | { 54 | var (buffer, avalidLength) = kcp.TryRecv(); 55 | while (buffer == null) 56 | { 57 | await Task.Delay(10); 58 | (buffer, avalidLength) = kcp.TryRecv(); 59 | } 60 | 61 | var s = buffer.Memory.Span.Slice(0, avalidLength).ToArray(); 62 | return s; 63 | } 64 | 65 | private async void BeginRecv() 66 | { 67 | var res = await client.ReceiveAsync(); 68 | EndPoint = res.RemoteEndPoint; 69 | kcp.Input(res.Buffer); 70 | BeginRecv(); 71 | } 72 | } 73 | } 74 | 75 | #endif 76 | 77 | 78 | -------------------------------------------------------------------------------- /KCP/Kcp/SingleThreadAssert.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using YYHEggEgg.Logger; 7 | 8 | namespace OuterCode 9 | { 10 | /// 11 | /// Assert 是否存在线程安全问题 12 | /// 13 | public class SingleThreadAssert 14 | { 15 | #if ASSERT_STAINVOKE 16 | private bool occupying = false; 17 | #if DEBUG 18 | private string occupier_StackTrace = "-----STA Assert not invoked yet-----"; 19 | #endif 20 | public readonly string FriendlyName; 21 | public readonly UInt64 Unique_ID; 22 | 23 | private static object increasing_id_lock = "wtf am I debugging"; 24 | private static UInt64 increasing_id = 0; 25 | #endif 26 | 27 | public SingleThreadAssert(string friendlyName) 28 | { 29 | #if ASSERT_STAINVOKE 30 | FriendlyName = friendlyName; 31 | lock (increasing_id_lock) Unique_ID = increasing_id++; 32 | #endif 33 | } 34 | 35 | public void Enter() 36 | { 37 | #if ASSERT_STAINVOKE 38 | if (occupying) 39 | { 40 | Log.Erro($"STA Assert failed! 2nd invoker stacktrace: \n{Environment.StackTrace}", $"{nameof(SingleThreadAssert)}({FriendlyName}, ID:{Unique_ID})"); 41 | #if DEBUG 42 | Log.Erro($"1st invoker stacktrace: \n{occupier_StackTrace}", $"{nameof(SingleThreadAssert)}({FriendlyName}, ID:{Unique_ID})"); 43 | throw new InvalidOperationException($"STA Assert for ({FriendlyName}, ID:{Unique_ID}) failed!"); 44 | #endif 45 | } 46 | else 47 | { 48 | occupying = true; 49 | #if DEBUG 50 | occupier_StackTrace = Environment.StackTrace; 51 | #endif 52 | } 53 | #endif 54 | } 55 | 56 | public void Exit() 57 | { 58 | #if ASSERT_STAINVOKE 59 | occupying = false; 60 | #endif 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /KCP/Kcp/UniqueIDManager.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace OuterCode 8 | { 9 | public class UniqueIDManager 10 | { 11 | private static Dictionary idAssigner = new(); 12 | public readonly UInt64 ID; 13 | 14 | public UniqueIDManager(string friendlyName) 15 | { 16 | lock (idAssigner) 17 | { 18 | if (!idAssigner.ContainsKey(friendlyName)) 19 | idAssigner.Add(friendlyName, 0); 20 | ID = ++idAssigner[friendlyName]; 21 | } 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 EggEgg 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /NewProtoHandlers/.gitignore: -------------------------------------------------------------------------------- 1 | Google.Protobuf* 2 | AskCmdId.cs -------------------------------------------------------------------------------- /NewProtoHandlers/NewProtoHandlers.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0 5 | Major 6 | enable 7 | enable 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /OldProtoHandlers/.gitignore: -------------------------------------------------------------------------------- 1 | Google.Protobuf* 2 | AskCmdId.cs -------------------------------------------------------------------------------- /OldProtoHandlers/OldProtoHandlers.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0 5 | Major 6 | enable 7 | enable 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /ProtoshiftHandlers/.gitignore: -------------------------------------------------------------------------------- 1 | Generated 2 | ProtoDispatch 3 | -------------------------------------------------------------------------------- /ProtoshiftHandlers/Example/Generated_std/HandlerExampleEnum.cs: -------------------------------------------------------------------------------- 1 | // Below is human-written, acting as an generated code example. 2 | // 3 | // ------------------------------------------------------------ 4 | // 5 | // 6 | // Generated by csharp-Protoshift.HandlerGenerator. 7 | // 8 | 9 | #region Designer Generated Code 10 | using Google.Protobuf; 11 | 12 | namespace csharp_Protoshift.Enhanced.Handlers.GeneratedCode 13 | { 14 | public class HandlerExampleEnum 15 | : HandlerEnumBase 16 | { 17 | [System.Diagnostics.DebuggerNonUserCode] 18 | [System.CodeDom.Compiler.GeneratedCode("YYHEggEgg/csharp_Protoshift.HandlerGenerator", "1.0.0.0")] 19 | public override OldProtos.ExampleEnum NewShiftToOld(NewProtos.ExampleEnum newprotocol) 20 | { 21 | switch (newprotocol) 22 | { 23 | case NewProtos.ExampleEnum.None: 24 | return OldProtos.ExampleEnum.None; 25 | case NewProtos.ExampleEnum.ObjFirst: 26 | return OldProtos.ExampleEnum.ObjFirst; 27 | case NewProtos.ExampleEnum.ObjSecond: 28 | return OldProtos.ExampleEnum.ObjSecond; 29 | case NewProtos.ExampleEnum.ObjThird: 30 | return OldProtos.ExampleEnum.ObjThird; 31 | default: // fallback 32 | return OldProtos.ExampleEnum.None; 33 | } 34 | } 35 | 36 | [System.Diagnostics.DebuggerNonUserCode] 37 | [System.CodeDom.Compiler.GeneratedCode("YYHEggEgg/csharp_Protoshift.HandlerGenerator", "1.0.0.0")] 38 | public override NewProtos.ExampleEnum OldShiftToNew(OldProtos.ExampleEnum oldprotocol) 39 | { 40 | switch (oldprotocol) 41 | { 42 | case OldProtos.ExampleEnum.None: 43 | return NewProtos.ExampleEnum.None; 44 | case OldProtos.ExampleEnum.ObjFirst: 45 | return NewProtos.ExampleEnum.ObjFirst; 46 | case OldProtos.ExampleEnum.ObjSecond: 47 | return NewProtos.ExampleEnum.ObjSecond; 48 | case OldProtos.ExampleEnum.ObjThird: 49 | return NewProtos.ExampleEnum.ObjThird; 50 | default: // fallback 51 | return NewProtos.ExampleEnum.None; 52 | } 53 | } 54 | 55 | private static HandlerExampleEnum _globalOnlyInstance = new HandlerExampleEnum(); 56 | [System.Diagnostics.DebuggerNonUserCode] 57 | [System.CodeDom.Compiler.GeneratedCode("YYHEggEgg/csharp_Protoshift.HandlerGenerator", "1.0.0.0")] 58 | public static HandlerExampleEnum GlobalInstance => _globalOnlyInstance; 59 | } 60 | } 61 | #endregion Designer generated code -------------------------------------------------------------------------------- /ProtoshiftHandlers/Example/Generated_std/ProtobufExtension.UnknownFieldSet.cs: -------------------------------------------------------------------------------- 1 | // Below is human-written, acting as an generated code example. 2 | // 3 | // ------------------------------------------------------------ 4 | // 5 | // 6 | // Generated by csharp-Protoshift.HandlerGenerator. 7 | // 8 | 9 | #region Designer Generated Code 10 | 11 | using pb = global::Google.Protobuf; 12 | using pbc = global::Google.Protobuf.Collections; 13 | using pbr = global::Google.Protobuf.Reflection; 14 | using scg = global::System.Collections.Generic; 15 | 16 | namespace OldProtos { 17 | public sealed partial class ExampleProto 18 | { 19 | public pb::UnknownFieldSet UnknownFields => _unknownFields; 20 | } 21 | public sealed partial class ExampleProto2 22 | { 23 | public pb::UnknownFieldSet UnknownFields => _unknownFields; 24 | 25 | public static partial class Types 26 | { 27 | public sealed partial class ExampleInnerProto 28 | { 29 | public pb::UnknownFieldSet UnknownFields => _unknownFields; 30 | } 31 | } 32 | } 33 | public sealed partial class InMessage 34 | { 35 | public pb::UnknownFieldSet UnknownFields => _unknownFields; 36 | } 37 | } 38 | 39 | namespace NewProtos { 40 | public sealed partial class ExampleProto 41 | { 42 | public pb::UnknownFieldSet UnknownFields => _unknownFields; 43 | } 44 | public sealed partial class ExampleProto2 45 | { 46 | public pb::UnknownFieldSet UnknownFields => _unknownFields; 47 | 48 | public static partial class Types 49 | { 50 | public sealed partial class ExampleInnerProto 51 | { 52 | public pb::UnknownFieldSet UnknownFields => _unknownFields; 53 | } 54 | } 55 | } 56 | public sealed partial class InMessage 57 | { 58 | public pb::UnknownFieldSet UnknownFields => _unknownFields; 59 | } 60 | } 61 | #endregion Designer Generated Code -------------------------------------------------------------------------------- /ProtoshiftHandlers/Example/NewProtos/Compiled/ExampleEnum.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Generated by the protocol buffer compiler. DO NOT EDIT! 3 | // source: ExampleEnum.proto 4 | // 5 | #pragma warning disable 1591, 0612, 3021, 8981 6 | #region Designer generated code 7 | 8 | using pb = global::Google.Protobuf; 9 | using pbc = global::Google.Protobuf.Collections; 10 | using pbr = global::Google.Protobuf.Reflection; 11 | using scg = global::System.Collections.Generic; 12 | namespace NewProtos { 13 | 14 | /// Holder for reflection information generated from ExampleEnum.proto 15 | public static partial class ExampleEnumReflection { 16 | 17 | #region Descriptor 18 | /// File descriptor for ExampleEnum.proto 19 | public static pbr::FileDescriptor Descriptor { 20 | get { return descriptor; } 21 | } 22 | private static pbr::FileDescriptor descriptor; 23 | 24 | static ExampleEnumReflection() { 25 | byte[] descriptorData = global::System.Convert.FromBase64String( 26 | string.Concat( 27 | "ChFFeGFtcGxlRW51bS5wcm90byp5CgtFeGFtcGxlRW51bRIVChFFWEFNUExF", 28 | "X0VOVU1fTk9ORRAAEhoKFkVYQU1QTEVfRU5VTV9PQkpfRklSU1QQARIbChdF", 29 | "WEFNUExFX0VOVU1fT0JKX1NFQ09ORBACEhoKFkVYQU1QTEVfRU5VTV9PQkpf", 30 | "VEhJUkQQA0IMqgIJTmV3UHJvdG9zYgZwcm90bzM=")); 31 | descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData, 32 | new pbr::FileDescriptor[] { }, 33 | new pbr::GeneratedClrTypeInfo(new[] {typeof(global::NewProtos.ExampleEnum), }, null, null)); 34 | } 35 | #endregion 36 | 37 | } 38 | #region Enums 39 | public enum ExampleEnum { 40 | [pbr::OriginalName("EXAMPLE_ENUM_NONE")] None = 0, 41 | [pbr::OriginalName("EXAMPLE_ENUM_OBJ_FIRST")] ObjFirst = 1, 42 | [pbr::OriginalName("EXAMPLE_ENUM_OBJ_SECOND")] ObjSecond = 2, 43 | [pbr::OriginalName("EXAMPLE_ENUM_OBJ_THIRD")] ObjThird = 3, 44 | } 45 | 46 | #endregion 47 | 48 | } 49 | 50 | #endregion Designer generated code 51 | -------------------------------------------------------------------------------- /ProtoshiftHandlers/Example/NewProtos/Proto/ExampleEnum.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | option csharp_namespace = "NewProtos"; 3 | 4 | enum ExampleEnum { 5 | EXAMPLE_ENUM_NONE = 0; 6 | EXAMPLE_ENUM_OBJ_FIRST = 1; 7 | EXAMPLE_ENUM_OBJ_SECOND = 2; 8 | EXAMPLE_ENUM_OBJ_THIRD = 3; 9 | } -------------------------------------------------------------------------------- /ProtoshiftHandlers/Example/NewProtos/Proto/ExampleProto.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | option csharp_namespace = "NewProtos"; 3 | 4 | import "InMessage.proto"; 5 | import "ExampleEnum.proto"; 6 | 7 | message ExampleProto { 8 | ExampleEnum eg_enum = 1; 9 | string eg_str = 2; 10 | map eg_proto2 = 4; 11 | oneof eg_onefield { 12 | ExampleEnum a_enum = 8; 13 | uint32 not_a_enum = 9; 14 | } 15 | uint32 UnkExample_FNSDOAGFD = 153; 16 | repeated InMessage UnkExample_NSKLDVKVC = 134; 17 | } 18 | 19 | message ExampleProto2 { 20 | bytes ex_bytes = 8; 21 | repeated string list_str = 3; 22 | ExampleInnerProto inner_msg = 6; 23 | ExampleInnerEnum inner_enum = 7; 24 | 25 | message ExampleInnerProto { 26 | uint32 inner_code = 2; 27 | } 28 | 29 | enum ExampleInnerEnum { 30 | EXAMPLE_INNER_ENUM_NONE = 0; 31 | EXAMPLE_INNER_ENUM_SOMEOBJ = 1; 32 | EXAMPLE_INNER_ENUM_OTHEROBJ = 2; 33 | } 34 | } -------------------------------------------------------------------------------- /ProtoshiftHandlers/Example/NewProtos/Proto/InMessage.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | option csharp_namespace = "NewProtos"; 3 | 4 | message InMessage { 5 | string in_str = 1; 6 | uint32 code = 2; 7 | } -------------------------------------------------------------------------------- /ProtoshiftHandlers/Example/OldProtos/Compiled/ExampleEnum.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Generated by the protocol buffer compiler. DO NOT EDIT! 3 | // source: ExampleEnum.proto 4 | // 5 | #pragma warning disable 1591, 0612, 3021, 8981 6 | #region Designer generated code 7 | 8 | using pb = global::Google.Protobuf; 9 | using pbc = global::Google.Protobuf.Collections; 10 | using pbr = global::Google.Protobuf.Reflection; 11 | using scg = global::System.Collections.Generic; 12 | namespace OldProtos { 13 | 14 | /// Holder for reflection information generated from ExampleEnum.proto 15 | public static partial class ExampleEnumReflection { 16 | 17 | #region Descriptor 18 | /// File descriptor for ExampleEnum.proto 19 | public static pbr::FileDescriptor Descriptor { 20 | get { return descriptor; } 21 | } 22 | private static pbr::FileDescriptor descriptor; 23 | 24 | static ExampleEnumReflection() { 25 | byte[] descriptorData = global::System.Convert.FromBase64String( 26 | string.Concat( 27 | "ChFFeGFtcGxlRW51bS5wcm90byp5CgtFeGFtcGxlRW51bRIVChFFWEFNUExF", 28 | "X0VOVU1fTk9ORRAAEhoKFkVYQU1QTEVfRU5VTV9PQkpfRklSU1QQARIbChdF", 29 | "WEFNUExFX0VOVU1fT0JKX1NFQ09ORBACEhoKFkVYQU1QTEVfRU5VTV9PQkpf", 30 | "VEhJUkQQA0IMqgIJT2xkUHJvdG9zYgZwcm90bzM=")); 31 | descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData, 32 | new pbr::FileDescriptor[] { }, 33 | new pbr::GeneratedClrTypeInfo(new[] {typeof(global::OldProtos.ExampleEnum), }, null, null)); 34 | } 35 | #endregion 36 | 37 | } 38 | #region Enums 39 | public enum ExampleEnum { 40 | [pbr::OriginalName("EXAMPLE_ENUM_NONE")] None = 0, 41 | [pbr::OriginalName("EXAMPLE_ENUM_OBJ_FIRST")] ObjFirst = 1, 42 | [pbr::OriginalName("EXAMPLE_ENUM_OBJ_SECOND")] ObjSecond = 2, 43 | [pbr::OriginalName("EXAMPLE_ENUM_OBJ_THIRD")] ObjThird = 3, 44 | } 45 | 46 | #endregion 47 | 48 | } 49 | 50 | #endregion Designer generated code 51 | -------------------------------------------------------------------------------- /ProtoshiftHandlers/Example/OldProtos/Proto/ExampleEnum.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | option csharp_namespace = "OldProtos"; 3 | 4 | enum ExampleEnum { 5 | EXAMPLE_ENUM_NONE = 0; 6 | EXAMPLE_ENUM_OBJ_FIRST = 1; 7 | EXAMPLE_ENUM_OBJ_SECOND = 2; 8 | EXAMPLE_ENUM_OBJ_THIRD = 3; 9 | } -------------------------------------------------------------------------------- /ProtoshiftHandlers/Example/OldProtos/Proto/ExampleProto.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | option csharp_namespace = "OldProtos"; 3 | 4 | import "InMessage.proto"; 5 | import "ExampleEnum.proto"; 6 | 7 | message ExampleProto { 8 | ExampleEnum eg_enum = 2; 9 | string eg_str = 5; 10 | map eg_proto2 = 3; 11 | oneof eg_onefield { 12 | ExampleEnum a_enum = 7; 13 | uint32 not_a_enum = 12; 14 | } 15 | uint32 retcode = 53; 16 | repeated InMessage inner_messages = 18; 17 | } 18 | 19 | message ExampleProto2 { 20 | bytes ex_bytes = 8; 21 | repeated string list_str = 3; 22 | ExampleInnerProto inner_msg = 6; 23 | ExampleInnerEnum inner_enum = 7; 24 | 25 | message ExampleInnerProto { 26 | uint32 inner_code = 2; 27 | } 28 | 29 | enum ExampleInnerEnum { 30 | EXAMPLE_INNER_ENUM_NONE = 0; 31 | EXAMPLE_INNER_ENUM_SOMEOBJ = 1; 32 | EXAMPLE_INNER_ENUM_OTHEROBJ = 2; 33 | } 34 | } -------------------------------------------------------------------------------- /ProtoshiftHandlers/Example/OldProtos/Proto/InMessage.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | option csharp_namespace = "OldProtos"; 3 | 4 | message InMessage { 5 | string in_str = 67; 6 | uint32 code = 8; 7 | } -------------------------------------------------------------------------------- /ProtoshiftHandlers/Example/compile.sh: -------------------------------------------------------------------------------- 1 | ./protoc --proto_path="NewProtos/Proto" --csharp_out="NewProtos/Compiled" "NewProtos/Proto/ExampleEnum.proto" 2 | ./protoc --proto_path="NewProtos/Proto" --csharp_out="NewProtos/Compiled" "NewProtos/Proto/InMessage.proto" 3 | ./protoc --proto_path="NewProtos/Proto" --csharp_out="NewProtos/Compiled" "NewProtos/Proto/ExampleProto.proto" 4 | ./protoc --proto_path="OldProtos/Proto" --csharp_out="OldProtos/Compiled" "OldProtos/Proto/ExampleEnum.proto" 5 | ./protoc --proto_path="OldProtos/Proto" --csharp_out="OldProtos/Compiled" "OldProtos/Proto/ExampleProto.proto" 6 | ./protoc --proto_path="OldProtos/Proto" --csharp_out="OldProtos/Compiled" "OldProtos/Proto/InMessage.proto" -------------------------------------------------------------------------------- /ProtoshiftHandlers/HandlerBase.cs: -------------------------------------------------------------------------------- 1 | using Google.Protobuf; 2 | 3 | namespace csharp_Protoshift.Enhanced.Handlers 4 | { 5 | public abstract class HandlerBase : HandlerBase 6 | where TNewProtocol : IMessage 7 | where TOldProtocol : IMessage 8 | { 9 | public abstract TOldProtocol? NewShiftToOld(TNewProtocol? newprotocol); 10 | public abstract TNewProtocol? OldShiftToNew(TOldProtocol? oldprotocol); 11 | 12 | public abstract TNewProtocol GetNewShiftToOldJitInstance(); 13 | public virtual void RunJit() 14 | { 15 | var instance = NewShiftToOld(GetNewShiftToOldJitInstance()); 16 | OldShiftToNew(instance); 17 | 18 | var byteArray = Array.Empty(); 19 | var span = ReadOnlySpan.Empty; 20 | var byteString = ByteString.Empty; 21 | 22 | NewShiftToOld(byteArray); 23 | OldShiftToNew(byteArray); 24 | NewShiftToOld(span); 25 | OldShiftToNew(span); 26 | NewShiftToOld(byteString); 27 | OldShiftToNew(byteString); 28 | } 29 | } 30 | 31 | public abstract class HandlerBase 32 | { 33 | public virtual byte[] NewShiftToOld(byte[] arr) 34 | => NewShiftToOld(arr, 0, arr.Length); 35 | public abstract byte[] NewShiftToOld(byte[] arr, int offset, int length); 36 | public abstract IMessage? NewShiftToOld(ReadOnlySpan span); 37 | public abstract ByteString NewShiftToOld(ByteString bytes); 38 | public virtual byte[] OldShiftToNew(byte[] arr) 39 | => OldShiftToNew(arr, 0, arr.Length); 40 | public abstract byte[] OldShiftToNew(byte[] arr, int offset, int length); 41 | public abstract IMessage? OldShiftToNew(ReadOnlySpan span); 42 | public abstract ByteString OldShiftToNew(ByteString bytes); 43 | } 44 | 45 | public abstract class HandlerEnumBase 46 | where TNewProtocol : struct, System.Enum 47 | where TOldProtocol : struct, System.Enum 48 | { 49 | public abstract TOldProtocol NewShiftToOld(TNewProtocol newprotocol); 50 | public abstract TNewProtocol OldShiftToNew(TOldProtocol oldprotocol); 51 | 52 | public virtual TNewProtocol GetNewShiftToOldJitInstance() => Enum.GetValues()[0]; 53 | public virtual void RunJit() 54 | { 55 | var instance = NewShiftToOld(GetNewShiftToOldJitInstance()); 56 | OldShiftToNew(instance); 57 | } 58 | } 59 | } -------------------------------------------------------------------------------- /ProtoshiftHandlers/ProtoshiftHandlers.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0 5 | Major 6 | enable 7 | enable 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | $(DefineConstants);PACKET_HEAD_PROTO_DEFINED 37 | 38 | 39 | 40 | $(DefineConstants);PACKET_HEAD_PROTO_DEFINED 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /ProtoshiftHandlers/SpecialHandlers/CustomHandlers/HandlerUint32PairAndMap.cs: -------------------------------------------------------------------------------- 1 | using csharp_Protoshift.Enhanced.Handlers.GeneratedCode; 2 | using Google.Protobuf.Collections; 3 | 4 | namespace csharp_Protoshift.Enhanced.Handlers.CustomHandlers 5 | { 6 | internal class HandlerUint32PairAndMap 7 | { 8 | public void NewShiftToOld(MapField? newprotocol, 9 | /*ref*/ RepeatedField outputTo_oldprotocol) 10 | { 11 | if (newprotocol == null) return; 12 | outputTo_oldprotocol.AddRange( 13 | from pair in newprotocol 14 | select new OldProtos.Uint32Pair 15 | { 16 | Key = pair.Key, 17 | Value = pair.Value 18 | }); 19 | } 20 | 21 | public void OldShiftToNew(MapField? oldprotocol, 22 | /*ref*/ RepeatedField outputTo_newprotocol) 23 | { 24 | if (oldprotocol == null) return; 25 | outputTo_newprotocol.AddRange( 26 | from pair in oldprotocol 27 | select new NewProtos.Uint32Pair 28 | { 29 | Key = pair.Key, 30 | Value = pair.Value 31 | }); 32 | } 33 | 34 | public void NewShiftToOld(RepeatedField? newprotocol, 35 | /*ref*/ MapField outputTo_oldprotocol) 36 | { 37 | if (newprotocol == null) return; 38 | foreach (var pair in newprotocol) 39 | { 40 | outputTo_oldprotocol.Add(pair.Key, pair.Value); 41 | } 42 | } 43 | 44 | public void OldShiftToNew(RepeatedField? oldprotocol, 45 | /*ref*/ MapField outputTo_newprotocol) 46 | { 47 | if (oldprotocol == null) return; 48 | foreach (var pair in oldprotocol) 49 | { 50 | outputTo_newprotocol.Add(pair.Key, pair.Value); 51 | } 52 | } 53 | 54 | private static HandlerUint32PairAndMap _globalOnlyInstance = new HandlerUint32PairAndMap(); 55 | public static HandlerUint32PairAndMap GlobalInstance => _globalOnlyInstance; 56 | 57 | private HandlerUint32Pair handler_Uint32Pair = HandlerUint32Pair.GlobalInstance; 58 | public NewProtos.Uint32Pair GetNewShiftToOldJitInstance() => 59 | handler_Uint32Pair.GetNewShiftToOldJitInstance(); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /ProtoshiftHandlers/SpecialHandlers/README.md: -------------------------------------------------------------------------------- 1 | # Known packets have bytes field to fix 2 | 3 | ## Introduction 4 | It mainly solve the 'bytes' problem. 5 | In some packets, for unknown purposes, the anime game send original protobuf bin data as 'bytes', and along with any fields describe its protocol information. 6 | Though never could we know why they don't use oneof, we can do no more than adjust to it. 7 | 8 | ## Fix process info 9 | This is a issue tree, and the parent node is where the issue come from. 10 | In the protoshift-ex version, only the root nodes directly have bytes field and should implement Special handlers. 11 | 12 | 1. Bold lines refers to work done. 13 | 2. The bolded root nodes refers to SpecialHandlers implemented. 14 | 4. The other nodes may not be bolded. 15 | 5. Root nodes with `?` mean they're not confirmed whether they have skill issue to be fixed. 16 | 6. Nodes with ~~delete lines~~ mean they're duplicate with protos that have appeared below. 17 | 18 | - **AbilityInvokeEntry** 19 | - AbilityInvocationFailNotify 20 | - AbilityInvocationFixedNotify 21 | - AbilityInvocationsNotify 22 | - ClientAbilityChangeNotify 23 | - ClientAbilityInitFinishNotify 24 | - EntityAbilityInvokeEntry 25 | - ClientAbilitiesInitFinishCombineNotify 26 | - **CombatInvokeEntry** 27 | - CombatInvocationsNotify 28 | - **UnionCmd** 29 | - UnionCmdNotify 30 | - BlockInfo? 31 | - FeatureBlockInfo 32 | - PlayerLoginRsp 33 | - ~~PlayerLoginRsp~~ 34 | - HomeBlockDotPattern? 35 | - HomeBlockArrangementInfo 36 | - HomeSceneArrangementInfo 37 | - HomeCreateBlueprintReq 38 | - HomeGetArrangementInfoRsp 39 | - HomePreviewBlueprintRsp 40 | - HomeUpdateArrangementInfoReq 41 | - PlayerInjectFixNotify? -------------------------------------------------------------------------------- /Tests/.gitignore: -------------------------------------------------------------------------------- 1 | ## KCP Tests (Deprecated) 2 | KcpCsharpTest 3 | KcpTestClient 4 | KcpTestServer 5 | 6 | ## Benchmark 7 | ProtoshiftBenchmark/output_benchmark 8 | ProtoshiftBenchmark/Properties 9 | 10 | ## Replay 11 | csharp-Protoshift-Replay/windy_temp 12 | -------------------------------------------------------------------------------- /Tests/KcpTests/KcpPerformanceTest/Analysis/AnalysisResults.cs: -------------------------------------------------------------------------------- 1 | namespace csharp_Protoshift.MhyKCP.Test.Analysis 2 | { 3 | internal struct PacketLossResult 4 | { 5 | public readonly PacketRecordCollection baseSend, baseRecv; 6 | public readonly double packetLoss; 7 | // 丢掉的包、一边没有发另一边却收到了的包(后者不应出现) 8 | // 前者 ack 以 send 方为准,后者 ack 以 recv 方为准 9 | public readonly uint[] lost_ack, extra_ack; 10 | public readonly bool send_isClientAck, recv_isClientAck; 11 | 12 | public PacketLossResult(PacketRecordCollection baseSend, PacketRecordCollection baseRecv, double packetLoss, uint[] lost_ack, uint[] extra_ack, bool send_isClientAck, bool recv_isClientAck) 13 | { 14 | this.baseSend = baseSend; 15 | this.baseRecv = baseRecv; 16 | this.packetLoss = packetLoss; 17 | this.lost_ack = lost_ack; 18 | this.extra_ack = extra_ack; 19 | this.send_isClientAck = send_isClientAck; 20 | this.recv_isClientAck = recv_isClientAck; 21 | } 22 | } 23 | 24 | internal struct PacketDelayResult 25 | { 26 | public readonly PacketRecordCollection baseSend, baseRecv; 27 | public readonly TimeSpan average_packetDelay; 28 | public readonly TimeSpan minimum_packetDelay; 29 | public readonly TimeSpan maximum_packetDelay; 30 | /// 31 | /// 使用的包 ack 列表,为 send 与 recv 的交集,以 send 为标准。 为包的处理延迟 32 | /// 33 | public readonly (uint, TimeSpan)[] ack_list; 34 | /// 35 | /// 乱序的包 ack 列表,ack 是奇是偶以 send 为标准。 为包的处理延迟 36 | /// 37 | public readonly (uint, DateTime)[] inverted_ack_list; 38 | 39 | public PacketDelayResult(PacketRecordCollection baseSend, PacketRecordCollection baseRecv, TimeSpan average_packetDelay, TimeSpan minimum_packetDelay, TimeSpan maximum_packetDelay, (uint, TimeSpan)[] ack_list, (uint, DateTime)[] inverted_ack_list) 40 | { 41 | this.baseSend = baseSend; 42 | this.baseRecv = baseRecv; 43 | this.average_packetDelay = average_packetDelay; 44 | this.minimum_packetDelay = minimum_packetDelay; 45 | this.maximum_packetDelay = maximum_packetDelay; 46 | this.ack_list = ack_list; 47 | this.inverted_ack_list = inverted_ack_list; 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /Tests/KcpTests/KcpPerformanceTest/Analysis/ClientDataChannel.cs: -------------------------------------------------------------------------------- 1 | using csharp_Protoshift.MhyKCP.Test.App; 2 | using csharp_Protoshift.MhyKCP.Test.Protocol; 3 | using System.Collections.Concurrent; 4 | 5 | namespace csharp_Protoshift.MhyKCP.Test.Analysis 6 | { 7 | /// 8 | /// 由于Client变为多个因此添加了线程安全 9 | /// 由于实例线程安全因此不必锁定Channel来获取数据只读副本 10 | /// 11 | internal static class ClientDataChannel 12 | { 13 | public static ConcurrentBag sent_pkts = new(); 14 | public static ConcurrentBag recved_pkts = new(); 15 | 16 | /// 17 | /// KCP.Send后回调 18 | /// 19 | /// 20 | public static void PushSentPacket(BasePacket sentPkt) 21 | { 22 | sent_pkts.Add(sentPkt.AsReadOnly()); 23 | } 24 | 25 | /// 26 | /// 客户端收到服务器回传包的回调 27 | /// 28 | /// 29 | public static void PushReceivedPacket(BasePacket recvedPkt) 30 | { 31 | recved_pkts.Add(recvedPkt.AsReadOnly()); 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Tests/KcpTests/KcpPerformanceTest/Analysis/ProxyDataChannel.cs: -------------------------------------------------------------------------------- 1 | using csharp_Protoshift.MhyKCP.Test.Protocol; 2 | using System.Collections.Concurrent; 3 | 4 | namespace csharp_Protoshift.MhyKCP.Test.Analysis 5 | { 6 | /// 7 | /// 由于代理不保证顺序调用handler,因此本实例线程安全 8 | /// 由于实例线程安全因此不必锁定Channel来获取数据只读副本 9 | /// 10 | internal static class ProxyDataChannel 11 | { 12 | // 代理收到的客户端->服务器的包,即客户端->代理 13 | public static ConcurrentBag proxy_recved_client_pkts = new(); 14 | // 代理发出的客户端->服务器的包,即代理->服务器 15 | public static ConcurrentBag proxy_sent_client_pkts = new(); 16 | // 代理收到的服务器->客户端的包,即服务器->代理 17 | public static ConcurrentBag proxy_recved_server_pkts = new(); 18 | // 代理发出的服务器->客户端的包,即代理->客户端 19 | public static ConcurrentBag proxy_sent_server_pkts = new(); 20 | 21 | /// 22 | /// 代理收到客户端->服务器包的回调 23 | /// 24 | /// 25 | public static void PushReceivedClientPacket(BasePacket recvedPkt) 26 | { 27 | proxy_recved_client_pkts.Add(recvedPkt.AsReadOnly()); 28 | } 29 | 30 | /// 31 | /// 代理处理完毕客户端->服务器包的回调 32 | /// 33 | /// 34 | public static void PushSentClientPacket(BasePacket sentPkt) 35 | { 36 | proxy_sent_client_pkts.Add(sentPkt.AsReadOnly()); 37 | } 38 | 39 | /// 40 | /// 代理收到服务器->客户端包的回调 41 | /// 42 | /// 43 | public static void PushReceivedServerPacket(BasePacket recvedPkt) 44 | { 45 | proxy_recved_server_pkts.Add(recvedPkt.AsReadOnly()); 46 | } 47 | 48 | /// 49 | /// 代理处理完毕服务器->客户端包的回调 50 | /// 51 | /// 52 | public static void PushSentServerPacket(BasePacket sentPkt) 53 | { 54 | proxy_sent_server_pkts.Add(sentPkt.AsReadOnly()); 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /Tests/KcpTests/KcpPerformanceTest/Analysis/ServerDataChannel.cs: -------------------------------------------------------------------------------- 1 | using csharp_Protoshift.MhyKCP.Test.Protocol; 2 | using System.Collections.Concurrent; 3 | 4 | namespace csharp_Protoshift.MhyKCP.Test.Analysis 5 | { 6 | /// 7 | /// 由于Server数据Push时机不定因此需要线程安全 8 | /// 由于实例线程安全因此不必锁定Channel来获取数据只读副本 9 | /// 10 | internal static class ServerDataChannel 11 | { 12 | public static ConcurrentBag sent_pkts = new(); 13 | public static ConcurrentBag recved_pkts = new(); 14 | 15 | /// 16 | /// 服务器收到客户端请求包的回调 17 | /// 18 | /// 19 | public static void PushReceivedPacket(BasePacket recvedPkt) 20 | { 21 | recved_pkts.Add(recvedPkt.AsReadOnly()); 22 | } 23 | 24 | /// 25 | /// 服务器发出ack回传包后回调 26 | /// 27 | /// 28 | public static void PushSentPacket(BasePacket sentPkt) 29 | { 30 | sent_pkts.Add(sentPkt.AsReadOnly()); 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Tests/KcpTests/KcpPerformanceTest/Constants.cs: -------------------------------------------------------------------------------- 1 | namespace csharp_Protoshift.MhyKCP.Test.App 2 | { 3 | public static class Constants 4 | { 5 | public const ushort UDP_SERVER_PORT = 30351; 6 | public const ushort UDP_PROXY_PORT = 30341; 7 | 8 | public static int each_packet_size = 3500; 9 | // 是否随机包大小 最小为0 最大为each_packet_size 10 | // 目前包大小固定 不作更改 11 | // public const bool random_packet_size = false; 12 | 13 | // 发包总数量 14 | public static int packet_repeat_time = 5000; 15 | // 发包间隔 非严格间隔,即发完包后等待毫秒数 16 | public static int packet_interval_ms = 40; 17 | // 在Actions上跑要分配true 决定是否发包结束后10s退出 是否输出packet.log到控制台 18 | public static bool running_on_github_actions = true; 19 | 20 | // 同时向服务器并发请求的客户端数量 21 | public static int running_clients_count = 5; 22 | // 是否生成包延迟统计表 一般客户端数量>5时分配false 控制输出量 23 | public static bool output_packet_delaylog = true; 24 | } 25 | } -------------------------------------------------------------------------------- /Tests/KcpTests/KcpPerformanceTest/KcpPerformanceTest.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net6.0 6 | Major 7 | enable 8 | enable 9 | csharp_Protoshift.MhyKCP.Test 10 | 11 | 12 | 13 | 14 | $(DefineConstants) 15 | 16 | 17 | 18 | 19 | $(DefineConstants) 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /Tests/KcpTests/KcpPerformanceTest/Proxy/ProxyApp.cs: -------------------------------------------------------------------------------- 1 | using csharp_Protoshift.GameSession; 2 | using csharp_Protoshift.MhyKCP.Proxy; 3 | using System.Net; 4 | using YYHEggEgg.Logger; 5 | 6 | namespace csharp_Protoshift.MhyKCP.Test.App 7 | { 8 | public class ProxyApp 9 | { 10 | public static void Start() 11 | { 12 | #if CONNECT_SERVERONLY 13 | throw new NotImplementedException("Proxy should not be launched in CONNECT_SERVERONLY mode."); 14 | #else 15 | KcpProxyServer proxy = new(new(IPAddress.Loopback, Constants.UDP_PROXY_PORT), 16 | new(IPAddress.Loopback, Constants.UDP_SERVER_PORT)); 17 | ProxyHandlers handlers = new ProxyHandlers 18 | { 19 | OnServerPacketArrival = GameSessionDispatch.HandleServerPacket, 20 | OnClientPacketArrival = GameSessionDispatch.HandleClientPacket, 21 | ServerPacketOrdered = GameSessionDispatch.ServerPacketOrdered, 22 | ClientPacketOrdered = GameSessionDispatch.ClientPacketOrdered 23 | }; 24 | _ = Task.Run(() => proxy.StartProxy(handlers)); 25 | Log.Info($"KcpProxyServer started on 127.0.0.1:{Constants.UDP_PROXY_PORT}", nameof(ProxyApp)); 26 | #endif 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Tests/KcpTests/KcpPerformanceTest/resLoader/Resources.cs: -------------------------------------------------------------------------------- 1 | namespace csharp_Protoshift.resLoader 2 | { 3 | public static class Resources 4 | { 5 | public static byte[] dispatchKey = new byte[] { }; 6 | public static byte[] dispatchSeed = new byte[] { }; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /Tests/KcpTests/KcpPerformanceTest/resLoader/ResourcesLoader.cs: -------------------------------------------------------------------------------- 1 | using YYHEggEgg.Logger; 2 | 3 | namespace csharp_Protoshift.resLoader 4 | { 5 | public static class ResourcesLoader 6 | { 7 | public const string StructureDescription = 8 | "Resources Description\n" + 9 | "/resources\n" + 10 | " /xor\n" + 11 | " /dispatchSeed.bin -- dispatch Ec2b Seed\n" + 12 | " /dispatchKey.bin -- dispatch Ec2b Key"; 13 | 14 | /// 15 | /// Check for resources, if not complete then exit with code 114514. 16 | /// 17 | public static void CheckForRequiredResources() 18 | { 19 | bool passcheck = true; 20 | // Resources 21 | if (!Directory.Exists("resources")) 22 | { 23 | Log.Erro("resources dir missing! Please copy it from \"/resources\"!", "ResourcesCheck"); 24 | Log.Info(StructureDescription, "ResourcesCheck"); 25 | passcheck = false; 26 | } 27 | else 28 | { 29 | bool resourcesComplete = true; 30 | if (!File.Exists("resources/xor/dispatchKey.bin")) 31 | { 32 | Log.Erro("/resources/xor/dispatchKey.bin not found!"); 33 | resourcesComplete = false; 34 | } 35 | if (!resourcesComplete) 36 | { 37 | Log.Info(StructureDescription, "ResourcesCheck"); 38 | passcheck = false; 39 | } 40 | } 41 | if (!passcheck) 42 | { 43 | Log.Erro("Resources check didn't pass. Press Enter to exit.", "ResourcesCheck"); 44 | Console.ReadLine(); 45 | Environment.Exit(114514); 46 | } 47 | } 48 | 49 | /// 50 | /// Load resources to Resources Class. 51 | /// 52 | public static async Task Load() 53 | { 54 | Resources.dispatchKey = await File.ReadAllBytesAsync("resources/xor/dispatchKey.bin"); 55 | Resources.dispatchSeed = await File.ReadAllBytesAsync("resources/xor/dispatchSeed.bin"); 56 | return "Resources Loaded."; 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /Tests/KcpTests/KcpPerformanceTest/resources/xor/dispatchKey.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YYHEggEgg/csharp-Protoshift/979f787f183244c3d66ea14389b093bcc833e1da/Tests/KcpTests/KcpPerformanceTest/resources/xor/dispatchKey.bin -------------------------------------------------------------------------------- /Tests/KcpTests/KcpPerformanceTest/resources/xor/dispatchSeed.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/YYHEggEgg/csharp-Protoshift/979f787f183244c3d66ea14389b093bcc833e1da/Tests/KcpTests/KcpPerformanceTest/resources/xor/dispatchSeed.bin -------------------------------------------------------------------------------- /Tests/KcpTests/KcpTests.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.0.31903.59 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "KcpPerformanceTest", "KcpPerformanceTest\KcpPerformanceTest.csproj", "{4E88050C-F306-489C-A9B0-E5FF7DB91BEC}" 7 | EndProject 8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SharedLib", "SharedLib\SharedLib.csproj", "{DC06B44E-C725-42E4-8C23-CFF1A38E0605}" 9 | EndProject 10 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Kcp", "..\..\KCP\Kcp\Kcp.csproj", "{61EC0345-6AF7-488F-9C6A-77470A67F07A}" 11 | EndProject 12 | Global 13 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 14 | Debug|Any CPU = Debug|Any CPU 15 | Release|Any CPU = Release|Any CPU 16 | EndGlobalSection 17 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 18 | {4E88050C-F306-489C-A9B0-E5FF7DB91BEC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 19 | {4E88050C-F306-489C-A9B0-E5FF7DB91BEC}.Debug|Any CPU.Build.0 = Debug|Any CPU 20 | {4E88050C-F306-489C-A9B0-E5FF7DB91BEC}.Release|Any CPU.ActiveCfg = Release|Any CPU 21 | {4E88050C-F306-489C-A9B0-E5FF7DB91BEC}.Release|Any CPU.Build.0 = Release|Any CPU 22 | {DC06B44E-C725-42E4-8C23-CFF1A38E0605}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 23 | {DC06B44E-C725-42E4-8C23-CFF1A38E0605}.Debug|Any CPU.Build.0 = Debug|Any CPU 24 | {DC06B44E-C725-42E4-8C23-CFF1A38E0605}.Release|Any CPU.ActiveCfg = Release|Any CPU 25 | {DC06B44E-C725-42E4-8C23-CFF1A38E0605}.Release|Any CPU.Build.0 = Release|Any CPU 26 | {61EC0345-6AF7-488F-9C6A-77470A67F07A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 27 | {61EC0345-6AF7-488F-9C6A-77470A67F07A}.Debug|Any CPU.Build.0 = Debug|Any CPU 28 | {61EC0345-6AF7-488F-9C6A-77470A67F07A}.Release|Any CPU.ActiveCfg = Release|Any CPU 29 | {61EC0345-6AF7-488F-9C6A-77470A67F07A}.Release|Any CPU.Build.0 = Release|Any CPU 30 | EndGlobalSection 31 | GlobalSection(SolutionProperties) = preSolution 32 | HideSolutionNode = FALSE 33 | EndGlobalSection 34 | GlobalSection(ExtensibilityGlobals) = postSolution 35 | SolutionGuid = {6F550CAF-6AA9-4497-9820-6FDE6C3D5C9C} 36 | EndGlobalSection 37 | EndGlobal 38 | -------------------------------------------------------------------------------- /Tests/KcpTests/README.md: -------------------------------------------------------------------------------- 1 | # KcpPerformanceTest 2 | 3 | 本项目用于常规的网络协议(基于 KCP 的 mihoyonet)测试。 4 | 5 | 开启符号 `CONNECT_SERVERONLY` 以跳过中间代理,否则将会通过代理进行。 6 | 7 | 各项设置(包括 UDP 端口号)在 `Constants.cs` 中设置。 8 | 9 | ## 测试方法概述 10 | 11 | 测试由客户端生成一个奇数 ack,即 1,3,5,...; 12 | 服务端收到对应 ack 后,将 ack +1 并将 body 原封不动重传; 13 | 在此期间,三方将数据提交至统一的 Analysis 处理,分析速度、延迟、丢包等数据。 14 | 15 | 由于这套协议主要用于 Protobuf 传输,包数据只要有部分错误即视为全部丢包。 16 | 17 | 为了设计方便,此套测试程序仍使用 XOR 加密,但舍去了非对称密钥交换而只使用 dispatchKey. 18 | 19 | ## 命令行操作 20 | 21 | 程序支持使用命令行操作。 22 | 23 | English Usage: 24 | 25 | ```txt 26 | Usage: KcpPerformanceTest [options] 27 | 28 | Options: 29 | -s, --packet-size The size of each packet. 30 | -t, --packet-repeat-time