Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: NuclearPowered/Reactor
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 2.0.0
Choose a base ref
...
head repository: NuclearPowered/Reactor
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: master
Choose a head ref

Commits on Oct 27, 2022

  1. Verified

    This commit was signed with the committer’s verified signature.
    Copy the full SHA
    fa4cc03 View commit details
  2. Verified

    This commit was signed with the committer’s verified signature.
    Copy the full SHA
    9246458 View commit details
  3. Fix occasional NRE

    js6pak committed Oct 27, 2022

    Verified

    This commit was signed with the committer’s verified signature.
    Copy the full SHA
    da20e09 View commit details

Commits on Dec 2, 2022

  1. Fix Game lists not working on legacy mm servers

    This happens because InnerNetClient.CoConnect now sets the default
    LastDisconnectReason to Unknown instead of ExitGame, which breaks the
    public game list screen.
    
    Co-Authored-By: Edward Smale <essmale2005@gmail.com>
    miniduikboot and edqx committed Dec 2, 2022
    Copy the full SHA
    678730e View commit details

Commits on Dec 4, 2022

  1. Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    9ef4bd5 View commit details

Commits on Dec 9, 2022

  1. Update to 2022.12.8

    js6pak committed Dec 9, 2022

    Verified

    This commit was signed with the committer’s verified signature.
    Copy the full SHA
    eded283 View commit details

Commits on Dec 22, 2022

  1. 2.1.0

    js6pak committed Dec 22, 2022

    Verified

    This commit was signed with the committer’s verified signature.
    Copy the full SHA
    2407a99 View commit details

Commits on Jan 6, 2023

  1. Verified

    This commit was signed with the committer’s verified signature.
    Copy the full SHA
    4deb5f8 View commit details

Commits on Jan 7, 2023

  1. Log game version

    js6pak committed Jan 7, 2023

    Verified

    This commit was signed with the committer’s verified signature.
    Copy the full SHA
    375a417 View commit details

Commits on Jan 15, 2023

  1. Fix sealed warnings

    js6pak committed Jan 15, 2023

    Verified

    This commit was signed with the committer’s verified signature.
    Copy the full SHA
    30027d8 View commit details

Commits on Mar 21, 2023

  1. Verified

    This commit was signed with the committer’s verified signature.
    Copy the full SHA
    8553a2a View commit details

Commits on Jun 15, 2023

  1. Update to 2023.6.13

    js6pak committed Jun 15, 2023

    Verified

    This commit was signed with the committer’s verified signature.
    Copy the full SHA
    89146ce View commit details
  2. Don't disable auth server on officials

    Since 2023.6.13 official servers went back to using DTLS for auth only
    js6pak committed Jun 15, 2023

    Verified

    This commit was signed with the committer’s verified signature.
    Copy the full SHA
    c84d36a View commit details

Commits on Jun 17, 2023

  1. Fix positioning of the version shower on different aspect ratios (#73)

    Co-authored-by: js6pak <me@6pak.dev>
    simonkellly and js6pak authored Jun 17, 2023

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    f63569d View commit details

Commits on Jul 12, 2023

  1. 2023.7.11

    js6pak committed Jul 12, 2023

    Verified

    This commit was signed with the committer’s verified signature.
    Copy the full SHA
    6eb0bf1 View commit details

Commits on Dec 4, 2023

  1. Use .NET 8 SDK

    js6pak committed Dec 4, 2023

    Verified

    This commit was signed with the committer’s verified signature.
    Copy the full SHA
    1f2e240 View commit details
  2. Update dependencies

    js6pak committed Dec 4, 2023

    Verified

    This commit was signed with the committer’s verified signature.
    Copy the full SHA
    632a6f8 View commit details
  3. Remove the unused config option

    js6pak committed Dec 4, 2023

    Verified

    This commit was signed with the committer’s verified signature.
    Copy the full SHA
    710ca79 View commit details

Commits on Mar 2, 2024

  1. Add DisableServerAuthority to ModFlags (#78)

    js6pak authored Mar 2, 2024

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature.
    Copy the full SHA
    d82268b View commit details
  2. Rework debugger (#79)

    js6pak authored Mar 2, 2024

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature.
    Copy the full SHA
    5db20ca View commit details
  3. Make ModList#Current an array to preserve order

    js6pak committed Mar 2, 2024

    Verified

    This commit was signed with the committer’s verified signature.
    Copy the full SHA
    787b54b View commit details
  4. Improve handshake popup (#77)

    js6pak authored Mar 2, 2024

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature.
    Copy the full SHA
    014b6e3 View commit details

Commits on Jul 23, 2024

  1. Support 2024.6.18 (#84)

    Co-authored-by: Pietrodjaowjao <nicoleobenetti@gmail.com>
    Co-authored-by: js6pak <me@6pak.dev>
    3 people authored Jul 23, 2024

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature.
    Copy the full SHA
    f80b6a5 View commit details
  2. Wait for the PlayerName before kicking for missing required mods

    This is needed due to changes in 2024.6.18
    js6pak committed Jul 23, 2024

    Verified

    This commit was signed with the committer’s verified signature.
    Copy the full SHA
    84837fd View commit details
  3. Improve the message when kicking for missing required mods

    Closes #82
    js6pak committed Jul 23, 2024

    Verified

    This commit was signed with the committer’s verified signature.
    Copy the full SHA
    21c0e61 View commit details

Commits on Aug 1, 2024

  1. Update Unity version in Reactor.Assets

    <!-- ps-id: 7978e8c1-da06-45f4-9d7d-6f1591074889 -->
    js6pak committed Aug 1, 2024

    Verified

    This commit was signed with the committer’s verified signature.
    Copy the full SHA
    86b5a29 View commit details
  2. Add support for asset bundles without an architecture suffix

    Unity requires specifying the architecture when building asset bundles as part of BuildTarget. While compatibility between targets isn't guaranteed, in practice there are no differences between architectures.
    
    <!-- ps-id: 49397d5b-21fc-4201-a0d6-e0c2f9627bf3 -->
    js6pak committed Aug 1, 2024

    Verified

    This commit was signed with the committer’s verified signature.
    Copy the full SHA
    127f48f View commit details

Commits on Aug 17, 2024

  1. Verified

    This commit was signed with the committer’s verified signature.
    Copy the full SHA
    27e8cb1 View commit details
  2. Add a "Hard crash" button to debugger

    <!-- ps-id: 10f09e20-b954-4bd7-ac82-b1a523431770 -->
    js6pak committed Aug 17, 2024

    Verified

    This commit was signed with the committer’s verified signature.
    Copy the full SHA
    809b895 View commit details
  3. Update GameLibs to 2024.8.13

    Alexejhero authored and js6pak committed Aug 17, 2024

    Partially verified

    This commit is signed with the committer’s verified signature.
    js6pak’s contribution has been verified via GPG key.
    We cannot verify signatures from co-authors, and some of the co-authors attributed to this commit require their commits to be signed.
    Copy the full SHA
    f55036e View commit details
  4. Fix ambiguous patch exception

    Alexejhero authored and js6pak committed Aug 17, 2024

    Partially verified

    This commit is signed with the committer’s verified signature.
    js6pak’s contribution has been verified via GPG key.
    We cannot verify signatures from co-authors, and some of the co-authors attributed to this commit require their commits to be signed.
    Copy the full SHA
    bbdbd5b View commit details
  5. Fix free name textbox by not changing it as much

    I dont care that the text is smaller and no one else cares either
    Alexejhero authored and js6pak committed Aug 17, 2024

    Partially verified

    This commit is signed with the committer’s verified signature.
    js6pak’s contribution has been verified via GPG key.
    We cannot verify signatures from co-authors, and some of the co-authors attributed to this commit require their commits to be signed.
    Copy the full SHA
    de3b20e View commit details

Commits on Aug 20, 2024

  1. Bump patch version

    Alexejhero authored and js6pak committed Aug 20, 2024

    Partially verified

    This commit is signed with the committer’s verified signature.
    js6pak’s contribution has been verified via GPG key.
    We cannot verify signatures from co-authors, and some of the co-authors attributed to this commit require their commits to be signed.
    Copy the full SHA
    32875a2 View commit details
  2. Cleanup text after calling GetTextInfo

    Turns out GetTextInfo changes text internally and because TextBoxTMP#GiveFocus now sets caretPos based on text length it was causing crashes.
    js6pak committed Aug 20, 2024

    Verified

    This commit was signed with the committer’s verified signature.
    Copy the full SHA
    2b35751 View commit details
  3. Use a high default value for Window._lastWindowId to avoid conflicts …

    …with other mods
    js6pak committed Aug 20, 2024

    Verified

    This commit was signed with the committer’s verified signature.
    Copy the full SHA
    7d3ffa3 View commit details

Commits on Aug 22, 2024

  1. Update stylecop to support latest C#

    Alexejhero authored and js6pak committed Aug 22, 2024

    Partially verified

    This commit is signed with the committer’s verified signature.
    js6pak’s contribution has been verified via GPG key.
    We cannot verify signatures from co-authors, and some of the co-authors attributed to this commit require their commits to be signed.
    Copy the full SHA
    2c1eeaf View commit details
  2. Add ReactorCredits (#87)

    Co-authored-by: js6pak <me@6pak.dev>
    Alexejhero and js6pak authored Aug 22, 2024

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature.
    Copy the full SHA
    e27a792 View commit details
Showing with 2,394 additions and 684 deletions.
  1. +2 −2 .github/workflows/main.yml
  2. +10 −9 .github/workflows/unity.yml
  3. +2 −2 AmongUs.props
  4. +7 −2 Directory.Build.props
  5. +4 −4 Reactor.Assets/Assets/Build.cs
  6. +3 −3 Reactor.Assets/Packages/manifest.json
  7. +11 −11 Reactor.Assets/Packages/packages-lock.json
  8. +2 −2 Reactor.Assets/ProjectSettings/ProjectVersion.txt
  9. +3 −3 Reactor.Assets/build.sh
  10. +3 −3 Reactor.Benchmarks/AssetBundleBenchmarks.cs
  11. +1 −1 Reactor.Benchmarks/Reactor.Benchmarks.csproj
  12. +188 −115 Reactor.Benchmarks/packages.lock.json
  13. +82 −0 Reactor.Debugger/AutoJoin/AutoJoinClientConnection.cs
  14. +61 −0 Reactor.Debugger/AutoJoin/AutoJoinConnection.cs
  15. +113 −0 Reactor.Debugger/AutoJoin/AutoJoinConnectionListener.cs
  16. +66 −0 Reactor.Debugger/AutoJoin/AutoJoinConnectionManager.cs
  17. +38 −0 Reactor.Debugger/AutoJoin/AutoJoinServerConnection.cs
  18. +12 −0 Reactor.Debugger/AutoJoin/Messages/Extensions.cs
  19. +15 −0 Reactor.Debugger/AutoJoin/Messages/IMessage.cs
  20. +40 −0 Reactor.Debugger/AutoJoin/Messages/JoinGameMessage.cs
  21. +7 −0 Reactor.Debugger/AutoJoin/Messages/MessageType.cs
  22. +17 −0 Reactor.Debugger/AutoJoin/Messages/RequestJoinGameMessage.cs
  23. +26 −0 Reactor.Debugger/DebuggerConfig.cs
  24. +9 −97 Reactor.Debugger/DebuggerPlugin.cs
  25. +0 −70 Reactor.Debugger/Patches.cs
  26. +14 −0 Reactor.Debugger/Patches/AutoPlayAgainPatch.cs
  27. +18 −0 Reactor.Debugger/Patches/DisableGameEndPatch.cs
  28. +27 −0 Reactor.Debugger/Patches/DisableTimeoutPatch.cs
  29. +70 −0 Reactor.Debugger/Patches/GameOptionsPatches.cs
  30. +21 −0 Reactor.Debugger/Patches/GameStartManagerPatches.cs
  31. +14 −0 Reactor.Debugger/Patches/MiscellaneousPatches.cs
  32. +39 −0 Reactor.Debugger/Patches/RandomizeFreeplayServerPortPatch.cs
  33. +74 −0 Reactor.Debugger/Patches/RedirectLoggerPatch.cs
  34. +49 −0 Reactor.Debugger/Utilities/Extensions.cs
  35. +112 −0 Reactor.Debugger/Window/DebuggerWindow.cs
  36. +68 −0 Reactor.Debugger/Window/Tabs/AutoJoinTab.cs
  37. +8 −0 Reactor.Debugger/Window/Tabs/BaseTab.cs
  38. +29 −0 Reactor.Debugger/Window/Tabs/ConfigTab.cs
  39. +97 −0 Reactor.Debugger/Window/Tabs/GameTab.cs
  40. +120 −70 Reactor.Debugger/packages.lock.json
  41. +2 −0 Reactor.Example/ExamplePlugin.cs
  42. +119 −69 Reactor.Example/packages.lock.json
  43. +3 −3 Reactor.Networking.Shared/Mod.cs
  44. +5 −0 Reactor.Networking.Shared/ModFlags.cs
  45. BIN Reactor/Assets/default-android.bundle
  46. BIN Reactor/Assets/default-win-x86.bundle
  47. BIN Reactor/Assets/default-win.bundle
  48. +35 −0 Reactor/Networking/HandshakePopup.cs
  49. +34 −0 Reactor/Networking/MakePublicDisallowedPopup.cs
  50. +7 −1 Reactor/Networking/ModList.cs
  51. +73 −22 Reactor/Networking/Patches/ClientPatches.cs
  52. +8 −25 Reactor/Networking/Patches/HttpPatches.cs
  53. +1 −1 Reactor/Networking/Patches/ReactorClientData.cs
  54. +1 −1 Reactor/Networking/Rpc/UnsafeCustomRpc.cs
  55. +18 −0 Reactor/Patches/Fixes/CoFindGamePatch.cs
  56. +9 −1 Reactor/Patches/Fixes/CursorPosPatch.cs
  57. +17 −1 Reactor/Patches/Miscellaneous/CustomServersPatch.cs
  58. +41 −0 Reactor/Patches/Miscellaneous/DisableServerAuthorityPatch.cs
  59. +3 −6 Reactor/Patches/Miscellaneous/FreeNamePatch.cs
  60. +21 −0 Reactor/Patches/Miscellaneous/PingTrackerPatch.cs
  61. +57 −26 Reactor/Patches/ReactorVersionShower.cs
  62. +0 −6 Reactor/Reactor.csproj
  63. +22 −0 Reactor/ReactorConfig.cs
  64. +5 −7 Reactor/ReactorPlugin.cs
  65. +62 −30 Reactor/Utilities/AssetBundleManager.cs
  66. +1 −1 Reactor/Utilities/Coroutines.cs
  67. +40 −0 Reactor/Utilities/Extensions/RichTextExtensions.cs
  68. +19 −0 Reactor/Utilities/Extensions/VersionExtensions.cs
  69. +3 −2 Reactor/Utilities/ImGui/Window.cs
  70. +123 −0 Reactor/Utilities/ReactorCredits.cs
  71. +1 −1 Reactor/Utilities/RegionInfoWatcher.cs
  72. +58 −0 Reactor/Utilities/UI/ReactorPopup.cs
  73. +117 −87 Reactor/packages.lock.json
  74. +6 −0 global.json
  75. +1 −0 nuget.config
4 changes: 2 additions & 2 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
@@ -4,7 +4,7 @@ on: ["push", "pull_request"]

jobs:
build:
runs-on: ubuntu-20.04
runs-on: ubuntu-22.04

steps:
- uses: actions/checkout@v3
@@ -23,7 +23,7 @@ jobs:
- name: Setup .NET
uses: actions/setup-dotnet@v2
with:
dotnet-version: 6.x
dotnet-version: 8.0.x

- name: Run the Cake script
uses: cake-build/cake-action@v1
19 changes: 10 additions & 9 deletions .github/workflows/unity.yml
Original file line number Diff line number Diff line change
@@ -9,14 +9,15 @@ jobs:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4

- uses: actions/cache@v3
- uses: actions/cache@v4
with:
path: |
~/Unity/Hub/Editor
~/.config/unityhub
key: unity-2020.3.22f1
~/.local/share/unity3d/Unity/Unity_lic.ulf
key: unity-${{ hashFiles('./Reactor.Assets/ProjectSettings/ProjectVersion.txt') }}

- name: Setup Unity
uses: js6pak/setup-unity@master
@@ -25,17 +26,17 @@ jobs:
unity-modules: windows-mono android

- name: Activate Unity
uses: js6pak/activate-unity@master
with:
unity-username: ${{ secrets.UNITY_USERNAME }}
unity-password: ${{ secrets.UNITY_PASSWORD }}
unity-authenticator-key: ${{ secrets.UNITY_AUTHENTICATOR_KEY }}
env:
UNITY_USERNAME: ${{ secrets.UNITY_USERNAME }}
UNITY_PASSWORD: ${{ secrets.UNITY_PASSWORD }}
run: |
/opt/unityhub/UnityLicensingClient_V1/Unity.Licensing.Client --activate-ulf --username "$UNITY_USERNAME" --password "$UNITY_PASSWORD"
- name: Build
working-directory: ./Reactor.Assets
run: bash ./build.sh

- uses: actions/upload-artifact@v3
- uses: actions/upload-artifact@v4
with:
name: bundles
path: ./Reactor/Assets/*.bundle
4 changes: 2 additions & 2 deletions AmongUs.props
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project>
<ItemGroup>
<PackageReference Include="BepInEx.Unity.IL2CPP" Version="6.0.0-be.662" Private="false" ExcludeAssets="runtime;native" />
<PackageReference Include="AmongUs.GameLibs.Steam" Version="2022.10.25" PrivateAssets="all" />
<PackageReference Include="BepInEx.Unity.IL2CPP" Version="6.0.0-be.679" Private="false" ExcludeAssets="runtime;native" />
<PackageReference Include="AmongUs.GameLibs.Steam" Version="2024.8.13" 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" />
9 changes: 7 additions & 2 deletions Directory.Build.props
Original file line number Diff line number Diff line change
@@ -8,14 +8,19 @@

<RestorePackagesWithLockFile>true</RestorePackagesWithLockFile>

<VersionPrefix>2.0.0</VersionPrefix>
<VersionPrefix>2.3.1</VersionPrefix>
<VersionSuffix>dev</VersionSuffix>

<Authors>NuclearPowered</Authors>
<PackageIcon>icon.png</PackageIcon>
<RepositoryType>git</RepositoryType>
<RepositoryUrl>https://github.com/NuclearPowered/Reactor</RepositoryUrl>
<PackageLicenseExpression>LGPL-3.0-or-later</PackageLicenseExpression>

<!-- SourceLink -->
<EmbedUntrackedSources>true</EmbedUntrackedSources>
<IncludeSourceRevisionInInformationalVersion>false</IncludeSourceRevisionInInformationalVersion>
<ContinuousIntegrationBuild Condition="'$(GITHUB_ACTIONS)' == 'true'">true</ContinuousIntegrationBuild>
</PropertyGroup>

<ItemGroup>
@@ -30,7 +35,7 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.435" PrivateAssets="all" />
<PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.556" PrivateAssets="all" />
<AdditionalFiles Include="$(MSBuildThisFileDirectory)\stylecop.json" Link="stylecop.json" Visible="false" />
</ItemGroup>
<PropertyGroup>
8 changes: 4 additions & 4 deletions Reactor.Assets/Assets/Build.cs
Original file line number Diff line number Diff line change
@@ -69,14 +69,14 @@ public static void BuildAssetBundles()
}
}

private static string GetTargetName(BuildTarget target)
private static string GetTargetName(BuildTarget target, bool includeArchitecture = false)
{
return target switch
{
BuildTarget.StandaloneWindows => "win-x86",
BuildTarget.StandaloneWindows64 => "win-x64",
BuildTarget.StandaloneWindows => includeArchitecture ? "win-x86" : "win",
BuildTarget.StandaloneWindows64 => includeArchitecture ? "win-x64" : "win",
BuildTarget.Android => "android",
BuildTarget.StandaloneLinux64 => "linux-x64",
BuildTarget.StandaloneLinux64 => includeArchitecture ? "linux-x64" : "linux",
_ => throw new ArgumentOutOfRangeException(nameof(target), target, null),
};
}
6 changes: 3 additions & 3 deletions Reactor.Assets/Packages/manifest.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
{
"dependencies": {
"com.unity.2d.sprite": "1.0.0",
"com.unity.ide.rider": "2.0.7",
"com.unity.ide.visualstudio": "2.0.16",
"com.unity.ide.rider": "3.0.31",
"com.unity.ide.visualstudio": "2.0.22",
"com.unity.ide.vscode": "1.2.5",
"com.unity.toolchain.linux-x86_64": "2.0.2",
"com.unity.toolchain.linux-x86_64": "2.0.9",
"com.unity.modules.ai": "1.0.0",
"com.unity.modules.androidjni": "1.0.0",
"com.unity.modules.animation": "1.0.0",
22 changes: 11 additions & 11 deletions Reactor.Assets/Packages/packages-lock.json
Original file line number Diff line number Diff line change
@@ -8,22 +8,22 @@
},
"com.unity.ext.nunit": {
"version": "1.0.6",
"depth": 2,
"depth": 1,
"source": "registry",
"dependencies": {},
"url": "https://packages.unity.com"
},
"com.unity.ide.rider": {
"version": "2.0.7",
"version": "3.0.31",
"depth": 0,
"source": "registry",
"dependencies": {
"com.unity.test-framework": "1.1.1"
"com.unity.ext.nunit": "1.0.6"
},
"url": "https://packages.unity.com"
},
"com.unity.ide.visualstudio": {
"version": "2.0.16",
"version": "2.0.22",
"depth": 0,
"source": "registry",
"dependencies": {
@@ -39,23 +39,23 @@
"url": "https://packages.unity.com"
},
"com.unity.sysroot": {
"version": "2.0.3",
"version": "2.0.10",
"depth": 1,
"source": "registry",
"dependencies": {},
"url": "https://packages.unity.com"
},
"com.unity.sysroot.linux-x86_64": {
"version": "2.0.2",
"version": "2.0.9",
"depth": 1,
"source": "registry",
"dependencies": {
"com.unity.sysroot": "2.0.3"
"com.unity.sysroot": "2.0.10"
},
"url": "https://packages.unity.com"
},
"com.unity.test-framework": {
"version": "1.1.29",
"version": "1.1.33",
"depth": 1,
"source": "registry",
"dependencies": {
@@ -66,12 +66,12 @@
"url": "https://packages.unity.com"
},
"com.unity.toolchain.linux-x86_64": {
"version": "2.0.2",
"version": "2.0.9",
"depth": 0,
"source": "registry",
"dependencies": {
"com.unity.sysroot": "2.0.3",
"com.unity.sysroot.linux-x86_64": "2.0.2"
"com.unity.sysroot": "2.0.10",
"com.unity.sysroot.linux-x86_64": "2.0.9"
},
"url": "https://packages.unity.com"
},
4 changes: 2 additions & 2 deletions Reactor.Assets/ProjectSettings/ProjectVersion.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
m_EditorVersion: 2020.3.22f1
m_EditorVersionWithRevision: 2020.3.22f1 (e1a7f79fd887)
m_EditorVersion: 2020.3.45f1
m_EditorVersionWithRevision: 2020.3.45f1 (660cd1701bd5)
6 changes: 3 additions & 3 deletions Reactor.Assets/build.sh
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
#!/bin/bash

UNITY_VERSION=2020.3.22f1
UNITY_VERSION=2020.3.45f1

if [[ ! -v UNITY_PATH ]]; then
if command -v unityhub &>/dev/null; then
echo "Trying to get unity path from unityhub..."

UNITYHUB_INSTALL_PATH=$(unityhub --headless install-path)
UNITYHUB_INSTALL_PATH=$(unityhub -- --headless install-path)
UNITY_PATH="$UNITYHUB_INSTALL_PATH/$UNITY_VERSION/Editor/Unity"

if [[ ! -f $UNITY_PATH ]]; then
@@ -22,4 +22,4 @@ fi
echo "UNITY_PATH = $UNITY_PATH"

rm Library -rf # TODO figure out why having Library cached makes invalid bundles in batchmode
$UNITY_PATH -batchmode -nographics -quit -logFile "-" -projectPath $pwd -executeMethod Build.BuildAssetBundles
"$UNITY_PATH" -batchmode -nographics -quit -logFile "-" -projectPath "$PWD" -executeMethod Build.BuildAssetBundles
6 changes: 3 additions & 3 deletions Reactor.Benchmarks/AssetBundleBenchmarks.cs
Original file line number Diff line number Diff line change
@@ -16,7 +16,7 @@ namespace Reactor.Benchmarks;
[StopOnFirstError, Config(typeof(Config))]
public class AssetBundleBenchmarks
{
private class Config : ManualConfig
private sealed class Config : ManualConfig
{
public Config()
{
@@ -29,7 +29,7 @@ public Config()

public static IEnumerable<string> ValuesForAssetBundleName()
{
yield return $"default-{AssetBundleManager.TargetName}{AssetBundleManager.BundleExtension}";
yield return $"{AssetBundleManager.GetFileName("default", false)}";
// yield return "submerged";
}

@@ -41,7 +41,7 @@ public void IterationSetup()

private AssetBundle LoadAll(AssetBundle assetBundle)
{
if (assetBundle == null) throw new ArgumentNullException(nameof(assetBundle));
ArgumentNullException.ThrowIfNull(assetBundle);

assetBundle.LoadAllAssets();
return assetBundle;
2 changes: 1 addition & 1 deletion Reactor.Benchmarks/Reactor.Benchmarks.csproj
Original file line number Diff line number Diff line change
@@ -8,7 +8,7 @@

<ItemGroup>
<ProjectReference Include="..\Reactor\Reactor.csproj" Private="false" />
<PackageReference Include="BenchmarkDotNet" Version="0.13.2" />
<PackageReference Include="BenchmarkDotNet" Version="0.13.10" />
</ItemGroup>

<Import Project="../AmongUs.props" />
303 changes: 188 additions & 115 deletions Reactor.Benchmarks/packages.lock.json

Large diffs are not rendered by default.

82 changes: 82 additions & 0 deletions Reactor.Debugger/AutoJoin/AutoJoinClientConnection.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
using System;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.IO.Pipes;
using InnerNet;
using Reactor.Debugger.AutoJoin.Messages;
using Reactor.Utilities;

namespace Reactor.Debugger.AutoJoin;

internal sealed class AutoJoinClientConnection : AutoJoinConnection
{
public const string PipeName = "Reactor.Debugger.AutoJoin";

private AutoJoinClientConnection(NamedPipeClientStream pipe) : base(pipe)
{
}

protected override void Handle(BinaryReader reader, MessageType messageType)
{
switch (messageType)
{
case MessageType.JoinGame:
{
Handle(JoinGameMessage.Deserialize(reader));
break;
}

default:
{
throw new ArgumentOutOfRangeException(nameof(messageType), messageType, null);
}
}
}

private static void Handle(in JoinGameMessage message)
{
var (address, port, gameCode) = message;

Dispatcher.Instance.Enqueue(() =>
{
var gameCodeText = gameCode == InnerNetServer.LocalGameId ? "<local>" : GameCode.IntToGameName(gameCode);
Info($"Joining {gameCodeText} on {address}:{port}");

if (gameCode == InnerNetServer.LocalGameId)
{
AmongUsClient.Instance.NetworkMode = NetworkModes.LocalGame;
AmongUsClient.Instance.GameId = gameCode;
AmongUsClient.Instance.StartCoroutine(AmongUsClient.Instance.CoConnectToGameServer(MatchMakerModes.Client, address, port, null));
}
else
{
AmongUsClient.Instance.StartCoroutine(AmongUsClient.Instance.CoJoinOnlineGameDirect(gameCode, address, port, null));
}
});
}

public void SendRequestJoin()
{
Write(default(RequestJoinGameMessage));
}

public static bool TryConnect([NotNullWhen(true)] out AutoJoinClientConnection? client)
{
var pipeClient = new NamedPipeClientStream(".", PipeName, PipeDirection.InOut, PipeOptions.Asynchronous);

try
{
pipeClient.Connect(100);

client = new AutoJoinClientConnection(pipeClient);
return true;
}
catch (TimeoutException)
{
pipeClient.Dispose();

client = null;
return false;
}
}
}
61 changes: 61 additions & 0 deletions Reactor.Debugger/AutoJoin/AutoJoinConnection.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
using System;
using System.IO;
using System.IO.Pipes;
using System.Threading.Tasks;
using Reactor.Debugger.AutoJoin.Messages;

namespace Reactor.Debugger.AutoJoin;

internal abstract class AutoJoinConnection : IDisposable
{
private readonly BinaryWriter _writer;

protected AutoJoinConnection(PipeStream pipe)
{
_writer = new BinaryWriter(pipe);

Task.Run(() =>
{
try
{
var reader = new BinaryReader(pipe);

while (pipe.IsConnected)
{
try
{
var messageType = (MessageType) reader.ReadByte();
Debug($"Received {messageType}");
Handle(reader, messageType);
}
catch (EndOfStreamException)
{
break;
}
}

pipe.Dispose();
Disconnected?.Invoke();
}
catch (Exception e)
{
Error(e);
}
});
}

public event Action? Disconnected;

protected abstract void Handle(BinaryReader reader, MessageType messageType);

public void Write<T>(in T message) where T : IMessage<T>
{
Debug($"Writing {message}");
_writer.Write(message);
}

public void Dispose()
{
_writer.Dispose();
}
}
113 changes: 113 additions & 0 deletions Reactor.Debugger/AutoJoin/AutoJoinConnectionListener.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.IO.Pipes;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using InnerNet;
using Reactor.Debugger.AutoJoin.Messages;

namespace Reactor.Debugger.AutoJoin;

internal sealed class AutoJoinConnectionListener : IDisposable
{
private readonly CancellationTokenSource _cancellationTokenSource = new();
private readonly Mutex _mutex;

private AutoJoinConnectionListener(Mutex mutex)
{
_mutex = mutex;

Task.Run(async () =>
{
while (!_cancellationTokenSource.IsCancellationRequested)
{
try
{
Info("Listening for connections");

var pipeServer = new NamedPipeServerStream(
AutoJoinClientConnection.PipeName,
PipeDirection.InOut,
NamedPipeServerStream.MaxAllowedServerInstances,
PipeTransmissionMode.Byte,
PipeOptions.Asynchronous
);

try
{
await pipeServer.WaitForConnectionAsync(_cancellationTokenSource.Token);
}
catch (OperationCanceledException)
{
pipeServer.Dispose();
break;
}

Info("Client connected");

var client = new AutoJoinServerConnection(pipeServer);
Clients.Add(client);
client.Disconnected += () =>
{
Clients.Remove(client);
client.Dispose();
};
}
catch (Exception e)
{
Error(e);
}
}

Info("Stopped");
Stopped?.Invoke();
});
}

public event Action? Stopped;

public List<AutoJoinServerConnection> Clients { get; } = new();

public void Dispose()
{
_cancellationTokenSource.Cancel();
_cancellationTokenSource.Dispose();

foreach (var client in Clients)
{
client.Dispose();
}

Clients.Clear();

_mutex.Dispose();
}

public void SendJoinMe(InnerNetClient innerNetClient)
{
var joinGameMessage = JoinGameMessage.From(innerNetClient);

foreach (var client in Clients)
{
client.Write(joinGameMessage);
}
}

public static bool TryStart([NotNullWhen(true)] out AutoJoinConnectionListener? connectionListener)
{
var mutex = new Mutex(false, $@"Global\{AutoJoinClientConnection.PipeName}");

if (mutex.WaitOne(100))
{
connectionListener = new AutoJoinConnectionListener(mutex);
return true;
}

mutex.Dispose();

connectionListener = null;
return false;
}
}
66 changes: 66 additions & 0 deletions Reactor.Debugger/AutoJoin/AutoJoinConnectionManager.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
using HarmonyLib;
using InnerNet;

namespace Reactor.Debugger.AutoJoin;

internal static class AutoJoinConnectionManager
{
public static AutoJoinConnectionListener? Server { get; set; }
public static AutoJoinClientConnection? Client { get; set; }

public static void StartOrConnect()
{
if (AutoJoinConnectionListener.TryStart(out var connectionListener))
{
Info("Started an AutoJoin session");
Server = connectionListener;
Server.Stopped += () =>
{
if (Server == connectionListener)
{
Server = null;
}
};
}
else if (AutoJoinClientConnection.TryConnect(out var client))
{
Info("Connected to an AutoJoin session");
Client = client;
client.Disconnected += () =>
{
if (Client == client)
{
Client = null;

Info("Disconnected from an AutoJoin session, trying to reconnect");
StartOrConnect();
}
};
}
else
{
Error("Failed to start or connect to an AutoJoin session");
}
}

[HarmonyPatch(typeof(InnerNetClient), nameof(InnerNetClient.Start))]
public static class ConnectPatch
{
public static void Postfix(InnerNetClient __instance)
{
if (!DebuggerConfig.JoinGameOnStart.Value) return;

if (__instance.TryCast<AmongUsClient>() is { } amongUsClient)
{
if (Server != null)
{
amongUsClient.StartCoroutine(amongUsClient.CoCreateOnlineGame());
}
else if (Client is { } client)
{
client.SendRequestJoin();
}
}
}
}
}
38 changes: 38 additions & 0 deletions Reactor.Debugger/AutoJoin/AutoJoinServerConnection.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
using System;
using System.IO;
using System.IO.Pipes;
using Reactor.Debugger.AutoJoin.Messages;

namespace Reactor.Debugger.AutoJoin;

internal sealed class AutoJoinServerConnection : AutoJoinConnection
{
public AutoJoinServerConnection(NamedPipeServerStream pipe) : base(pipe)
{
}

protected override void Handle(BinaryReader reader, MessageType messageType)
{
switch (messageType)
{
case MessageType.RequestJoinGame:
{
Handle(RequestJoinGameMessage.Deserialize(reader));
break;
}

default:
{
throw new ArgumentOutOfRangeException(nameof(messageType), messageType, null);
}
}
}

private void Handle(in RequestJoinGameMessage message)
{
if (AmongUsClient.Instance.AmConnected)
{
Write(JoinGameMessage.From(AmongUsClient.Instance));
}
}
}
12 changes: 12 additions & 0 deletions Reactor.Debugger/AutoJoin/Messages/Extensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using System.IO;

namespace Reactor.Debugger.AutoJoin.Messages;

internal static class Extensions
{
public static void Write<T>(this BinaryWriter writer, in T message) where T : IMessage<T>
{
writer.Write((byte) T.Type);
message.Serialize(writer);
}
}
15 changes: 15 additions & 0 deletions Reactor.Debugger/AutoJoin/Messages/IMessage.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#pragma warning disable CA2252 // TODO Remove after BepInEx updates the .NET version
using System.IO;

namespace Reactor.Debugger.AutoJoin.Messages;

internal interface IMessage<TSelf> where TSelf : IMessage<TSelf>
{
static abstract MessageType Type { get; }

void Serialize(BinaryWriter writer);

static abstract TSelf Deserialize(BinaryReader reader);

string ToString();
}
40 changes: 40 additions & 0 deletions Reactor.Debugger/AutoJoin/Messages/JoinGameMessage.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
using System.IO;
using InnerNet;

namespace Reactor.Debugger.AutoJoin.Messages;

internal readonly record struct JoinGameMessage(
string Address,
ushort Port,
int GameCode
) : IMessage<JoinGameMessage>
{
public static MessageType Type => MessageType.JoinGame;

public void Serialize(BinaryWriter writer)
{
writer.Write(Address);
writer.Write(Port);
writer.Write(GameCode);
}

public static JoinGameMessage Deserialize(BinaryReader reader)
{
return new JoinGameMessage
{
Address = reader.ReadString(),
Port = reader.ReadUInt16(),
GameCode = reader.ReadInt32(),
};
}

public static JoinGameMessage From(InnerNetClient innerNetClient)
{
return new JoinGameMessage
{
Address = innerNetClient.networkAddress,
Port = (ushort) innerNetClient.networkPort,
GameCode = innerNetClient.GameId,
};
}
}
7 changes: 7 additions & 0 deletions Reactor.Debugger/AutoJoin/Messages/MessageType.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace Reactor.Debugger.AutoJoin.Messages;

internal enum MessageType : byte
{
JoinGame,
RequestJoinGame,
}
17 changes: 17 additions & 0 deletions Reactor.Debugger/AutoJoin/Messages/RequestJoinGameMessage.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
using System.IO;

namespace Reactor.Debugger.AutoJoin.Messages;

internal readonly record struct RequestJoinGameMessage : IMessage<RequestJoinGameMessage>
{
public static MessageType Type => MessageType.RequestJoinGame;

public void Serialize(BinaryWriter writer)
{
}

public static RequestJoinGameMessage Deserialize(BinaryReader reader)
{
return default;
}
}
26 changes: 26 additions & 0 deletions Reactor.Debugger/DebuggerConfig.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using BepInEx.Configuration;

namespace Reactor.Debugger;

internal static class DebuggerConfig
{
public const string FeaturesSection = "Features";
public const string AutoJoinSection = "AutoJoin";

public static ConfigEntry<bool> DisableGameEnd { get; private set; } = null!;
public static ConfigEntry<bool> RedirectLogger { get; private set; } = null!;
public static ConfigEntry<bool> AutoPlayAgain { get; private set; } = null!;
public static ConfigEntry<bool> DisableTimeout { get; private set; } = null!;

public static ConfigEntry<bool> JoinGameOnStart { get; private set; } = null!;

public static void Bind(ConfigFile config)
{
DisableGameEnd = config.Bind(FeaturesSection, nameof(DisableGameEnd), false, "Stops the game from ending regardless of conditions");
RedirectLogger = config.Bind(FeaturesSection, nameof(RedirectLogger), false, "Redirect base game Logger calls into BepInEx logging");
AutoPlayAgain = config.Bind(FeaturesSection, nameof(AutoPlayAgain), true, "Automatically calls Play Again after game ends");
DisableTimeout = config.Bind(FeaturesSection, nameof(DisableTimeout), false, "Disable the network disconnection timeout");

JoinGameOnStart = config.Bind(AutoJoinSection, nameof(JoinGameOnStart), false, "Automatically hosts/joins a game on start");
}
}
106 changes: 9 additions & 97 deletions Reactor.Debugger/DebuggerPlugin.cs
Original file line number Diff line number Diff line change
@@ -1,15 +1,10 @@
using System;
using System.Linq;
using AmongUs.Data;
global using static Reactor.Utilities.Logger<Reactor.Debugger.DebuggerPlugin>;
using BepInEx;
using BepInEx.Unity.IL2CPP;
using HarmonyLib;
using Il2CppInterop.Runtime.Attributes;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using InnerNet;
using Reactor.Utilities.Attributes;
using Reactor.Utilities.ImGui;
using UnityEngine;
using Reactor.Debugger.AutoJoin;
using Reactor.Debugger.Patches;
using Reactor.Debugger.Window;

namespace Reactor.Debugger;

@@ -19,100 +14,17 @@ namespace Reactor.Debugger;
public partial class DebuggerPlugin : BasePlugin
{
public Harmony Harmony { get; } = new(Id);
public DebuggerComponent Component { get; private set; } = null!;

public override void Load()
{
Component = this.AddComponent<DebuggerComponent>();
DebuggerConfig.Bind(Config);

GameOptionsData.MaxImpostors = GameOptionsData.RecommendedImpostors = Enumerable.Repeat((int) byte.MaxValue, byte.MaxValue).ToArray();
GameOptionsData.MinPlayers = Enumerable.Repeat(1, 4).ToArray();
this.AddComponent<DebuggerWindow>();

Harmony.PatchAll();
}

[RegisterInIl2Cpp]
public class DebuggerComponent : MonoBehaviour
{
[HideFromIl2Cpp]
public bool DisableGameEnd { get; set; }

[HideFromIl2Cpp]
public DragWindow TestWindow { get; }

public DebuggerComponent(IntPtr ptr) : base(ptr)
{
TestWindow = new DragWindow(new Rect(20, 20, 0, 0), "Debugger", () =>
{
GUILayout.Label("Name: " + DataManager.Player.Customization.Name);
DisableGameEnd = GUILayout.Toggle(DisableGameEnd, "Disable game end");

if (ShipStatus.Instance && AmongUsClient.Instance.AmHost)
{
if (GUILayout.Button("Force game end"))
{
ShipStatus.Instance.enabled = false;
ShipStatus.RpcEndGame(GameOverReason.ImpostorDisconnect, false);
}
GameOptionsPatches.Initialize();

if (GUILayout.Button("Call a meeting"))
{
PlayerControl.LocalPlayer.CmdReportDeadBody(null);
}
}

if (TutorialManager.InstanceExists && PlayerControl.LocalPlayer)
{
var data = PlayerControl.LocalPlayer.Data;

var newIsImpostor = GUILayout.Toggle(data.Role.IsImpostor, "Is Impostor");
if (data.Role.IsImpostor != newIsImpostor)
{
PlayerControl.LocalPlayer.RpcSetRole(newIsImpostor ? RoleTypes.Impostor : RoleTypes.Crewmate);
}

if (GUILayout.Button("Spawn a dummy"))
{
var playerControl = Instantiate(TutorialManager.Instance.PlayerPrefab);
var i = playerControl.PlayerId = (byte) GameData.Instance.GetAvailableId();
GameData.Instance.AddPlayer(playerControl);
AmongUsClient.Instance.Spawn(playerControl, -2, SpawnFlags.None);
playerControl.transform.position = PlayerControl.LocalPlayer.transform.position;
playerControl.GetComponent<DummyBehaviour>().enabled = true;
playerControl.NetTransform.enabled = false;
playerControl.SetName($"{TranslationController.Instance.GetString(StringNames.Dummy, Array.Empty<Il2CppSystem.Object>())} {i}");
var color = (byte) (i % Palette.PlayerColors.Length);
playerControl.SetColor(color);
playerControl.SetHat(HatManager.Instance.allHats[i % HatManager.Instance.allHats.Count].ProdId, playerControl.Data.DefaultOutfit.ColorId);
playerControl.SetPet(HatManager.Instance.allPets[i % HatManager.Instance.allPets.Count].ProdId);
playerControl.SetSkin(HatManager.Instance.allSkins[i % HatManager.Instance.allSkins.Count].ProdId, color);
GameData.Instance.RpcSetTasks(playerControl.PlayerId, new Il2CppStructArray<byte>(0));
}
}

if (PlayerControl.LocalPlayer)
{
var position = PlayerControl.LocalPlayer.transform.position;
GUILayout.Label($"x: {position.x}");
GUILayout.Label($"y: {position.y}");
}
})
{
Enabled = false,
};
}

private void Update()
{
if (Input.GetKeyDown(KeyCode.F1))
{
TestWindow.Enabled = !TestWindow.Enabled;
}
}
Harmony.PatchAll();

private void OnGUI()
{
TestWindow.OnGUI();
}
AutoJoinConnectionManager.StartOrConnect();
}
}
70 changes: 0 additions & 70 deletions Reactor.Debugger/Patches.cs

This file was deleted.

14 changes: 14 additions & 0 deletions Reactor.Debugger/Patches/AutoPlayAgainPatch.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using HarmonyLib;

namespace Reactor.Debugger.Patches;

[HarmonyPatch(typeof(EndGameNavigation), nameof(EndGameNavigation.ShowDefaultNavigation))]
internal static class AutoPlayAgainPatch
{
public static void Postfix(EndGameNavigation __instance)
{
if (!DebuggerConfig.AutoPlayAgain.Value) return;

__instance.NextGame();
}
}
18 changes: 18 additions & 0 deletions Reactor.Debugger/Patches/DisableGameEndPatch.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
using HarmonyLib;

namespace Reactor.Debugger.Patches;

[HarmonyPatch]
[HarmonyPriority(Priority.First)]
internal static class DisableGameEndPatch
{
private static bool Enabled => DebuggerConfig.DisableGameEnd.Value;

[HarmonyPatch(typeof(LogicGameFlow), nameof(LogicGameFlow.CheckEndCriteria))]
[HarmonyPatch(typeof(LogicGameFlowNormal), nameof(LogicGameFlow.CheckEndCriteria))]
[HarmonyPatch(typeof(LogicGameFlowHnS), nameof(LogicGameFlow.CheckEndCriteria))]
public static bool Prefix()
{
return !Enabled;
}
}
27 changes: 27 additions & 0 deletions Reactor.Debugger/Patches/DisableTimeoutPatch.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
using HarmonyLib;
using Hazel.Udp;

namespace Reactor.Debugger.Patches;

[HarmonyPatch]
internal static class DisableTimeoutPatch
{
private static bool Enabled => DebuggerConfig.DisableTimeout.Value;

[HarmonyPatch(typeof(UdpConnection), nameof(UdpConnection.HandleKeepAlive))]
[HarmonyPrefix]
public static bool DisableKeepAlive()
{
return !Enabled;
}

[HarmonyPatch(typeof(UnityUdpClientConnection), nameof(UnityUdpClientConnection.ConnectAsync))]
[HarmonyPostfix]
public static void DisableTimeout(UnityUdpClientConnection __instance)
{
if (!Enabled) return;

__instance.DisconnectTimeoutMs = int.MaxValue;
__instance.ResendLimit = 0;
}
}
70 changes: 70 additions & 0 deletions Reactor.Debugger/Patches/GameOptionsPatches.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
using System.Linq;
using AmongUs.GameOptions;
using HarmonyLib;
using Il2CppInterop.Runtime;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppSystem.Reflection;
using UnityEngine;

namespace Reactor.Debugger.Patches;

[HarmonyPatch]
internal static class GameOptionsPatches
{
public static void Initialize()
{
var maxImpostors = (Il2CppStructArray<int>) Enumerable.Repeat((int) byte.MaxValue, byte.MaxValue).ToArray();
GameOptionsData.MaxImpostors = maxImpostors;
NormalGameOptionsV07.MaxImpostors = maxImpostors;
HideNSeekGameOptionsV07.MaxImpostors = maxImpostors;

var minPlayers = (Il2CppStructArray<int>) Enumerable.Repeat(1, byte.MaxValue).ToArray();
GameOptionsData.MinPlayers = minPlayers;
NormalGameOptionsV07.MinPlayers = minPlayers;
HideNSeekGameOptionsV07.MinPlayers = minPlayers;
}

[HarmonyPatch(typeof(GameSettingMenu), nameof(GameSettingMenu.Start))]
[HarmonyPrefix]
public static void UnlockAllOptions(GameSettingMenu __instance)
{
__instance.GameSettingsTab.HideForOnline = new Il2CppReferenceArray<Transform>(0);
}

[HarmonyPatch(typeof(NumberOption), nameof(NumberOption.SetUpFromData))]
[HarmonyPostfix]
public static void UnlockOptionRange(NumberOption __instance)
{
__instance.ValidRange.min = float.MinValue;
__instance.ValidRange.max = float.MaxValue;
}

[HarmonyPatch(typeof(CreateOptionsPicker), nameof(CreateOptionsPicker.SetImpostorButtons))]
public static class DisableImpostorCountReset
{
private static readonly MethodInfo _refreshMethod = Il2CppType.Of<CreateOptionsPicker>().GetMethod("Refresh", BindingFlags.Public | BindingFlags.Instance);

public static bool Prefix()
{
foreach (var stackFrame in new Il2CppSystem.Diagnostics.StackTrace().GetFrames())
{
if (_refreshMethod.Equals(stackFrame.GetMethod()))
{
return false;
}
}

return true;
}
}

[HarmonyPatch(typeof(CrewVisualizer), nameof(CrewVisualizer.SetCrewSize))]
[HarmonyPrefix]
public static void SetCrewSizePatch(int numPlayers, ref int numImpostors)
{
if (numImpostors >= numPlayers)
{
numImpostors = 0;
}
}
}
21 changes: 21 additions & 0 deletions Reactor.Debugger/Patches/GameStartManagerPatches.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
using HarmonyLib;

namespace Reactor.Debugger.Patches;

[HarmonyPatch(typeof(GameStartManager))]
internal static class GameStartManagerPatches
{
[HarmonyPatch(nameof(GameStartManager.Start))]
[HarmonyPrefix]
public static void StartPatch(GameStartManager __instance)
{
__instance.MinPlayers = 1;
}

[HarmonyPatch(nameof(GameStartManager.Update))]
[HarmonyPrefix]
public static void UpdatePatch(GameStartManager __instance)
{
__instance.countDownTimer = 0;
}
}
14 changes: 14 additions & 0 deletions Reactor.Debugger/Patches/MiscellaneousPatches.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using HarmonyLib;

namespace Reactor.Debugger.Patches;

[HarmonyPatch]
internal static class MiscellaneousPatches
{
[HarmonyPatch(typeof(StatsManager), nameof(StatsManager.AmBanned), MethodType.Getter)]
[HarmonyPrefix]
public static void AmBannedPatch(out bool __result)
{
__result = false;
}
}
39 changes: 39 additions & 0 deletions Reactor.Debugger/Patches/RandomizeFreeplayServerPortPatch.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
using System;
using System.Net;
using HarmonyLib;
using InnerNet;

namespace Reactor.Debugger.Patches;

[HarmonyPatch]
internal static class RandomizeFreeplayServerPortPatch
{
private static ushort? _lastPort;

[HarmonyPatch(typeof(InnerNetServer), nameof(InnerNetServer.StartAsLocalServer))]
public static class StartServerPatch
{
public static void Prefix(InnerNetServer __instance)
{
var port = (ushort) Random.Shared.Next(1024, IPEndPoint.MaxPort);
_lastPort = port;
__instance.Port = port;
}

public static void Postfix(InnerNetServer __instance)
{
__instance.Port = Constants.GamePlayPort;
}
}

[HarmonyPatch(typeof(InnerNetClient), nameof(InnerNetClient.SetEndpoint))]
[HarmonyPrefix]
public static void SetEndpointPatch(InnerNetClient __instance, string addr, ref ushort port)
{
if (_lastPort != null && __instance.NetworkMode == NetworkModes.FreePlay)
{
port = _lastPort.Value;
_lastPort = null;
}
}
}
74 changes: 74 additions & 0 deletions Reactor.Debugger/Patches/RedirectLoggerPatch.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
using System;
using System.Globalization;
using System.Text;
using BepInEx.Logging;
using HarmonyLib;
using Object = UnityEngine.Object;

namespace Reactor.Debugger.Patches;

[HarmonyPatch(typeof(Logger))]
internal static class RedirectLoggerPatch
{
private static readonly ManualLogSource _log = BepInEx.Logging.Logger.CreateLogSource("Among Us");

private static bool Enabled => DebuggerConfig.RedirectLogger.Value;

private static void Log(Logger logger, Logger.Level level, Il2CppSystem.Object message, Object? context = null)
{
var finalMessage = new StringBuilder();

if (logger.category != Logger.Category.None) finalMessage.Append(CultureInfo.InvariantCulture, $"[{logger.category}] ");
if (!string.IsNullOrEmpty(logger.tag)) finalMessage.Append(CultureInfo.InvariantCulture, $"[{logger.tag}] ");
if (context != null) finalMessage.Append(CultureInfo.InvariantCulture, $"[{context.name} ({context.GetIl2CppType().FullName})]");
finalMessage.Append(CultureInfo.InvariantCulture, $" {message.ToString()} ");

_log.Log(
level switch
{
Logger.Level.Debug => LogLevel.Debug,
Logger.Level.Error => LogLevel.Error,
Logger.Level.Warning => LogLevel.Warning,
Logger.Level.Info => LogLevel.Info,
_ => throw new ArgumentOutOfRangeException(nameof(level), level, null),
},
finalMessage
);
}

[HarmonyPatch(nameof(Logger.Debug))]
[HarmonyPrefix]
public static bool DebugPatch(Logger __instance, Il2CppSystem.Object message, Object? context)
{
if (!Enabled) return true;
Log(__instance, Logger.Level.Debug, message, context);
return false;
}

[HarmonyPatch(nameof(Logger.Info))]
[HarmonyPrefix]
public static bool InfoPatch(Logger __instance, Il2CppSystem.Object message, Object? context)
{
if (!Enabled) return true;
Log(__instance, Logger.Level.Info, message, context);
return false;
}

[HarmonyPatch(nameof(Logger.Warning))]
[HarmonyPrefix]
public static bool WarningPatch(Logger __instance, Il2CppSystem.Object message, Object? context)
{
if (!Enabled) return true;
Log(__instance, Logger.Level.Warning, message, context);
return false;
}

[HarmonyPatch(nameof(Logger.Error))]
[HarmonyPrefix]
public static bool ErrorPatch(Logger __instance, Il2CppSystem.Object message, Object? context)
{
if (!Enabled) return true;
Log(__instance, Logger.Level.Error, message, context);
return false;
}
}
49 changes: 49 additions & 0 deletions Reactor.Debugger/Utilities/Extensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
using System;
using System.Collections;
using Il2CppInterop.Runtime;
using InnerNet;

namespace Reactor.Debugger.Utilities;

internal static class Extensions
{
public static IEnumerator CoCreateLocalGame(this AmongUsClient client, bool isFreePlay = false)
{
try
{
if (isFreePlay)
{
client.NetworkMode = NetworkModes.FreePlay;

InnerNetServer.Instance.StartAsLocalServer();

client.MainMenuScene = "MainMenu";
client.OnlineScene = "Tutorial";
}
else
{
client.NetworkMode = NetworkModes.LocalGame;

InnerNetServer.Instance.StartAsServer();

client.MainMenuScene = "MatchMaking";
client.OnlineScene = "OnlineGame";
}

client.SetEndpoint(Constants.LocalNetAddress, Constants.GamePlayPort, false);
}
catch (Il2CppException e)
{
Error(e);
DisconnectPopup.Instance.ShowCustom(e.Message[..e.Message.IndexOf("\n--- BEGIN IL2CPP STACK TRACE ---\n", StringComparison.Ordinal)]);
MatchMaker.Instance.NotConnecting();
yield break;
}

client.Connect(MatchMakerModes.HostAndClient, null);

yield return client.WaitForConnectionOrFail();

DestroyableSingleton<MatchMaker>.Instance.NotConnecting();
}
}
112 changes: 112 additions & 0 deletions Reactor.Debugger/Window/DebuggerWindow.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
using System;
using System.Collections;
using System.Linq;
using AmongUs.Data;
using BepInEx.Unity.IL2CPP.Utils;
using Il2CppInterop.Runtime.Attributes;
using Il2CppInterop.Runtime.InteropTypes;
using Reactor.Debugger.Utilities;
using Reactor.Debugger.Window.Tabs;
using Reactor.Utilities.Attributes;
using Reactor.Utilities.ImGui;
using UnityEngine;

namespace Reactor.Debugger.Window;

[RegisterInIl2Cpp]
internal sealed class DebuggerWindow : MonoBehaviour
{
private readonly DragWindow _window;

[HideFromIl2Cpp]
public BaseTab[] Tabs { get; } =
{
new ConfigTab(),
new GameTab(),
new AutoJoinTab(),
};

[HideFromIl2Cpp]
public BaseTab SelectedTab { get; private set; }

public DebuggerWindow(IntPtr ptr) : base(ptr)
{
SelectedTab = Tabs[0];

_window = new DragWindow(new Rect(20, 20, 0, 0), "Reactor.Debugger", () =>
{
var clientName = DataManager.Player.Customization.Name;
if (AmongUsClient.Instance && AmongUsClient.Instance.AmHost) clientName += " (host)";
GUILayout.Label("Name: " + clientName);

if (GUILayout.Button("Hard crash"))
{
static unsafe void Corrupt(Il2CppObjectBase o)
{
var x = (IntPtr*) o.Pointer;
x[0] = (IntPtr) 0xF00;
}

static IEnumerator CoCrash()
{
if (!PlayerControl.LocalPlayer || !ShipStatus.Instance)
{
yield return AmongUsClient.Instance.CoCreateLocalGame(true);

while (!PlayerControl.LocalPlayer || !ShipStatus.Instance)
{
yield return null;
}
}

var usable = FindObjectsOfType<MonoBehaviour>().First(x => x.TryCast<IUsable>() != null);
if (!usable)
{
Error("Failed to find an IUsable to crash with");
yield break;
}

var cloned = Instantiate(usable, PlayerControl.LocalPlayer.transform.position, default);

Warning($"Crashing with {cloned.name}");

Corrupt(cloned);
}

this.StartCoroutine(CoCrash());
}

GUILayout.BeginHorizontal();
{
foreach (var tab in Tabs)
{
if (GUILayout.Toggle(tab == SelectedTab, tab.Name, new GUIStyle(GUI.skin.button)))
{
SelectedTab = tab;
}
}
}
GUILayout.EndHorizontal();

GUILayout.Space(5f);

SelectedTab.OnGUI();
})
{
Enabled = false,
};
}

public void Update()
{
if (Input.GetKeyDown(KeyCode.F1))
{
_window.Enabled = !_window.Enabled;
}
}

public void OnGUI()
{
_window.OnGUI();
}
}
68 changes: 68 additions & 0 deletions Reactor.Debugger/Window/Tabs/AutoJoinTab.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
using BepInEx.Unity.IL2CPP.Utils;
using Reactor.Debugger.AutoJoin;
using Reactor.Debugger.Utilities;
using UnityEngine;

namespace Reactor.Debugger.Window.Tabs;

internal sealed class AutoJoinTab : BaseTab
{
public override string Name => "AutoJoin";

public override void OnGUI()
{
if (AutoJoinConnectionManager.Server is { } server)
{
GUILayout.Label($"Hosting ({server.Clients.Count} clients)");

if (GUILayout.Button("Stop"))
{
server.Dispose();
}

if (AmongUsClient.Instance)
{
if (GUILayout.Button("Create an online game"))
{
AmongUsClient.Instance.StartCoroutine(AmongUsClient.Instance.CoCreateOnlineGame());
}

if (GUILayout.Button("Create a local game"))
{
AmongUsClient.Instance.StartCoroutine(AmongUsClient.Instance.CoCreateLocalGame());
}

if (
AmongUsClient.Instance.AmConnected &&
AmongUsClient.Instance.NetworkMode != NetworkModes.FreePlay &&
GUILayout.Button("Join me")
)
{
server.SendJoinMe(AmongUsClient.Instance);
}
}
}
else if (AutoJoinConnectionManager.Client is { } client)
{
GUILayout.Label("Connected");

if (GUILayout.Button("Disconnect"))
{
AutoJoinConnectionManager.Client = null;
client.Dispose();
}

if (GUILayout.Button("Request join"))
{
client.SendRequestJoin();
}
}
else
{
if (GUILayout.Button("Connect"))
{
AutoJoinConnectionManager.StartOrConnect();
}
}
}
}
8 changes: 8 additions & 0 deletions Reactor.Debugger/Window/Tabs/BaseTab.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace Reactor.Debugger.Window.Tabs;

internal abstract class BaseTab
{
public abstract string Name { get; }

public abstract void OnGUI();
}
29 changes: 29 additions & 0 deletions Reactor.Debugger/Window/Tabs/ConfigTab.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
using System.Linq;
using BepInEx.Configuration;
using Reactor.Utilities;
using UnityEngine;

namespace Reactor.Debugger.Window.Tabs;

internal sealed class ConfigTab : BaseTab
{
public override string Name => "Config";

public override void OnGUI()
{
var configs = PluginSingleton<ReactorPlugin>.Instance.Config.Concat(PluginSingleton<DebuggerPlugin>.Instance.Config);

foreach (var section in configs.GroupBy(e => e.Key.Section))
{
GUILayout.Label(section.Key);

foreach (var (definition, entry) in section)
{
if (entry is ConfigEntry<bool> booleanEntry)
{
booleanEntry.Value = GUILayout.Toggle(booleanEntry.Value, definition.Key);
}
}
}
}
}
97 changes: 97 additions & 0 deletions Reactor.Debugger/Window/Tabs/GameTab.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
using AmongUs.GameOptions;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using UnityEngine;
using Object = UnityEngine.Object;

namespace Reactor.Debugger.Window.Tabs;

internal sealed class GameTab : BaseTab
{
public override string Name => "Game";

public override void OnGUI()
{
var localPlayer = PlayerControl.LocalPlayer;
if (!localPlayer)
{
return;
}

var amHost = AmongUsClient.Instance.AmHost;

var position = localPlayer.transform.position;
GUILayout.Label($"Position: ({position.x:F3}, {position.y:F3})");

var physics = localPlayer.MyPhysics;
GUILayout.Label($"Speed: {physics.Speed}");
physics.Speed = GUILayout.HorizontalSlider(physics.Speed, 0, 25);

localPlayer.Collider.enabled = GUILayout.Toggle(localPlayer.Collider.enabled, "Collisions");

if (ShipStatus.Instance)
{
if (amHost && GUILayout.Button("Force game end"))
{
ShipStatus.Instance.enabled = false;
GameManager.Instance.RpcEndGame(GameOverReason.ImpostorDisconnect, false);
}

if (MeetingHud.Instance)
{
if (GUILayout.Button("Stop the meeting"))
{
MeetingHud.Instance.RpcClose();
}
}
else
{
if (GUILayout.Button("Call a meeting"))
{
localPlayer.CmdReportDeadBody(null);
}
}

if (TutorialManager.InstanceExists)
{
var newIsImpostor = GUILayout.Toggle(localPlayer.Data.Role.IsImpostor, "Is Impostor");
if (localPlayer.Data.Role.IsImpostor != newIsImpostor)
{
localPlayer.RpcSetRole(newIsImpostor ? RoleTypes.Impostor : RoleTypes.Crewmate);
}

if (GUILayout.Button("Spawn a dummy"))
{
SpawnDummy();
}
}
}
}

private static void SpawnDummy()
{
var playerControl = Object.Instantiate(AmongUsClient.Instance.PlayerPrefab);
var playerId = playerControl.PlayerId = (byte) GameData.Instance.GetAvailableId();

var data = GameData.Instance.AddDummy(playerControl);
AmongUsClient.Instance.Spawn(data);
AmongUsClient.Instance.Spawn(playerControl);
playerControl.isDummy = true;

playerControl.transform.position = PlayerControl.LocalPlayer.transform.position;
playerControl.GetComponent<DummyBehaviour>().enabled = true;
playerControl.NetTransform.enabled = false;

playerControl.SetName($"{TranslationController.Instance.GetString(StringNames.Dummy)} {playerId}");

var color = (byte) (playerId % Palette.PlayerColors.Length);
playerControl.SetColor(color);
playerControl.SetHat(HatManager.Instance.allHats[playerId % HatManager.Instance.allHats.Count].ProdId, playerControl.Data.DefaultOutfit.ColorId);
playerControl.SetPet(HatManager.Instance.allPets[playerId % HatManager.Instance.allPets.Count].ProdId);
playerControl.SetSkin(HatManager.Instance.allSkins[playerId % HatManager.Instance.allSkins.Count].ProdId, color);
playerControl.SetVisor(HatManager.Instance.allVisors[playerId % HatManager.Instance.allVisors.Count].ProdId, color);
playerControl.SetNamePlate(HatManager.Instance.allNamePlates[playerId % HatManager.Instance.allNamePlates.Count].ProdId);
data.PlayerLevel = playerId;

data.RpcSetTasks(new Il2CppStructArray<byte>(0));
}
}
190 changes: 120 additions & 70 deletions Reactor.Debugger/packages.lock.json
Original file line number Diff line number Diff line change
@@ -4,9 +4,9 @@
"net6.0": {
"AmongUs.GameLibs.Steam": {
"type": "Direct",
"requested": "[2022.10.25, )",
"resolved": "2022.10.25",
"contentHash": "PWgkH/VvMlShVhZB8G432q0tnMaNVZrbIdbEMCZN/fETUlT/ch+qQj4PdTcZhPHREbnJHH3ijHxlca1d7QMBcQ=="
"requested": "[2024.8.13, )",
"resolved": "2024.8.13",
"contentHash": "xYZBHQJcwSF5wABtJIZlmpNwZ7jXWafe6vid6/YEWSxpk1fcYLxz42bHSTYcGjpu4wVz1p1ZG/QC4Eu0SbGhrg=="
},
"BepInEx.AutoPlugin": {
"type": "Direct",
@@ -22,72 +22,107 @@
},
"BepInEx.Unity.IL2CPP": {
"type": "Direct",
"requested": "[6.0.0-be.662, )",
"resolved": "6.0.0-be.662",
"contentHash": "fn7jQ88IBmjssoY9XjGBTg3cULkS+N/le/eUijYf2VV8raWok/6cU/GbU9bejkJS8g+2MvzIwnROAhAxvrGI2Q==",
"dependencies": {
"BepInEx.Core": "6.0.0-be.662",
"BepInEx.Unity.Common": "6.0.0-be.662",
"HarmonyX": "2.10.0",
"Iced": "1.17.0",
"Il2CppInterop.Generator": "1.3.0",
"Il2CppInterop.HarmonySupport": "1.3.0",
"Il2CppInterop.Runtime": "1.3.0",
"requested": "[6.0.0-be.679, )",
"resolved": "6.0.0-be.679",
"contentHash": "KnfMjWSXI5+dxbkLCy8VssEnZtTN3MXUHDdBkvPbMiZ6oR1RGZWdLlA90/XQkY/4kMA5P4OCZP4eQ1o0XftbSQ==",
"dependencies": {
"BepInEx.Core": "6.0.0-be.679",
"BepInEx.Unity.Common": "6.0.0-be.679",
"HarmonyX": "2.10.1",
"Iced": "1.18.0",
"Il2CppInterop.Generator": "1.4.6-ci.389",
"Il2CppInterop.HarmonySupport": "1.4.6-ci.389",
"Il2CppInterop.Runtime": "1.4.6-ci.389",
"MonoMod.RuntimeDetour": "22.5.1.1",
"Samboy063.Cpp2IL.Core": "2022.0.7.2"
"Samboy063.Cpp2IL.Core": "2022.1.0-development.866"
}
},
"StyleCop.Analyzers": {
"type": "Direct",
"requested": "[1.2.0-beta.435, )",
"resolved": "1.2.0-beta.435",
"contentHash": "TADk7vdGXtfTnYCV7GyleaaRTQjfoSfZXprQrVMm7cSJtJbFc1QIbWPyLvrgrfGdfHbGmUPvaN4ODKNxg2jgPQ==",
"requested": "[1.2.0-beta.556, )",
"resolved": "1.2.0-beta.556",
"contentHash": "llRPgmA1fhC0I0QyFLEcjvtM2239QzKr/tcnbsjArLMJxJlu0AA5G7Fft0OI30pHF3MW63Gf4aSSsjc5m82J1Q==",
"dependencies": {
"StyleCop.Analyzers.Unstable": "1.2.0.556"
}
},
"AsmResolver": {
"type": "Transitive",
"resolved": "5.1.0",
"contentHash": "7PjujQzgQ3wjzqZYT4CY8SV6zx7FY6swIwj3Yk4QLolLqo9sBPb7FLF3W30QFvCsCkNfiVWXlSbeZKs4xGgQOQ=="
},
"AsmResolver.DotNet": {
"type": "Transitive",
"resolved": "5.1.0",
"contentHash": "oKrBU94OaSrbbTwydvpLRFalYxozrNXGkl13nIkm823ZFQtPNYOiOMJb5DQLvkCJlWyis7q865tg803T5zg9IA==",
"dependencies": {
"StyleCop.Analyzers.Unstable": "1.2.0.435"
"AsmResolver.PE": "5.1.0",
"System.Text.Json": "6.0.7"
}
},
"AsmResolver.PE": {
"type": "Transitive",
"resolved": "5.1.0",
"contentHash": "XD3iAgLSInJIODKUUlpHWXf8MR9H1SFMb1lsmabb4GxxxnDQRPjMxjglv2NOCjQQuNB2Oh0bvjHE7ewf82UqyQ==",
"dependencies": {
"AsmResolver.PE.File": "5.1.0"
}
},
"AsmResolver.PE.File": {
"type": "Transitive",
"resolved": "5.1.0",
"contentHash": "YituBYe0Fh471sXQMfu+f4tWKX/JZvRwrX6g/SVsr4XkUIUzYi/aGT3/QvjHoYx19fE1KYOB6zBKqPkkOK7HPw==",
"dependencies": {
"AsmResolver": "5.1.0"
}
},
"AssetRipper.VersionUtilities": {
"type": "Transitive",
"resolved": "1.2.1",
"contentHash": "knQ/W1YwTZS2AbdaZh+nhyyBEZQPQDcahhSOnh88i+cdg4/FEoFJiCwaavgFvCMNuUeHTbcZc4qttF8WQ8xLIA=="
"resolved": "1.3.1",
"contentHash": "/1D18NOpqm7rS7+qVUbAReVMNWwgDuYpsnf0RkX1Aah/I0a0irqldoFJ+Kku7YdbSm0zqD+Z6iYUGKoP3GwTNQ=="
},
"BepInEx.Core": {
"type": "Transitive",
"resolved": "6.0.0-be.662",
"contentHash": "VVBeCD/KQVy0/TK3V6SD8QZ/es35Xb1mEz/+PbBs3ST1yUC1r7k2JOymhSnmghVqf6UsvlMglOO9pljqhuE/Pw==",
"resolved": "6.0.0-be.679",
"contentHash": "yg6NSGeevv86P2ERe3VDEa7W/l0lmM7m+AdPSW78dcBOe36Zc3QK/vmNEq57txGa+1kwv+macXLSwkL4UpucjA==",
"dependencies": {
"HarmonyX": "2.10.0",
"HarmonyX": "2.10.1",
"MonoMod.Utils": "22.5.1.1",
"SemanticVersioning": "2.0.2"
}
},
"BepInEx.Unity.Common": {
"type": "Transitive",
"resolved": "6.0.0-be.662",
"contentHash": "BgETw6+snwY//3xjQxLiiEAFRmXaMTcSkg+1UQz6fVBG0YA5Usm/m4GflhTc3nwF61KO3Iznn1AORi5CwLJoUw==",
"resolved": "6.0.0-be.679",
"contentHash": "q4Sux3ULBDasSQAtlAWzAKpAfCyV3ujxVJpK7ydV1bUIksaHNqw9yYTLCUrw8p4DQ/wHvShECFjzeMGHi+wylA==",
"dependencies": {
"AssetRipper.VersionUtilities": "1.2.1",
"MonoMod.Utils": "22.5.1.1"
}
},
"Disarm": {
"type": "Transitive",
"resolved": "2022.1.0-master.26",
"contentHash": "YnZEbRGr0nG+N3G8WbRQ4Lkg8dTD3oso9iJlCVBmyhEyhLyqs+drBs1kWQbQqFPnb9mi/RJ++R9bPb+L3HF03Q=="
},
"HarmonyX": {
"type": "Transitive",
"resolved": "2.10.0",
"contentHash": "4ayiy/dlCiW86K2N7Jvbf+VpI5wvP7dncv/6oRmfwRi32UCmCRzCGzsxdMfzJZkp6/26oBW+DrD8vi4UejzVAg==",
"resolved": "2.10.1",
"contentHash": "9LodMC9Y0u1TW96eKJoWrFJFpmzbgojEO38/Q+e7c1mFPhmHt8xcR8qhI06iF1rf0Dnsk+hqENFVSgbtwl/bEw==",
"dependencies": {
"MonoMod.RuntimeDetour": "22.3.23.4",
"System.Reflection.Emit": "4.7.0"
}
},
"Iced": {
"type": "Transitive",
"resolved": "1.17.0",
"contentHash": "8x+HCVTl/HHTGpscH3vMBhV8sknN/muZFw9s3TsI8SA6+c43cOTCi2+jE4KsU8pNLbJ++iF2ZFcpcXHXtDglnw=="
"resolved": "1.18.0",
"contentHash": "G60lZOvbvqttA+SBSv/yY6/wUboXKJlkffhSNR9iOrx0M5gpcK1TRr6xrFR+qAhqIAhvrsPF1jkn9fYb4lEufQ=="
},
"Il2CppInterop.Common": {
"type": "Transitive",
"resolved": "1.3.0",
"contentHash": "IR3BrZXvL2nvJAn4pruPMgC78Y87hVa5xTYZCuHN67OzRD6WDl5dTO55vtvTl8dXFALKvlN+spja2tXhVuquOw==",
"resolved": "1.4.6-ci.389",
"contentHash": "KTyf2f66Q2mS9a6xhvoPWwD0VzRIoskPMVQehaVMo1dx4Di1FPFsKqukQ+ob6wgP5Rbnx53kiH0PY+IRSb35XA==",
"dependencies": {
"Iced": "1.17.0",
"Microsoft.Extensions.Logging.Abstractions": "6.0.1",
@@ -96,36 +131,31 @@
},
"Il2CppInterop.Generator": {
"type": "Transitive",
"resolved": "1.3.0",
"contentHash": "FuhPxbh/K4K94U3xac/ClMaaBp+MZ4aIaqi5dR0QihyGQoombT+OM/A22RwAIzbaCTbFbvabWaAuOSgB69ZwWQ==",
"resolved": "1.4.6-ci.389",
"contentHash": "XJX4sn/RzAEBNIZZXuyDcLZrFx5tCoahujDu5aKWjApiMj/nTRQAxZn17daIIvd9aHqLaAfiWWth5QDLIt2bKw==",
"dependencies": {
"Il2CppInterop.Common": "1.3.0",
"Il2CppInterop.Common": "1.4.6-ci.389",
"Mono.Cecil": "0.11.3"
}
},
"Il2CppInterop.HarmonySupport": {
"type": "Transitive",
"resolved": "1.3.0",
"contentHash": "VppBnXtbMNGFhX8a1gg/85E883t2pW/+FZyV7eOaOXMNQyorg++u+kUFOIYwNpzTVqxWmMeoPS0DH0toVpjoKA==",
"resolved": "1.4.6-ci.389",
"contentHash": "Xd2zK6sLqwA0ReyUy83SWKcALwY99fq6vVL5gFOMN5Ct8OOVhtNIws0ysCWsfx1GL0RJiRYfR4pza/MmWRz4PQ==",
"dependencies": {
"HarmonyX": "2.10.0",
"Il2CppInterop.Runtime": "1.3.0"
"Il2CppInterop.Runtime": "1.4.6-ci.389"
}
},
"Il2CppInterop.Runtime": {
"type": "Transitive",
"resolved": "1.3.0",
"contentHash": "8A+N2yvja960Ap+s2RpW7Nb6HSpyuXJy2ipIlU+1erYU9SWHMyU9JZzUZGOhwWXJChKGvRmDdTZAg12k1+72dg==",
"resolved": "1.4.6-ci.389",
"contentHash": "nzYjuVzDG/O8+AQ8ax3WVHf+ZVsQKrVtp/yvuW8XoEPLdkbgryIrMo75dvN+tPqxOU3o2MPt9MZ9j25P5aVJMw==",
"dependencies": {
"Iced": "1.17.0",
"Il2CppInterop.Common": "1.3.0"
"Il2CppInterop.Common": "1.4.6-ci.389"
}
},
"IndexRange": {
"type": "Transitive",
"resolved": "1.0.0",
"contentHash": "6TgS1JLSUkpmPLfXBPaAgB39ZUix8E4soXWk2XSDcscVe84i1JKzIAtA7jHbRHSkOOrcr6YA0MpLCeq98y9mYQ=="
},
"js6pak.Gee.External.Capstone": {
"type": "Transitive",
"resolved": "2.1.0",
@@ -280,42 +310,45 @@
},
"Samboy063.Cpp2IL.Core": {
"type": "Transitive",
"resolved": "2022.0.7.2",
"contentHash": "e17CAhKSxdAp7vFcYEVxjSc7t7rcvVGBipGhgE9tAjRXY85wZXLlHEVO0AEvMRkLmf9U+if4wK/nZEC1AX6VqQ==",
"resolved": "2022.1.0-development.866",
"contentHash": "QPMuix/3jRngWBdNSLhAbm9BHYf95Ln1Ph1eCK/cDZdVibxFDFP3a6Yczyx1p7GbN7bRQwrhs2skPJSS/z3m2w==",
"dependencies": {
"HarmonyX": "2.5.5",
"Iced": "1.11.1",
"IndexRange": "1.0.0",
"Mono.Cecil": "0.11.4",
"Samboy063.LibCpp2IL": "2022.0.7.2",
"System.Runtime.InteropServices": "4.3.0",
"System.ValueTuple": "4.5.0",
"AsmResolver.DotNet": "5.1.0",
"Disarm": "2022.1.0-master.26",
"Iced": "1.18.0",
"Samboy063.LibCpp2IL": "2022.1.0-development.866",
"StableNameDotNet": "0.1.0-development.866",
"js6pak.Gee.External.Capstone": "2.1.0"
}
},
"Samboy063.LibCpp2IL": {
"type": "Transitive",
"resolved": "2022.0.7.2",
"contentHash": "DpVeU0dQkUJCpbw0f1xKOG8vimdK2oYhrVABC7HDE3/ikGjhnMZd3i5b1joKDHZ+AiL90TWOaEXPcy24rCZ0dA==",
"resolved": "2022.1.0-development.866",
"contentHash": "EcJSWTfQko8SQozozoUT+aQJVWC8wj8C0YUiPBF4rNRId19yTKp2IXcXnI747v+8/aal222QR6WHfoBK2WlVLg==",
"dependencies": {
"IndexRange": "1.0.0",
"Samboy063.WasmDisassembler": "2022.0.2"
"AssetRipper.VersionUtilities": "1.3.1",
"Samboy063.WasmDisassembler": "2022.1.0-development.866"
}
},
"Samboy063.WasmDisassembler": {
"type": "Transitive",
"resolved": "2022.0.2",
"contentHash": "2uu+xBb7M3HKfBx9tAY6jiDieAf0hRnQjSmGX+7IdE6i24dYsx6TYgtrLvRx5lOuF2M8DijZ5H8yQ1pcuCs2SA=="
"resolved": "2022.1.0-development.866",
"contentHash": "2QK8F3eISkLcoW/Nt7wtxyQh31EXAqEMBVXXjEnuxyvXpBXxOIGpjmE3pWhGwxQwDCbe4zBsLF1zUiqq3/pXRA=="
},
"SemanticVersioning": {
"type": "Transitive",
"resolved": "2.0.2",
"contentHash": "4EQgYdNZ92SyaO7YFk6olVnebF5V+jrHyMUjvPq89tLeMo8NSfgDF+6Zwq/lgh9j/0yfQp9Lkm0ZA0rUATCZFA=="
},
"StableNameDotNet": {
"type": "Transitive",
"resolved": "0.1.0-development.866",
"contentHash": "DJb8x4dV3ucDgM12sU28HxCdeqY/JudJbeJG6mgXWDJzpFZw2Jd7JF1pKFRNLzh/0gpo8bCGLQS9gOWZmBjdtg=="
},
"StyleCop.Analyzers.Unstable": {
"type": "Transitive",
"resolved": "1.2.0.435",
"contentHash": "ouwPWZxbOV3SmCZxIRqHvljkSzkCyi1tDoMzQtDb/bRP8ctASV/iRJr+A2Gdj0QLaLmWnqTWDrH82/iP+X80Lg=="
"resolved": "1.2.0.556",
"contentHash": "zvn9Mqs/ox/83cpYPignI8hJEM2A93s2HkHs8HYMOAQW0PkampyoErAiIyKxgTLqbbad29HX/shv/6LGSjPJNQ=="
},
"System.Collections": {
"type": "Transitive",
@@ -642,6 +675,11 @@
"Microsoft.NETCore.Targets": "1.1.0"
}
},
"System.Runtime.CompilerServices.Unsafe": {
"type": "Transitive",
"resolved": "6.0.0",
"contentHash": "/iUeP3tq1S0XdNNoMz5C9twLSrM/TH+qElHkXWaPvuNOt+99G75NrV0OS2EqHx5wMN7popYjpc8oTjC1y16DLg=="
},
"System.Runtime.Extensions": {
"type": "Transitive",
"resolved": "4.3.0",
@@ -840,6 +878,23 @@
"System.Runtime": "4.3.0"
}
},
"System.Text.Encodings.Web": {
"type": "Transitive",
"resolved": "6.0.0",
"contentHash": "Vg8eB5Tawm1IFqj4TVK1czJX89rhFxJo9ELqc/Eiq0eXy13RK00eubyU6TJE6y+GQXjyV5gSfiewDUZjQgSE0w==",
"dependencies": {
"System.Runtime.CompilerServices.Unsafe": "6.0.0"
}
},
"System.Text.Json": {
"type": "Transitive",
"resolved": "6.0.7",
"contentHash": "/Tf/9XjprpHolbcDOrxsKVYy/mUG/FS7aGd9YUgBVEiHeQH4kAE0T1sMbde7q6B5xcrNUsJ5iW7D1RvHudQNqA==",
"dependencies": {
"System.Runtime.CompilerServices.Unsafe": "6.0.0",
"System.Text.Encodings.Web": "6.0.0"
}
},
"System.Threading": {
"type": "Transitive",
"resolved": "4.3.0",
@@ -859,17 +914,12 @@
"System.Runtime": "4.3.0"
}
},
"System.ValueTuple": {
"type": "Transitive",
"resolved": "4.5.0",
"contentHash": "okurQJO6NRE/apDIP23ajJ0hpiNmJ+f0BwOlB/cSqTLQlw5upkf+5+96+iG2Jw40G1fCVCyPz/FhIABUjMR+RQ=="
},
"reactor": {
"type": "Project",
"dependencies": {
"BepInEx.Unity.IL2CPP": "[6.0.0-be.662, )"
"BepInEx.Unity.IL2CPP": "[6.0.0-be.679, )"
}
}
}
}
}
}
2 changes: 2 additions & 0 deletions Reactor.Example/ExamplePlugin.cs
Original file line number Diff line number Diff line change
@@ -25,6 +25,8 @@ public partial class ExamplePlugin : BasePlugin

public override void Load()
{
ReactorCredits.Register<ExamplePlugin>(ReactorCredits.AlwaysShow);

this.AddComponent<ExampleComponent>();

_helloStringName = CustomStringName.CreateAndRegister("Hello!");
188 changes: 119 additions & 69 deletions Reactor.Example/packages.lock.json
Original file line number Diff line number Diff line change
@@ -4,9 +4,9 @@
"net6.0": {
"AmongUs.GameLibs.Steam": {
"type": "Direct",
"requested": "[2022.10.25, )",
"resolved": "2022.10.25",
"contentHash": "PWgkH/VvMlShVhZB8G432q0tnMaNVZrbIdbEMCZN/fETUlT/ch+qQj4PdTcZhPHREbnJHH3ijHxlca1d7QMBcQ=="
"requested": "[2024.8.13, )",
"resolved": "2024.8.13",
"contentHash": "xYZBHQJcwSF5wABtJIZlmpNwZ7jXWafe6vid6/YEWSxpk1fcYLxz42bHSTYcGjpu4wVz1p1ZG/QC4Eu0SbGhrg=="
},
"BepInEx.AutoPlugin": {
"type": "Direct",
@@ -22,72 +22,107 @@
},
"BepInEx.Unity.IL2CPP": {
"type": "Direct",
"requested": "[6.0.0-be.662, )",
"resolved": "6.0.0-be.662",
"contentHash": "fn7jQ88IBmjssoY9XjGBTg3cULkS+N/le/eUijYf2VV8raWok/6cU/GbU9bejkJS8g+2MvzIwnROAhAxvrGI2Q==",
"dependencies": {
"BepInEx.Core": "6.0.0-be.662",
"BepInEx.Unity.Common": "6.0.0-be.662",
"HarmonyX": "2.10.0",
"Iced": "1.17.0",
"Il2CppInterop.Generator": "1.3.0",
"Il2CppInterop.HarmonySupport": "1.3.0",
"Il2CppInterop.Runtime": "1.3.0",
"requested": "[6.0.0-be.679, )",
"resolved": "6.0.0-be.679",
"contentHash": "KnfMjWSXI5+dxbkLCy8VssEnZtTN3MXUHDdBkvPbMiZ6oR1RGZWdLlA90/XQkY/4kMA5P4OCZP4eQ1o0XftbSQ==",
"dependencies": {
"BepInEx.Core": "6.0.0-be.679",
"BepInEx.Unity.Common": "6.0.0-be.679",
"HarmonyX": "2.10.1",
"Iced": "1.18.0",
"Il2CppInterop.Generator": "1.4.6-ci.389",
"Il2CppInterop.HarmonySupport": "1.4.6-ci.389",
"Il2CppInterop.Runtime": "1.4.6-ci.389",
"MonoMod.RuntimeDetour": "22.5.1.1",
"Samboy063.Cpp2IL.Core": "2022.0.7.2"
"Samboy063.Cpp2IL.Core": "2022.1.0-development.866"
}
},
"StyleCop.Analyzers": {
"type": "Direct",
"requested": "[1.2.0-beta.435, )",
"resolved": "1.2.0-beta.435",
"contentHash": "TADk7vdGXtfTnYCV7GyleaaRTQjfoSfZXprQrVMm7cSJtJbFc1QIbWPyLvrgrfGdfHbGmUPvaN4ODKNxg2jgPQ==",
"requested": "[1.2.0-beta.556, )",
"resolved": "1.2.0-beta.556",
"contentHash": "llRPgmA1fhC0I0QyFLEcjvtM2239QzKr/tcnbsjArLMJxJlu0AA5G7Fft0OI30pHF3MW63Gf4aSSsjc5m82J1Q==",
"dependencies": {
"StyleCop.Analyzers.Unstable": "1.2.0.556"
}
},
"AsmResolver": {
"type": "Transitive",
"resolved": "5.1.0",
"contentHash": "7PjujQzgQ3wjzqZYT4CY8SV6zx7FY6swIwj3Yk4QLolLqo9sBPb7FLF3W30QFvCsCkNfiVWXlSbeZKs4xGgQOQ=="
},
"AsmResolver.DotNet": {
"type": "Transitive",
"resolved": "5.1.0",
"contentHash": "oKrBU94OaSrbbTwydvpLRFalYxozrNXGkl13nIkm823ZFQtPNYOiOMJb5DQLvkCJlWyis7q865tg803T5zg9IA==",
"dependencies": {
"StyleCop.Analyzers.Unstable": "1.2.0.435"
"AsmResolver.PE": "5.1.0",
"System.Text.Json": "6.0.7"
}
},
"AsmResolver.PE": {
"type": "Transitive",
"resolved": "5.1.0",
"contentHash": "XD3iAgLSInJIODKUUlpHWXf8MR9H1SFMb1lsmabb4GxxxnDQRPjMxjglv2NOCjQQuNB2Oh0bvjHE7ewf82UqyQ==",
"dependencies": {
"AsmResolver.PE.File": "5.1.0"
}
},
"AsmResolver.PE.File": {
"type": "Transitive",
"resolved": "5.1.0",
"contentHash": "YituBYe0Fh471sXQMfu+f4tWKX/JZvRwrX6g/SVsr4XkUIUzYi/aGT3/QvjHoYx19fE1KYOB6zBKqPkkOK7HPw==",
"dependencies": {
"AsmResolver": "5.1.0"
}
},
"AssetRipper.VersionUtilities": {
"type": "Transitive",
"resolved": "1.2.1",
"contentHash": "knQ/W1YwTZS2AbdaZh+nhyyBEZQPQDcahhSOnh88i+cdg4/FEoFJiCwaavgFvCMNuUeHTbcZc4qttF8WQ8xLIA=="
"resolved": "1.3.1",
"contentHash": "/1D18NOpqm7rS7+qVUbAReVMNWwgDuYpsnf0RkX1Aah/I0a0irqldoFJ+Kku7YdbSm0zqD+Z6iYUGKoP3GwTNQ=="
},
"BepInEx.Core": {
"type": "Transitive",
"resolved": "6.0.0-be.662",
"contentHash": "VVBeCD/KQVy0/TK3V6SD8QZ/es35Xb1mEz/+PbBs3ST1yUC1r7k2JOymhSnmghVqf6UsvlMglOO9pljqhuE/Pw==",
"resolved": "6.0.0-be.679",
"contentHash": "yg6NSGeevv86P2ERe3VDEa7W/l0lmM7m+AdPSW78dcBOe36Zc3QK/vmNEq57txGa+1kwv+macXLSwkL4UpucjA==",
"dependencies": {
"HarmonyX": "2.10.0",
"HarmonyX": "2.10.1",
"MonoMod.Utils": "22.5.1.1",
"SemanticVersioning": "2.0.2"
}
},
"BepInEx.Unity.Common": {
"type": "Transitive",
"resolved": "6.0.0-be.662",
"contentHash": "BgETw6+snwY//3xjQxLiiEAFRmXaMTcSkg+1UQz6fVBG0YA5Usm/m4GflhTc3nwF61KO3Iznn1AORi5CwLJoUw==",
"resolved": "6.0.0-be.679",
"contentHash": "q4Sux3ULBDasSQAtlAWzAKpAfCyV3ujxVJpK7ydV1bUIksaHNqw9yYTLCUrw8p4DQ/wHvShECFjzeMGHi+wylA==",
"dependencies": {
"AssetRipper.VersionUtilities": "1.2.1",
"MonoMod.Utils": "22.5.1.1"
}
},
"Disarm": {
"type": "Transitive",
"resolved": "2022.1.0-master.26",
"contentHash": "YnZEbRGr0nG+N3G8WbRQ4Lkg8dTD3oso9iJlCVBmyhEyhLyqs+drBs1kWQbQqFPnb9mi/RJ++R9bPb+L3HF03Q=="
},
"HarmonyX": {
"type": "Transitive",
"resolved": "2.10.0",
"contentHash": "4ayiy/dlCiW86K2N7Jvbf+VpI5wvP7dncv/6oRmfwRi32UCmCRzCGzsxdMfzJZkp6/26oBW+DrD8vi4UejzVAg==",
"resolved": "2.10.1",
"contentHash": "9LodMC9Y0u1TW96eKJoWrFJFpmzbgojEO38/Q+e7c1mFPhmHt8xcR8qhI06iF1rf0Dnsk+hqENFVSgbtwl/bEw==",
"dependencies": {
"MonoMod.RuntimeDetour": "22.3.23.4",
"System.Reflection.Emit": "4.7.0"
}
},
"Iced": {
"type": "Transitive",
"resolved": "1.17.0",
"contentHash": "8x+HCVTl/HHTGpscH3vMBhV8sknN/muZFw9s3TsI8SA6+c43cOTCi2+jE4KsU8pNLbJ++iF2ZFcpcXHXtDglnw=="
"resolved": "1.18.0",
"contentHash": "G60lZOvbvqttA+SBSv/yY6/wUboXKJlkffhSNR9iOrx0M5gpcK1TRr6xrFR+qAhqIAhvrsPF1jkn9fYb4lEufQ=="
},
"Il2CppInterop.Common": {
"type": "Transitive",
"resolved": "1.3.0",
"contentHash": "IR3BrZXvL2nvJAn4pruPMgC78Y87hVa5xTYZCuHN67OzRD6WDl5dTO55vtvTl8dXFALKvlN+spja2tXhVuquOw==",
"resolved": "1.4.6-ci.389",
"contentHash": "KTyf2f66Q2mS9a6xhvoPWwD0VzRIoskPMVQehaVMo1dx4Di1FPFsKqukQ+ob6wgP5Rbnx53kiH0PY+IRSb35XA==",
"dependencies": {
"Iced": "1.17.0",
"Microsoft.Extensions.Logging.Abstractions": "6.0.1",
@@ -96,36 +131,31 @@
},
"Il2CppInterop.Generator": {
"type": "Transitive",
"resolved": "1.3.0",
"contentHash": "FuhPxbh/K4K94U3xac/ClMaaBp+MZ4aIaqi5dR0QihyGQoombT+OM/A22RwAIzbaCTbFbvabWaAuOSgB69ZwWQ==",
"resolved": "1.4.6-ci.389",
"contentHash": "XJX4sn/RzAEBNIZZXuyDcLZrFx5tCoahujDu5aKWjApiMj/nTRQAxZn17daIIvd9aHqLaAfiWWth5QDLIt2bKw==",
"dependencies": {
"Il2CppInterop.Common": "1.3.0",
"Il2CppInterop.Common": "1.4.6-ci.389",
"Mono.Cecil": "0.11.3"
}
},
"Il2CppInterop.HarmonySupport": {
"type": "Transitive",
"resolved": "1.3.0",
"contentHash": "VppBnXtbMNGFhX8a1gg/85E883t2pW/+FZyV7eOaOXMNQyorg++u+kUFOIYwNpzTVqxWmMeoPS0DH0toVpjoKA==",
"resolved": "1.4.6-ci.389",
"contentHash": "Xd2zK6sLqwA0ReyUy83SWKcALwY99fq6vVL5gFOMN5Ct8OOVhtNIws0ysCWsfx1GL0RJiRYfR4pza/MmWRz4PQ==",
"dependencies": {
"HarmonyX": "2.10.0",
"Il2CppInterop.Runtime": "1.3.0"
"Il2CppInterop.Runtime": "1.4.6-ci.389"
}
},
"Il2CppInterop.Runtime": {
"type": "Transitive",
"resolved": "1.3.0",
"contentHash": "8A+N2yvja960Ap+s2RpW7Nb6HSpyuXJy2ipIlU+1erYU9SWHMyU9JZzUZGOhwWXJChKGvRmDdTZAg12k1+72dg==",
"resolved": "1.4.6-ci.389",
"contentHash": "nzYjuVzDG/O8+AQ8ax3WVHf+ZVsQKrVtp/yvuW8XoEPLdkbgryIrMo75dvN+tPqxOU3o2MPt9MZ9j25P5aVJMw==",
"dependencies": {
"Iced": "1.17.0",
"Il2CppInterop.Common": "1.3.0"
"Il2CppInterop.Common": "1.4.6-ci.389"
}
},
"IndexRange": {
"type": "Transitive",
"resolved": "1.0.0",
"contentHash": "6TgS1JLSUkpmPLfXBPaAgB39ZUix8E4soXWk2XSDcscVe84i1JKzIAtA7jHbRHSkOOrcr6YA0MpLCeq98y9mYQ=="
},
"js6pak.Gee.External.Capstone": {
"type": "Transitive",
"resolved": "2.1.0",
@@ -280,42 +310,45 @@
},
"Samboy063.Cpp2IL.Core": {
"type": "Transitive",
"resolved": "2022.0.7.2",
"contentHash": "e17CAhKSxdAp7vFcYEVxjSc7t7rcvVGBipGhgE9tAjRXY85wZXLlHEVO0AEvMRkLmf9U+if4wK/nZEC1AX6VqQ==",
"resolved": "2022.1.0-development.866",
"contentHash": "QPMuix/3jRngWBdNSLhAbm9BHYf95Ln1Ph1eCK/cDZdVibxFDFP3a6Yczyx1p7GbN7bRQwrhs2skPJSS/z3m2w==",
"dependencies": {
"HarmonyX": "2.5.5",
"Iced": "1.11.1",
"IndexRange": "1.0.0",
"Mono.Cecil": "0.11.4",
"Samboy063.LibCpp2IL": "2022.0.7.2",
"System.Runtime.InteropServices": "4.3.0",
"System.ValueTuple": "4.5.0",
"AsmResolver.DotNet": "5.1.0",
"Disarm": "2022.1.0-master.26",
"Iced": "1.18.0",
"Samboy063.LibCpp2IL": "2022.1.0-development.866",
"StableNameDotNet": "0.1.0-development.866",
"js6pak.Gee.External.Capstone": "2.1.0"
}
},
"Samboy063.LibCpp2IL": {
"type": "Transitive",
"resolved": "2022.0.7.2",
"contentHash": "DpVeU0dQkUJCpbw0f1xKOG8vimdK2oYhrVABC7HDE3/ikGjhnMZd3i5b1joKDHZ+AiL90TWOaEXPcy24rCZ0dA==",
"resolved": "2022.1.0-development.866",
"contentHash": "EcJSWTfQko8SQozozoUT+aQJVWC8wj8C0YUiPBF4rNRId19yTKp2IXcXnI747v+8/aal222QR6WHfoBK2WlVLg==",
"dependencies": {
"IndexRange": "1.0.0",
"Samboy063.WasmDisassembler": "2022.0.2"
"AssetRipper.VersionUtilities": "1.3.1",
"Samboy063.WasmDisassembler": "2022.1.0-development.866"
}
},
"Samboy063.WasmDisassembler": {
"type": "Transitive",
"resolved": "2022.0.2",
"contentHash": "2uu+xBb7M3HKfBx9tAY6jiDieAf0hRnQjSmGX+7IdE6i24dYsx6TYgtrLvRx5lOuF2M8DijZ5H8yQ1pcuCs2SA=="
"resolved": "2022.1.0-development.866",
"contentHash": "2QK8F3eISkLcoW/Nt7wtxyQh31EXAqEMBVXXjEnuxyvXpBXxOIGpjmE3pWhGwxQwDCbe4zBsLF1zUiqq3/pXRA=="
},
"SemanticVersioning": {
"type": "Transitive",
"resolved": "2.0.2",
"contentHash": "4EQgYdNZ92SyaO7YFk6olVnebF5V+jrHyMUjvPq89tLeMo8NSfgDF+6Zwq/lgh9j/0yfQp9Lkm0ZA0rUATCZFA=="
},
"StableNameDotNet": {
"type": "Transitive",
"resolved": "0.1.0-development.866",
"contentHash": "DJb8x4dV3ucDgM12sU28HxCdeqY/JudJbeJG6mgXWDJzpFZw2Jd7JF1pKFRNLzh/0gpo8bCGLQS9gOWZmBjdtg=="
},
"StyleCop.Analyzers.Unstable": {
"type": "Transitive",
"resolved": "1.2.0.435",
"contentHash": "ouwPWZxbOV3SmCZxIRqHvljkSzkCyi1tDoMzQtDb/bRP8ctASV/iRJr+A2Gdj0QLaLmWnqTWDrH82/iP+X80Lg=="
"resolved": "1.2.0.556",
"contentHash": "zvn9Mqs/ox/83cpYPignI8hJEM2A93s2HkHs8HYMOAQW0PkampyoErAiIyKxgTLqbbad29HX/shv/6LGSjPJNQ=="
},
"System.Collections": {
"type": "Transitive",
@@ -642,6 +675,11 @@
"Microsoft.NETCore.Targets": "1.1.0"
}
},
"System.Runtime.CompilerServices.Unsafe": {
"type": "Transitive",
"resolved": "6.0.0",
"contentHash": "/iUeP3tq1S0XdNNoMz5C9twLSrM/TH+qElHkXWaPvuNOt+99G75NrV0OS2EqHx5wMN7popYjpc8oTjC1y16DLg=="
},
"System.Runtime.Extensions": {
"type": "Transitive",
"resolved": "4.3.0",
@@ -840,6 +878,23 @@
"System.Runtime": "4.3.0"
}
},
"System.Text.Encodings.Web": {
"type": "Transitive",
"resolved": "6.0.0",
"contentHash": "Vg8eB5Tawm1IFqj4TVK1czJX89rhFxJo9ELqc/Eiq0eXy13RK00eubyU6TJE6y+GQXjyV5gSfiewDUZjQgSE0w==",
"dependencies": {
"System.Runtime.CompilerServices.Unsafe": "6.0.0"
}
},
"System.Text.Json": {
"type": "Transitive",
"resolved": "6.0.7",
"contentHash": "/Tf/9XjprpHolbcDOrxsKVYy/mUG/FS7aGd9YUgBVEiHeQH4kAE0T1sMbde7q6B5xcrNUsJ5iW7D1RvHudQNqA==",
"dependencies": {
"System.Runtime.CompilerServices.Unsafe": "6.0.0",
"System.Text.Encodings.Web": "6.0.0"
}
},
"System.Threading": {
"type": "Transitive",
"resolved": "4.3.0",
@@ -859,15 +914,10 @@
"System.Runtime": "4.3.0"
}
},
"System.ValueTuple": {
"type": "Transitive",
"resolved": "4.5.0",
"contentHash": "okurQJO6NRE/apDIP23ajJ0hpiNmJ+f0BwOlB/cSqTLQlw5upkf+5+96+iG2Jw40G1fCVCyPz/FhIABUjMR+RQ=="
},
"reactor": {
"type": "Project",
"dependencies": {
"BepInEx.Unity.IL2CPP": "[6.0.0-be.662, )"
"BepInEx.Unity.IL2CPP": "[6.0.0-be.679, )"
}
}
}
6 changes: 3 additions & 3 deletions Reactor.Networking.Shared/Mod.cs
Original file line number Diff line number Diff line change
@@ -94,18 +94,18 @@ internal static bool Validate(IReadOnlyCollection<Mod> clientMods, IReadOnlyColl
var clientMissing = hostMods.Where(mod => mod.IsRequiredOnAllClients && !clientMods.Contains(mod)).ToArray();
var hostMissing = clientMods.Where(mod => mod.IsRequiredOnAllClients && !hostMods.Contains(mod)).ToArray();

if (clientMissing.Any() || hostMissing.Any())
if (clientMissing.Length != 0 || hostMissing.Length != 0)
{
var message = new StringBuilder();

if (clientMissing.Any())
if (clientMissing.Length != 0)
{
message.Append("You are missing: ");
message.AppendJoin(", ", clientMissing.Select(x => x.ToString()));
message.AppendLine();
}

if (hostMissing.Any())
if (hostMissing.Length != 0)
{
message.Append("Host is missing: ");
message.AppendJoin(", ", hostMissing.Select(x => x.ToString()));
5 changes: 5 additions & 0 deletions Reactor.Networking.Shared/ModFlags.cs
Original file line number Diff line number Diff line change
@@ -27,4 +27,9 @@ public enum ModFlags : ushort
/// Requires the host of the lobby to have the mod.
/// </summary>
RequireOnHost = 1 << 2,

/// <summary>
/// Notifies the game server that the host has authority over game logic.
/// </summary>
DisableServerAuthority = 1 << 3,
}
Binary file modified Reactor/Assets/default-android.bundle
Binary file not shown.
Binary file removed Reactor/Assets/default-win-x86.bundle
Binary file not shown.
Binary file added Reactor/Assets/default-win.bundle
Binary file not shown.
35 changes: 35 additions & 0 deletions Reactor/Networking/HandshakePopup.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
using Reactor.Utilities.UI;
using UnityEngine;

namespace Reactor.Networking;

internal static class HandshakePopup
{
public const string Message =
"""
This server doesn't support Reactor's modded handshake.
The lobbies shown could be incompatible with your current mods.
For more info see <link=https://reactor.gg/handshake>reactor.gg/handshake</link>
""";

private static ReactorPopup? _popup;

public static void Show()
{
if (_popup == null)
{
_popup = ReactorPopup.Create(nameof(HandshakePopup));
_popup.Background.transform.localPosition = new Vector3(0, 0.20f, 0);
_popup.Background.size = new Vector2(6.5f, 1.7f);
_popup.BackButton.transform.SetLocalY(-0.2f);
}

var message = ReactorConfig.HandshakePopupMessage.Value;
if (string.IsNullOrEmpty(message))
{
message = Message;
}

_popup.Show(message);
}
}
34 changes: 34 additions & 0 deletions Reactor/Networking/MakePublicDisallowedPopup.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
using Reactor.Utilities.UI;
using UnityEngine;

namespace Reactor.Networking;

internal static class MakePublicDisallowedPopup
{
public const string Message =
"""
You can't make public lobbies on servers that don't support modded handshake.
For more info see <link=https://reactor.gg/handshake>reactor.gg/handshake</link>
""";

private static ReactorPopup? _popup;

public static void Show()
{
if (_popup == null)
{
_popup = ReactorPopup.Create(nameof(MakePublicDisallowedPopup));
_popup.Background.transform.localPosition = new Vector3(0, 0.25f, 0);
_popup.Background.size = new Vector2(7.5f, 1.5f);
_popup.BackButton.transform.SetLocalY(-0.1f);
}

var message = ReactorConfig.MakePublicDisallowedPopupMessage.Value;
if (string.IsNullOrEmpty(message))
{
message = Message;
}

_popup.Show(message);
}
}
8 changes: 7 additions & 1 deletion Reactor/Networking/ModList.cs
Original file line number Diff line number Diff line change
@@ -39,6 +39,9 @@ internal static Mod GetByPluginType(Type pluginType)
return _modByPluginType[pluginType];
}

internal static bool IsAnyModRequiredOnAllClients { get; private set; }
internal static bool IsAnyModDisableServerAuthority { get; private set; }

private static readonly Dictionary<uint, Mod> _modByNetId = new();
private static readonly Dictionary<Mod, uint> _netIdByMod = new();

@@ -98,7 +101,7 @@ private static void Refresh()
.Select(pluginInfo => GetById(pluginInfo.Metadata.GUID))
.OrderByDescending(x => x.Id == ReactorPlugin.Id)
.ThenBy(x => x.Id, StringComparer.Ordinal)
.ToHashSet();
.ToArray();

_modByNetId.Clear();
_netIdByMod.Clear();
@@ -113,6 +116,9 @@ private static void Refresh()
netId++;
}

IsAnyModRequiredOnAllClients = Current.Any(m => m.IsRequiredOnAllClients);
IsAnyModDisableServerAuthority = Current.Any(m => (m.Flags & ModFlags.DisableServerAuthority) != 0);

var debug = new StringBuilder("Mod list:");
foreach (var mod in Current)
{
95 changes: 73 additions & 22 deletions Reactor/Networking/Patches/ClientPatches.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
using System;
using System.Linq;
using AmongUs.Data;
using BepInEx.Unity.IL2CPP.Utils;
using HarmonyLib;
using Hazel;
using Il2CppInterop.Runtime;
@@ -7,6 +10,7 @@
using Reactor.Networking.Extensions;
using Reactor.Networking.Messages;
using UnityEngine;
using IEnumerator = System.Collections.IEnumerator;

namespace Reactor.Networking.Patches;

@@ -25,10 +29,10 @@ public static void Prefix(InnerNetClient __instance, ref DisconnectReasons reaso
}
}

[HarmonyPatch(typeof(InnerNetClient._HandleGameDataInner_d__39), nameof(InnerNetClient._HandleGameDataInner_d__39.MoveNext))]
[HarmonyPatch(typeof(InnerNetClient._HandleGameDataInner_d__41), nameof(InnerNetClient._HandleGameDataInner_d__41.MoveNext))]
public static class HandleGameDataInnerPatch
{
public static bool Prefix(InnerNetClient._HandleGameDataInner_d__39 __instance, ref bool __result)
public static bool Prefix(InnerNetClient._HandleGameDataInner_d__41 __instance, ref bool __result)
{
var innerNetClient = __instance.__4__this;
var reader = __instance.reader;
@@ -59,7 +63,7 @@ public static bool Prefix(InnerNetClient._HandleGameDataInner_d__39 __instance,
return false;
}

if (ReactorConnection.Instance!.Syncer == Syncer.Host && reader.Tag == InnerNetClient.SceneChangeFlag)
if (reader.Tag == InnerNetClient.SceneChangeFlag && ReactorConnection.Instance?.Syncer == Syncer.Host)
{
var clientId = reader.ReadPackedInt32();
var clientData = innerNetClient.FindClientById(clientId);
@@ -83,17 +87,56 @@ public static bool Prefix(InnerNetClient._HandleGameDataInner_d__39 __instance,

if (innerNetClient.AmHost)
{
if (reactorClientData == null)
if (reactorClientData == null && ModList.IsAnyModRequiredOnAllClients)
{
Warning("Kicking " + clientData.PlayerName + " for not having Reactor installed");
PlayerControl.LocalPlayer.RpcSendChat(clientData.PlayerName + " tried joining without Reactor installed");
innerNetClient.KickPlayer(clientData.Id, false);
IEnumerator CoKick()
{
var startTime = DateTimeOffset.UtcNow;
string? playerName;

__result = false;
return false;
}
do
{
yield return null;

if (DateTimeOffset.UtcNow - startTime > TimeSpan.FromSeconds(2))
{
playerName = "(unknown)";
break;
}

playerName = GameData.Instance.GetPlayerByClient(clientData)?.PlayerName;
} while (string.IsNullOrEmpty(playerName));

Warning("Kicking " + playerName + " for not having Reactor installed");

const int ChatMessageLimit = 100;

var chatText = $"{playerName} tried joining without the following mods:";
foreach (var mod in ModList.Current.Where(m => m.IsRequiredOnAllClients))
{
chatText += $"\n- {mod}";
}

HudManager.Instance.Chat.AddChat(PlayerControl.LocalPlayer, chatText, false);

if (!Mod.Validate(reactorClientData.Mods, ModList.Current, out var reason))
if (DataManager.Settings.Multiplayer.ChatMode == QuickChatModes.FreeChatOrQuickChat)
{
var truncatedChatText = chatText.Length > ChatMessageLimit
? chatText[..(ChatMessageLimit - 3)] + "..."
: chatText;

// Write SendChat directly instead of using RpcSendChat so we can call AddChat ourselves
var messageWriter = AmongUsClient.Instance.StartRpc(PlayerControl.LocalPlayer.NetId, (byte) RpcCalls.SendChat);
messageWriter.Write(truncatedChatText);
messageWriter.EndMessage();
}

innerNetClient.KickPlayer(clientData.Id, false);
}

innerNetClient.StartCoroutine(CoKick());
}
else if (!Mod.Validate(reactorClientData?.Mods ?? Array.Empty<Mod>(), ModList.Current, out var reason))
{
innerNetClient.KickWithReason(clientData.Id, reason);
__result = false;
@@ -118,18 +161,22 @@ public static bool Prefix(InnerNetClient._HandleGameDataInner_d__39 __instance,
}
}

[HarmonyPatch(typeof(InnerNetClient._CoSendSceneChange_d__30), nameof(InnerNetClient._CoSendSceneChange_d__30.MoveNext))]
[HarmonyPatch(typeof(InnerNetClient._CoSendSceneChange_d__32), nameof(InnerNetClient._CoSendSceneChange_d__32.MoveNext))]
public static class CoSendSceneChangePatch
{
public static bool Prefix(InnerNetClient._CoSendSceneChange_d__30 __instance, ref bool __result)
public static bool Prefix(InnerNetClient._CoSendSceneChange_d__32 __instance, ref bool __result)
{
if (ReactorConnection.Instance!.Syncer != Syncer.Host) return true;

var innerNetClient = __instance.__4__this;

if (__instance.__1__state == 2)
// Check for the conditions when the scene change message should be sent
if (!innerNetClient.AmHost &&
innerNetClient.connection.State == ConnectionState.Connected &&
innerNetClient.ClientId >= 0)
{
if (!innerNetClient.AmHost && innerNetClient.connection.State == ConnectionState.Connected)
var clientData = innerNetClient.FindClientById(innerNetClient.ClientId);
if (clientData != null)
{
var writer = MessageWriter.Get(SendOption.Reliable);
writer.StartMessage(Tags.GameData);
@@ -147,21 +194,25 @@ public static bool Prefix(InnerNetClient._CoSendSceneChange_d__30 __instance, re
writer.EndMessage();
innerNetClient.SendOrDisconnect(writer);
writer.Recycle();
}

__instance.__1__state = -1;
__result = false;
return false;
// Create a new coroutine to let AmongUsClient handle scene changes too
innerNetClient.StartCoroutine(innerNetClient.CoOnPlayerChangedScene(clientData, __instance.sceneName));

// Cancel this coroutine
__instance.__1__state = -1;
__result = false;
return false;
}
}

return true;
}
}

[HarmonyPatch(typeof(InnerNetClient._CoHandleSpawn_d__40), nameof(InnerNetClient._CoHandleSpawn_d__40.MoveNext))]
[HarmonyPatch(typeof(InnerNetClient._CoHandleSpawn_d__42), nameof(InnerNetClient._CoHandleSpawn_d__42.MoveNext))]
public static class CoHandleSpawnPatch
{
public static void Postfix(InnerNetClient._CoHandleSpawn_d__40 __instance, bool __result)
public static void Postfix(InnerNetClient._CoHandleSpawn_d__42 __instance, bool __result)
{
if (ReactorConnection.Instance!.Syncer != Syncer.Host) return;

@@ -234,7 +285,7 @@ public static class HandleMessagePatch
{
public static bool Prefix(InnerNetClient __instance, [HarmonyArgument(0)] MessageReader reader)
{
if (__instance.GameMode == GameModes.FreePlay) return true;
if (__instance.NetworkMode == NetworkModes.FreePlay) return true;

var isFirst = false;

33 changes: 8 additions & 25 deletions Reactor/Networking/Patches/HttpPatches.cs
Original file line number Diff line number Diff line change
@@ -5,7 +5,6 @@
using UnityEngine;
using UnityEngine.Networking;
using UnityEngine.UI;
using Object = UnityEngine.Object;

namespace Reactor.Networking.Patches;

@@ -85,9 +84,9 @@ public static void Postfix(UnityWebRequest __instance, UnityWebRequestAsyncOpera

if (__instance.GetMethod() == UnityWebRequest.UnityWebRequestMethod.Get)
{
if (responseHeader == null)
if (responseHeader == null && ModList.IsAnyModRequiredOnAllClients)
{
DisconnectPopup.Instance.ShowCustom("This region doesn't support modded handshake.\nThe lobbies shown may not be compatible with your current mods.\nFor more info see https://reactor.gg/handshake");
HandshakePopup.Show();
}
}

@@ -102,32 +101,16 @@ private static class GameStartManagerPatch
{
public static void Postfix(GameStartManager __instance)
{
if (AmongUsClient.Instance.GameMode != GameModes.OnlineGame) return;
if (ModList.Current.Any(m => m.IsRequiredOnAllClients) && !IsCurrentRegionModded())
if (AmongUsClient.Instance.NetworkMode != NetworkModes.OnlineGame) return;
if (ModList.IsAnyModRequiredOnAllClients && !IsCurrentRegionModded())
{
Warning("Vanilla region, locking public toggle");

__instance.MakePublicButtonBehaviour.enabled = false;
var actionMapGlyphDisplay = __instance.MakePublicButton.GetComponentInChildren<ActionMapGlyphDisplay>(includeInactive: true);
if (actionMapGlyphDisplay)
{
actionMapGlyphDisplay.gameObject.SetActive(value: false);
}

__instance.MakePublicButton.color = new Color(1, 1, 1, 0.5f);
__instance.MakePublicButton.sprite = __instance.PrivateGameImage;
__instance.HostPublicButton.enabled = false;
__instance.HostPrivateButton.transform.FindChild("Inactive").GetComponent<SpriteRenderer>().color = new Color(1, 1, 1, 0.5f);

var onClick = __instance.MakePublicButton.GetComponent<PassiveButton>().OnClick = new Button.ButtonClickedEvent();
onClick.AddListener((Action) (() =>
{
var popup = Object.Instantiate(DiscordManager.Instance.discordPopup, Camera.main!.transform);
var background = popup.transform.Find("Background").GetComponent<SpriteRenderer>();
var size = background.size;
size.x *= 2.5f;
background.size = size;
popup.TextAreaTMP.fontSizeMin = 2;
popup.Show("You can't make public lobbies on regions that don't support modded handshake.\nFor more info see https://reactor.gg/handshake");
}));
var onClick = __instance.HostPrivateButton.OnClick = new Button.ButtonClickedEvent();
onClick.AddListener((Action) MakePublicDisallowedPopup.Show);

if (AmongUsClient.Instance.AmHost && AmongUsClient.Instance.IsGamePublic)
{
2 changes: 1 addition & 1 deletion Reactor/Networking/Patches/ReactorClientData.cs
Original file line number Diff line number Diff line change
@@ -4,7 +4,7 @@

namespace Reactor.Networking.Patches;

internal class ReactorClientData
internal sealed class ReactorClientData
{
public ClientData ClientData { get; }

2 changes: 1 addition & 1 deletion Reactor/Networking/Rpc/UnsafeCustomRpc.cs
Original file line number Diff line number Diff line change
@@ -96,7 +96,7 @@ protected UnsafeCustomRpc(BasePlugin plugin, uint id)
/// <param name="ackCallback">The callback to invoke when this packet is acknowledged.</param>
public void UnsafeSend(InnerNetObject innerNetObject, object? data, bool immediately = false, int targetClientId = -1, Action? ackCallback = null)
{
if (innerNetObject == null) throw new ArgumentNullException(nameof(innerNetObject));
ArgumentNullException.ThrowIfNull(innerNetObject);

if (Manager == null)
{
18 changes: 18 additions & 0 deletions Reactor/Patches/Fixes/CoFindGamePatch.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
using HarmonyLib;

namespace Reactor.Patches.Fixes;

/// <summary>
/// Fixes Game Lists not working on servers using legacy matchmaking.
/// </summary>
[HarmonyPatch(typeof(AmongUsClient._CoFindGame_d__3), nameof(AmongUsClient._CoFindGame_d__3.MoveNext))]
internal static class CoFindGamePatch
{
public static void Prefix()
{
if (AmongUsClient.Instance.LastDisconnectReason == DisconnectReasons.Unknown)
{
AmongUsClient.Instance.LastDisconnectReason = DisconnectReasons.ExitGame;
}
}
}
10 changes: 9 additions & 1 deletion Reactor/Patches/Fixes/CursorPosPatch.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using HarmonyLib;
using TMPro;
using UnityEngine;
@@ -8,14 +10,20 @@ namespace Reactor.Patches.Fixes;
/// <summary>
/// "Fixes" an issue where empty TextBoxes have wrong cursor positions.
/// </summary>
[HarmonyPatch(typeof(TextMeshProExtensions), nameof(TextMeshProExtensions.CursorPos))]
[HarmonyPatch]
internal static class CursorPosPatch
{
public static IEnumerable<MethodBase> TargetMethods()
{
return AccessTools.GetDeclaredMethods(typeof(TextMeshProExtensions)).Where(m => m.Name == nameof(TextMeshProExtensions.CursorPos));
}

public static bool Prefix(TextMeshPro self, ref Vector2 __result)
{
if (self.textInfo == null || self.textInfo.lineCount == 0 || self.textInfo.lineInfo[0].characterCount <= 0)
{
__result = self.GetTextInfo(" ").lineInfo.First().lineExtents.max;
self.text = string.Empty;
return false;
}

18 changes: 17 additions & 1 deletion Reactor/Patches/Miscellaneous/CustomServersPatch.cs
Original file line number Diff line number Diff line change
@@ -1,15 +1,31 @@
using System;
using System.Linq;
using HarmonyLib;

namespace Reactor.Patches.Miscellaneous;

[HarmonyPatch]
internal static class CustomServersPatch
{
private static bool IsCurrentServerOfficial()
{
const string Domain = "among.us";

return ServerManager.Instance.CurrentRegion?.TryCast<StaticHttpRegionInfo>() is { } regionInfo &&
regionInfo.PingServer.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(typeof(AuthManager._CoWaitForNonce_d__6), nameof(AuthManager._CoWaitForNonce_d__6.MoveNext))]
[HarmonyPrefix]
public static bool DisableAuthServer(out bool __result)
public static bool DisableAuthServer(ref bool __result)
{
if (IsCurrentServerOfficial())
{
return true;
}

__result = false;
return false;
}
41 changes: 41 additions & 0 deletions Reactor/Patches/Miscellaneous/DisableServerAuthorityPatch.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
using HarmonyLib;
using Reactor.Networking;

namespace Reactor.Patches.Miscellaneous;

[HarmonyPatch]
internal static class DisableServerAuthorityPatch
{
private const int DisableServerAuthorityFlag = 25;

public static bool Enabled => ModList.IsAnyModDisableServerAuthority || ReactorConfig.ForceDisableServerAuthority.Value;

[HarmonyPatch(typeof(Constants), nameof(Constants.GetBroadcastVersion))]
[HarmonyPostfix]
public static void GetBroadcastVersionPatch(ref int __result)
{
if (!Enabled) return;
if (AmongUsClient.Instance.NetworkMode != NetworkModes.OnlineGame) return;

Debug("Sending the DisableServerAuthority flag");

var revision = __result % 50;
if (revision < DisableServerAuthorityFlag)
{
__result += DisableServerAuthorityFlag;
}
}

[HarmonyPatch(typeof(Constants), nameof(Constants.IsVersionModded))]
[HarmonyPrefix]
public static bool IsVersionModdedPatch(ref bool __result)
{
if (Enabled)
{
__result = true;
return false;
}

return true;
}
}
9 changes: 3 additions & 6 deletions Reactor/Patches/Miscellaneous/FreeNamePatch.cs
Original file line number Diff line number Diff line change
@@ -30,20 +30,17 @@ public static void Initialize()
var editName = DestroyableSingleton<AccountManager>.Instance.accountTab.editNameScreen;
var nameText = Object.Instantiate(editName.nameText.gameObject);

nameText.transform.localPosition += Vector3.up * 2.2f;
nameText.transform.localPosition += Vector3.up * (AccountManager.Instance.isActiveAndEnabled ? 1.85f : 2.2f);

var textBox = nameText.GetComponent<TextBoxTMP>();
textBox.outputText.alignment = TextAlignmentOptions.CenterGeoAligned;
textBox.outputText.transform.position = nameText.transform.position;
textBox.outputText.fontSize = 4f;

textBox.OnChange.AddListener((Action) (() =>
{
DataManager.Player.Customization.Name = textBox.text;
}));
textBox.OnEnter = textBox.OnFocusLost = textBox.OnChange;

textBox.Pipe.GetComponent<TextMeshPro>().fontSize = 4f;
}));
}

@@ -56,10 +53,10 @@ private static bool TryMoveObjects()
"JoinGameButton",
};

var yStart = Vector3.up;
var yStart = Vector3.up * (AccountManager.Instance.isActiveAndEnabled ? 0.9f : 1.1f);
var yOffset = Vector3.down * 1.5f;

var gameObjects = toMove.Select(x => GameObject.Find("NormalMenu/" + x)).ToList();
var gameObjects = toMove.Select(x => GameObject.Find("NormalMenu/Buttons/" + x)).ToList();
if (gameObjects.Any(x => x == null)) return false;

for (var i = 0; i < gameObjects.Count; i++)
21 changes: 21 additions & 0 deletions Reactor/Patches/Miscellaneous/PingTrackerPatch.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
using System;
using HarmonyLib;
using Reactor.Utilities;

namespace Reactor.Patches.Miscellaneous;

[HarmonyPatch(typeof(PingTracker), nameof(PingTracker.Update))]
internal static class PingTrackerPatch
{
[HarmonyPostfix]
[HarmonyPriority(Priority.Last)]
public static void Postfix(PingTracker __instance)
{
var extraText = ReactorCredits.GetText(ReactorCredits.Location.PingTracker);
if (extraText != null)
{
if (!__instance.text.text.EndsWith("\n", StringComparison.InvariantCulture)) __instance.text.text += "\n";
__instance.text.text += extraText;
}
}
}
83 changes: 57 additions & 26 deletions Reactor/Patches/ReactorVersionShower.cs
Original file line number Diff line number Diff line change
@@ -2,6 +2,7 @@
using BepInEx;
using BepInEx.Unity.IL2CPP;
using HarmonyLib;
using Reactor.Utilities;
using Reactor.Utilities.Extensions;
using TMPro;
using UnityEngine;
@@ -25,56 +26,86 @@ public static class ReactorVersionShower
/// </summary>
public static event Action<TextMeshPro>? TextUpdated;

private static void SetMainMenuPositionFromAspect(float aspectRatio)
{
if (Text == null) return;
var pos = new Vector3(-1.2287f * aspectRatio + 10.9f, -0.57f, 4.5f);
Text.transform.position = pos;
}

private static readonly ResolutionManager.ResolutionChangedHandler _resolutionChangedHandler = (Action<float, int, int, bool>) ((aspectRatio, _, _, _) =>
{
SetMainMenuPositionFromAspect(aspectRatio);
});

internal static void Initialize()
{
SceneManager.add_sceneLoaded((Action<Scene, LoadSceneMode>) ((_, _) =>
SceneManager.add_sceneLoaded((Action<Scene, LoadSceneMode>) ((scene, _) =>
{
var original = UnityEngine.Object.FindObjectOfType<VersionShower>();
if (!original)
return;

var gameObject = new GameObject("ReactorVersion " + Guid.NewGuid());
gameObject.transform.parent = original.transform.parent;

var aspectPosition = gameObject.AddComponent<AspectPosition>();

aspectPosition.Alignment = AspectPosition.EdgeAlignments.LeftTop;

var originalAspectPosition = original.GetComponent<AspectPosition>();
var originalPosition = originalAspectPosition.DistanceFromEdge;
originalPosition.y = 0.15f;
originalAspectPosition.DistanceFromEdge = originalPosition;
originalAspectPosition.AdjustPosition();

var position = originalPosition;
position.x += 10.075f - 0.1f;
position.y += 2.75f - 0.15f;
position.z -= 1;
aspectPosition.DistanceFromEdge = position;
var originalText = original.GetComponentInChildren<TextMeshPro>();

aspectPosition.AdjustPosition();
var gameObject = new GameObject("ReactorVersion");

Text = gameObject.AddComponent<TextMeshPro>();
Text.font = originalText.font;
Text.fontMaterial = originalText.fontMaterial;
Text.UpdateFontAsset();
Text.overflowMode = TextOverflowModes.Overflow;
Text.fontSize = 2;
Text.outlineWidth = 0.1f;
Text.enableWordWrapping = false;
Text.alignment = TextAlignmentOptions.TopLeft;

if (scene.name == "MainMenu")
{
ResolutionManager.add_ResolutionChanged(_resolutionChangedHandler);
SetMainMenuPositionFromAspect(Screen.width / (float) Screen.height);
}
else
{
ResolutionManager.remove_ResolutionChanged(_resolutionChangedHandler);
var aspectPosition = gameObject.AddComponent<AspectPosition>();
var distanceFromEdge = new Vector3(10.13f, 2.55f, -1);
if (originalAspectPosition.Alignment == AspectPosition.EdgeAlignments.LeftTop)
{
distanceFromEdge.y += 0.2f;
}
else if (AccountManager.Instance.isActiveAndEnabled)
{
distanceFromEdge.x += 0.2f;
distanceFromEdge.y += 0.575f;
}

aspectPosition.Alignment = AspectPosition.EdgeAlignments.LeftTop;
aspectPosition.DistanceFromEdge = distanceFromEdge;
aspectPosition.AdjustPosition();
}

UpdateText();
}));
}

private static string ToStringWithoutBuild(Version version)
{
return $"{version.Major}.{version.Minor}.{version.Patch}{(version.PreRelease == null ? string.Empty : $"-{version.PreRelease}")}";
}

/// <summary>
/// Updates <see cref="Text"/> with reactor version and fires <see cref="TextUpdated"/>.
/// </summary>
public static void UpdateText()
{
if (Text == null) return;
Text.text = "Reactor " + ReactorPlugin.Version;
Text.text += "\nBepInEx " + ToStringWithoutBuild(Paths.BepInExVersion);
Text.text = "Reactor " + Version.Parse(ReactorPlugin.Version).WithoutBuild();
Text.text += "\nBepInEx " + Paths.BepInExVersion.WithoutBuild();
Text.text += "\nMods: " + IL2CPPChainloader.Instance.Plugins.Count;

var creditsText = ReactorCredits.GetText(ReactorCredits.Location.MainMenu);
if (creditsText != null)
{
Text.text += "\n" + creditsText;
}

TextUpdated?.Invoke(Text);
}

6 changes: 0 additions & 6 deletions Reactor/Reactor.csproj
Original file line number Diff line number Diff line change
@@ -6,15 +6,9 @@

<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<GenerateDocumentationFile>true</GenerateDocumentationFile>

<!-- SourceLink -->
<EmbedUntrackedSources>true</EmbedUntrackedSources>
<IncludeSourceRevisionInInformationalVersion>false</IncludeSourceRevisionInInformationalVersion>
<ContinuousIntegrationBuild Condition="'$(GITHUB_ACTIONS)' == 'true'">true</ContinuousIntegrationBuild>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.1.1" PrivateAssets="All" />
<Compile Include="..\Reactor.Networking.Shared\**\*.cs" LinkBase="Networking" Visible="false" />
</ItemGroup>

22 changes: 22 additions & 0 deletions Reactor/ReactorConfig.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
using BepInEx.Configuration;

namespace Reactor;

internal static class ReactorConfig
{
public const string FeaturesSection = "Features";
public const string MessagesSection = "Messages";

public static ConfigEntry<bool> ForceDisableServerAuthority { get; private set; } = null!;

public static ConfigEntry<string> HandshakePopupMessage { get; private set; } = null!;
public static ConfigEntry<string> MakePublicDisallowedPopupMessage { get; private set; } = null!;

public static void Bind(ConfigFile config)
{
ForceDisableServerAuthority = config.Bind(FeaturesSection, nameof(ForceDisableServerAuthority), false, "Enables the DisableServerAuthority flag even when no mods declare it");

HandshakePopupMessage = config.Bind(MessagesSection, nameof(HandshakePopupMessage), string.Empty);
MakePublicDisallowedPopupMessage = config.Bind(MessagesSection, nameof(MakePublicDisallowedPopupMessage), string.Empty);
}
}
12 changes: 5 additions & 7 deletions Reactor/ReactorPlugin.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
global using static Reactor.Utilities.Logger<Reactor.ReactorPlugin>;
using System;
using System.Linq;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Unity.IL2CPP;
using HarmonyLib;
using Il2CppInterop.Runtime.Attributes;
@@ -37,13 +35,13 @@ public partial class ReactorPlugin : BasePlugin
/// </summary>
public CustomRpcManager CustomRpcManager { get; } = new();

internal ConfigEntry<bool>? AllowVanillaServers { get; private set; }

internal RegionInfoWatcher RegionInfoWatcher { get; } = new();

/// <inheritdoc />
public ReactorPlugin()
{
Log.LogMessage($"Among Us {Application.version} {Constants.GetCurrentPlatformName()}");

PluginSingleton<ReactorPlugin>.Instance = this;
PluginSingleton<BasePlugin>.Initialize();

@@ -60,7 +58,7 @@ public ReactorPlugin()
/// <inheritdoc />
public override void Load()
{
AllowVanillaServers = Config.Bind("Features", "Allow vanilla servers", false, "Whether reactor should ignore servers not responding to modded handshake. This config is ignored if any plugin uses custom rpcs!");
ReactorConfig.Bind(Config);

Harmony.PatchAll();

@@ -91,7 +89,7 @@ public override bool Unload()
}

[RegisterInIl2Cpp]
private class ReactorComponent : MonoBehaviour
private sealed class ReactorComponent : MonoBehaviour
{
[HideFromIl2Cpp]
public ReactorPlugin? Plugin { get; internal set; }
@@ -109,7 +107,7 @@ private void Update()
foreach (var pluginInfo in IL2CPPChainloader.Instance.Plugins.Values)
{
var config = ((BasePlugin) pluginInfo.Instance).Config;
if (!config.Any())
if (config.Count == 0)
{
continue;
}
Loading