Compare commits
31 Commits
de80b67367
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| ae54aab490 | |||
| 4800fe995a | |||
| 9f5eb531b6 | |||
| b861c0236a | |||
| 18eab45ec3 | |||
| 2ff60f8399 | |||
| 4649042ac1 | |||
| 672b34b556 | |||
| 10e8797ba2 | |||
| 584f19b016 | |||
| a924465919 | |||
| 8ac42d3fc5 | |||
| 628977263e | |||
| 8b3665e873 | |||
| 9318ac75d6 | |||
| d45fc2c953 | |||
| 909a433979 | |||
| a05d6aac7c | |||
| b796a6b075 | |||
| 0f0dcf6a70 | |||
| cef766f23d | |||
| 6ab33a36ae | |||
| 1a92e2dea7 | |||
| 8fd4e6f92d | |||
| 526f5264f8 | |||
| 5d54c59817 | |||
| 95cfd7ebb0 | |||
| 2c647e7103 | |||
| b80d92eef8 | |||
| aeb6a8f6b2 | |||
| eeae720d56 |
6
Core/Config/BaseOptionConfig.cs
Normal file
6
Core/Config/BaseOptionConfig.cs
Normal file
@@ -0,0 +1,6 @@
|
||||
namespace undead_universal_patch_il2cpp.Core.Config;
|
||||
|
||||
public class BaseOptionConfig
|
||||
{
|
||||
public bool Enabled { get; set; } = false;
|
||||
}
|
||||
@@ -22,6 +22,8 @@ namespace undead_universal_patch_il2cpp.Core.Config
|
||||
public static ConfigEntry<bool> ImageSignaturePatch;
|
||||
public static ConfigEntry<bool> RegistrationPatch;
|
||||
public static ConfigEntry<bool> AFKPatch;
|
||||
public static ConfigEntry<bool> RefreshTokenFix;
|
||||
public static ConfigEntry<bool> ProtonDeviceIdFix;
|
||||
}
|
||||
public static class PatchConfigDefaults
|
||||
{
|
||||
@@ -31,16 +33,24 @@ namespace undead_universal_patch_il2cpp.Core.Config
|
||||
public static bool ImageSignaturePatch = false;
|
||||
public static bool RegistrationPatch = false;
|
||||
public static bool AFKPatch = false;
|
||||
public static bool RefreshTokenFix = false;
|
||||
public static bool ProtonDeviceIdFix = false;
|
||||
}
|
||||
public static class ServerPatchesConfig
|
||||
{
|
||||
public static ConfigEntry<bool> CustomEmotes;
|
||||
public static ConfigEntry<bool> CustomPhoton;
|
||||
public static ConfigEntry<bool> CustomMarquee;
|
||||
public static ConfigEntry<bool> CustomKnownDlls;
|
||||
public static ConfigEntry<bool> CustomGameConfigurations;
|
||||
}
|
||||
public static class ServerPatchesConfigDefaults
|
||||
{
|
||||
public static bool CustomEmotes = false;
|
||||
public static bool CustomPhoton = false;
|
||||
public static bool CustomMarquee = false;
|
||||
public static bool CustomKnownDlls = false;
|
||||
public static bool CustomGameConfigurations = false;
|
||||
}
|
||||
public static class GameManagerConfig
|
||||
{
|
||||
|
||||
@@ -2,7 +2,7 @@ using System;
|
||||
using System.IO;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace undead_universal_patch_il2cpp.Core;
|
||||
namespace undead_universal_patch_il2cpp.Core.Config;
|
||||
|
||||
public class DediConfig<T>
|
||||
{
|
||||
@@ -23,7 +23,8 @@ public class DediConfig<T>
|
||||
_options = options;
|
||||
}
|
||||
|
||||
private string GetAlways() {
|
||||
private string GetAlways()
|
||||
{
|
||||
if (!File.Exists(path))
|
||||
{
|
||||
File.WriteAllText(path, _default);
|
||||
@@ -36,11 +37,11 @@ public class DediConfig<T>
|
||||
if (loaded) return cached;
|
||||
|
||||
string data = GetAlways();
|
||||
cached = JsonSerializer.Deserialize<T>(data, _options == null ? new JsonSerializerOptions()
|
||||
cached = JsonSerializer.Deserialize<T>(data, _options ?? new JsonSerializerOptions()
|
||||
{
|
||||
PropertyNameCaseInsensitive = true,
|
||||
AllowTrailingCommas = true
|
||||
} : _options);
|
||||
});
|
||||
|
||||
loaded = true;
|
||||
return cached;
|
||||
38
Core/Content/CustomRecNet/CheatManager/CustomCheatManager.cs
Normal file
38
Core/Content/CustomRecNet/CheatManager/CustomCheatManager.cs
Normal file
@@ -0,0 +1,38 @@
|
||||
using BestHTTP;
|
||||
using System.Collections.Generic;
|
||||
using undead_universal_patch_il2cpp.Core.Config;
|
||||
using undead_universal_patch_il2cpp.Patches;
|
||||
using UnityEngine;
|
||||
|
||||
namespace undead_universal_patch_il2cpp.Core.Content.CustomRecNet.CheatManager;
|
||||
|
||||
public class CustomCheatManager : MonoBehaviour
|
||||
{
|
||||
|
||||
public void Start()
|
||||
{
|
||||
if (ServerPatchesConfig.CustomKnownDlls.Value) RecNetInteractions.postNameServerActions.Add(DownloadKnownDlls);
|
||||
}
|
||||
|
||||
void Patch(HTTPResponse _res, List<string> dlls)
|
||||
{
|
||||
UniversalPatchPlugin.Log.LogInfo("Setting new KnownDlls (server)");
|
||||
|
||||
HilePatch.Patch([.. dlls]);
|
||||
}
|
||||
|
||||
void OnFailed(HTTPResponse _res)
|
||||
{
|
||||
if (PatchConfig.HilePatch.Value)
|
||||
{
|
||||
UniversalPatchPlugin.Log.LogInfo("Setting new KnownDlls (local fallback)");
|
||||
HilePatch.Patch();
|
||||
}
|
||||
}
|
||||
|
||||
void DownloadKnownDlls()
|
||||
{
|
||||
RecNetInteractions.SendRequest<List<string>>(HTTPMethods.Get, RecNet.Service.API, "/api/undead/v1/knowndlls", Patch, OnFailed);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
using BestHTTP;
|
||||
using undead_universal_patch_il2cpp.Patches.UndeadGameManager;
|
||||
using UnityEngine;
|
||||
|
||||
namespace undead_universal_patch_il2cpp.Core.Content.CustomRecNet.CustomGameManager;
|
||||
|
||||
public class CustomFreeSpawns : MonoBehaviour
|
||||
{
|
||||
public void Start()
|
||||
{
|
||||
RecNetInteractions.postAuthenticationActions.Add(DownloadFreeSpawns);
|
||||
}
|
||||
|
||||
public void OnFailed([Optional] HTTPResponse res)
|
||||
{
|
||||
Util.ConditionalDebug($"CustomFreeSpawns failed: HTTP Error {res.StatusCode}");
|
||||
}
|
||||
|
||||
public void Finished(HTTPResponse res, List<string> spawns)
|
||||
{
|
||||
FreeSpawnsPatch_Array.spawns = spawns;
|
||||
}
|
||||
|
||||
public void DownloadFreeSpawns()
|
||||
{
|
||||
RecNetInteractions.SendRequest<List<string>>(HTTPMethods.Get, RecNet.Service.API, "/api/undead/v1/freespawns", Finished, OnFailed);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
using BestHTTP;
|
||||
using undead_universal_patch_il2cpp.Core.Content.UndeadGameManager;
|
||||
using undead_universal_patch_il2cpp.Patches.UndeadGameManager;
|
||||
using UnityEngine;
|
||||
|
||||
namespace undead_universal_patch_il2cpp.Core.Content.CustomRecNet.CustomGameManager;
|
||||
|
||||
public class CustomGameManager : MonoBehaviour
|
||||
{
|
||||
public void Start()
|
||||
{
|
||||
RecNetInteractions.postAuthenticationActions.Add(DownloadGameConfigAssets);
|
||||
}
|
||||
|
||||
public void OnFailed([Optional] HTTPResponse res)
|
||||
{
|
||||
Util.ConditionalDebug($"CustomGameManager failed: HTTP Error {res.StatusCode}");
|
||||
}
|
||||
|
||||
public void Finished(HTTPResponse res, Dictionary<string, GameConfigurationAssetDTO> configs)
|
||||
{
|
||||
GameConfiguratorPatch.gameConfig = configs;
|
||||
}
|
||||
|
||||
public void DownloadGameConfigAssets()
|
||||
{
|
||||
RecNetInteractions.SendRequest<Dictionary<string, GameConfigurationAssetDTO>>(HTTPMethods.Get, RecNet.Service.API, "/api/undead/v1/gameconfigassets", Finished, OnFailed);
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
using System;
|
||||
using BestHTTP;
|
||||
using Il2CppInterop.Runtime;
|
||||
using undead_universal_patch_il2cpp.Core.Config;
|
||||
using undead_universal_patch_il2cpp.Patches.Photon;
|
||||
using UnityEngine;
|
||||
@@ -24,31 +23,32 @@ public class CustomPhoton : MonoBehaviour
|
||||
|
||||
public void Start()
|
||||
{
|
||||
RecNetInteractions.postLocalAccountActions.Add(DownloadServerConfig);
|
||||
if (ServerPatchesConfig.CustomPhoton.Value) RecNetInteractions.postLocalAccountActions.Add(DownloadServerConfig);
|
||||
else if (PhotonConfig.PatchPhotonIds.Value) LocalPatch();
|
||||
}
|
||||
|
||||
void LocalPatch()
|
||||
{
|
||||
UniversalPatchPlugin.Log.LogInfo("Attempting Photon patch from local configuration");
|
||||
PhotonPatch.Patch(new PhotonConfigDTO
|
||||
{
|
||||
Logging = PhotonConfig.PunLogging.Value,
|
||||
AppID = PhotonConfig.AppID.Value,
|
||||
VoiceAppID = PhotonConfig.VoiceAppID.Value,
|
||||
SelfHosted = PhotonConfig.SelfHosted.Value,
|
||||
ServerAddress = PhotonConfig.ServerAddress.Value,
|
||||
ServerPort = PhotonConfig.ServerPort.Value,
|
||||
ConnectionProtocol = PhotonConfig.ConnectionProtocol.Value
|
||||
});
|
||||
}
|
||||
|
||||
void OnServerConfigFailed(HTTPResponse res)
|
||||
{
|
||||
ServerConfigFailed = true;
|
||||
if (PhotonConfig.PatchPhotonIds.Value)
|
||||
{
|
||||
UniversalPatchPlugin.Log.LogInfo("Attempting Photon patch from local configuration");
|
||||
PhotonPatch.Patch(new PhotonConfigDTO
|
||||
{
|
||||
Logging = PhotonConfig.PunLogging.Value,
|
||||
AppID = PhotonConfig.AppID.Value,
|
||||
VoiceAppID = PhotonConfig.VoiceAppID.Value,
|
||||
SelfHosted = PhotonConfig.SelfHosted.Value,
|
||||
ServerAddress = PhotonConfig.ServerAddress.Value,
|
||||
ServerPort = PhotonConfig.ServerPort.Value,
|
||||
ConnectionProtocol = PhotonConfig.ConnectionProtocol.Value
|
||||
});
|
||||
}
|
||||
if (PhotonConfig.PatchPhotonIds.Value) LocalPatch();
|
||||
}
|
||||
void ApplyPhotonConfig(HTTPResponse res, PhotonConfigDTO photonConfig)
|
||||
{
|
||||
if (!ServerPatchesConfig.CustomPhoton.Value) return;
|
||||
|
||||
try
|
||||
{
|
||||
UniversalPatchPlugin.Log.LogInfo("Attempting Photon patch from server configuration");
|
||||
|
||||
@@ -15,6 +15,9 @@ public class RecNetInteractions
|
||||
public static List<Action> postNameServerActions = [];
|
||||
public static List<Action> postAuthenticationActions = [];
|
||||
public static List<Action> postLocalAccountActions = [];
|
||||
public static List<Action> onNotificationsOpen = [];
|
||||
public static List<Action> onLogout = [];
|
||||
public static List<Action> onPlatformInitialize = [];
|
||||
|
||||
public static Il2CppSystem.Uri CreateServiceUri(Service service, string pathAndQuery)
|
||||
{
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace undead_universal_patch_il2cpp.Core.Content.UndeadGameManager;
|
||||
|
||||
public static class GameConfigurator
|
||||
{
|
||||
static readonly string name = "GameConfigurations";
|
||||
public static DediConfig<Dictionary<string, GameConfigurationAssetDTO>> config = new(name, "{}", null);
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace undead_universal_patch_il2cpp.Core.Content.UndeadGameManager;
|
||||
|
||||
public static class GameFreeSpawns
|
||||
{
|
||||
static readonly string name = "GameFreeSpawns";
|
||||
public static DediConfig<List<string>> config = new(name, "[]", null);
|
||||
}
|
||||
67
Core/Init.cs
67
Core/Init.cs
@@ -1,12 +1,16 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Il2CppInterop.Runtime.InteropTypes.Arrays;
|
||||
using Mapster;
|
||||
using undead_universal_patch_il2cpp.Core.Config;
|
||||
using undead_universal_patch_il2cpp.Core.Content.CustomRecNet.CheatManager;
|
||||
using undead_universal_patch_il2cpp.Core.Content.CustomRecNet.CustomEmotes;
|
||||
using undead_universal_patch_il2cpp.Core.Content.CustomRecNet.CustomGameManager;
|
||||
using undead_universal_patch_il2cpp.Core.Content.CustomRecNet.CustomPhoton;
|
||||
using undead_universal_patch_il2cpp.Core.Content.UndeadGameManager;
|
||||
using undead_universal_patch_il2cpp.Patches.Video;
|
||||
using UnityEngine;
|
||||
|
||||
namespace undead_universal_patch_il2cpp.Core;
|
||||
@@ -32,10 +36,14 @@ public class Initialization
|
||||
{
|
||||
UniversalPatchPlugin.Log.LogInfo("PATCH LIST START =========================");
|
||||
foreach (var method in UniversalPatchPlugin.Instance.HarmonyInstance.GetPatchedMethods())
|
||||
UniversalPatchPlugin.Log.LogInfo($"- {method.ToString()}");
|
||||
{
|
||||
var paramStr = string.Join(" ", [.. method.GetParameters().Select(param => param.ParameterType.FullName)]);
|
||||
UniversalPatchPlugin.Log.LogInfo($"- {method.DeclaringType.FullName} {method.Name}({paramStr})");
|
||||
}
|
||||
UniversalPatchPlugin.Log.LogInfo("PATCH LIST END =========================");
|
||||
}
|
||||
|
||||
// to be removed in a future update
|
||||
try
|
||||
{
|
||||
CacheChangePatchConfigs();
|
||||
@@ -48,16 +56,18 @@ public class Initialization
|
||||
|
||||
private static void CacheChangePatchConfigs()
|
||||
{
|
||||
if (GameManagerConfig.AnyGameFreeSpawn.Value) GameFreeSpawns.config.Get();
|
||||
if (GameManagerConfig.StaticGameConfig.Value) GameConfigurator.config.Get();
|
||||
VideoTamperPatch.config.Get();
|
||||
}
|
||||
|
||||
private static void AttachGameObjects()
|
||||
{
|
||||
UniversalPatchPlugin.Log.LogInfo("Attaching game objects");
|
||||
|
||||
if (ServerPatchesConfig.CustomEmotes.Value) UniversalPatchPlugin.Instance.AddComponent<CustomEmotes>();
|
||||
UniversalPatchPlugin.Instance.AddComponent<SteamPlatform>();
|
||||
UniversalPatchPlugin.Instance.AddComponent<CustomPhoton>();
|
||||
if (ServerPatchesConfig.CustomEmotes.Value) UniversalPatchPlugin.Instance.AddComponent<CustomEmotes>();
|
||||
if (ServerPatchesConfig.CustomKnownDlls.Value) UniversalPatchPlugin.Instance.AddComponent<CustomCheatManager>();
|
||||
if (ServerPatchesConfig.CustomGameConfigurations.Value) UniversalPatchPlugin.Instance.AddComponent<CustomGameManager>();
|
||||
}
|
||||
|
||||
private static void FetchConfigurations()
|
||||
@@ -68,55 +78,66 @@ public class Initialization
|
||||
"Log all BestHTTP requests sent by the game.");
|
||||
GenericConfig.VerboseRequestLogs = UniversalPatchPlugin.Instance.Config.Bind("Generic", "VerboseRequestLogs", GenericConfigDefaults.VerboseRequestLogs,
|
||||
"Add additional request information to BestHTTPProxy logs. Requires LogAllRequest to be enabled.");
|
||||
PatchConfig.CertificatePatch = UniversalPatchPlugin.Instance.Config.Bind("Generic", "CertificatePatch", PatchConfigDefaults.CertificatePatch,
|
||||
PatchConfig.CertificatePatch = UniversalPatchPlugin.Instance.Config.Bind("Patches", "CertificatePatch", PatchConfigDefaults.CertificatePatch,
|
||||
"The game expects a certain certificate from rec.net when making HTTPS requests. Enable this to allow any valid certificate.");
|
||||
PatchConfig.HilePatch = UniversalPatchPlugin.Instance.Config.Bind("Generic", "HilePatch", PatchConfigDefaults.HilePatch,
|
||||
PatchConfig.HilePatch = UniversalPatchPlugin.Instance.Config.Bind("Patches", "HilePatch", PatchConfigDefaults.HilePatch,
|
||||
"The game will close after a short period of time if BepInEx is found. Enable to stop this from happening." +
|
||||
"\nThis will also enable the AGRoomRuntimeConfig patch. See the README for more info.");
|
||||
PatchConfig.SignalRHandshakeFix = UniversalPatchPlugin.Instance.Config.Bind("Generic", "SignalRHandshakeFix", PatchConfigDefaults.SignalRHandshakeFix,
|
||||
PatchConfig.SignalRHandshakeFix = UniversalPatchPlugin.Instance.Config.Bind("Patches", "SignalRHandshakeFix", PatchConfigDefaults.SignalRHandshakeFix,
|
||||
"Replace apostrophes with quotes in the initial SignalR handshake.");
|
||||
PatchConfig.ImageSignaturePatch = UniversalPatchPlugin.Instance.Config.Bind("Generic", "ImageSignaturePatch", PatchConfigDefaults.ImageSignaturePatch,
|
||||
PatchConfig.ImageSignaturePatch = UniversalPatchPlugin.Instance.Config.Bind("Patches", "ImageSignaturePatch", PatchConfigDefaults.ImageSignaturePatch,
|
||||
"When enabled, all image signatures will be valid." +
|
||||
"\nWorks only if the server appends a properly formatted signature header (signature does not need to be valid)");
|
||||
PatchConfig.RegistrationPatch = UniversalPatchPlugin.Instance.Config.Bind("Generic", "RegistrationPatch", PatchConfigDefaults.RegistrationPatch,
|
||||
PatchConfig.RegistrationPatch = UniversalPatchPlugin.Instance.Config.Bind("Patches", "RegistrationPatch", PatchConfigDefaults.RegistrationPatch,
|
||||
"Always disable the registration prompt.");
|
||||
PatchConfig.AFKPatch = UniversalPatchPlugin.Instance.Config.Bind("Generic", "AFKPatch", PatchConfigDefaults.AFKPatch,
|
||||
"Always present patch. Never get kicked to dorm.");
|
||||
PatchConfig.AFKPatch = UniversalPatchPlugin.Instance.Config.Bind("Patches", "AFKPatch", PatchConfigDefaults.AFKPatch,
|
||||
"Always present patch. Never get kicked to dorm for being AFK.");
|
||||
PatchConfig.RefreshTokenFix = UniversalPatchPlugin.Instance.Config.Bind("Patches", "RefreshTokenFix", PatchConfigDefaults.RefreshTokenFix,
|
||||
"Fix for the game needlessly requesting a refresh token in a loop. Cause for this issue is unknown." +
|
||||
"\nDon't enable unless you know what this does.");
|
||||
PatchConfig.ProtonDeviceIdFix = UniversalPatchPlugin.Instance.Config.Bind("Patches", "ProtonDeviceIdFix", PatchConfigDefaults.ProtonDeviceIdFix,
|
||||
"Fix for device IDs on Wine/Proton. Enable if you get a null reference exception related to cryptography APIs during connect/token.");
|
||||
|
||||
ServerPatchesConfig.CustomEmotes = UniversalPatchPlugin.Instance.Config.Bind("ServerPatches", "CustomEmotes", ServerPatchesConfigDefaults.CustomEmotes,
|
||||
"Modify the game's emote text with a configuration from the server. Requires a custom server.");
|
||||
"Modify the game's emote text with a configuration from the server.");
|
||||
ServerPatchesConfig.CustomPhoton = UniversalPatchPlugin.Instance.Config.Bind("ServerPatches", "CustomPhoton", ServerPatchesConfigDefaults.CustomPhoton,
|
||||
"Patch ServerSettings values with a configuration from the server." +
|
||||
"Patch Photon ServerSettings values with a configuration from the server." +
|
||||
"\nWhen the server fails to provide a valid configuration, values from the local config will be used." +
|
||||
"\nPhoton.PatchPhotonIds must be enabled for this fallback to work.");
|
||||
ServerPatchesConfig.CustomMarquee = UniversalPatchPlugin.Instance.Config.Bind("ServerPatches", "CustomMarquee", ServerPatchesConfigDefaults.CustomMarquee,
|
||||
"Set custom text on the ^reccenter theater marquee.");
|
||||
ServerPatchesConfig.CustomKnownDlls = UniversalPatchPlugin.Instance.Config.Bind("ServerPatches", "CustomKnownDlls", ServerPatchesConfigDefaults.CustomKnownDlls,
|
||||
"Add items to the list of known DLLs.");
|
||||
ServerPatchesConfig.CustomGameConfigurations = UniversalPatchPlugin.Instance.Config.Bind("ServerPatches", "CustomGameConfigurations", ServerPatchesConfigDefaults.CustomGameConfigurations,
|
||||
"Custom GameAssetConfigurations.");
|
||||
|
||||
GameManagerConfig.AnyGameFreeSpawn = UniversalPatchPlugin.Instance.Config.Bind("GameManagerConfig", "AnyGameFreeSpawn", GameManagerConfigDefaults.AnyGameFreeSpawn,
|
||||
$"Use patches from '{GameFreeSpawns.config.path}' to spawn in any valid player spawnpoint in specified games. See README.md");
|
||||
$"Spawn in any valid player spawnpoint in specified games. See README.md");
|
||||
GameManagerConfig.StaticGameConfig = UniversalPatchPlugin.Instance.Config.Bind("GameManagerConfig", "StaticGameConfig", GameManagerConfigDefaults.StaticGameConfig,
|
||||
$"Use patches from '{GameConfigurator.config.path}' to set new configurations for built-in games. See README.md");
|
||||
$"Set new configurations for built-in games. See README.md");
|
||||
|
||||
PhotonConfig.PatchPhotonIds = UniversalPatchPlugin.Instance.Config.Bind("Photon", "PatchPhotonIds", PhotonConfigDefaults.PatchPhotonIds,
|
||||
"Patch Photon configuration.");
|
||||
PhotonConfig.PunLogging = UniversalPatchPlugin.Instance.Config.Bind("Photon", "PunLogging", PhotonConfigDefaults.PunLogging,
|
||||
"Enable all logging sent by Photon/PUN/Voice (useful for server debugging)");
|
||||
"Enable all PUN/Voice logging (useful for server debugging)");
|
||||
PhotonConfig.SelfHosted = UniversalPatchPlugin.Instance.Config.Bind("Photon", "IsSelfHosted", PhotonConfigDefaults.SelfHosted,
|
||||
"When enabled, use a self-hosted 'OnPremises' PhotonSocketServer. (EXPERIMENTAL)" +
|
||||
"When enabled, use a self-hosted ('OnPremises' or 'PhotonSocketServer') Photon server." +
|
||||
"\nWhen disabled, AppID and VoiceAppID are sent to Photon Cloud and a cloud masterserver is used.");
|
||||
PhotonConfig.AppID = UniversalPatchPlugin.Instance.Config.Bind("Photon", "AppID", PhotonConfigDefaults.AppID,
|
||||
"The new target (PUN) App ID from the Photon dashboard." +
|
||||
"\nWhen self-hosting, this should be the name of your application (either 'Master' or 'Game')");
|
||||
"\nWhen self-hosting, this should be the name of your Photon application (usually 'Master' without quotes)");
|
||||
PhotonConfig.VoiceAppID = UniversalPatchPlugin.Instance.Config.Bind("Photon", "VoiceAppID", PhotonConfigDefaults.VoiceAppID,
|
||||
"The new target Voice App ID from the Photon dashboard." +
|
||||
"\nWhen self-hosting, this value is ignored, since Photon voice in Rec Room is based on PUN.");
|
||||
"\nWhen self-hosting, this should be the same as AppID.");
|
||||
PhotonConfig.ServerAddress = UniversalPatchPlugin.Instance.Config.Bind("Photon", "ServerAddress", PhotonConfigDefaults.ServerAddress,
|
||||
"Address of the Photon target server (ignored if not using self-hosted)");
|
||||
"Address of the Photon Master server (ignored if using cloud)");
|
||||
PhotonConfig.ServerPort = UniversalPatchPlugin.Instance.Config.Bind("Photon", "ServerPort", PhotonConfigDefaults.ServerPort,
|
||||
"Photon target server port (ignored if not using self-hosted)." +
|
||||
"Photon Master server port (ignored if using cloud)." +
|
||||
"\nYou can set this port to the matching protocol port from the server, e.g. 5055 for UDP, 9091 for WebSockets");
|
||||
PhotonConfig.ConnectionProtocol = UniversalPatchPlugin.Instance.Config.Bind("Photon", "ConnectionProtocol", PhotonConfigDefaults.ConnectionProtocol,
|
||||
"Connection protocol to use when connecting to the target port (ignored if not using self-hosted)." +
|
||||
"Connection protocol to use when connecting to the Photon servers (ignored if using cloud)." +
|
||||
"\n0: UDP, 1: TCP;" +
|
||||
"\nWebSockets are not supported by Photon in this build.");
|
||||
"\nWebSockets are not supported by Photon in this build. TCP is experimental and may cause instability/crashes.");
|
||||
|
||||
NameserverConfig.Rewrite = UniversalPatchPlugin.Instance.Config.Bind("Nameserver", "Rewrite", NameserverConfigDefaults.Rewrite,
|
||||
"Enable/disable rewriting the URL for nameserver requests.");
|
||||
|
||||
14
Core/PluginHash.cs
Normal file
14
Core/PluginHash.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Security.Cryptography;
|
||||
|
||||
namespace undead_universal_patch_il2cpp.Core;
|
||||
|
||||
public class PluginHash
|
||||
{
|
||||
public static string GetHash()
|
||||
{
|
||||
return BitConverter.ToString(MD5.Create().ComputeHash(File.OpenRead(Assembly.GetExecutingAssembly().Location))).Replace("-", "").ToLowerInvariant();
|
||||
}
|
||||
}
|
||||
46
Core/SteamPlatform.cs
Normal file
46
Core/SteamPlatform.cs
Normal file
@@ -0,0 +1,46 @@
|
||||
using Il2CppInterop.Runtime;
|
||||
using Steamworks;
|
||||
using System;
|
||||
using undead_universal_patch_il2cpp.Core.Content.CustomRecNet;
|
||||
using UnityEngine;
|
||||
|
||||
namespace undead_universal_patch_il2cpp.Core;
|
||||
|
||||
public class SteamPlatform : MonoBehaviour
|
||||
{
|
||||
public static string AuthTicket { get; set; } = null;
|
||||
|
||||
void GetAuthTicket() {
|
||||
SteamPlatformManager manager = PlatformManager.Instance.GetComponentInChildren<SteamPlatformManager>();
|
||||
manager.GetAuthSessionTicket().Then(
|
||||
DelegateSupport.ConvertDelegate<Il2CppSystem.Action<SteamPlatformManager.AuthSessionTicket>>((SteamPlatformManager.AuthSessionTicket ticket) =>
|
||||
{
|
||||
if (!string.IsNullOrEmpty(ticket.Error)) UniversalPatchPlugin.Log.LogError($"Could not get Steam auth ticket!: {ticket.Error}");
|
||||
else
|
||||
{
|
||||
AuthTicket = BitConverter.ToString(ticket.Ticket).Replace("-", "").ToUpperInvariant().TrimEnd('0');
|
||||
Util.ConditionalDebug($"Got new Steam auth ticket");
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
void Start()
|
||||
{
|
||||
RecNetInteractions.onLogout.Add(GetAuthTicket);
|
||||
RecNetInteractions.onPlatformInitialize.Add(GetAuthTicket);
|
||||
|
||||
/*
|
||||
Every time the user logs out of matchmaking
|
||||
or when PlatformManager initializes, fetch a new ticket.
|
||||
The user might be logging out to the account selection screen
|
||||
where they might create a new one; a Steam auth ticket is added to
|
||||
the auth params in the create request and it must be valid.
|
||||
|
||||
It *is* possible (though very unlikely) that the user creates a new account
|
||||
before the first ticket is fetched, since the method that gets a ticket is
|
||||
an IPromise.
|
||||
|
||||
If this way of doing things isn't the best, fix it and I'll merge
|
||||
*/
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2024 proxnet.dev
|
||||
Copyright (c) 2025 proxnet.dev by @zombieb
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
29
LINUX.md
Normal file
29
LINUX.md
Normal file
@@ -0,0 +1,29 @@
|
||||
# Linux Users
|
||||
|
||||
[<-- Back to README.md](./README.md)
|
||||
|
||||
**Linux support is currently broken due to Proton bugs with .NET cryptography APIs. This may be resolved in a future update.**
|
||||
|
||||
No native Linux build exists for the game. Proton, however, works just fine. You can install it using the instructions below.
|
||||
|
||||
Reminder that EAC or Referee builds will never be supported by Undead Universal Patch.
|
||||
|
||||
### General process
|
||||
* Install Steam
|
||||
* Add Recroom_Release.exe as a non-steam game
|
||||
* Install `protontricks`; depends on your distribution (see sections)
|
||||
* Add the doorstop DLL using `protontricks --gui` [(more info)](https://linux-gaming.kwindu.eu/index.php?title=Installing_dlls)
|
||||
- Select default wineprefix
|
||||
- Install DLL
|
||||
- Select the doorstop DLL `winhttp.dll`
|
||||
* Run the game through Steam
|
||||
|
||||
### Arch Linux
|
||||
`protontricks` can be installed from the [AUR](https://aur.archlinux.org/packages/protontricks)<br>
|
||||
You should use the built-in Steam package [(instructions here)](https://wiki.archlinux.org/title/Steam) if you don't have Steam installed already.
|
||||
|
||||
### Other distributions
|
||||
|
||||
If you have any success doing this on Debian-based systems (Ubuntu 2x.x, elementary OS, etc)<br>
|
||||
or any other kind of system, add an issue and explain the process - I'll add it to this document.<br>
|
||||
If you feel like making a pull request, that's okay as well.
|
||||
@@ -1,9 +1,12 @@
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using System.Threading.Tasks;
|
||||
using BestHTTP;
|
||||
using BestHTTP.Forms;
|
||||
using HarmonyLib;
|
||||
using undead_universal_patch_il2cpp.Core;
|
||||
using undead_universal_patch_il2cpp.Core.Config;
|
||||
using UnityEngine;
|
||||
|
||||
namespace undead_universal_patch_il2cpp.Patches
|
||||
{
|
||||
@@ -22,6 +25,8 @@ namespace undead_universal_patch_il2cpp.Patches
|
||||
|
||||
static readonly MethodInfo getHeaderMethod = requestType?.GetMethod("GetFirstHeaderValue");
|
||||
static readonly MethodInfo addHeaderMethod = requestType?.GetMethod("AddHeader");
|
||||
static readonly MethodInfo getFormFields = requestType?.GetMethod("GetFormFields");
|
||||
static readonly PropertyInfo formImplProp = requestType?.GetProperty("FormImpl");
|
||||
static readonly PropertyInfo methodTypeProp = requestType?.GetProperty("MethodType");
|
||||
static readonly PropertyInfo uriProp = requestType?.GetProperty("Uri");
|
||||
static readonly PropertyInfo customCertProp = requestType?.GetProperty("CustomCertificateVerifyer");
|
||||
@@ -30,13 +35,13 @@ namespace undead_universal_patch_il2cpp.Patches
|
||||
getHeaderMethod,
|
||||
addHeaderMethod,
|
||||
methodTypeProp,
|
||||
getFormFields,
|
||||
formImplProp,
|
||||
uriProp,
|
||||
customCertProp
|
||||
]).Success;
|
||||
|
||||
static MethodBase TargetMethod() => patchResult.Method;
|
||||
|
||||
[HarmonyPrefix]
|
||||
static void Prefix(ref object request)
|
||||
{
|
||||
if (PatchConfig.CertificatePatch.Value) customCertProp.GetSetMethod().Invoke(request, [null]);
|
||||
@@ -59,6 +64,16 @@ namespace undead_universal_patch_il2cpp.Patches
|
||||
|
||||
if (newUri.Host.Contains("ns.rec.net")) newUri = new Il2CppSystem.Uri(NameserverConfig.NewUrl.Value);
|
||||
|
||||
bool isAccCreate = newUri.PathAndQuery.Contains("account/create");
|
||||
if (isAccCreate && SteamPlatform.AuthTicket != null)
|
||||
{
|
||||
HTTPFormBase form = (HTTPFormBase)formImplProp.GetValue(request, null);
|
||||
|
||||
form.AddField("x-steam-ticket", SteamPlatform.AuthTicket);
|
||||
Util.ConditionalDebug("Added Steam ticket to create request");
|
||||
}
|
||||
else if (isAccCreate) UniversalPatchPlugin.Log.LogError("The Steam auth ticket has not yet been fetched, account creation might fail!");
|
||||
|
||||
// Finish request changes
|
||||
|
||||
string afterUrl = newUri.ToString();
|
||||
@@ -66,14 +81,13 @@ namespace undead_universal_patch_il2cpp.Patches
|
||||
|
||||
if (GenericConfig.LogAllRequests.Value)
|
||||
{
|
||||
if (GenericConfig.VerboseRequestLogs.Value) UniversalPatchPlugin.Log.LogInfo("BestHTTP Request Log\n" +
|
||||
if (GenericConfig.VerboseRequestLogs.Value) UniversalPatchPlugin.Log.LogInfo($"BestHTTP Request Log{(customCertProp.GetGetMethod().Invoke(request, []) == null ? "" : " (verify)")}\n" +
|
||||
$" URL Before : {beforeUrl}\n" +
|
||||
$" URL After : {(beforeUrl == afterUrl ? "(unmodified)" : afterUrl)}\n" +
|
||||
$" Method : {method}\n" +
|
||||
$" Content-Type : {contentType ?? "(not set)"}");
|
||||
else UniversalPatchPlugin.Log.LogInfo("BestHTTPProxy Request Log\n" +
|
||||
$" Before : {beforeUrl}\n" +
|
||||
$" After : {afterUrl}");
|
||||
else UniversalPatchPlugin.Log.LogInfo("BestHTTPProxy Request\n" +
|
||||
$" {method} {afterUrl}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,17 +1,15 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using HarmonyLib;
|
||||
using undead_universal_patch_il2cpp.Core;
|
||||
using undead_universal_patch_il2cpp.Core.Config;
|
||||
using undead_universal_patch_il2cpp.Core.Content.UndeadGameManager;
|
||||
|
||||
namespace undead_universal_patch_il2cpp.Patches.UndeadGameManager;
|
||||
|
||||
[HarmonyPatch]
|
||||
public class FreeSpawnsPatch_Array
|
||||
{
|
||||
public static List<string> config = GameFreeSpawns.config.Get();
|
||||
public static List<string> spawns = null;
|
||||
|
||||
static PatchTypesResult patchResult = Util.ConfigPreparePatchTypes(
|
||||
GameManagerConfig.AnyGameFreeSpawn,
|
||||
@@ -26,6 +24,12 @@ public class FreeSpawnsPatch_Array
|
||||
|
||||
public static void Postfix(ref GamePlayerSpawnPoint __instance)
|
||||
{
|
||||
if (spawns == null)
|
||||
{
|
||||
Util.ConditionalDebug("FreeSpawns was not yet fetched!");
|
||||
return;
|
||||
}
|
||||
|
||||
Util.ConditionalDebug("Attempting FreeSpawns patch");
|
||||
GameManager man = NetworkedSingletonMonoBehaviour<GameManager>.instance;
|
||||
|
||||
@@ -39,7 +43,7 @@ public class FreeSpawnsPatch_Array
|
||||
Util.ConditionalDebug("CurrentGameConfiguration.configurationData was null");
|
||||
return;
|
||||
}
|
||||
if (!config.Contains(man.CurrentGameConfiguration.configurationData.Name))
|
||||
if (!spawns.Contains(man.CurrentGameConfiguration.configurationData.Name))
|
||||
{
|
||||
Util.ConditionalDebug($"Game '{man.CurrentGameConfiguration.configurationData.Name}' is not specified by GameFreeSpawns");
|
||||
return;
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using HarmonyLib;
|
||||
@@ -13,7 +12,7 @@ namespace undead_universal_patch_il2cpp.Patches.UndeadGameManager;
|
||||
[HarmonyPatch]
|
||||
public class GameConfiguratorPatch
|
||||
{
|
||||
static Dictionary<string, GameConfigurationAssetDTO> gameConfig = GameConfigurator.config.Get();
|
||||
public static Dictionary<string, GameConfigurationAssetDTO> gameConfig = null;
|
||||
|
||||
static PatchTypesResult patchResult = Util.ConfigPreparePatchTypes(
|
||||
GameManagerConfig.StaticGameConfig,
|
||||
@@ -28,6 +27,12 @@ public class GameConfiguratorPatch
|
||||
|
||||
public static void Prefix(ref GameConfigurationAsset config, ref bool showNotification)
|
||||
{
|
||||
if (gameConfig == null)
|
||||
{
|
||||
Util.ConditionalDebug("gameconfigassets was not yet fetched!");
|
||||
return;
|
||||
}
|
||||
|
||||
var conf = config;
|
||||
showNotification = GenericConfig.PatchDebug.Value;
|
||||
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
using System.Reflection;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
using HarmonyLib;
|
||||
using undead_universal_patch_il2cpp.Core;
|
||||
using undead_universal_patch_il2cpp.Core.Config;
|
||||
@@ -22,19 +24,16 @@ namespace undead_universal_patch_il2cpp.Patches
|
||||
|
||||
static void Prefix()
|
||||
{
|
||||
if (PatchConfig.HilePatch.Value) HilePatch.Patch();
|
||||
if (!ServerPatchesConfig.CustomKnownDlls.Value && PatchConfig.HilePatch.Value) HilePatch.Patch();
|
||||
}
|
||||
}
|
||||
|
||||
public static class HilePatch
|
||||
{
|
||||
public static void Patch()
|
||||
public static void Patch([Optional] string[] dlls)
|
||||
{
|
||||
GameObject cheatManagerObject = GameObject.Find("[CheatManager]");
|
||||
HileManager hileManager = cheatManagerObject.GetComponent<HileManager>();
|
||||
|
||||
PropertyInfo knownDllsProperty = AccessTools.Property(typeof(HileManager), "KnownDlls");
|
||||
knownDllsProperty.SetValue(hileManager, new Il2CppInterop.Runtime.InteropTypes.Arrays.Il2CppStringArray([
|
||||
Util.ConditionalDebug($"Patching KnownDlls with {(dlls != null ? dlls.Length : 0)} new filenames");
|
||||
string[] baseDlls = [
|
||||
"GameAssembly.dll",
|
||||
"UnityPlayer.dll",
|
||||
"WinPixEventRuntime.dll",
|
||||
@@ -46,9 +45,16 @@ namespace undead_universal_patch_il2cpp.Patches
|
||||
"ddraw.dll",
|
||||
"dxgi.dll",
|
||||
"winhttp.dll"
|
||||
]));
|
||||
];
|
||||
if (dlls != null) baseDlls = baseDlls.Concat(dlls).ToArray();
|
||||
|
||||
UniversalPatchPlugin.Log.LogInfo("Hile patch succeeded.");
|
||||
GameObject cheatManagerObject = GameObject.Find("[CheatManager]");
|
||||
HileManager hileManager = cheatManagerObject.GetComponent<HileManager>();
|
||||
|
||||
PropertyInfo knownDllsProperty = AccessTools.Property(typeof(HileManager), "KnownDlls");
|
||||
knownDllsProperty.SetValue(hileManager, new Il2CppInterop.Runtime.InteropTypes.Arrays.Il2CppStringArray(baseDlls));
|
||||
|
||||
UniversalPatchPlugin.Log.LogInfo($"Hile patch succeeded: {baseDlls.Length} new KnownDlls.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
29
Patches/Internals/DeviceIdBuilder.cs
Normal file
29
Patches/Internals/DeviceIdBuilder.cs
Normal file
@@ -0,0 +1,29 @@
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using HarmonyLib;
|
||||
using Il2CppInterop.Runtime.InteropTypes.Arrays;
|
||||
using undead_universal_patch_il2cpp.Core;
|
||||
using undead_universal_patch_il2cpp.Core.Config;
|
||||
|
||||
namespace undead_universal_patch_il2cpp.Patches.Internals;
|
||||
|
||||
[HarmonyPatch]
|
||||
public class DeviceIdBuilder
|
||||
{
|
||||
static PatchTypesResult typesResult = Util.ConfigPreparePatchTypes(
|
||||
PatchConfig.ProtonDeviceIdFix,
|
||||
"Proton quickfix for device ID errors",
|
||||
"RecRoom.Utils.DeviceIdBuilder",
|
||||
"CalculateOtherDeviceId"
|
||||
);
|
||||
|
||||
static MethodBase TargetMethod() => typesResult.Method;
|
||||
static bool Prepare() => typesResult.Success;
|
||||
|
||||
static bool Prefix(ref Il2CppStructArray<byte> __result)
|
||||
{
|
||||
Util.ConditionalDebug("Device ID patched");
|
||||
__result = new Il2CppStructArray<byte>(Encoding.UTF8.GetBytes("Wine/Proton"));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
30
Patches/Internals/LockerroomOOBEFlow.cs
Normal file
30
Patches/Internals/LockerroomOOBEFlow.cs
Normal file
@@ -0,0 +1,30 @@
|
||||
using HarmonyLib;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using undead_universal_patch_il2cpp.Core;
|
||||
using UnityEngine;
|
||||
|
||||
namespace undead_universal_patch_il2cpp.Patches.Internals
|
||||
{
|
||||
/*[HarmonyPatch]
|
||||
public class LockerroomOOBEFlow
|
||||
{
|
||||
static PatchTypesResult patchResult = Util.PreparePatchTypes(
|
||||
"Event patch for changing marquee text in the reccenter",
|
||||
"LockerroomOOBEFlow",
|
||||
"Start"
|
||||
);
|
||||
|
||||
static bool Prepare() => patchResult.Success;
|
||||
static MethodBase TargetMethod() => patchResult.Method;
|
||||
|
||||
static void Postfix()
|
||||
{
|
||||
|
||||
}
|
||||
}*/
|
||||
}
|
||||
30
Patches/Internals/LoginHelper.cs
Normal file
30
Patches/Internals/LoginHelper.cs
Normal file
@@ -0,0 +1,30 @@
|
||||
using BestHTTP.Forms;
|
||||
using HarmonyLib;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using undead_universal_patch_il2cpp.Core;
|
||||
|
||||
namespace undead_universal_patch_il2cpp.Patches.Internals;
|
||||
|
||||
[HarmonyPatch]
|
||||
public class LoginHelperFieldsPatch
|
||||
{
|
||||
static PatchTypesResult typesResult = Util.PreparePatchTypes(
|
||||
"Add patch hash to the login form",
|
||||
"RecNet.Login",
|
||||
"LoginHelper"
|
||||
);
|
||||
|
||||
static MethodBase TargetMethod() => typesResult.Method;
|
||||
static bool Prepare() => typesResult.Success;
|
||||
|
||||
static void Prefix(ref HTTPUrlEncodedForm loginParams)
|
||||
{
|
||||
loginParams.AddField("x-patch-plugin-hash", PluginHash.GetHash());
|
||||
Util.ConditionalDebug("Added hash to login form");
|
||||
}
|
||||
}
|
||||
43
Patches/Internals/NotificationTargets/MarqueeTexts.cs
Normal file
43
Patches/Internals/NotificationTargets/MarqueeTexts.cs
Normal file
@@ -0,0 +1,43 @@
|
||||
using Il2CppInterop.Runtime;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using undead_universal_patch_il2cpp.Core.Config;
|
||||
using UnityEngine;
|
||||
|
||||
namespace undead_universal_patch_il2cpp.Patches.Internals.NotificationTargets
|
||||
{
|
||||
public class MarqueeTexts : MonoBehaviour
|
||||
{
|
||||
void Start()
|
||||
{
|
||||
if (ServerPatchesConfig.CustomMarquee.Value)
|
||||
{
|
||||
UniversalPatchPlugin.Log.LogWarning("CustomMarquee patch is unavailable at this time. A future update may resolve this.");
|
||||
//RecNetInteractions.onNotificationsOpen.Add(OnSocketOpen);
|
||||
}
|
||||
}
|
||||
|
||||
/*void OnSocketOpen()
|
||||
{
|
||||
var d = DelegateSupport.ConvertDelegate<RecNet.Notifications.NotificationHandler>(OnTextChange);
|
||||
RecNet.Notifications.RegisterHandler("MarqueeTexts", d);
|
||||
}
|
||||
|
||||
void OnTextChange(Dictionary<string, string> args)
|
||||
{
|
||||
GameObject go = GameObject.Find("DynamicObjects/[RecCenter_Marquee]");
|
||||
|
||||
string[] transforms = ["Text", "Now Playing", "SubText"];
|
||||
var texts = transforms.Select(str => go.transform.Find(str).GetComponent<TextMesh>()).ToArray();
|
||||
|
||||
foreach (var t in transforms)
|
||||
{
|
||||
TextMesh tm = go.transform.Find(t).GetComponent<TextMesh>();
|
||||
args.TryGetValue(t, out string res);
|
||||
tm.text = res;
|
||||
}
|
||||
|
||||
Core.Util.ConditionalDebug("Replaced marquee texts");
|
||||
}*/
|
||||
}
|
||||
}
|
||||
28
Patches/Internals/Notifications.cs
Normal file
28
Patches/Internals/Notifications.cs
Normal file
@@ -0,0 +1,28 @@
|
||||
using HarmonyLib;
|
||||
using Il2CppInterop.Runtime;
|
||||
using RecNet;
|
||||
using System.Reflection;
|
||||
using undead_universal_patch_il2cpp.Core;
|
||||
using undead_universal_patch_il2cpp.Core.Content.CustomRecNet;
|
||||
|
||||
namespace undead_universal_patch_il2cpp.Patches.Internals
|
||||
{
|
||||
[HarmonyPatch]
|
||||
public class Notifications
|
||||
{
|
||||
static PatchTypesResult patchResult = Core.Util.PreparePatchTypes(
|
||||
"Event patch for notification availability",
|
||||
"RecNet.Notifications",
|
||||
"OnOpenInternal"
|
||||
);
|
||||
|
||||
static bool Prepare() => patchResult.Success;
|
||||
static MethodBase TargetMethod() => patchResult.Method;
|
||||
|
||||
static void Postfix(ref SignalRHubConnection hub)
|
||||
{
|
||||
UniversalPatchPlugin.Log.LogInfo("Running onNotificationsOpen actions");
|
||||
foreach (var action in RecNetInteractions.onNotificationsOpen) action();
|
||||
}
|
||||
}
|
||||
}
|
||||
30
Patches/Internals/OnLogout.cs
Normal file
30
Patches/Internals/OnLogout.cs
Normal file
@@ -0,0 +1,30 @@
|
||||
using HarmonyLib;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using undead_universal_patch_il2cpp.Core;
|
||||
using undead_universal_patch_il2cpp.Core.Content.CustomRecNet;
|
||||
|
||||
namespace undead_universal_patch_il2cpp.Patches.Internals;
|
||||
|
||||
[HarmonyPatch]
|
||||
public class LogoutEvent
|
||||
{
|
||||
static PatchTypesResult typesResult = Util.PreparePatchTypes(
|
||||
"RecNet logout event patch",
|
||||
"RecNet.Login",
|
||||
"OnLogout"
|
||||
);
|
||||
|
||||
static MethodBase TargetMethod() => typesResult.Method;
|
||||
static bool Prepare() => typesResult.Success;
|
||||
|
||||
static void Postfix()
|
||||
{
|
||||
Util.ConditionalDebug("Running onLogout actions");
|
||||
foreach (var action in RecNetInteractions.onLogout) action();
|
||||
}
|
||||
}
|
||||
29
Patches/Internals/PlatformManager.cs
Normal file
29
Patches/Internals/PlatformManager.cs
Normal file
@@ -0,0 +1,29 @@
|
||||
using HarmonyLib;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using undead_universal_patch_il2cpp.Core;
|
||||
using undead_universal_patch_il2cpp.Core.Content.CustomRecNet;
|
||||
|
||||
namespace undead_universal_patch_il2cpp.Patches.Internals;
|
||||
|
||||
[HarmonyPatch]
|
||||
public class SteamPlatformManagerEvent
|
||||
{
|
||||
static PatchTypesResult typesResult = Util.PreparePatchTypes(
|
||||
"On SteamPlatformManager.Initialize",
|
||||
"SteamPlatformManager",
|
||||
"Initialize"
|
||||
);
|
||||
|
||||
static MethodBase TargetMethod() => typesResult.Method;
|
||||
static bool Prepare() => typesResult.Success;
|
||||
|
||||
static void Postfix()
|
||||
{
|
||||
UniversalPatchPlugin.Log.LogInfo("Running post-steam platform initialize actions");
|
||||
foreach (var action in RecNetInteractions.onPlatformInitialize) action();
|
||||
}
|
||||
}
|
||||
@@ -22,20 +22,13 @@ public class AuthenticationEventPatch
|
||||
|
||||
static MethodBase TargetMethod() => patchResult.Method;
|
||||
|
||||
private static bool RanPostActions { get; set; } = false;
|
||||
static void Postfix(ref string accessToken)
|
||||
{
|
||||
UniversalPatchPlugin.Log.LogInfo("Intercepted AccessToken");
|
||||
RecNetInteractions.AccessToken = accessToken;
|
||||
|
||||
if (!RanPostActions)
|
||||
{
|
||||
bool value = (bool)hasAccessTokenProperty.GetValue(patchResult.Type);
|
||||
if (value) UniversalPatchPlugin.Log.LogInfo("Running post-authentication actions");
|
||||
foreach (var action in RecNetInteractions.postAuthenticationActions)
|
||||
action();
|
||||
}
|
||||
else RanPostActions = true;
|
||||
|
||||
UniversalPatchPlugin.Log.LogInfo("Running post-authentication actions");
|
||||
foreach (var action in RecNetInteractions.postAuthenticationActions)
|
||||
action();
|
||||
}
|
||||
}
|
||||
27
Patches/Internals/RefreshTokenFix.cs
Normal file
27
Patches/Internals/RefreshTokenFix.cs
Normal file
@@ -0,0 +1,27 @@
|
||||
using HarmonyLib;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using undead_universal_patch_il2cpp.Core;
|
||||
using undead_universal_patch_il2cpp.Core.Config;
|
||||
|
||||
namespace undead_universal_patch_il2cpp.Patches.Internals;
|
||||
|
||||
[HarmonyPatch]
|
||||
public class RefreshTokenFix
|
||||
{
|
||||
static PatchTypesResult patchResult = Util.ConfigPreparePatchTypes(
|
||||
PatchConfig.RefreshTokenFix,
|
||||
"Refresh token implementation fix for some servers",
|
||||
"RecNet.Login",
|
||||
"OnLocalAccountUpdated"
|
||||
);
|
||||
|
||||
static MethodBase TargetMethod() => patchResult.Method;
|
||||
static bool Prepare() => patchResult.Success;
|
||||
|
||||
static bool Prefix() => false;
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
using System.Reflection;
|
||||
using HarmonyLib;
|
||||
using undead_universal_patch_il2cpp.Core;
|
||||
|
||||
namespace undead_universal_patch_il2cpp.Patches.Photon;
|
||||
|
||||
[HarmonyPatch]
|
||||
public class NameserverTest
|
||||
{
|
||||
static PatchTypesResult patchTypesResult = Util.PreparePatchTypes(
|
||||
"Photon nameserver test",
|
||||
"NetworkingPeer",
|
||||
"GetNameServerAddress"
|
||||
);
|
||||
|
||||
static bool Prepare() => patchTypesResult.Success;
|
||||
static MethodBase TargetMethod() => patchTypesResult.Method;
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using HarmonyLib;
|
||||
using Mapster;
|
||||
using undead_universal_patch_il2cpp.Core;
|
||||
using undead_universal_patch_il2cpp.Core.Config;
|
||||
using undead_universal_patch_il2cpp.Core.Content.CustomRecNet.CustomPhoton;
|
||||
@@ -101,7 +103,12 @@ public class PhotonThrottlingPatch
|
||||
"UpdatePhotonThrottling"
|
||||
);
|
||||
|
||||
static bool Prepare() => patchTypesResult.Success;
|
||||
static bool Prepare()
|
||||
{
|
||||
if (PhotonConfig.ConnectionProtocol.Value == 1) return patchTypesResult.Success;
|
||||
else return false;
|
||||
}
|
||||
|
||||
static MethodBase TargetMethod() => patchTypesResult.Method;
|
||||
|
||||
static bool Prefix() => PhotonConfig.ConnectionProtocol.Value != 1;
|
||||
|
||||
@@ -37,7 +37,7 @@ public class PhotonPatch
|
||||
PropertyInfo voiceAppIdProperty = serverSettingsType.GetRuntimeProperty("VoiceAppID");
|
||||
|
||||
Util.ConditionalDebug($"New Photon AppID: '{photonConfig.AppID}'");
|
||||
Util.ConditionalDebug($"New Photon AppID: '{photonConfig.VoiceAppID}'");
|
||||
Util.ConditionalDebug($"New Photon VoiceAppID: '{photonConfig.VoiceAppID}'");
|
||||
appIdProperty.SetValue(serverSettings, photonConfig.AppID);
|
||||
voiceAppIdProperty.SetValue(serverSettings, photonConfig.VoiceAppID);
|
||||
|
||||
|
||||
@@ -10,22 +10,15 @@ namespace undead_universal_patch_il2cpp.Patches
|
||||
{
|
||||
static PatchTypesResult patchResult = Util.ConfigPreparePatchTypes(
|
||||
PatchConfig.RegistrationPatch,
|
||||
"Registration patch (to be vetted, might not work)",
|
||||
"UnityEngine.PlayerPrefs",
|
||||
"GetInt"
|
||||
"Registration patch",
|
||||
"ProfileWatchUIFlow",
|
||||
"Button_Email"
|
||||
);
|
||||
|
||||
static bool Prepare() => patchResult.Success;
|
||||
|
||||
static MethodInfo TargetMethod() => patchResult.Method;
|
||||
|
||||
static void Postfix(ref string key, ref int defaultValue, ref int __result)
|
||||
{
|
||||
if (key.StartsWith("IncompleteRegistration-"))
|
||||
{
|
||||
__result = 0;
|
||||
UniversalPatchPlugin.Log.LogInfo("Detour'd IncompleteRegistration pref key");
|
||||
}
|
||||
}
|
||||
static bool Prefix() => false;
|
||||
}
|
||||
}
|
||||
63
Patches/Video/VideoTamperPatch.cs
Normal file
63
Patches/Video/VideoTamperPatch.cs
Normal file
@@ -0,0 +1,63 @@
|
||||
using System.Reflection;
|
||||
using System.Text.Json;
|
||||
using HarmonyLib;
|
||||
using undead_universal_patch_il2cpp.Core;
|
||||
using undead_universal_patch_il2cpp.Core.Config;
|
||||
|
||||
namespace undead_universal_patch_il2cpp.Patches.Video;
|
||||
|
||||
[HarmonyPatch]
|
||||
public class VideoTamperPatch
|
||||
{
|
||||
public static DediConfig<BaseOptionConfig> config = new("VideoTamperPatchConfig", JsonSerializer.Serialize(
|
||||
new BaseOptionConfig
|
||||
{
|
||||
Enabled = false
|
||||
}
|
||||
), null);
|
||||
|
||||
static PatchTypesResult patchTypesResult = Util.PreparePatchTypes(
|
||||
"Video anti-tamper hash disabler patch",
|
||||
"RecRoom.Core.Cinematics.CinematicVideoPlayer",
|
||||
"Start"
|
||||
);
|
||||
|
||||
static bool Prepare()
|
||||
{
|
||||
if (config.Get().Enabled) return patchTypesResult.Success;
|
||||
else return false;
|
||||
}
|
||||
|
||||
static MethodBase TargetMethod() => patchTypesResult.Method;
|
||||
|
||||
static void Prefix(ref object __instance)
|
||||
{
|
||||
PropertyInfo useProp = __instance.GetType().GetRuntimeProperty("useAntiTamperHash");
|
||||
if (useProp == null)
|
||||
{
|
||||
UniversalPatchPlugin.Log.LogError("VideoTamperPatch prefix: useAntiTamperHash was not found!");
|
||||
return;
|
||||
}
|
||||
|
||||
useProp.SetValue(__instance, false);
|
||||
}
|
||||
|
||||
static void Postfix(ref object __instance)
|
||||
{
|
||||
PropertyInfo autoProp = __instance.GetType().GetRuntimeProperty("autoPlay");
|
||||
if (autoProp == null)
|
||||
{
|
||||
UniversalPatchPlugin.Log.LogError("VideoTamperPatch postfix: autoPlay was not found!");
|
||||
return;
|
||||
}
|
||||
|
||||
MethodInfo playMethod = __instance.GetType().GetMethod("Play");
|
||||
if (playMethod == null)
|
||||
{
|
||||
UniversalPatchPlugin.Log.LogError("VideoTamperPatch postfix: playMethod was not found!");
|
||||
return;
|
||||
}
|
||||
|
||||
if ((bool)autoProp.GetValue(__instance)) playMethod.Invoke(__instance, []);
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,7 @@ using undead_universal_patch_il2cpp.Core;
|
||||
|
||||
namespace undead_universal_patch_il2cpp;
|
||||
|
||||
[BepInPlugin("dev.proxnet.recroom.universalpatch.noneac.il2cpp", "Undead Universal Patch", "2.1.0")]
|
||||
[BepInPlugin("dev.proxnet.recroom.universalpatch.noneac.il2cpp", "Undead Universal Patch", "3.1.0")]
|
||||
public class UniversalPatchPlugin : BasePlugin
|
||||
{
|
||||
public static new readonly ManualLogSource Log = Logger.CreateLogSource("UUPatch");
|
||||
|
||||
18
README.md
18
README.md
@@ -1,4 +1,9 @@
|
||||
# Undead Universal Patch
|
||||
## Undead Universal Patch
|
||||
|
||||
# Moved
|
||||
Moved to https://gitea.proxnet.dev/GalvanicCorrosion/UndeadUniversalPatch
|
||||
|
||||
## Legacy Patch Plugin
|
||||
|
||||
Non-EAC, IL2CPP build patcher for Rec Room (Dec 2018\*-*Apr 3 2020)
|
||||
|
||||
@@ -31,7 +36,9 @@ Run BepInEx interop on your build and add the following assemblies to new folder
|
||||
- `BepInEx/interop/Il2CppSystem.dll`
|
||||
- `BepInEx/interop/Photon3Unity3D.dll`
|
||||
- `BepInEx/interop/RecRoom.Datastructures.Runtime`
|
||||
- `BepInEx/interop/RecRoom.Promises.Runtime`
|
||||
- `BepInEx/interop/UnityEngine.CoreModule.dll`
|
||||
- `BepInEx/interop/UnityEngine.TextRenderingModule.dll`
|
||||
|
||||
## Dependencies
|
||||
|
||||
@@ -40,14 +47,7 @@ Run BepInEx interop on your build and add the following assemblies to new folder
|
||||
- [Mapster on GitHub](https://github.com/MapsterMapper/Mapster)
|
||||
|
||||
## Linux users
|
||||
|
||||
If you're unsure how to start your build on linux:
|
||||
|
||||
- Install Steam
|
||||
- Add Rec Room as a non-steam game
|
||||
- Set the compatibility mode to the latest stable version of proton
|
||||
- Use protontricks to add the doorstop DLL
|
||||
- Start Rec Room through Steam
|
||||
See [the Linux installation instructions](./LINUX.md). You may need to work around your distribution's package manager to install the necessary packages.
|
||||
|
||||
## GameManager Patches
|
||||
|
||||
|
||||
51
SERVERS.md
51
SERVERS.md
@@ -5,18 +5,43 @@
|
||||
Requests are sent after any of these events:
|
||||
* Nameserver response
|
||||
* Authentication response
|
||||
* Local account fetch response
|
||||
* Local account fetch response (has auth)
|
||||
|
||||
## Endpoints
|
||||
### `API: GET "/api/undead/v1/emotes"`
|
||||
Expects: `List<EmoteConfigDTO>`
|
||||
|
||||
[EmoteConfigDTO](#emoteconfigdto)
|
||||
### `API: GET "/api/undead/v1/emotes"` (after local account response)
|
||||
Expects: `List<EmoteConfigDTO>` [(to DTO)](#emoteconfigdto)
|
||||
|
||||
Replace existing emotes in the game with these, keyed by `UniqueName`.
|
||||
See [the source](./Core/CustomRecNet/CustomEmotes/RecNetEmotes.cs) for more information.
|
||||
Replace existing emotes in the game with these, keyed by `UniqueName`.<br>
|
||||
This is mostly a change to VR emotes. See "ContextualEmotesConfig" in the game's assets.
|
||||
|
||||
See [the source](./Core/Content/CustomRecNet/CustomEmotes/RecNetEmotes.cs) for more information.
|
||||
|
||||
### `API: GET "/api/undead/v1/photon"` (after local account response)
|
||||
Expects: `PhotonConfigDTO` [(to DTO)](#photonconfigdto)
|
||||
|
||||
The patch uses a Photon configuration given by the server.<br>
|
||||
When this fails, the patch will fall back to the local config, if enabled.
|
||||
|
||||
`ConnectionProtocol` is 0 for UDP, or 1 for TCP. Use UDP if you don't know what to use.<br>
|
||||
`ServerAddress`, `ServerPort`, and `ConnectionProtocol` are ignored when `SelfHosted` is enabled.
|
||||
|
||||
When using a self-hosted server, ideally, you should set the `AppID` *and* `VoiceAppID` to the name<br>
|
||||
of your application, e.g. Master when using the port for a default Masterserver.<br>
|
||||
Voice will go over the same gameserver port as PUN does when selfhosting.
|
||||
|
||||
See [the source](./Core/Content/CustomRecNet/CustomPhoton/CustomPhoton.cs) for more information.
|
||||
|
||||
### `API: GET "/api/undead/v1/knowndlls"` (post-nameserver)
|
||||
Expects: `List<string>`
|
||||
|
||||
Add custom DLL filenames to `CheatManager.KnownDlls`. `winhttp.dll` is added by default and does not need to be specified by the server.
|
||||
When the server patch is enabled at the same time as the local patch (HilePatch), the local patch will be used as a fallback and will add only `winhttp.dll`.
|
||||
|
||||
See [the source](./Core/Content/CustomRecNet/CheatManager/CustomCheatManager.cs) for more information.
|
||||
|
||||
## DTOs
|
||||
|
||||
### `EmoteConfigDTO`
|
||||
```c#
|
||||
public class EmoteConfigDTO
|
||||
@@ -29,3 +54,17 @@ public class EmoteConfigDTO
|
||||
public bool OnlyBroadcastToTeam { get; set; }
|
||||
}
|
||||
```
|
||||
|
||||
### `PhotonConfigDTO`
|
||||
```c#
|
||||
public class PhotonConfigDTO
|
||||
{
|
||||
public bool Logging { get; set; }
|
||||
public string AppID { get; set; }
|
||||
public string VoiceAppID { get; set; }
|
||||
public bool SelfHosted { get; set; }
|
||||
public string ServerAddress { get; set; }
|
||||
public int ServerPort { get; set; }
|
||||
public byte ConnectionProtocol { get; set; }
|
||||
}
|
||||
```
|
||||
@@ -4,7 +4,7 @@
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<AssemblyName>undead_universal_patch_il2cpp</AssemblyName>
|
||||
<Description>Non-EAC, IL2CPP build patcher for Rec Room (Late 2018*-*April 2020) </Description>
|
||||
<Version>2.1.0</Version>
|
||||
<Version>3.1.0</Version>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<RestoreAdditionalProjectSources>
|
||||
@@ -15,6 +15,10 @@
|
||||
<RootNamespace>undead_universal_patch_il2cpp</RootNamespace>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Include="Core\Content\CustomRecNet\CheatManager\CustomCheatManager.cs" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="BepInEx.Unity.IL2CPP" Version="6.0.0-be.*" IncludeAssets="compile" />
|
||||
<PackageReference Include="Mapster" Version="7.4.0" />
|
||||
@@ -42,5 +46,8 @@
|
||||
<Reference Include="UnityEngine.CoreModule">
|
||||
<HintPath>AssemblyReferences\UnityEngine.CoreModule.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="UnityEngine.TextRenderingModule">
|
||||
<HintPath>AssemblyReferences\UnityEngine.TextRenderingModule.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
||||
Reference in New Issue
Block a user