18 Commits
Author SHA1 Message Date
Chipseq 100b89125c fix string ids 2026-09-28 23:03:05 +02:00
miniduikboot 04100970b6 Bump version 2026-06-10 00:24:43 +02:00
XtraCube 16c8c3e553 fix comments and warnings 2026-06-10 00:24:01 +02:00
XtraCube c3775ff33f Use typed delegates for faster invoke 2026-06-10 00:24:01 +02:00
XtraCube 6381d79a18 Fix CoHandleSpawnPatch 2026-06-10 00:24:01 +02:00
XtraCube 5818041b27 Use compiler generated wrappers for patching 2026-06-10 00:24:01 +02:00
XtraCube a1f6164ca0 add CompilerGeneratedObjectWrapper.cs and StateMachineWrapper.cs 2026-06-10 00:24:01 +02:00
miniduikboot 9bd370bfc1 Bump version 2025-06-05 17:55:51 +02:00
AS 5cb6c35dac Enhancements and additions to Reactor Networking (#91)
* Update ExtraMessageExtensions.cs

Added enum methods

* Update MessageSerializer.cs

Add enum serialisation

* Oops documentation fix

* Fix errors + add long serialisation

* Correction: ulong not long

* Specify format

* Add long serialisation + improve enum serialisation

* Add a shorthand method

* Removed generic enum write and fix long write

* Add generic converter support + read enum improvement

* Remove leftover code

* Better long serialisation

* Serialise the array directly

* Allow serialising color values

* Update .gitignore

* Update ExtraMessageExtensions.cs

* Discard changes to .gitignore
2025-06-05 17:43:39 +02:00
miniduikboot 8505eb5974 Merge pull request #96 from XtraCube/master-2
Update to 2025.5.20
2025-05-28 23:19:54 +02:00
XtraCube b1fa5410c9 Update BepInEx MSBuild 2025-05-24 00:05:52 -04:00
miniduikboot 26bd155a42 Fix compile warnings 2025-05-22 22:48:13 -04:00
XtraCube 859183a849 update reasoning 2025-05-21 18:34:50 -04:00
XtraCube c58ccc1643 Revert API changes and add Obsolete attribute to SendImmediate 2025-05-21 17:24:40 -04:00
XtraCube 3229475361 Fix bug (bad code) in SpawnGameDataMessage patch 2025-05-21 15:23:14 -04:00
XtraCube db452bf7e4 fix modded handshake + compile problems 2025-05-20 18:24:22 -04:00
XtraCube 7b7ba31e94 Update Empty Texture utility for new Unity Version 2025-05-20 17:51:47 -04:00
XtraCube ccade1be0e Update http patches to account for new innersloth APIs 2025-05-07 21:16:13 -04:00
22 changed files with 765 additions and 271 deletions

No files matched your search

+3 -3
View File
@@ -1,10 +1,10 @@
<Project> <Project>
<ItemGroup> <ItemGroup>
<PackageReference Include="BepInEx.Unity.IL2CPP" Version="6.0.0-be.733" Private="false" ExcludeAssets="runtime;native" /> <PackageReference Include="BepInEx.Unity.IL2CPP" Version="6.0.0-be.735" Private="false" ExcludeAssets="runtime;native" />
<PackageReference Include="AmongUs.GameLibs.Steam" Version="2025.3.25" PrivateAssets="all" /> <PackageReference Include="AmongUs.GameLibs.Steam" Version="2025.4.15" PrivateAssets="all" />
<PackageReference Include="BepInEx.AutoPlugin" Version="1.1.0" PrivateAssets="all" /> <PackageReference Include="BepInEx.AutoPlugin" Version="1.1.0" PrivateAssets="all" />
<PackageReference Include="BepInEx.IL2CPP.MSBuild" Version="2.0.1" PrivateAssets="all" ExcludeAssets="runtime" /> <PackageReference Include="BepInEx.IL2CPP.MSBuild" Version="2.1.0-rc.1" PrivateAssets="all" ExcludeAssets="runtime" />
</ItemGroup> </ItemGroup>
<Target Name="Copy" AfterTargets="Build" Condition="'$(AmongUs)' != ''"> <Target Name="Copy" AfterTargets="Build" Condition="'$(AmongUs)' != ''">
+1 -1
View File
@@ -8,7 +8,7 @@
<RestorePackagesWithLockFile>true</RestorePackagesWithLockFile> <RestorePackagesWithLockFile>true</RestorePackagesWithLockFile>
<VersionPrefix>2.4.0</VersionPrefix> <VersionPrefix>2.5.1</VersionPrefix>
<VersionSuffix>dev</VersionSuffix> <VersionSuffix>dev</VersionSuffix>
<Authors>NuclearPowered</Authors> <Authors>NuclearPowered</Authors>
+35 -35
View File
@@ -4,9 +4,9 @@
"net6.0": { "net6.0": {
"AmongUs.GameLibs.Steam": { "AmongUs.GameLibs.Steam": {
"type": "Direct", "type": "Direct",
"requested": "[2025.3.25, )", "requested": "[2025.4.15, )",
"resolved": "2025.3.25", "resolved": "2025.4.15",
"contentHash": "2QxQXgZDcQOdAIDXrNLrQ7veEzD6EBzuaRjzSbHptWUPUsuVc3I5Ur3xMkPPwmSGsDHjLuAGE84yRjV6oJxGxw==" "contentHash": "R3RxzHGZOGUJ9nMwrP0cjS6g+sh60QUU506Mo47lh17155enUjH6PtErijihSoU7t3aQpzCIyC67W3XrrHhH4g=="
}, },
"BenchmarkDotNet": { "BenchmarkDotNet": {
"type": "Direct", "type": "Direct",
@@ -34,25 +34,25 @@
}, },
"BepInEx.IL2CPP.MSBuild": { "BepInEx.IL2CPP.MSBuild": {
"type": "Direct", "type": "Direct",
"requested": "[2.0.1, )", "requested": "[2.1.0-rc.1, )",
"resolved": "2.0.1", "resolved": "2.1.0-rc.1",
"contentHash": "hUZjCV0t8dkw/Z/zq4Zl405QP7frBk/LVfMdUmUz+7XOhGd7lYPKrR48A5vbGl2QeHudMxlkXzAr9WM3Duq2SQ==" "contentHash": "WI/7TbJwWl5P4B6UXGtKI1VMe6fA6h3fcbp3ZjJKqOBQ5MJfDMmeVB4fb+RW1tUQdxnlSWV3Ul62PHFyTqp4PA=="
}, },
"BepInEx.Unity.IL2CPP": { "BepInEx.Unity.IL2CPP": {
"type": "Direct", "type": "Direct",
"requested": "[6.0.0-be.733, )", "requested": "[6.0.0-be.735, )",
"resolved": "6.0.0-be.733", "resolved": "6.0.0-be.735",
"contentHash": "lnoGaPHjIdGfEiKtf89knaTdLXe4IUqVLdoYqW8NYhhNqgxa3oNwScjTmuYQpa4Leew3937+slq2WIjvX/DUwQ==", "contentHash": "2+eFJGKMR1GFPeU9wuF+TVrMANIaWIc/6N9e8x4b7b/fNiY9B6vicYNiMDb2deYQpWZtOei+2btnar5dDE5BPg==",
"dependencies": { "dependencies": {
"BepInEx.Core": "6.0.0-be.733", "BepInEx.Core": "6.0.0-be.735",
"BepInEx.Unity.Common": "6.0.0-be.733", "BepInEx.Unity.Common": "6.0.0-be.735",
"HarmonyX": "2.10.2", "HarmonyX": "2.10.2",
"Iced": "1.21.0", "Iced": "1.21.0",
"Il2CppInterop.Generator": "1.4.6-ci.426", "Il2CppInterop.Generator": "1.4.6-ci.426",
"Il2CppInterop.HarmonySupport": "1.4.6-ci.426", "Il2CppInterop.HarmonySupport": "1.4.6-ci.426",
"Il2CppInterop.Runtime": "1.4.6-ci.426", "Il2CppInterop.Runtime": "1.4.6-ci.426",
"MonoMod.RuntimeDetour": "22.7.31.1", "MonoMod.RuntimeDetour": "22.7.31.1",
"Samboy063.Cpp2IL.Core": "2022.1.0-pre-release.18" "Samboy063.Cpp2IL.Core": "2022.1.0-pre-release.19"
} }
}, },
"StyleCop.Analyzers": { "StyleCop.Analyzers": {
@@ -95,8 +95,8 @@
}, },
"AssetRipper.CIL": { "AssetRipper.CIL": {
"type": "Transitive", "type": "Transitive",
"resolved": "1.1.0", "resolved": "1.1.2",
"contentHash": "nSz1cBjgVeKv+esfDtyQGC1mY9b4C4NFStytdoa9DMozDC8uth6930kAsuWZEivj9GqWSqENnaQUGnl23WpmnQ==", "contentHash": "BRPcHORadIzSFkrVOvGkSs54j19mQdXH8dmRTVM51mS8MZLSbTpi9CDPpnWN2IdDsILUrAqbPUFo3zJodYxErw==",
"dependencies": { "dependencies": {
"AsmResolver.DotNet": "6.0.0-beta.1" "AsmResolver.DotNet": "6.0.0-beta.1"
} }
@@ -118,8 +118,8 @@
}, },
"BepInEx.Core": { "BepInEx.Core": {
"type": "Transitive", "type": "Transitive",
"resolved": "6.0.0-be.733", "resolved": "6.0.0-be.735",
"contentHash": "uRzpyUdU3L8Y4ZW+ZnF73orq0E40MjGK6XcPzm24CrrWB5bUshwdrtFQfrwZB6jcZVNVV6PXE92hScEI+Jaoqw==", "contentHash": "FuHm9UCzjSKeiZJc3IF70Fiuqi+FynRn62PwBoOeZcHK3/qm+vl1YwbZyFlmUyf45g+UKxg2Td40iZGx88LVAQ==",
"dependencies": { "dependencies": {
"HarmonyX": "2.10.2", "HarmonyX": "2.10.2",
"MonoMod.Utils": "22.7.31.1", "MonoMod.Utils": "22.7.31.1",
@@ -128,8 +128,8 @@
}, },
"BepInEx.Unity.Common": { "BepInEx.Unity.Common": {
"type": "Transitive", "type": "Transitive",
"resolved": "6.0.0-be.733", "resolved": "6.0.0-be.735",
"contentHash": "KfdiHVSOPnIbDEF7zLPTSXDjKqIEq7SgffqFFKIxOBkCws7LdtSRQsamUcxdD0H8yopcgdlqobIp6t8e4M/k9Q==", "contentHash": "vmK//OBSr+jotqTk//HSdvHtMFTKu+NlQkiEsvr0dZApTVmQM2AgpVMhEAakQPmrSsM6LRJIHCBcLFO1ypfMPQ==",
"dependencies": { "dependencies": {
"AssetRipper.Primitives": "3.1.3", "AssetRipper.Primitives": "3.1.3",
"MonoMod.Utils": "22.7.31.1" "MonoMod.Utils": "22.7.31.1"
@@ -142,8 +142,8 @@
}, },
"Disarm": { "Disarm": {
"type": "Transitive", "type": "Transitive",
"resolved": "2022.1.0-master.34", "resolved": "2022.1.0-master.57",
"contentHash": "sxzTci5eSdl+sFoaGsMZIp7X/eB5ZzplM3CppvD1CWoiZ8rSa43XGLC19G5e8n6mjutNBfN9yL+RER5PCspHFg==" "contentHash": "/dkg7hg8iPBQN4bTV1lMQacarH6fMpgUXhJuo6iI7Wv7YpH7g5F9hJfje7dSMhqG0YlDacLuyWvcph5GzKUXog=="
}, },
"Gee.External.Capstone": { "Gee.External.Capstone": {
"type": "Transitive", "type": "Transitive",
@@ -489,31 +489,31 @@
}, },
"Samboy063.Cpp2IL.Core": { "Samboy063.Cpp2IL.Core": {
"type": "Transitive", "type": "Transitive",
"resolved": "2022.1.0-pre-release.18", "resolved": "2022.1.0-pre-release.19",
"contentHash": "eX9d1IK05jWaEaeuMAE0L5WYHT7thtxz+aWLL/CAaCzZ0TzRPD+WFTjJ0KQO0YWBVO300CX3GwmPmf7TNO+wUg==", "contentHash": "mAYIrMo0VdOZzh1NS5bZeflg80gtYNY7kZo9q/blEYheUPyLXu5ozQOjX+Bq2yDh40pA+yiE2MXTnN2Is2hjgw==",
"dependencies": { "dependencies": {
"AsmResolver.DotNet": "6.0.0-beta.1", "AsmResolver.DotNet": "6.0.0-beta.1",
"AssetRipper.CIL": "1.1.0", "AssetRipper.CIL": "1.1.2",
"AssetRipper.Gee.External.Capstone": "2.3.2", "AssetRipper.Gee.External.Capstone": "2.3.2",
"Disarm": "2022.1.0-master.34", "Disarm": "2022.1.0-master.57",
"Iced": "1.21.0", "Iced": "1.21.0",
"Samboy063.LibCpp2IL": "2022.1.0-pre-release.18", "Samboy063.LibCpp2IL": "2022.1.0-pre-release.19",
"StableNameDotNet": "0.1.0-pre-release.15" "StableNameDotNet": "0.1.0-pre-release.19"
} }
}, },
"Samboy063.LibCpp2IL": { "Samboy063.LibCpp2IL": {
"type": "Transitive", "type": "Transitive",
"resolved": "2022.1.0-pre-release.18", "resolved": "2022.1.0-pre-release.19",
"contentHash": "9zJdTAeErpwJpYDHYwwI0MAC1OyBEfC1ce7dpAOYRUUYCfeaKVWxnSCcyaoY6HDzIoxPkhbfllbwOe49ZmUYuQ==", "contentHash": "/n8p81ltd38BeNNS2xUNPGMSzxk/UGXr9cRNqG1MaLogzANNNrvCAXqWmNMM3tZctjp7vqTxEA+e4J4ngul8Fg==",
"dependencies": { "dependencies": {
"AssetRipper.Primitives": "3.1.2", "AssetRipper.Primitives": "3.1.3",
"Samboy063.WasmDisassembler": "2022.1.0-pre-release.15" "Samboy063.WasmDisassembler": "2022.1.0-pre-release.19"
} }
}, },
"Samboy063.WasmDisassembler": { "Samboy063.WasmDisassembler": {
"type": "Transitive", "type": "Transitive",
"resolved": "2022.1.0-pre-release.15", "resolved": "2022.1.0-pre-release.19",
"contentHash": "e6qw81SHS+fS7iZ3qfqZBavVarYbkPElNgDCANF6dNFTYq5+hc80am+4FqQDl+ZVNS47bZDZobxIzHhmriCXGg==" "contentHash": "uVQdYm/J6+jJ1xt6GJ3hNhXhciwlX+LmHTPITu9jjZ75T33YJuuTD7pLVYuMymr+4gSVisg7f1wterFSyqJBWA=="
}, },
"SemanticVersioning": { "SemanticVersioning": {
"type": "Transitive", "type": "Transitive",
@@ -522,8 +522,8 @@
}, },
"StableNameDotNet": { "StableNameDotNet": {
"type": "Transitive", "type": "Transitive",
"resolved": "0.1.0-pre-release.15", "resolved": "0.1.0-pre-release.19",
"contentHash": "aIkEOo8V76vE+9CppHpTFLGXalBw6TAl4/tb6vadmS+gHJMshTVehzQv9cJXy4xZDdANV1uGMRaUFZERcDA2xQ==" "contentHash": "5BPWtntv3PXeFIg9CuGW6OM3f5GnwvdQJbzRpufPsistFwFyt1xYW1wSDr+QIdDO7vLndr7iNpWD3FyYp9LL4g=="
}, },
"StyleCop.Analyzers.Unstable": { "StyleCop.Analyzers.Unstable": {
"type": "Transitive", "type": "Transitive",
@@ -1138,7 +1138,7 @@
"reactor": { "reactor": {
"type": "Project", "type": "Project",
"dependencies": { "dependencies": {
"BepInEx.Unity.IL2CPP": "[6.0.0-be.733, )" "BepInEx.Unity.IL2CPP": "[6.0.0-be.735, )"
} }
} }
} }
+35 -35
View File
@@ -4,9 +4,9 @@
"net6.0": { "net6.0": {
"AmongUs.GameLibs.Steam": { "AmongUs.GameLibs.Steam": {
"type": "Direct", "type": "Direct",
"requested": "[2025.3.25, )", "requested": "[2025.4.15, )",
"resolved": "2025.3.25", "resolved": "2025.4.15",
"contentHash": "2QxQXgZDcQOdAIDXrNLrQ7veEzD6EBzuaRjzSbHptWUPUsuVc3I5Ur3xMkPPwmSGsDHjLuAGE84yRjV6oJxGxw==" "contentHash": "R3RxzHGZOGUJ9nMwrP0cjS6g+sh60QUU506Mo47lh17155enUjH6PtErijihSoU7t3aQpzCIyC67W3XrrHhH4g=="
}, },
"BepInEx.AutoPlugin": { "BepInEx.AutoPlugin": {
"type": "Direct", "type": "Direct",
@@ -16,25 +16,25 @@
}, },
"BepInEx.IL2CPP.MSBuild": { "BepInEx.IL2CPP.MSBuild": {
"type": "Direct", "type": "Direct",
"requested": "[2.0.1, )", "requested": "[2.1.0-rc.1, )",
"resolved": "2.0.1", "resolved": "2.1.0-rc.1",
"contentHash": "hUZjCV0t8dkw/Z/zq4Zl405QP7frBk/LVfMdUmUz+7XOhGd7lYPKrR48A5vbGl2QeHudMxlkXzAr9WM3Duq2SQ==" "contentHash": "WI/7TbJwWl5P4B6UXGtKI1VMe6fA6h3fcbp3ZjJKqOBQ5MJfDMmeVB4fb+RW1tUQdxnlSWV3Ul62PHFyTqp4PA=="
}, },
"BepInEx.Unity.IL2CPP": { "BepInEx.Unity.IL2CPP": {
"type": "Direct", "type": "Direct",
"requested": "[6.0.0-be.733, )", "requested": "[6.0.0-be.735, )",
"resolved": "6.0.0-be.733", "resolved": "6.0.0-be.735",
"contentHash": "lnoGaPHjIdGfEiKtf89knaTdLXe4IUqVLdoYqW8NYhhNqgxa3oNwScjTmuYQpa4Leew3937+slq2WIjvX/DUwQ==", "contentHash": "2+eFJGKMR1GFPeU9wuF+TVrMANIaWIc/6N9e8x4b7b/fNiY9B6vicYNiMDb2deYQpWZtOei+2btnar5dDE5BPg==",
"dependencies": { "dependencies": {
"BepInEx.Core": "6.0.0-be.733", "BepInEx.Core": "6.0.0-be.735",
"BepInEx.Unity.Common": "6.0.0-be.733", "BepInEx.Unity.Common": "6.0.0-be.735",
"HarmonyX": "2.10.2", "HarmonyX": "2.10.2",
"Iced": "1.21.0", "Iced": "1.21.0",
"Il2CppInterop.Generator": "1.4.6-ci.426", "Il2CppInterop.Generator": "1.4.6-ci.426",
"Il2CppInterop.HarmonySupport": "1.4.6-ci.426", "Il2CppInterop.HarmonySupport": "1.4.6-ci.426",
"Il2CppInterop.Runtime": "1.4.6-ci.426", "Il2CppInterop.Runtime": "1.4.6-ci.426",
"MonoMod.RuntimeDetour": "22.7.31.1", "MonoMod.RuntimeDetour": "22.7.31.1",
"Samboy063.Cpp2IL.Core": "2022.1.0-pre-release.18" "Samboy063.Cpp2IL.Core": "2022.1.0-pre-release.19"
} }
}, },
"StyleCop.Analyzers": { "StyleCop.Analyzers": {
@@ -77,8 +77,8 @@
}, },
"AssetRipper.CIL": { "AssetRipper.CIL": {
"type": "Transitive", "type": "Transitive",
"resolved": "1.1.0", "resolved": "1.1.2",
"contentHash": "nSz1cBjgVeKv+esfDtyQGC1mY9b4C4NFStytdoa9DMozDC8uth6930kAsuWZEivj9GqWSqENnaQUGnl23WpmnQ==", "contentHash": "BRPcHORadIzSFkrVOvGkSs54j19mQdXH8dmRTVM51mS8MZLSbTpi9CDPpnWN2IdDsILUrAqbPUFo3zJodYxErw==",
"dependencies": { "dependencies": {
"AsmResolver.DotNet": "6.0.0-beta.1" "AsmResolver.DotNet": "6.0.0-beta.1"
} }
@@ -95,8 +95,8 @@
}, },
"BepInEx.Core": { "BepInEx.Core": {
"type": "Transitive", "type": "Transitive",
"resolved": "6.0.0-be.733", "resolved": "6.0.0-be.735",
"contentHash": "uRzpyUdU3L8Y4ZW+ZnF73orq0E40MjGK6XcPzm24CrrWB5bUshwdrtFQfrwZB6jcZVNVV6PXE92hScEI+Jaoqw==", "contentHash": "FuHm9UCzjSKeiZJc3IF70Fiuqi+FynRn62PwBoOeZcHK3/qm+vl1YwbZyFlmUyf45g+UKxg2Td40iZGx88LVAQ==",
"dependencies": { "dependencies": {
"HarmonyX": "2.10.2", "HarmonyX": "2.10.2",
"MonoMod.Utils": "22.7.31.1", "MonoMod.Utils": "22.7.31.1",
@@ -105,8 +105,8 @@
}, },
"BepInEx.Unity.Common": { "BepInEx.Unity.Common": {
"type": "Transitive", "type": "Transitive",
"resolved": "6.0.0-be.733", "resolved": "6.0.0-be.735",
"contentHash": "KfdiHVSOPnIbDEF7zLPTSXDjKqIEq7SgffqFFKIxOBkCws7LdtSRQsamUcxdD0H8yopcgdlqobIp6t8e4M/k9Q==", "contentHash": "vmK//OBSr+jotqTk//HSdvHtMFTKu+NlQkiEsvr0dZApTVmQM2AgpVMhEAakQPmrSsM6LRJIHCBcLFO1ypfMPQ==",
"dependencies": { "dependencies": {
"AssetRipper.Primitives": "3.1.3", "AssetRipper.Primitives": "3.1.3",
"MonoMod.Utils": "22.7.31.1" "MonoMod.Utils": "22.7.31.1"
@@ -114,8 +114,8 @@
}, },
"Disarm": { "Disarm": {
"type": "Transitive", "type": "Transitive",
"resolved": "2022.1.0-master.34", "resolved": "2022.1.0-master.57",
"contentHash": "sxzTci5eSdl+sFoaGsMZIp7X/eB5ZzplM3CppvD1CWoiZ8rSa43XGLC19G5e8n6mjutNBfN9yL+RER5PCspHFg==" "contentHash": "/dkg7hg8iPBQN4bTV1lMQacarH6fMpgUXhJuo6iI7Wv7YpH7g5F9hJfje7dSMhqG0YlDacLuyWvcph5GzKUXog=="
}, },
"HarmonyX": { "HarmonyX": {
"type": "Transitive", "type": "Transitive",
@@ -317,31 +317,31 @@
}, },
"Samboy063.Cpp2IL.Core": { "Samboy063.Cpp2IL.Core": {
"type": "Transitive", "type": "Transitive",
"resolved": "2022.1.0-pre-release.18", "resolved": "2022.1.0-pre-release.19",
"contentHash": "eX9d1IK05jWaEaeuMAE0L5WYHT7thtxz+aWLL/CAaCzZ0TzRPD+WFTjJ0KQO0YWBVO300CX3GwmPmf7TNO+wUg==", "contentHash": "mAYIrMo0VdOZzh1NS5bZeflg80gtYNY7kZo9q/blEYheUPyLXu5ozQOjX+Bq2yDh40pA+yiE2MXTnN2Is2hjgw==",
"dependencies": { "dependencies": {
"AsmResolver.DotNet": "6.0.0-beta.1", "AsmResolver.DotNet": "6.0.0-beta.1",
"AssetRipper.CIL": "1.1.0", "AssetRipper.CIL": "1.1.2",
"AssetRipper.Gee.External.Capstone": "2.3.2", "AssetRipper.Gee.External.Capstone": "2.3.2",
"Disarm": "2022.1.0-master.34", "Disarm": "2022.1.0-master.57",
"Iced": "1.21.0", "Iced": "1.21.0",
"Samboy063.LibCpp2IL": "2022.1.0-pre-release.18", "Samboy063.LibCpp2IL": "2022.1.0-pre-release.19",
"StableNameDotNet": "0.1.0-pre-release.15" "StableNameDotNet": "0.1.0-pre-release.19"
} }
}, },
"Samboy063.LibCpp2IL": { "Samboy063.LibCpp2IL": {
"type": "Transitive", "type": "Transitive",
"resolved": "2022.1.0-pre-release.18", "resolved": "2022.1.0-pre-release.19",
"contentHash": "9zJdTAeErpwJpYDHYwwI0MAC1OyBEfC1ce7dpAOYRUUYCfeaKVWxnSCcyaoY6HDzIoxPkhbfllbwOe49ZmUYuQ==", "contentHash": "/n8p81ltd38BeNNS2xUNPGMSzxk/UGXr9cRNqG1MaLogzANNNrvCAXqWmNMM3tZctjp7vqTxEA+e4J4ngul8Fg==",
"dependencies": { "dependencies": {
"AssetRipper.Primitives": "3.1.2", "AssetRipper.Primitives": "3.1.3",
"Samboy063.WasmDisassembler": "2022.1.0-pre-release.15" "Samboy063.WasmDisassembler": "2022.1.0-pre-release.19"
} }
}, },
"Samboy063.WasmDisassembler": { "Samboy063.WasmDisassembler": {
"type": "Transitive", "type": "Transitive",
"resolved": "2022.1.0-pre-release.15", "resolved": "2022.1.0-pre-release.19",
"contentHash": "e6qw81SHS+fS7iZ3qfqZBavVarYbkPElNgDCANF6dNFTYq5+hc80am+4FqQDl+ZVNS47bZDZobxIzHhmriCXGg==" "contentHash": "uVQdYm/J6+jJ1xt6GJ3hNhXhciwlX+LmHTPITu9jjZ75T33YJuuTD7pLVYuMymr+4gSVisg7f1wterFSyqJBWA=="
}, },
"SemanticVersioning": { "SemanticVersioning": {
"type": "Transitive", "type": "Transitive",
@@ -350,8 +350,8 @@
}, },
"StableNameDotNet": { "StableNameDotNet": {
"type": "Transitive", "type": "Transitive",
"resolved": "0.1.0-pre-release.15", "resolved": "0.1.0-pre-release.19",
"contentHash": "aIkEOo8V76vE+9CppHpTFLGXalBw6TAl4/tb6vadmS+gHJMshTVehzQv9cJXy4xZDdANV1uGMRaUFZERcDA2xQ==" "contentHash": "5BPWtntv3PXeFIg9CuGW6OM3f5GnwvdQJbzRpufPsistFwFyt1xYW1wSDr+QIdDO7vLndr7iNpWD3FyYp9LL4g=="
}, },
"StyleCop.Analyzers.Unstable": { "StyleCop.Analyzers.Unstable": {
"type": "Transitive", "type": "Transitive",
@@ -903,7 +903,7 @@
"reactor": { "reactor": {
"type": "Project", "type": "Project",
"dependencies": { "dependencies": {
"BepInEx.Unity.IL2CPP": "[6.0.0-be.733, )" "BepInEx.Unity.IL2CPP": "[6.0.0-be.735, )"
} }
} }
} }
+35 -35
View File
@@ -4,9 +4,9 @@
"net6.0": { "net6.0": {
"AmongUs.GameLibs.Steam": { "AmongUs.GameLibs.Steam": {
"type": "Direct", "type": "Direct",
"requested": "[2025.3.25, )", "requested": "[2025.4.15, )",
"resolved": "2025.3.25", "resolved": "2025.4.15",
"contentHash": "2QxQXgZDcQOdAIDXrNLrQ7veEzD6EBzuaRjzSbHptWUPUsuVc3I5Ur3xMkPPwmSGsDHjLuAGE84yRjV6oJxGxw==" "contentHash": "R3RxzHGZOGUJ9nMwrP0cjS6g+sh60QUU506Mo47lh17155enUjH6PtErijihSoU7t3aQpzCIyC67W3XrrHhH4g=="
}, },
"BepInEx.AutoPlugin": { "BepInEx.AutoPlugin": {
"type": "Direct", "type": "Direct",
@@ -16,25 +16,25 @@
}, },
"BepInEx.IL2CPP.MSBuild": { "BepInEx.IL2CPP.MSBuild": {
"type": "Direct", "type": "Direct",
"requested": "[2.0.1, )", "requested": "[2.1.0-rc.1, )",
"resolved": "2.0.1", "resolved": "2.1.0-rc.1",
"contentHash": "hUZjCV0t8dkw/Z/zq4Zl405QP7frBk/LVfMdUmUz+7XOhGd7lYPKrR48A5vbGl2QeHudMxlkXzAr9WM3Duq2SQ==" "contentHash": "WI/7TbJwWl5P4B6UXGtKI1VMe6fA6h3fcbp3ZjJKqOBQ5MJfDMmeVB4fb+RW1tUQdxnlSWV3Ul62PHFyTqp4PA=="
}, },
"BepInEx.Unity.IL2CPP": { "BepInEx.Unity.IL2CPP": {
"type": "Direct", "type": "Direct",
"requested": "[6.0.0-be.733, )", "requested": "[6.0.0-be.735, )",
"resolved": "6.0.0-be.733", "resolved": "6.0.0-be.735",
"contentHash": "lnoGaPHjIdGfEiKtf89knaTdLXe4IUqVLdoYqW8NYhhNqgxa3oNwScjTmuYQpa4Leew3937+slq2WIjvX/DUwQ==", "contentHash": "2+eFJGKMR1GFPeU9wuF+TVrMANIaWIc/6N9e8x4b7b/fNiY9B6vicYNiMDb2deYQpWZtOei+2btnar5dDE5BPg==",
"dependencies": { "dependencies": {
"BepInEx.Core": "6.0.0-be.733", "BepInEx.Core": "6.0.0-be.735",
"BepInEx.Unity.Common": "6.0.0-be.733", "BepInEx.Unity.Common": "6.0.0-be.735",
"HarmonyX": "2.10.2", "HarmonyX": "2.10.2",
"Iced": "1.21.0", "Iced": "1.21.0",
"Il2CppInterop.Generator": "1.4.6-ci.426", "Il2CppInterop.Generator": "1.4.6-ci.426",
"Il2CppInterop.HarmonySupport": "1.4.6-ci.426", "Il2CppInterop.HarmonySupport": "1.4.6-ci.426",
"Il2CppInterop.Runtime": "1.4.6-ci.426", "Il2CppInterop.Runtime": "1.4.6-ci.426",
"MonoMod.RuntimeDetour": "22.7.31.1", "MonoMod.RuntimeDetour": "22.7.31.1",
"Samboy063.Cpp2IL.Core": "2022.1.0-pre-release.18" "Samboy063.Cpp2IL.Core": "2022.1.0-pre-release.19"
} }
}, },
"StyleCop.Analyzers": { "StyleCop.Analyzers": {
@@ -77,8 +77,8 @@
}, },
"AssetRipper.CIL": { "AssetRipper.CIL": {
"type": "Transitive", "type": "Transitive",
"resolved": "1.1.0", "resolved": "1.1.2",
"contentHash": "nSz1cBjgVeKv+esfDtyQGC1mY9b4C4NFStytdoa9DMozDC8uth6930kAsuWZEivj9GqWSqENnaQUGnl23WpmnQ==", "contentHash": "BRPcHORadIzSFkrVOvGkSs54j19mQdXH8dmRTVM51mS8MZLSbTpi9CDPpnWN2IdDsILUrAqbPUFo3zJodYxErw==",
"dependencies": { "dependencies": {
"AsmResolver.DotNet": "6.0.0-beta.1" "AsmResolver.DotNet": "6.0.0-beta.1"
} }
@@ -95,8 +95,8 @@
}, },
"BepInEx.Core": { "BepInEx.Core": {
"type": "Transitive", "type": "Transitive",
"resolved": "6.0.0-be.733", "resolved": "6.0.0-be.735",
"contentHash": "uRzpyUdU3L8Y4ZW+ZnF73orq0E40MjGK6XcPzm24CrrWB5bUshwdrtFQfrwZB6jcZVNVV6PXE92hScEI+Jaoqw==", "contentHash": "FuHm9UCzjSKeiZJc3IF70Fiuqi+FynRn62PwBoOeZcHK3/qm+vl1YwbZyFlmUyf45g+UKxg2Td40iZGx88LVAQ==",
"dependencies": { "dependencies": {
"HarmonyX": "2.10.2", "HarmonyX": "2.10.2",
"MonoMod.Utils": "22.7.31.1", "MonoMod.Utils": "22.7.31.1",
@@ -105,8 +105,8 @@
}, },
"BepInEx.Unity.Common": { "BepInEx.Unity.Common": {
"type": "Transitive", "type": "Transitive",
"resolved": "6.0.0-be.733", "resolved": "6.0.0-be.735",
"contentHash": "KfdiHVSOPnIbDEF7zLPTSXDjKqIEq7SgffqFFKIxOBkCws7LdtSRQsamUcxdD0H8yopcgdlqobIp6t8e4M/k9Q==", "contentHash": "vmK//OBSr+jotqTk//HSdvHtMFTKu+NlQkiEsvr0dZApTVmQM2AgpVMhEAakQPmrSsM6LRJIHCBcLFO1ypfMPQ==",
"dependencies": { "dependencies": {
"AssetRipper.Primitives": "3.1.3", "AssetRipper.Primitives": "3.1.3",
"MonoMod.Utils": "22.7.31.1" "MonoMod.Utils": "22.7.31.1"
@@ -114,8 +114,8 @@
}, },
"Disarm": { "Disarm": {
"type": "Transitive", "type": "Transitive",
"resolved": "2022.1.0-master.34", "resolved": "2022.1.0-master.57",
"contentHash": "sxzTci5eSdl+sFoaGsMZIp7X/eB5ZzplM3CppvD1CWoiZ8rSa43XGLC19G5e8n6mjutNBfN9yL+RER5PCspHFg==" "contentHash": "/dkg7hg8iPBQN4bTV1lMQacarH6fMpgUXhJuo6iI7Wv7YpH7g5F9hJfje7dSMhqG0YlDacLuyWvcph5GzKUXog=="
}, },
"HarmonyX": { "HarmonyX": {
"type": "Transitive", "type": "Transitive",
@@ -317,31 +317,31 @@
}, },
"Samboy063.Cpp2IL.Core": { "Samboy063.Cpp2IL.Core": {
"type": "Transitive", "type": "Transitive",
"resolved": "2022.1.0-pre-release.18", "resolved": "2022.1.0-pre-release.19",
"contentHash": "eX9d1IK05jWaEaeuMAE0L5WYHT7thtxz+aWLL/CAaCzZ0TzRPD+WFTjJ0KQO0YWBVO300CX3GwmPmf7TNO+wUg==", "contentHash": "mAYIrMo0VdOZzh1NS5bZeflg80gtYNY7kZo9q/blEYheUPyLXu5ozQOjX+Bq2yDh40pA+yiE2MXTnN2Is2hjgw==",
"dependencies": { "dependencies": {
"AsmResolver.DotNet": "6.0.0-beta.1", "AsmResolver.DotNet": "6.0.0-beta.1",
"AssetRipper.CIL": "1.1.0", "AssetRipper.CIL": "1.1.2",
"AssetRipper.Gee.External.Capstone": "2.3.2", "AssetRipper.Gee.External.Capstone": "2.3.2",
"Disarm": "2022.1.0-master.34", "Disarm": "2022.1.0-master.57",
"Iced": "1.21.0", "Iced": "1.21.0",
"Samboy063.LibCpp2IL": "2022.1.0-pre-release.18", "Samboy063.LibCpp2IL": "2022.1.0-pre-release.19",
"StableNameDotNet": "0.1.0-pre-release.15" "StableNameDotNet": "0.1.0-pre-release.19"
} }
}, },
"Samboy063.LibCpp2IL": { "Samboy063.LibCpp2IL": {
"type": "Transitive", "type": "Transitive",
"resolved": "2022.1.0-pre-release.18", "resolved": "2022.1.0-pre-release.19",
"contentHash": "9zJdTAeErpwJpYDHYwwI0MAC1OyBEfC1ce7dpAOYRUUYCfeaKVWxnSCcyaoY6HDzIoxPkhbfllbwOe49ZmUYuQ==", "contentHash": "/n8p81ltd38BeNNS2xUNPGMSzxk/UGXr9cRNqG1MaLogzANNNrvCAXqWmNMM3tZctjp7vqTxEA+e4J4ngul8Fg==",
"dependencies": { "dependencies": {
"AssetRipper.Primitives": "3.1.2", "AssetRipper.Primitives": "3.1.3",
"Samboy063.WasmDisassembler": "2022.1.0-pre-release.15" "Samboy063.WasmDisassembler": "2022.1.0-pre-release.19"
} }
}, },
"Samboy063.WasmDisassembler": { "Samboy063.WasmDisassembler": {
"type": "Transitive", "type": "Transitive",
"resolved": "2022.1.0-pre-release.15", "resolved": "2022.1.0-pre-release.19",
"contentHash": "e6qw81SHS+fS7iZ3qfqZBavVarYbkPElNgDCANF6dNFTYq5+hc80am+4FqQDl+ZVNS47bZDZobxIzHhmriCXGg==" "contentHash": "uVQdYm/J6+jJ1xt6GJ3hNhXhciwlX+LmHTPITu9jjZ75T33YJuuTD7pLVYuMymr+4gSVisg7f1wterFSyqJBWA=="
}, },
"SemanticVersioning": { "SemanticVersioning": {
"type": "Transitive", "type": "Transitive",
@@ -350,8 +350,8 @@
}, },
"StableNameDotNet": { "StableNameDotNet": {
"type": "Transitive", "type": "Transitive",
"resolved": "0.1.0-pre-release.15", "resolved": "0.1.0-pre-release.19",
"contentHash": "aIkEOo8V76vE+9CppHpTFLGXalBw6TAl4/tb6vadmS+gHJMshTVehzQv9cJXy4xZDdANV1uGMRaUFZERcDA2xQ==" "contentHash": "5BPWtntv3PXeFIg9CuGW6OM3f5GnwvdQJbzRpufPsistFwFyt1xYW1wSDr+QIdDO7vLndr7iNpWD3FyYp9LL4g=="
}, },
"StyleCop.Analyzers.Unstable": { "StyleCop.Analyzers.Unstable": {
"type": "Transitive", "type": "Transitive",
@@ -903,7 +903,7 @@
"reactor": { "reactor": {
"type": "Project", "type": "Project",
"dependencies": { "dependencies": {
"BepInEx.Unity.IL2CPP": "[6.0.0-be.733, )" "BepInEx.Unity.IL2CPP": "[6.0.0-be.735, )"
} }
} }
} }
-1
View File
@@ -1 +0,0 @@
global using AmongUsClient_CoFindGame = AmongUsClient._CoFindGame_d__6;
@@ -19,6 +19,23 @@ internal static class GetStringPatch
return true; return true;
} }
[HarmonyPatch(typeof(TranslationController), nameof(TranslationController.GetString), typeof(string), typeof(string), typeof(Il2CppReferenceArray<Il2CppSystem.Object>))]
[HarmonyPrefix]
public static bool SystemTypesStringPatch(
TranslationController __instance,
string id,
Il2CppReferenceArray<Il2CppSystem.Object> parts,
ref string __result)
{
if (!int.TryParse(id, out var intId))
{
return true;
}
var stringName = (StringNames) intId;
return !LocalizationManager.TryGetTextFormatted(stringName, parts, out __result);
}
[HarmonyPatch(typeof(TranslationController), nameof(TranslationController.GetString), typeof(SystemTypes))] [HarmonyPatch(typeof(TranslationController), nameof(TranslationController.GetString), typeof(SystemTypes))]
[HarmonyPrefix] [HarmonyPrefix]
public static bool SystemTypesStringPatch(TranslationController __instance, SystemTypes room, ref string __result) public static bool SystemTypesStringPatch(TranslationController __instance, SystemTypes room, ref string __result)
@@ -38,8 +38,7 @@ public sealed class MessageConverterAttribute : Attribute
try try
{ {
var messageConverter = (UnsafeMessageConverter) Activator.CreateInstance(type)!; MessageSerializer.Register(type);
MessageSerializer.Register(messageConverter);
} }
catch (Exception e) catch (Exception e)
{ {
@@ -52,5 +51,6 @@ public sealed class MessageConverterAttribute : Attribute
internal static void Initialize() internal static void Initialize()
{ {
IL2CPPChainloader.Instance.PluginLoad += (_, assembly, _) => Register(assembly); IL2CPPChainloader.Instance.PluginLoad += (_, assembly, _) => Register(assembly);
IL2CPPChainloader.Instance.Finished += MessageSerializer.ClearMaps;
} }
} }
@@ -36,7 +36,8 @@ public sealed class MethodRpcAttribute : Attribute
/// <summary> /// <summary>
/// Gets or sets a value indicating whether the rpc should be sent immediately. /// Gets or sets a value indicating whether the rpc should be sent immediately.
/// </summary> /// </summary>
public bool SendImmediately { get; set; } [Obsolete("Non-immediate RPCs were removed in 2025.5.20. All RPCs are immediate. This property will be removed in a future version.")]
public bool SendImmediately { get; set; } = true;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="MethodRpcAttribute"/> class. /// Initializes a new instance of the <see cref="MethodRpcAttribute"/> class.
@@ -71,7 +72,7 @@ public sealed class MethodRpcAttribute : Attribute
try try
{ {
var customRpc = new MethodRpc(plugin, method, attribute.Id, attribute.SendOption, attribute.LocalHandling, attribute.SendImmediately); var customRpc = new MethodRpc(plugin, method, attribute.Id, attribute.SendOption, attribute.LocalHandling);
PluginSingleton<ReactorPlugin>.Instance.CustomRpcManager.Register(customRpc); PluginSingleton<ReactorPlugin>.Instance.CustomRpcManager.Register(customRpc);
} }
catch (Exception e) catch (Exception e)
@@ -1,6 +1,8 @@
using System; using System;
using System.Globalization;
using Hazel; using Hazel;
using Hazel.Udp; using Hazel.Udp;
using Reactor.Networking.Serialization;
using UnityEngine; using UnityEngine;
namespace Reactor.Networking.Extensions; namespace Reactor.Networking.Extensions;
@@ -12,10 +14,11 @@ public static class ExtraMessageExtensions
{ {
private const float MIN = -50f; private const float MIN = -50f;
private const float MAX = 50f; private const float MAX = 50f;
private const float DIFF = MAX - MIN;
private static float ReverseLerp(float t) private static float ReverseLerp(float t)
{ {
return Mathf.Clamp((t - MIN) / (MAX - MIN), 0f, 1f); return Mathf.Clamp01((t - MIN) / DIFF);
} }
/// <summary> /// <summary>
@@ -32,6 +35,33 @@ public static class ExtraMessageExtensions
writer.Write(y); writer.Write(y);
} }
/// <summary>
/// Writes an Enum value to the <paramref name="writer"/>.
/// </summary>
/// <param name="writer">The <see cref="MessageWriter"/> to write to.</param>
/// <param name="value">The <see cref="Enum"/> to write.</param>
public static void Write(this MessageWriter writer, Enum value) => writer.Serialize(Convert.ChangeType(value, Enum.GetUnderlyingType(value.GetType()), CultureInfo.InvariantCulture));
/// <summary>
/// Writes a long value to the <paramref name="writer"/>.
/// </summary>
/// <param name="writer">The <see cref="MessageWriter"/> to write to.</param>
/// <param name="value">The <see cref="long"/> to write.</param>
public static void Write(this MessageWriter writer, long value) => writer.Write(BitConverter.GetBytes(value));
/// <summary>
/// Writes a color value to the <paramref name="writer"/>.
/// </summary>
/// <param name="writer">The <see cref="MessageWriter"/> to write to.</param>
/// <param name="value">The <see cref="Color32"/> to write.</param>
public static void Write(this MessageWriter writer, Color32 value)
{
writer.Write(value.r);
writer.Write(value.g);
writer.Write(value.b);
writer.Write(value.a);
}
/// <summary> /// <summary>
/// Reads a <see cref="Vector2"/> from the <paramref name="reader"/>. /// Reads a <see cref="Vector2"/> from the <paramref name="reader"/>.
/// </summary> /// </summary>
@@ -45,6 +75,43 @@ public static class ExtraMessageExtensions
return new Vector2(Mathf.Lerp(MIN, MAX, x), Mathf.Lerp(MIN, MAX, y)); return new Vector2(Mathf.Lerp(MIN, MAX, x), Mathf.Lerp(MIN, MAX, y));
} }
/// <summary>
/// Reads an enum value and casts it to the specified type from a network message.
/// </summary>
/// <param name="reader">The <see cref="MessageReader"/> to read from.</param>
/// <typeparam name="T">The <see cref="Enum"/> type to convert to.</typeparam>
/// <returns>An <see cref="Enum"/> value from the <paramref name="reader"/>.</returns>
public static T ReadEnum<T>(this MessageReader reader) where T : struct, Enum => (T) reader.ReadEnum(typeof(T));
/// <summary>
/// Reads an enum value from a network message.
/// </summary>
/// <param name="reader">The <see cref="MessageReader"/> to read from.</param>
/// <param name="enumType">The type of the enum.</param>
/// <returns>The resulting enum value from the <paramref name="reader"/>.</returns>
public static object ReadEnum(this MessageReader reader, Type enumType) => Enum.ToObject(enumType, reader.Deserialize(Enum.GetUnderlyingType(enumType)));
/// <summary>
/// Reads a long value from a network message.
/// </summary>
/// <param name="reader">The <see cref="MessageReader"/> to read from.</param>
/// <returns>The resulting long value from the <paramref name="reader"/>.</returns>
public static long ReadInt64(this MessageReader reader) => BitConverter.ToInt64(reader.ReadBytes(8), 0);
/// <summary>
/// Reads a color value from a network message.
/// </summary>
/// <param name="reader">The <see cref="MessageReader"/> to read from.</param>
/// <returns>The resulting Color32 value from the <paramref name="reader"/>.</returns>
public static Color32 ReadColor32(this MessageReader reader) => new(reader.ReadByte(), reader.ReadByte(), reader.ReadByte(), reader.ReadByte());
/// <summary>
/// Reads a color value from a network message.
/// </summary>
/// <param name="reader">The <see cref="MessageReader"/> to read from.</param>
/// <returns>The resulting Color value from the <paramref name="reader"/>.</returns>
public static Color ReadColor(this MessageReader reader) => new(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle());
/// <summary> /// <summary>
/// Sends a message on the <paramref name="connection"/> with an <paramref name="ackCallback"/>. /// Sends a message on the <paramref name="connection"/> with an <paramref name="ackCallback"/>.
/// </summary> /// </summary>
+56 -50
View File
@@ -1,14 +1,18 @@
using System; using System;
using System.Linq; using System.Linq;
using System.Reflection;
using AmongUs.Data; using AmongUs.Data;
using AmongUs.InnerNet.GameDataMessages;
using BepInEx.Unity.IL2CPP.Utils; using BepInEx.Unity.IL2CPP.Utils;
using HarmonyLib; using HarmonyLib;
using Hazel; using Hazel;
using Il2CppInterop.Runtime; using Il2CppInterop.Runtime;
using Il2CppInterop.Runtime.InteropTypes;
using Il2CppInterop.Runtime.InteropTypes.Arrays; using Il2CppInterop.Runtime.InteropTypes.Arrays;
using InnerNet; using InnerNet;
using Reactor.Networking.Extensions; using Reactor.Networking.Extensions;
using Reactor.Networking.Messages; using Reactor.Networking.Messages;
using Reactor.Utilities;
using UnityEngine; using UnityEngine;
using IEnumerator = System.Collections.IEnumerator; using IEnumerator = System.Collections.IEnumerator;
@@ -29,15 +33,22 @@ internal static class ClientPatches
} }
} }
[HarmonyPatch(typeof(InnerNetClient._HandleGameDataInner_d__41), nameof(InnerNetClient._HandleGameDataInner_d__41.MoveNext))] [HarmonyPatch]
public static class HandleGameDataInnerPatch public static class HandleGameDataInnerPatch
{ {
public static bool Prefix(InnerNetClient._HandleGameDataInner_d__41 __instance, ref bool __result) public static MethodBase TargetMethod()
{ {
var innerNetClient = __instance.__4__this; return Il2CppStateMachineWrapper<InnerNetClient>.GetStateMachineMoveNext(nameof(InnerNetClient.HandleGameDataInner))!;
var reader = __instance.reader; }
if (__instance.__1__state != 0) return true; public static bool Prefix(Il2CppObjectBase __instance, ref bool __result)
{
var wrapper = new Il2CppStateMachineWrapper<InnerNetClient>(__instance);
var innerNetClient = wrapper.Instance;
var reader = wrapper.GetParameter<MessageReader>("reader");
if (wrapper.State != 0) return true;
if (reader.Tag == byte.MaxValue) if (reader.Tag == byte.MaxValue)
{ {
@@ -63,7 +74,7 @@ internal static class ClientPatches
return false; return false;
} }
if (reader.Tag == InnerNetClient.SceneChangeFlag && ReactorConnection.Instance?.Syncer == Syncer.Host) if (reader.Tag == (byte) GameDataTypes.SceneChangeFlag && ReactorConnection.Instance?.Syncer == Syncer.Host)
{ {
var clientId = reader.ReadPackedInt32(); var clientId = reader.ReadPackedInt32();
var clientData = innerNetClient.FindClientById(clientId); var clientData = innerNetClient.FindClientById(clientId);
@@ -126,7 +137,7 @@ internal static class ClientPatches
: chatText; : chatText;
// Write SendChat directly instead of using RpcSendChat so we can call AddChat ourselves // Write SendChat directly instead of using RpcSendChat so we can call AddChat ourselves
var messageWriter = AmongUsClient.Instance.StartRpc(PlayerControl.LocalPlayer.NetId, (byte) RpcCalls.SendChat); var messageWriter = AmongUsClient.Instance.StartRpcImmediately(PlayerControl.LocalPlayer.NetId, (byte) RpcCalls.SendChat, SendOption.Reliable);
messageWriter.Write(truncatedChatText); messageWriter.Write(truncatedChatText);
messageWriter.EndMessage(); messageWriter.EndMessage();
} }
@@ -161,14 +172,22 @@ internal static class ClientPatches
} }
} }
[HarmonyPatch(typeof(InnerNetClient._CoSendSceneChange_d__32), nameof(InnerNetClient._CoSendSceneChange_d__32.MoveNext))] [HarmonyPatch]
public static class CoSendSceneChangePatch public static class CoSendSceneChangePatch
{ {
public static bool Prefix(InnerNetClient._CoSendSceneChange_d__32 __instance, ref bool __result) public static MethodBase TargetMethod()
{ {
return Il2CppStateMachineWrapper<InnerNetClient>.GetStateMachineMoveNext(nameof(InnerNetClient.CoSendSceneChange))!;
}
public static bool Prefix(Il2CppObjectBase __instance, ref bool __result)
{
var wrapper = new Il2CppStateMachineWrapper<InnerNetClient>(__instance);
if (ReactorConnection.Instance!.Syncer != Syncer.Host) return true; if (ReactorConnection.Instance!.Syncer != Syncer.Host) return true;
var innerNetClient = __instance.__4__this; var innerNetClient = wrapper.Instance;
var sceneName = wrapper.GetParameter<string>("sceneName");
// Check for the conditions when the scene change message should be sent // Check for the conditions when the scene change message should be sent
if (!innerNetClient.AmHost && if (!innerNetClient.AmHost &&
@@ -181,9 +200,9 @@ internal static class ClientPatches
var writer = MessageWriter.Get(SendOption.Reliable); var writer = MessageWriter.Get(SendOption.Reliable);
writer.StartMessage(Tags.GameData); writer.StartMessage(Tags.GameData);
writer.Write(innerNetClient.GameId); writer.Write(innerNetClient.GameId);
writer.StartMessage(InnerNetClient.SceneChangeFlag); writer.StartMessage((byte) GameDataTypes.SceneChangeFlag);
writer.WritePacked(innerNetClient.ClientId); writer.WritePacked(innerNetClient.ClientId);
writer.Write(__instance.sceneName); writer.Write(sceneName);
// PATCH - Inject ReactorHandshakeC2S // PATCH - Inject ReactorHandshakeC2S
Debug("Injecting ReactorHandshakeC2S to CoSendSceneChange"); Debug("Injecting ReactorHandshakeC2S to CoSendSceneChange");
@@ -196,10 +215,10 @@ internal static class ClientPatches
writer.Recycle(); writer.Recycle();
// Create a new coroutine to let AmongUsClient handle scene changes too // Create a new coroutine to let AmongUsClient handle scene changes too
innerNetClient.StartCoroutine(innerNetClient.CoOnPlayerChangedScene(clientData, __instance.sceneName)); innerNetClient.StartCoroutine(innerNetClient.CoOnPlayerChangedScene(clientData, sceneName));
// Cancel this coroutine // Cancel this coroutine
__instance.__1__state = -1; wrapper.State = -1;
__result = false; __result = false;
return false; return false;
} }
@@ -209,16 +228,24 @@ internal static class ClientPatches
} }
} }
[HarmonyPatch(typeof(InnerNetClient._CoHandleSpawn_d__42), nameof(InnerNetClient._CoHandleSpawn_d__42.MoveNext))] [HarmonyPatch]
public static class CoHandleSpawnPatch public static class CoHandleSpawnPatch
{ {
public static void Postfix(InnerNetClient._CoHandleSpawn_d__42 __instance, bool __result) public static MethodBase TargetMethod()
{
return Il2CppStateMachineWrapper<InnerNetClient>.GetStateMachineMoveNext(nameof(InnerNetClient.CoHandleSpawn))!;
}
public static void Postfix(Il2CppObjectBase __instance, bool __result)
{ {
if (ReactorConnection.Instance!.Syncer != Syncer.Host) return; if (ReactorConnection.Instance!.Syncer != Syncer.Host) return;
if (!__result && !AmongUsClient.Instance.AmHost && __instance._ownerId_5__2 == AmongUsClient.Instance.ClientId) var wrapper = new Il2CppStateMachineWrapper<InnerNetClient>(__instance);
var ownerId = wrapper.GetParameter<int>("_ownerId_5__2");
if (!__result && !AmongUsClient.Instance.AmHost && ownerId == AmongUsClient.Instance.ClientId)
{ {
var reader = __instance.reader; var reader = wrapper.GetParameter<MessageReader>("reader");
if (reader.BytesRemaining >= ReactorHeader.Size && ReactorHeader.Read(reader)) if (reader.BytesRemaining >= ReactorHeader.Size && ReactorHeader.Read(reader))
{ {
ModdedHandshakeS2C.Deserialize(reader, out var serverName, out var serverVersion, out _); ModdedHandshakeS2C.Deserialize(reader, out var serverName, out var serverVersion, out _);
@@ -227,7 +254,7 @@ internal static class ClientPatches
else else
{ {
Debug("Host is not modded"); Debug("Host is not modded");
if (!Mod.Validate(ModList.Current, Array.Empty<Mod>(), out var reason)) if (!Mod.Validate(ModList.Current, [], out var reason))
{ {
AmongUsClient.Instance.DisconnectWithReason(reason); AmongUsClient.Instance.DisconnectWithReason(reason);
} }
@@ -236,47 +263,23 @@ internal static class ClientPatches
} }
} }
[HarmonyPatch(typeof(InnerNetClient), nameof(InnerNetClient.WriteSpawnMessage))] [HarmonyPatch(typeof(SpawnGameDataMessage), nameof(SpawnGameDataMessage.SerializeValues))]
public static class WriteSpawnMessagePatch public static class SpawnGameDataMessagePatch
{ {
public static bool Prefix(InnerNetClient __instance, InnerNetObject netObjParent, int ownerId, SpawnFlags flags, MessageWriter msg) public static void Postfix(SpawnGameDataMessage __instance, MessageWriter msg)
{ {
if (ReactorConnection.Instance!.Syncer != Syncer.Host) return true; if (ReactorConnection.Instance!.Syncer != Syncer.Host)
msg.StartMessage(4);
msg.WritePacked(netObjParent.SpawnId);
msg.WritePacked(ownerId);
msg.Write((byte) flags);
InnerNetObject[] componentsInChildren = netObjParent.GetComponentsInChildren<InnerNetObject>();
msg.WritePacked(componentsInChildren.Length);
foreach (var innerNetObject in componentsInChildren)
{ {
innerNetObject.OwnerId = ownerId; return;
innerNetObject.SpawnFlags = flags;
if (innerNetObject.NetId == 0)
{
innerNetObject.NetId = __instance.NetIdCnt++;
__instance.allObjects.Add(innerNetObject);
__instance.allObjectsFast.Add(innerNetObject.NetId, innerNetObject);
}
msg.WritePacked(innerNetObject.NetId);
msg.StartMessage(1);
innerNetObject.Serialize(msg, initialState: true);
msg.EndMessage();
} }
// PATCH - Inject ReactorHandshakeS2C // PATCH - Inject ReactorHandshakeS2C
if (__instance.ClientId != ownerId && IL2CPP.il2cpp_object_get_class(netObjParent.Pointer) == Il2CppClassPointerStore<PlayerControl>.NativeClassPtr) if (AmongUsClient.Instance.ClientId != __instance.ownerId && __instance.NetObjectType == Il2CppType.Of<PlayerControl>())
{ {
Debug("Injecting ReactorHandshakeS2C to WriteSpawnMessage"); Debug("Injecting ReactorHandshakeS2C to WriteSpawnMessage");
ReactorHeader.Write(msg); ReactorHeader.Write(msg);
ModdedHandshakeS2C.Serialize(msg, "Among Us", Application.version, 0); // TODO ModdedHandshakeS2C.Serialize(msg, "Among Us", Application.version, 0); // TODO
} }
msg.EndMessage();
return false;
} }
} }
@@ -285,7 +288,10 @@ internal static class ClientPatches
{ {
public static bool Prefix(InnerNetClient __instance, [HarmonyArgument(0)] MessageReader reader) public static bool Prefix(InnerNetClient __instance, [HarmonyArgument(0)] MessageReader reader)
{ {
if (__instance.NetworkMode == NetworkModes.FreePlay) return true; if (__instance.NetworkMode == NetworkModes.FreePlay)
{
return true;
}
var isFirst = false; var isFirst = false;
+12 -4
View File
@@ -54,8 +54,12 @@ internal static class HttpPatches
public static void Prefix(UnityWebRequest __instance) public static void Prefix(UnityWebRequest __instance)
{ {
var path = __instance.uri.AbsolutePath; // new Uri() is necessary because uri property got stripped.
if (path == "/api/games") var path = new Uri(__instance.url).AbsolutePath;
// Public lobby menu uses /api/games/filtered, code requests use /api/games/code,
// creating a game uses /api/games.
// So we need to match everything that contains /api/games
if (path.Contains("/api/games"))
{ {
Debug($"{__instance.method} {path}"); Debug($"{__instance.method} {path}");
__instance.SetRequestHeader("Client-Mods", BuildHeader()); __instance.SetRequestHeader("Client-Mods", BuildHeader());
@@ -64,8 +68,12 @@ internal static class HttpPatches
public static void Postfix(UnityWebRequest __instance, UnityWebRequestAsyncOperation __result) public static void Postfix(UnityWebRequest __instance, UnityWebRequestAsyncOperation __result)
{ {
var path = __instance.uri.AbsolutePath; // new Uri() is necessary because uri property got stripped.
if (path == "/api/games") var path = new Uri(__instance.url).AbsolutePath;
// Public lobby menu uses /api/games/filtered, code requests use /api/games/code,
// creating a game uses /api/games.
// So we need to match everything that contains /api/games
if (path.Contains("/api/games"))
{ {
__result.add_completed((Action<AsyncOperation>) (_ => __result.add_completed((Action<AsyncOperation>) (_ =>
{ {
@@ -1,5 +1,7 @@
using System.Reflection;
using HarmonyLib; using HarmonyLib;
using InnerNet; using InnerNet;
using Reactor.Utilities;
namespace Reactor.Networking.Patches; namespace Reactor.Networking.Patches;
@@ -20,20 +22,29 @@ public class ReactorConnection
/// </summary> /// </summary>
public static ReactorConnection? Instance { get; private set; } public static ReactorConnection? Instance { get; private set; }
// CoConnect(string) was inlined, so we patch the MoveNext method instead.
[HarmonyPatch] [HarmonyPatch]
private static class Patches internal static class CoConnectPatch
{ {
[HarmonyPatch(typeof(InnerNetClient), nameof(InnerNetClient.CoConnect), typeof(string))] public static MethodBase TargetMethod()
[HarmonyPrefix]
public static void CoConnect()
{ {
Debug("New ReactorConnection created"); return Il2CppStateMachineWrapper<InnerNetClient>.GetStateMachineMoveNext(nameof(InnerNetClient.CoConnect))!;
Instance = new ReactorConnection();
} }
[HarmonyPatch(typeof(InnerNetClient), nameof(InnerNetClient.DisconnectInternal))] public static void Prefix()
[HarmonyPostfix] {
public static void DisconnectInternalPostfix() if (Instance == null)
{
Debug("New ReactorConnection created");
Instance = new ReactorConnection();
}
}
}
[HarmonyPatch(typeof(InnerNetClient), nameof(InnerNetClient.DisconnectInternal))]
internal static class InnerNetClientDisconnectPatch
{
public static void Postfix()
{ {
Debug("ReactorConnection disconnected"); Debug("ReactorConnection disconnected");
Instance = null; Instance = null;
+20 -5
View File
@@ -32,13 +32,11 @@ public class MethodRpc : UnsafeCustomRpc
/// <param name="id">The id of the rpc.</param> /// <param name="id">The id of the rpc.</param>
/// <param name="option">The send option of the rpc.</param> /// <param name="option">The send option of the rpc.</param>
/// <param name="localHandling">The local handling method of the rpc.</param> /// <param name="localHandling">The local handling method of the rpc.</param>
/// <param name="sendImmediately">The value indicating whether the rpc should be sent immediately.</param> public MethodRpc(BasePlugin plugin, MethodInfo method, uint id, SendOption option, RpcLocalHandling localHandling) : base(plugin, id)
public MethodRpc(BasePlugin plugin, MethodInfo method, uint id, SendOption option, RpcLocalHandling localHandling, bool sendImmediately) : base(plugin, id)
{ {
Method = method; Method = method;
LocalHandling = localHandling; LocalHandling = localHandling;
SendOption = option; SendOption = option;
SendImmediately = sendImmediately;
var parameters = method.GetParameters(); var parameters = method.GetParameters();
@@ -71,6 +69,22 @@ public class MethodRpc : UnsafeCustomRpc
_handle = Hook(method, parameters, method.IsStatic); _handle = Hook(method, parameters, method.IsStatic);
} }
/// <summary>
/// Initializes a new instance of the <see cref="MethodRpc"/> class.
/// </summary>
/// <param name="plugin">The plugin that the rpc is attached to.</param>
/// <param name="method">The method of the method rpc.</param>
/// <param name="id">The id of the rpc.</param>
/// <param name="option">The send option of the rpc.</param>
/// <param name="localHandling">The local handling method of the rpc.</param>
/// <param name="sendImmediately">The value indicating whether the rpc should be sent immediately.</param>
[Obsolete("Non-immediate RPCs were removed in 2025.5.20. All RPCs are immediate. Remove sendImmediately from the parameter list.")]
public MethodRpc(BasePlugin plugin, MethodInfo method, uint id, SendOption option, RpcLocalHandling localHandling, bool sendImmediately)
: this(plugin, method, id, option, localHandling)
{
SendImmediately = sendImmediately;
}
/// <summary> /// <summary>
/// Gets the method of the method rpc. /// Gets the method of the method rpc.
/// </summary> /// </summary>
@@ -91,7 +105,8 @@ public class MethodRpc : UnsafeCustomRpc
/// <summary> /// <summary>
/// Gets a value indicating whether the method rpc should be sent immediately. /// Gets a value indicating whether the method rpc should be sent immediately.
/// </summary> /// </summary>
public bool SendImmediately { get; } [Obsolete("Non-immediate RPCs were removed in 2025.5.20. All RPCs are immediate. This property will be removed in a future version.")]
public bool SendImmediately { get; } = true;
/// <inheritdoc /> /// <inheritdoc />
public override void UnsafeWrite(MessageWriter writer, object? data) public override void UnsafeWrite(MessageWriter writer, object? data)
@@ -134,7 +149,7 @@ public class MethodRpc : UnsafeCustomRpc
/// <param name="args">The arguments to serialize and send.</param> /// <param name="args">The arguments to serialize and send.</param>
public void Send(InnerNetObject innerNetObject, object[] args) public void Send(InnerNetObject innerNetObject, object[] args)
{ {
UnsafeSend(innerNetObject, args, SendImmediately); UnsafeSend(innerNetObject, args);
} }
private static readonly MethodInfo _sendMethod = AccessTools.Method(typeof(MethodRpc), nameof(Send)); private static readonly MethodInfo _sendMethod = AccessTools.Method(typeof(MethodRpc), nameof(Send));
+10 -12
View File
@@ -108,11 +108,16 @@ public abstract class UnsafeCustomRpc
UnsafeHandle(innerNetObject, data); UnsafeHandle(innerNetObject, data);
} }
var writer = immediately switch if (immediately == false)
{ {
false => AmongUsClient.Instance.StartRpc(innerNetObject.NetId, CustomRpcManager.CallId, SendOption), Warning("Non-immediate RPCs were removed in 2025.5.20! Reactor will now always send immediately!");
true => AmongUsClient.Instance.StartRpcImmediately(innerNetObject.NetId, CustomRpcManager.CallId, SendOption, targetClientId), }
};
var writer = AmongUsClient.Instance.StartRpcImmediately(
innerNetObject.NetId,
CustomRpcManager.CallId,
SendOption,
targetClientId);
writer.Write(Mod); writer.Write(Mod);
writer.WritePacked(Id); writer.WritePacked(Id);
@@ -127,14 +132,7 @@ public abstract class UnsafeCustomRpc
AckCallbacks.TryAdd(writer, ackCallback); AckCallbacks.TryAdd(writer, ackCallback);
} }
if (immediately) AmongUsClient.Instance.FinishRpcImmediately(writer);
{
AmongUsClient.Instance.FinishRpcImmediately(writer);
}
else
{
writer.EndMessage();
}
if (LocalHandling == RpcLocalHandling.After) if (LocalHandling == RpcLocalHandling.After)
{ {
@@ -15,33 +15,83 @@ public static class MessageSerializer
private static List<UnsafeMessageConverter> MessageConverters { get; } = new(); private static List<UnsafeMessageConverter> MessageConverters { get; } = new();
private static Dictionary<Type, UnsafeMessageConverter?> MessageConverterMap { get; } = new(); private static Dictionary<Type, UnsafeMessageConverter?> MessageConverterMap { get; } = new();
private static Dictionary<Type, Type> GenericConvertersMap { get; } = new();
internal static void ClearMaps()
{
MessageConverterMap.Clear();
}
/// <summary> /// <summary>
/// Registers a MessageConverter. /// Registers a MessageConverter.
/// </summary> /// </summary>
/// <param name="messageConverter">The MessageConverter to be registered.</param> /// <param name="type">The Type of the MessageConverter to be registered.</param>
public static void Register(UnsafeMessageConverter messageConverter) public static void Register(Type type)
{ {
MessageConverters.Add(messageConverter); if (type.IsGenericTypeDefinition)
MessageConverterMap.Clear(); {
var baseType = type.BaseType!;
if (!baseType.Name.Contains("MessageConverter"))
throw new InvalidOperationException($"{type.Name} should directly inherit from MessageConverter<T>");
var generics = baseType.GetGenericArguments();
var param = generics[0];
GenericConvertersMap.Add(param.GetGenericTypeDefinition(), type);
}
else
{
var messageConverter = (UnsafeMessageConverter) Activator.CreateInstance(type)!;
MessageConverters.Add(messageConverter);
}
} }
/// <summary> /// <summary>
/// Finds a MessageConverter for the specified <paramref name="type"/>. /// Finds a MessageConverter for the specified <paramref name="type"/>.
/// </summary> /// </summary>
/// <param name="type">The type of an object.</param> /// <param name="type">The type of an object.</param>
/// <returns>A MessageConverted that can convert the specified <see cref="Type"/>.</returns> /// <returns>A MessageConverter that can convert the specified <see cref="Type"/>.</returns>
public static UnsafeMessageConverter? FindConverter(Type type) public static UnsafeMessageConverter? FindConverter(Type type)
{ {
if (MessageConverterMap.TryGetValue(type, out var value)) if (!MessageConverterMap.TryGetValue(type, out var value))
{ {
return value; value = MessageConverters.SingleOrDefault(x => x.CanConvert(type));
if (value == null)
return null;
MessageConverterMap.Add(type, value);
} }
var converter = MessageConverters.SingleOrDefault(x => x.CanConvert(type)); return value;
MessageConverterMap.Add(type, converter); }
return converter; /// <summary>
/// Finds and builds a MessageConverter for the specified <paramref name="type"/> using a registered generic converter.
/// </summary>
/// <param name="type">The type of an object.</param>
/// <returns>A MessageConverter that can convert the specified <see cref="Type"/>.</returns>
public static UnsafeMessageConverter? FindGenericConverter(Type type)
{
if (MessageConverterMap.TryGetValue(type, out var value))
return value;
if (!type.IsGenericType)
return null;
var typeDef = type.GetGenericTypeDefinition();
if (!GenericConvertersMap.TryGetValue(typeDef, out var builder))
return null;
var generic = builder.MakeGenericType(type.GetGenericArguments());
value = (UnsafeMessageConverter) Activator.CreateInstance(generic)!;
MessageConverters.Add(value);
MessageConverterMap.Add(type, value);
return value;
} }
/// <summary> /// <summary>
@@ -49,7 +99,7 @@ public static class MessageSerializer
/// </summary> /// </summary>
/// <param name="writer">The <see cref="MessageWriter"/> to write to.</param> /// <param name="writer">The <see cref="MessageWriter"/> to write to.</param>
/// <param name="args">The args to be written.</param> /// <param name="args">The args to be written.</param>
public static void Serialize(MessageWriter writer, object[] args) public static void Serialize(this MessageWriter writer, params object[] args)
{ {
foreach (var arg in args) foreach (var arg in args)
{ {
@@ -87,24 +137,48 @@ public static class MessageSerializer
case bool i: case bool i:
writer.Write(i); writer.Write(i);
break; break;
case ulong i:
writer.Write(i);
break;
case long i:
ExtraMessageExtensions.Write(writer, i); // For some reason this insists on referring the to float write method, so this is me taking precautions
break;
case Vector2 i: case Vector2 i:
writer.Write(i); writer.Write(i);
break; break;
case string i: case string i:
writer.Write(i); writer.Write(i);
break; break;
case Color i:
writer.Write(i);
break;
case Color32 i:
writer.Write(i);
break;
case Enum i:
writer.Write(i);
break;
default: default:
var converter = FindConverter(@object.GetType()); var type = @object.GetType();
if (converter != null) var converter = FindGenericConverter(type) ?? FindConverter(type);
{
converter.UnsafeWrite(writer, @object);
break;
}
throw new NotSupportedException("Couldn't serialize " + @object.GetType()); if (converter != null)
converter.UnsafeWrite(writer, @object);
else
throw new NotSupportedException("Couldn't serialize " + type.Name);
break;
} }
} }
/// <summary>
/// Deserializes a generic <typeparamref name="T"/> value from the <paramref name="reader"/>.
/// </summary>
/// <param name="reader">The <see cref="MessageReader"/> to read from.</param>
/// <typeparam name="T">The type to be read.</typeparam>
/// <returns>A generic <typeparamref name="T"/> value from the <paramref name="reader"/>.</returns>
public static T Deserialize<T>(this MessageReader reader) => (T) reader.Deserialize(typeof(T));
/// <summary> /// <summary>
/// Deserializes an <see cref="object"/> of <paramref name="objectType"/> from the <paramref name="reader"/>. /// Deserializes an <see cref="object"/> of <paramref name="objectType"/> from the <paramref name="reader"/>.
/// </summary> /// </summary>
@@ -158,7 +232,33 @@ public static class MessageSerializer
return reader.ReadString(); return reader.ReadString();
} }
var converter = FindConverter(objectType); if (objectType == typeof(ulong))
{
return reader.ReadUInt64();
}
if (objectType == typeof(long))
{
return reader.ReadInt64();
}
if (objectType == typeof(Color))
{
return reader.ReadColor();
}
if (objectType == typeof(Color32))
{
return reader.ReadColor32();
}
if (objectType.IsEnum)
{
return reader.ReadEnum(objectType);
}
var converter = FindGenericConverter(objectType) ?? FindConverter(objectType);
if (converter != null) if (converter != null)
{ {
return converter.UnsafeRead(reader, objectType); return converter.UnsafeRead(reader, objectType);
+8 -1
View File
@@ -1,13 +1,20 @@
using System.Reflection;
using HarmonyLib; using HarmonyLib;
using Reactor.Utilities;
namespace Reactor.Patches.Fixes; namespace Reactor.Patches.Fixes;
/// <summary> /// <summary>
/// Fixes Game Lists not working on servers using legacy matchmaking. /// Fixes Game Lists not working on servers using legacy matchmaking.
/// </summary> /// </summary>
[HarmonyPatch(typeof(AmongUsClient_CoFindGame), nameof(AmongUsClient_CoFindGame.MoveNext))] [HarmonyPatch]
internal static class CoFindGamePatch internal static class CoFindGamePatch
{ {
public static MethodBase TargetMethod()
{
return Il2CppStateMachineWrapper<AmongUsClient>.GetStateMachineMoveNext(nameof(AmongUsClient.CoFindGame))!;
}
public static void Prefix() public static void Prefix()
{ {
if (AmongUsClient.Instance.LastDisconnectReason == DisconnectReasons.Unknown) if (AmongUsClient.Instance.LastDisconnectReason == DisconnectReasons.Unknown)
@@ -1,10 +1,13 @@
using System; using System;
using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Reflection;
using HarmonyLib; using HarmonyLib;
using Il2CppInterop.Runtime.InteropTypes;
using Reactor.Utilities;
namespace Reactor.Patches.Miscellaneous; namespace Reactor.Patches.Miscellaneous;
[HarmonyPatch]
internal static class CustomServersPatch internal static class CustomServersPatch
{ {
private static bool IsCurrentServerOfficial() private static bool IsCurrentServerOfficial()
@@ -16,32 +19,55 @@ internal static class CustomServersPatch
regionInfo.Servers.All(serverInfo => serverInfo.Ip.EndsWith(Domain, StringComparison.Ordinal)); regionInfo.Servers.All(serverInfo => serverInfo.Ip.EndsWith(Domain, StringComparison.Ordinal));
} }
[HarmonyPatch(typeof(AuthManager._CoConnect_d__4), nameof(AuthManager._CoConnect_d__4.MoveNext))] [HarmonyPatch]
[HarmonyPatch(typeof(AuthManager._CoWaitForNonce_d__6), nameof(AuthManager._CoWaitForNonce_d__6.MoveNext))] public static class DisableAuthServerPatch
[HarmonyPrefix]
public static bool DisableAuthServer(ref bool __result)
{ {
if (IsCurrentServerOfficial()) public static IEnumerable<MethodBase> TargetMethods() =>
{ [
return true; Il2CppStateMachineWrapper<AuthManager>.GetStateMachineMoveNext(nameof(AuthManager.CoConnect))!,
} Il2CppStateMachineWrapper<AuthManager>.GetStateMachineMoveNext(nameof(AuthManager.CoWaitForNonce))!
];
__result = false; public static bool Prefix(ref bool __result)
return false; {
if (IsCurrentServerOfficial())
{
return true;
}
__result = false;
return false;
}
} }
[HarmonyPatch(typeof(AmongUsClient._CoJoinOnlinePublicGame_d__1), nameof(AmongUsClient._CoJoinOnlinePublicGame_d__1.MoveNext))] [HarmonyPatch]
[HarmonyPrefix] public static class EnableUdpPatch
public static void EnableUdpMatchmaking(AmongUsClient._CoJoinOnlinePublicGame_d__1 __instance)
{ {
// Skip to state 1 which just calls CoJoinOnlineGameDirect public static MethodBase TargetMethod()
if (__instance.__1__state == 0 && !ServerManager.Instance.IsHttp)
{ {
__instance.__1__state = 1; return Il2CppStateMachineWrapper<AmongUsClient>.GetStateMachineMoveNext(nameof(AmongUsClient.CoJoinOnlinePublicGame))!;
__instance.__8__1 = new AmongUsClient.__c__DisplayClass1_0 }
public static void Prefix(Il2CppObjectBase __instance)
{
var stateMachine = new Il2CppStateMachineWrapper<AmongUsClient>(__instance);
// Skip to state 1 which just calls CoJoinOnlineGameDirect
if (stateMachine.State == 0 && !ServerManager.Instance.IsHttp)
{ {
matchmakerToken = string.Empty, stateMachine.State = 1;
}; var lambdaType = stateMachine.GetParameter<Il2CppObjectBase>("__8__1").GetType();
var newDisplayClassObject = Activator.CreateInstance(lambdaType);
if (newDisplayClassObject == null)
{
throw new InvalidOperationException($"Could not create display class of type '{lambdaType}'.");
}
var wrappedDisplayClassObject = new Il2CppCompilerGeneratedObjectWrapper(newDisplayClassObject);
wrappedDisplayClassObject.SetField("matchmakerToken", string.Empty);
stateMachine.SetParameter("__8__1", newDisplayClassObject);
}
} }
} }
} }
+1 -2
View File
@@ -1,4 +1,3 @@
using System;
using UnityEngine; using UnityEngine;
using UnityEngine.EventSystems; using UnityEngine.EventSystems;
using UnityEngine.UI; using UnityEngine.UI;
@@ -52,6 +51,6 @@ public static class CanvasUtilities
/// <returns>An empty texture of specified size.</returns> /// <returns>An empty texture of specified size.</returns>
public static Texture2D CreateEmptyTexture(int width = 0, int height = 0) public static Texture2D CreateEmptyTexture(int width = 0, int height = 0)
{ {
return new Texture2D(width, height, TextureFormat.RGBA32, Texture.GenerateAllMips, false, IntPtr.Zero); return new Texture2D(width, height, TextureFormat.RGBA32, Texture.GenerateAllMips, false);
} }
} }
@@ -0,0 +1,132 @@
using System;
using System.Collections.Generic;
using System.Reflection;
using HarmonyLib;
namespace Reactor.Utilities;
/// <summary>
/// A safe wrapper around IL2CPP compiler generated classes like DisplayClass or IEnumerator state machines.
/// This is useful for gracefully handling changes across different game versions and updates, which may affect
/// compiler generated names.
/// To use this class, pass the instance object of the compiler generated class into the constructor.
/// Then you can use the GetField and SetField methods to access the fields of the compiler generated class
/// by their original names.
/// </summary>
public class Il2CppCompilerGeneratedObjectWrapper
{
/// <summary>
/// Gets a reference to the compiler generated object.
/// </summary>
public object GeneratedObject { get; }
/// <summary>
/// Gets the type of the compiler generated object.
/// </summary>
protected Type GeneratedType { get; }
/// <summary>
/// Gets the property info cache for faster lookups.
/// </summary>
protected Dictionary<string, PropertyInfo> PropertyCache { get; }
/// <summary>
/// Gets the getter cache for faster property access.
/// </summary>
protected Dictionary<string, Delegate> GetterCache { get; }
/// <summary>
/// Gets the setter cache for faster property access.
/// </summary>
protected Dictionary<string, Delegate> SetterCache { get; }
/// <summary>
/// Initializes a new instance of the <see cref="Il2CppCompilerGeneratedObjectWrapper"/> class.
/// </summary>
/// <param name="generatedObject">An instance of the compiler generated object.</param>
public Il2CppCompilerGeneratedObjectWrapper(object generatedObject)
{
GeneratedObject = generatedObject;
GeneratedType = generatedObject.GetType();
PropertyCache = [];
GetterCache = [];
SetterCache = [];
}
/// <summary>
/// Caches the property info, getter, and setter for a given field name and type.
/// </summary>
/// <param name="fieldName">The name of the field to cache.</param>
/// <typeparam name="T">The expected type of the field.</typeparam>
/// <returns>The cached <see cref="PropertyInfo"/> for the specified field.</returns>
/// <exception cref="MissingMemberException">Thrown if the field does not exist in the compiler generated type.</exception>
/// <exception cref="InvalidCastException">Thrown if the field exists but is not of the expected type.</exception>
public PropertyInfo CacheProperty<T>(string fieldName)
{
var propertyInfo = AccessTools.Property(GeneratedType, fieldName)
?? throw new MissingMemberException(
$"Could not find field '{fieldName}' in type '{GeneratedType}'.");
if (propertyInfo.PropertyType != typeof(T))
{
throw new InvalidCastException(
$"Field '{fieldName}' is of type '{propertyInfo.PropertyType}', not '{typeof(T)}'.");
}
PropertyCache[fieldName] = propertyInfo;
var funcType = typeof(Func<T>);
GetterCache[fieldName] = propertyInfo.GetMethod!.CreateDelegate(funcType, GeneratedObject);
var actionType = typeof(Action<T>);
SetterCache[fieldName] = propertyInfo.SetMethod!.CreateDelegate(actionType, GeneratedObject);
return propertyInfo;
}
/// <summary>
/// Gets the value of a field in the compiler generated object.
/// </summary>
/// <param name="fieldName">The name of the field to get.</param>
/// <typeparam name="TField">The type of the field.</typeparam>
/// <returns>>The value of the field.</returns>
/// <exception cref="MissingMemberException">Thrown if the field does not exist.</exception>
public TField GetField<TField>(string fieldName)
{
if (!PropertyCache.TryGetValue(fieldName, out var propertyInfo))
{
propertyInfo = CacheProperty<TField>(fieldName);
}
if (GetterCache.TryGetValue(fieldName, out var getter))
{
return ((Func<TField>) getter)();
}
return (TField) propertyInfo.GetValue(GeneratedObject)!;
}
/// <summary>
/// Sets the value of a field in the compiler generated object.
/// </summary>
/// <param name="fieldName">The name of the field to set.</param>
/// <param name="value">The value to set.</param>
/// <typeparam name="TField">The type of the field.</typeparam>
/// <exception cref="MissingMemberException">Thrown if the field does not exist.</exception>
public void SetField<TField>(string fieldName, TField value)
{
if (!PropertyCache.TryGetValue(fieldName, out var propertyInfo))
{
propertyInfo = CacheProperty<TField>(fieldName);
}
if (SetterCache.TryGetValue(fieldName, out var setter))
{
((Action<TField>) setter)(value);
return;
}
propertyInfo.SetValue(GeneratedObject, value);
}
}
@@ -0,0 +1,108 @@
using System;
using System.Linq;
using System.Reflection;
using HarmonyLib;
namespace Reactor.Utilities;
/// <summary>
/// A wrapper for IL2CPP state machine objects to access their parent instance and state.
/// This class is useful for working with IL2CPP state machines across different game versions.
/// To use it, pass the instance object of the state machine into the constructor. To access the parent class,
/// use the Instance property. To access the current state of the state machine, use the State property.
/// </summary>
/// <typeparam name="T">The type of the parent class that owns the state machine.</typeparam>
public class Il2CppStateMachineWrapper<T> : Il2CppCompilerGeneratedObjectWrapper
{
// normally it is fields, but IL2CPP turns them into properties
private readonly PropertyInfo _thisProperty;
private readonly PropertyInfo _stateProperty;
private T? _parentInstance;
/// <summary>
/// Gets the instance of the parent class that owns the state machine.
/// </summary>
public T Instance => _parentInstance ??= (T) _thisProperty.GetValue(GeneratedObject)!;
/// <summary>
/// Gets or sets the current state of the state machine.
/// </summary>
/// <returns>The current state as an integer.</returns>
public int State
{
get => (int) _stateProperty.GetValue(GeneratedObject)!;
set => _stateProperty.SetValue(GeneratedObject, value);
}
/// <summary>
/// Initializes a new instance of the <see cref="Il2CppStateMachineWrapper{T}"/> class.
/// </summary>
/// <param name="stateMachine">The instance object of the state machine being wrapped.</param>
public Il2CppStateMachineWrapper(object stateMachine) : base(stateMachine)
{
// The names of these properties are implementation details of the IL compiler used by Unity.
// They should be stable as long as Unity sticks to mono.
_thisProperty = AccessTools.Property(GeneratedType, "__4__this");
_stateProperty = AccessTools.Property(GeneratedType, "__1__state");
if (_thisProperty == null || _stateProperty == null)
{
throw new MissingMemberException($"Could not find required properties in type '{GeneratedType}'.");
}
}
/// <summary>
/// Gets a parameter from the state machine by its name.
/// </summary>
/// <param name="parameterName">The name of the parameter to retrieve.</param>
/// <typeparam name="TField">The type of the parameter to retrieve.</typeparam>
/// <returns>>The value of the specified parameter.</returns>
/// <exception cref="MissingFieldException">Thrown if the specified parameter does not exist.</exception>
public TField GetParameter<TField>(string parameterName)
{
return GetField<TField>(parameterName);
}
/// <summary>
/// Sets a parameter in the state machine by its name.
/// </summary>
/// <param name="parameterName">The name of the parameter to set.</param>
/// <param name="value">The value to set for the parameter.</param>
/// <typeparam name="TField">The type of the parameter to set.</typeparam>
/// <exception cref="MissingFieldException">Thrown if the specified parameter does not exist.</exception>
public void SetParameter<TField>(string parameterName, TField value)
{
SetField(parameterName, value);
}
/// <summary>
/// Attempts to retrieve the MoveNext method of a state machine for the specified method name.
/// </summary>
/// <param name="methodName">The name of the method whose state machine MoveNext method is to be retrieved.</param>
/// <returns>The MoveNext <see cref="MethodBase"/> if found; otherwise, null.</returns>
public static MethodBase? GetStateMachineMoveNext(string methodName)
{
var typeName = typeof(T).FullName;
var showRoleStateMachine =
typeof(T)
.GetNestedTypes()
.FirstOrDefault(x => x.Name.Contains(methodName));
if (showRoleStateMachine == null)
{
Error($"Failed to find {methodName} state machine for {typeName}");
return null;
}
var moveNext = AccessTools.Method(showRoleStateMachine, "MoveNext");
if (moveNext == null)
{
Error($"Failed to find MoveNext method for {typeName}.{methodName}");
return null;
}
Info($"Found {methodName}.MoveNext");
return moveNext;
}
}
+34 -34
View File
@@ -4,9 +4,9 @@
"net6.0": { "net6.0": {
"AmongUs.GameLibs.Steam": { "AmongUs.GameLibs.Steam": {
"type": "Direct", "type": "Direct",
"requested": "[2025.3.25, )", "requested": "[2025.4.15, )",
"resolved": "2025.3.25", "resolved": "2025.4.15",
"contentHash": "2QxQXgZDcQOdAIDXrNLrQ7veEzD6EBzuaRjzSbHptWUPUsuVc3I5Ur3xMkPPwmSGsDHjLuAGE84yRjV6oJxGxw==" "contentHash": "R3RxzHGZOGUJ9nMwrP0cjS6g+sh60QUU506Mo47lh17155enUjH6PtErijihSoU7t3aQpzCIyC67W3XrrHhH4g=="
}, },
"BepInEx.AutoPlugin": { "BepInEx.AutoPlugin": {
"type": "Direct", "type": "Direct",
@@ -16,25 +16,25 @@
}, },
"BepInEx.IL2CPP.MSBuild": { "BepInEx.IL2CPP.MSBuild": {
"type": "Direct", "type": "Direct",
"requested": "[2.0.1, )", "requested": "[2.1.0-rc.1, )",
"resolved": "2.0.1", "resolved": "2.1.0-rc.1",
"contentHash": "hUZjCV0t8dkw/Z/zq4Zl405QP7frBk/LVfMdUmUz+7XOhGd7lYPKrR48A5vbGl2QeHudMxlkXzAr9WM3Duq2SQ==" "contentHash": "WI/7TbJwWl5P4B6UXGtKI1VMe6fA6h3fcbp3ZjJKqOBQ5MJfDMmeVB4fb+RW1tUQdxnlSWV3Ul62PHFyTqp4PA=="
}, },
"BepInEx.Unity.IL2CPP": { "BepInEx.Unity.IL2CPP": {
"type": "Direct", "type": "Direct",
"requested": "[6.0.0-be.733, )", "requested": "[6.0.0-be.735, )",
"resolved": "6.0.0-be.733", "resolved": "6.0.0-be.735",
"contentHash": "lnoGaPHjIdGfEiKtf89knaTdLXe4IUqVLdoYqW8NYhhNqgxa3oNwScjTmuYQpa4Leew3937+slq2WIjvX/DUwQ==", "contentHash": "2+eFJGKMR1GFPeU9wuF+TVrMANIaWIc/6N9e8x4b7b/fNiY9B6vicYNiMDb2deYQpWZtOei+2btnar5dDE5BPg==",
"dependencies": { "dependencies": {
"BepInEx.Core": "6.0.0-be.733", "BepInEx.Core": "6.0.0-be.735",
"BepInEx.Unity.Common": "6.0.0-be.733", "BepInEx.Unity.Common": "6.0.0-be.735",
"HarmonyX": "2.10.2", "HarmonyX": "2.10.2",
"Iced": "1.21.0", "Iced": "1.21.0",
"Il2CppInterop.Generator": "1.4.6-ci.426", "Il2CppInterop.Generator": "1.4.6-ci.426",
"Il2CppInterop.HarmonySupport": "1.4.6-ci.426", "Il2CppInterop.HarmonySupport": "1.4.6-ci.426",
"Il2CppInterop.Runtime": "1.4.6-ci.426", "Il2CppInterop.Runtime": "1.4.6-ci.426",
"MonoMod.RuntimeDetour": "22.7.31.1", "MonoMod.RuntimeDetour": "22.7.31.1",
"Samboy063.Cpp2IL.Core": "2022.1.0-pre-release.18" "Samboy063.Cpp2IL.Core": "2022.1.0-pre-release.19"
} }
}, },
"StyleCop.Analyzers": { "StyleCop.Analyzers": {
@@ -77,8 +77,8 @@
}, },
"AssetRipper.CIL": { "AssetRipper.CIL": {
"type": "Transitive", "type": "Transitive",
"resolved": "1.1.0", "resolved": "1.1.2",
"contentHash": "nSz1cBjgVeKv+esfDtyQGC1mY9b4C4NFStytdoa9DMozDC8uth6930kAsuWZEivj9GqWSqENnaQUGnl23WpmnQ==", "contentHash": "BRPcHORadIzSFkrVOvGkSs54j19mQdXH8dmRTVM51mS8MZLSbTpi9CDPpnWN2IdDsILUrAqbPUFo3zJodYxErw==",
"dependencies": { "dependencies": {
"AsmResolver.DotNet": "6.0.0-beta.1" "AsmResolver.DotNet": "6.0.0-beta.1"
} }
@@ -95,8 +95,8 @@
}, },
"BepInEx.Core": { "BepInEx.Core": {
"type": "Transitive", "type": "Transitive",
"resolved": "6.0.0-be.733", "resolved": "6.0.0-be.735",
"contentHash": "uRzpyUdU3L8Y4ZW+ZnF73orq0E40MjGK6XcPzm24CrrWB5bUshwdrtFQfrwZB6jcZVNVV6PXE92hScEI+Jaoqw==", "contentHash": "FuHm9UCzjSKeiZJc3IF70Fiuqi+FynRn62PwBoOeZcHK3/qm+vl1YwbZyFlmUyf45g+UKxg2Td40iZGx88LVAQ==",
"dependencies": { "dependencies": {
"HarmonyX": "2.10.2", "HarmonyX": "2.10.2",
"MonoMod.Utils": "22.7.31.1", "MonoMod.Utils": "22.7.31.1",
@@ -105,8 +105,8 @@
}, },
"BepInEx.Unity.Common": { "BepInEx.Unity.Common": {
"type": "Transitive", "type": "Transitive",
"resolved": "6.0.0-be.733", "resolved": "6.0.0-be.735",
"contentHash": "KfdiHVSOPnIbDEF7zLPTSXDjKqIEq7SgffqFFKIxOBkCws7LdtSRQsamUcxdD0H8yopcgdlqobIp6t8e4M/k9Q==", "contentHash": "vmK//OBSr+jotqTk//HSdvHtMFTKu+NlQkiEsvr0dZApTVmQM2AgpVMhEAakQPmrSsM6LRJIHCBcLFO1ypfMPQ==",
"dependencies": { "dependencies": {
"AssetRipper.Primitives": "3.1.3", "AssetRipper.Primitives": "3.1.3",
"MonoMod.Utils": "22.7.31.1" "MonoMod.Utils": "22.7.31.1"
@@ -114,8 +114,8 @@
}, },
"Disarm": { "Disarm": {
"type": "Transitive", "type": "Transitive",
"resolved": "2022.1.0-master.34", "resolved": "2022.1.0-master.57",
"contentHash": "sxzTci5eSdl+sFoaGsMZIp7X/eB5ZzplM3CppvD1CWoiZ8rSa43XGLC19G5e8n6mjutNBfN9yL+RER5PCspHFg==" "contentHash": "/dkg7hg8iPBQN4bTV1lMQacarH6fMpgUXhJuo6iI7Wv7YpH7g5F9hJfje7dSMhqG0YlDacLuyWvcph5GzKUXog=="
}, },
"HarmonyX": { "HarmonyX": {
"type": "Transitive", "type": "Transitive",
@@ -317,31 +317,31 @@
}, },
"Samboy063.Cpp2IL.Core": { "Samboy063.Cpp2IL.Core": {
"type": "Transitive", "type": "Transitive",
"resolved": "2022.1.0-pre-release.18", "resolved": "2022.1.0-pre-release.19",
"contentHash": "eX9d1IK05jWaEaeuMAE0L5WYHT7thtxz+aWLL/CAaCzZ0TzRPD+WFTjJ0KQO0YWBVO300CX3GwmPmf7TNO+wUg==", "contentHash": "mAYIrMo0VdOZzh1NS5bZeflg80gtYNY7kZo9q/blEYheUPyLXu5ozQOjX+Bq2yDh40pA+yiE2MXTnN2Is2hjgw==",
"dependencies": { "dependencies": {
"AsmResolver.DotNet": "6.0.0-beta.1", "AsmResolver.DotNet": "6.0.0-beta.1",
"AssetRipper.CIL": "1.1.0", "AssetRipper.CIL": "1.1.2",
"AssetRipper.Gee.External.Capstone": "2.3.2", "AssetRipper.Gee.External.Capstone": "2.3.2",
"Disarm": "2022.1.0-master.34", "Disarm": "2022.1.0-master.57",
"Iced": "1.21.0", "Iced": "1.21.0",
"Samboy063.LibCpp2IL": "2022.1.0-pre-release.18", "Samboy063.LibCpp2IL": "2022.1.0-pre-release.19",
"StableNameDotNet": "0.1.0-pre-release.15" "StableNameDotNet": "0.1.0-pre-release.19"
} }
}, },
"Samboy063.LibCpp2IL": { "Samboy063.LibCpp2IL": {
"type": "Transitive", "type": "Transitive",
"resolved": "2022.1.0-pre-release.18", "resolved": "2022.1.0-pre-release.19",
"contentHash": "9zJdTAeErpwJpYDHYwwI0MAC1OyBEfC1ce7dpAOYRUUYCfeaKVWxnSCcyaoY6HDzIoxPkhbfllbwOe49ZmUYuQ==", "contentHash": "/n8p81ltd38BeNNS2xUNPGMSzxk/UGXr9cRNqG1MaLogzANNNrvCAXqWmNMM3tZctjp7vqTxEA+e4J4ngul8Fg==",
"dependencies": { "dependencies": {
"AssetRipper.Primitives": "3.1.2", "AssetRipper.Primitives": "3.1.3",
"Samboy063.WasmDisassembler": "2022.1.0-pre-release.15" "Samboy063.WasmDisassembler": "2022.1.0-pre-release.19"
} }
}, },
"Samboy063.WasmDisassembler": { "Samboy063.WasmDisassembler": {
"type": "Transitive", "type": "Transitive",
"resolved": "2022.1.0-pre-release.15", "resolved": "2022.1.0-pre-release.19",
"contentHash": "e6qw81SHS+fS7iZ3qfqZBavVarYbkPElNgDCANF6dNFTYq5+hc80am+4FqQDl+ZVNS47bZDZobxIzHhmriCXGg==" "contentHash": "uVQdYm/J6+jJ1xt6GJ3hNhXhciwlX+LmHTPITu9jjZ75T33YJuuTD7pLVYuMymr+4gSVisg7f1wterFSyqJBWA=="
}, },
"SemanticVersioning": { "SemanticVersioning": {
"type": "Transitive", "type": "Transitive",
@@ -350,8 +350,8 @@
}, },
"StableNameDotNet": { "StableNameDotNet": {
"type": "Transitive", "type": "Transitive",
"resolved": "0.1.0-pre-release.15", "resolved": "0.1.0-pre-release.19",
"contentHash": "aIkEOo8V76vE+9CppHpTFLGXalBw6TAl4/tb6vadmS+gHJMshTVehzQv9cJXy4xZDdANV1uGMRaUFZERcDA2xQ==" "contentHash": "5BPWtntv3PXeFIg9CuGW6OM3f5GnwvdQJbzRpufPsistFwFyt1xYW1wSDr+QIdDO7vLndr7iNpWD3FyYp9LL4g=="
}, },
"StyleCop.Analyzers.Unstable": { "StyleCop.Analyzers.Unstable": {
"type": "Transitive", "type": "Transitive",