mirror of
https://github.com/DorkSquadRR/DorkNet.git
synced 2026-10-26 07:28:45 -07:00
Improve client mod patching setup
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
## .NET
|
## .NET
|
||||||
bin/
|
bin/
|
||||||
obj/
|
obj/
|
||||||
|
build/
|
||||||
*.user
|
*.user
|
||||||
*.suo
|
*.suo
|
||||||
.vs/
|
.vs/
|
||||||
|
|||||||
@@ -19,17 +19,32 @@
|
|||||||
they would be derivative works of the game anyway, so we never
|
they would be derivative works of the game anyway, so we never
|
||||||
reference them. Only MelonLoader's own DLLs are needed.
|
reference them. Only MelonLoader's own DLLs are needed.
|
||||||
|
|
||||||
tools/build-patcher-zip.ps1 downloads the MelonLoader release zip
|
By default the project downloads the pinned MelonLoader release
|
||||||
and points MelonLoaderDir at its extracted contents, so a fresh
|
into DorkNet.ClientMod/build/ and references those DLLs. Pass
|
||||||
contributor checkout builds without a local Rec Room install.
|
-p:MelonLoaderDir=<path-to-extracted-MelonLoader> only when you
|
||||||
|
deliberately want to use a local override.
|
||||||
To build outside the script (manual dev loop):
|
|
||||||
dotnet build -p:MelonLoaderDir=<path-to-extracted-MelonLoader>
|
|
||||||
-->
|
-->
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<MelonLoaderDir Condition="'$(MelonLoaderDir)' == ''">$(MSBuildThisFileDirectory)..\build\melonloader</MelonLoaderDir>
|
<MelonLoaderVersion Condition="'$(MelonLoaderVersion)' == ''">v0.6.6</MelonLoaderVersion>
|
||||||
|
<MelonLoaderCacheRoot>$(MSBuildThisFileDirectory)build\melonloader</MelonLoaderCacheRoot>
|
||||||
|
<MelonLoaderZip>$(MelonLoaderCacheRoot)\MelonLoader.x64.$(MelonLoaderVersion).zip</MelonLoaderZip>
|
||||||
|
<MelonLoaderDir Condition="'$(MelonLoaderDir)' == ''">$(MelonLoaderCacheRoot)\MelonLoader</MelonLoaderDir>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<Target Name="EnsureMelonLoaderReferences"
|
||||||
|
BeforeTargets="ResolveAssemblyReferences"
|
||||||
|
Condition="!Exists('$(MelonLoaderDir)\net6\MelonLoader.dll')">
|
||||||
|
<MakeDir Directories="$(MelonLoaderCacheRoot)" />
|
||||||
|
<DownloadFile
|
||||||
|
SourceUrl="https://github.com/LavaGang/MelonLoader/releases/download/$(MelonLoaderVersion)/MelonLoader.x64.zip"
|
||||||
|
DestinationFolder="$(MelonLoaderCacheRoot)"
|
||||||
|
DestinationFileName="MelonLoader.x64.$(MelonLoaderVersion).zip"
|
||||||
|
SkipUnchangedFiles="true" />
|
||||||
|
<Unzip SourceFiles="$(MelonLoaderZip)"
|
||||||
|
DestinationFolder="$(MelonLoaderCacheRoot)"
|
||||||
|
OverwriteReadOnlyFiles="true" />
|
||||||
|
</Target>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Reference Include="MelonLoader">
|
<Reference Include="MelonLoader">
|
||||||
<HintPath>$(MelonLoaderDir)\net6\MelonLoader.dll</HintPath>
|
<HintPath>$(MelonLoaderDir)\net6\MelonLoader.dll</HintPath>
|
||||||
|
|||||||
+110
-10
@@ -42,6 +42,7 @@ public class Mod : MelonMod
|
|||||||
internal static string? DiagnosticsLogPath;
|
internal static string? DiagnosticsLogPath;
|
||||||
private static readonly Dictionary<string, Type> ResolvedTypeCache = new();
|
private static readonly Dictionary<string, Type> ResolvedTypeCache = new();
|
||||||
private readonly HashSet<string> _diagnosticPatchLabels = new();
|
private readonly HashSet<string> _diagnosticPatchLabels = new();
|
||||||
|
private bool _networkPatchesRegistered;
|
||||||
private bool _diagnosticCoreRegistered;
|
private bool _diagnosticCoreRegistered;
|
||||||
private bool _diagnosticGameComplete;
|
private bool _diagnosticGameComplete;
|
||||||
private int _diagnosticRetryFrame;
|
private int _diagnosticRetryFrame;
|
||||||
@@ -75,6 +76,7 @@ public class Mod : MelonMod
|
|||||||
Instance = this;
|
Instance = this;
|
||||||
Log.Msg("=== DorkNet ClientMod loading ===");
|
Log.Msg("=== DorkNet ClientMod loading ===");
|
||||||
LoadConfig();
|
LoadConfig();
|
||||||
|
RegisterNetworkPatches();
|
||||||
DiagnosticPatches.Write("[lifecycle] OnInitializeMelon");
|
DiagnosticPatches.Write("[lifecycle] OnInitializeMelon");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -82,12 +84,7 @@ public class Mod : MelonMod
|
|||||||
{
|
{
|
||||||
DiagnosticPatches.Write("[lifecycle] OnLateInitializeMelon");
|
DiagnosticPatches.Write("[lifecycle] OnLateInitializeMelon");
|
||||||
Log.Msg("=== Registering client patches ===");
|
Log.Msg("=== Registering client patches ===");
|
||||||
TryPatch("Uri ctor (string)", typeof(Uri), "ctor",
|
RegisterNetworkPatches();
|
||||||
new[] { typeof(string) },
|
|
||||||
prefix: nameof(UriPatches.UriStringCtor_Prefix));
|
|
||||||
TryPatch("Uri ctor (string, UriKind)", typeof(Uri), "ctor",
|
|
||||||
new[] { typeof(string), typeof(UriKind) },
|
|
||||||
prefix: nameof(UriPatches.UriStringCtor_Prefix));
|
|
||||||
TryPatchByName("PhotonNetwork", "ConnectUsingSettings",
|
TryPatchByName("PhotonNetwork", "ConnectUsingSettings",
|
||||||
prefix: nameof(PhotonPatches.PhotonAppIdOverride_Prefix));
|
prefix: nameof(PhotonPatches.PhotonAppIdOverride_Prefix));
|
||||||
// Hook the watch's own AppSettings + AuthValues builders directly.
|
// Hook the watch's own AppSettings + AuthValues builders directly.
|
||||||
@@ -223,6 +220,57 @@ public class Mod : MelonMod
|
|||||||
Log.Msg("=== Client patches registered ===");
|
Log.Msg("=== Client patches registered ===");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void RegisterNetworkPatches()
|
||||||
|
{
|
||||||
|
if (_networkPatchesRegistered) return;
|
||||||
|
|
||||||
|
var complete = true;
|
||||||
|
complete &= TryPatch("Uri ctor (string)", typeof(Uri), "ctor",
|
||||||
|
new[] { typeof(string) },
|
||||||
|
prefix: nameof(UriPatches.UriStringCtor_Prefix));
|
||||||
|
complete &= TryPatch("Uri ctor (string, UriKind)", typeof(Uri), "ctor",
|
||||||
|
new[] { typeof(string), typeof(UriKind) },
|
||||||
|
prefix: nameof(UriPatches.UriStringCtor_Prefix));
|
||||||
|
complete &= TryPatchByName("BestHTTP.HTTPRequest", "Send",
|
||||||
|
prefix: nameof(UriPatches.HttpRequestSend_Prefix));
|
||||||
|
complete &= TryPatchHttpManagerStringSendRequestOverloads();
|
||||||
|
complete &= TryPatchByName("BestHTTP.HTTPManager", "SendRequest",
|
||||||
|
args: new[] { ResolveType("BestHTTP.HTTPRequest") ?? typeof(object) },
|
||||||
|
prefix: nameof(UriPatches.HttpManagerSendRequestObject_Prefix));
|
||||||
|
|
||||||
|
_networkPatchesRegistered = complete;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool TryPatchHttpManagerStringSendRequestOverloads()
|
||||||
|
{
|
||||||
|
var type = ResolveType("BestHTTP.HTTPManager");
|
||||||
|
if (type is null)
|
||||||
|
{
|
||||||
|
Log.Warning("[patch-miss] BestHTTP.HTTPManager.SendRequest(string): type not found");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var prefix = GetPatchMethod(nameof(UriPatches.HttpManagerSendRequestString_Prefix));
|
||||||
|
var patched = 0;
|
||||||
|
foreach (var method in AccessTools.GetDeclaredMethods(type))
|
||||||
|
{
|
||||||
|
if (method.Name != "SendRequest") continue;
|
||||||
|
var parameters = method.GetParameters();
|
||||||
|
if (parameters.Length == 0 || parameters[0].ParameterType != typeof(string)) continue;
|
||||||
|
HarmonyInstance.Patch(method, prefix: new HarmonyMethod(prefix));
|
||||||
|
patched++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (patched == 0)
|
||||||
|
{
|
||||||
|
Log.Warning("[patch-miss] BestHTTP.HTTPManager.SendRequest(string)");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Log.Msg($"[patch-ok] BestHTTP.HTTPManager.SendRequest(string) overloads x{patched}");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
public override void OnUpdate()
|
public override void OnUpdate()
|
||||||
{
|
{
|
||||||
if (_diagnosticGameComplete) return;
|
if (_diagnosticGameComplete) return;
|
||||||
@@ -504,18 +552,70 @@ public class Mod : MelonMod
|
|||||||
|
|
||||||
internal static class UriPatches
|
internal static class UriPatches
|
||||||
{
|
{
|
||||||
|
public static void HttpManagerSendRequestString_Prefix(ref string url)
|
||||||
|
{
|
||||||
|
RewriteString(ref url, "httpmanager-rewrite");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void HttpManagerSendRequestObject_Prefix(object request)
|
||||||
|
{
|
||||||
|
RewriteRequestUri(request, "httpmanager-request-rewrite");
|
||||||
|
}
|
||||||
|
|
||||||
public static void UriStringCtor_Prefix(ref string uriString)
|
public static void UriStringCtor_Prefix(ref string uriString)
|
||||||
|
{
|
||||||
|
RewriteString(ref uriString, "uri-rewrite");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void HttpRequestSend_Prefix(object __instance)
|
||||||
|
{
|
||||||
|
RewriteRequestUri(__instance, "http-rewrite");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void RewriteRequestUri(object request, string label)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var uriProp = request.GetType().GetProperty("Uri", BindingFlags.Public | BindingFlags.Instance);
|
||||||
|
if (uriProp?.GetValue(request) is not Uri uri) return;
|
||||||
|
|
||||||
|
var rewritten = RewriteUri(uri);
|
||||||
|
if (rewritten is null) return;
|
||||||
|
|
||||||
|
uriProp.SetValue(request, rewritten);
|
||||||
|
Mod.Log.Msg($"[{label}] {uri} → {rewritten}");
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Mod.Log.Warning($"[{label}] failed: {ex.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void RewriteString(ref string uriString, string label)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(uriString)) return;
|
if (string.IsNullOrEmpty(uriString)) return;
|
||||||
var host = Mod.Cfg.ServerHost;
|
var host = Mod.Cfg.ServerHost;
|
||||||
if (string.IsNullOrEmpty(host)) return;
|
if (string.IsNullOrEmpty(host)) return;
|
||||||
if (uriString.IndexOf(".rec.net", StringComparison.OrdinalIgnoreCase) < 0) return;
|
if (uriString.IndexOf(".rec.net", StringComparison.OrdinalIgnoreCase) < 0) return;
|
||||||
var rewritten = uriString.Replace(".rec.net", "." + host);
|
var rewritten = uriString.Replace(".rec.net", "." + host);
|
||||||
if (rewritten != uriString)
|
if (rewritten == uriString) return;
|
||||||
|
Mod.Log.Msg($"[{label}] {uriString} → {rewritten}");
|
||||||
|
uriString = rewritten;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Uri? RewriteUri(Uri uri)
|
||||||
|
{
|
||||||
|
var host = Mod.Cfg.ServerHost;
|
||||||
|
if (string.IsNullOrEmpty(host)) return null;
|
||||||
|
if (!uri.Host.EndsWith(".rec.net", StringComparison.OrdinalIgnoreCase)) return null;
|
||||||
|
|
||||||
|
var service = uri.Host[..^".rec.net".Length];
|
||||||
|
if (string.IsNullOrWhiteSpace(service)) return null;
|
||||||
|
|
||||||
|
return new UriBuilder(uri)
|
||||||
{
|
{
|
||||||
Mod.Log.Msg($"[uri-rewrite] {uriString} → {rewritten}");
|
Host = service + "." + host,
|
||||||
uriString = rewritten;
|
}.Uri;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user