using System; using System.Reflection; using HarmonyLib; using undead_universal_patch_il2cpp.Core; using undead_universal_patch_il2cpp.Core.Config; namespace undead_universal_patch_il2cpp.Patches { [HarmonyPatch] public class PhotonPatchEvent { static PatchTypesResult patchResult = Util.ConfigPreparePatchTypes( PhotonConfig.PatchPhotonIds, "Photon ConnectUsingSettings event path", "PhotonNetwork", "ConnectUsingSettings" ); static bool Prepare() => patchResult.Success; static MethodInfo TargetMethod() => patchResult.Method; static void Prefix() { Util.ConditionalDebug("Attempting Photon patch"); PhotonPatch.Patch(); } } [HarmonyPatch] public class ForceSelfHostedPhoton { class HarmonyState { public object code; } static PatchTypesResult patchResult = Util.ConfigsPreparePatchTypes( [ PhotonConfig.PatchPhotonIds, PhotonConfig.SelfHosted ], "Force JoinOrCreateRoom when connected to master", "PUNNetworkManager", "OnConnectedToMaster" ); static bool Prepare() => patchResult.Success; static MethodBase TargetMethod() => patchResult.Method; static void Prefix(ref PUNNetworkManager __instance, ref HarmonyState __state) { __state = new HarmonyState(); PropertyInfo targetGameSessionProperty = __instance.GetType().GetRuntimeProperty("targetGameSession"); if (targetGameSessionProperty == null) { UniversalPatchPlugin.Log.LogFatal("Cannot force masterserver: targetGameSessionProperty was null."); return; } var targetGameSession = targetGameSessionProperty.GetValue(__instance); if (targetGameSession == null) { UniversalPatchPlugin.Log.LogFatal("Cannot force masterserver: targetGameSession was null."); return; } PropertyInfo photonRegionIdProperty = targetGameSession.GetType().GetRuntimeProperty("PhotonRegionId"); if (photonRegionIdProperty == null) { UniversalPatchPlugin.Log.LogFatal("Cannot force masterserver: photonRegionIdProperty was null."); return; } __state.code = photonRegionIdProperty.GetValue(targetGameSession); photonRegionIdProperty.SetValue(targetGameSession, 4); Util.ConditionalDebug("Forcing masterserver"); } static void Postfix(ref PUNNetworkManager __instance, ref HarmonyState __state) { PropertyInfo targetGameSessionProperty = __instance.GetType().GetRuntimeProperty("targetGameSession"); if (targetGameSessionProperty == null) { UniversalPatchPlugin.Log.LogFatal("Cannot force masterserver postfix: targetGameSessionProperty was null."); return; } var targetGameSession = targetGameSessionProperty.GetValue(__instance); if (targetGameSession == null) { UniversalPatchPlugin.Log.LogFatal("Cannot force masterserver postfix: targetGameSession was null."); return; } PropertyInfo photonRegionIdProperty = targetGameSession.GetType().GetRuntimeProperty("PhotonRegionId"); if (photonRegionIdProperty == null) { UniversalPatchPlugin.Log.LogFatal("Cannot force masterserver: photonRegionIdProperty was null."); return; } photonRegionIdProperty.SetValue(targetGameSession, __state.code); Util.ConditionalDebug("Masterserver regionId roundtrip"); } } public class PhotonPatch { public static void Patch() { // It's fine to reference enums after we're pretty sure the relevant types exist // i think Type photonNetworkType = AccessTools.TypeByName("PhotonNetwork"); Type serverSettingsType = AccessTools.TypeByName("ServerSettings"); if (photonNetworkType == null || serverSettingsType == null) { UniversalPatchPlugin.Log.LogError("Cannot patch Photon: PhotonNetwork or ServerSettings types were not found. Is this build supported?"); return; } PropertyInfo photonServerSettingsProperty = photonNetworkType.GetRuntimeProperty("PhotonServerSettings"); object serverSettings = photonServerSettingsProperty.GetValue(serverSettingsType); if (PhotonConfig.PunLogging.Value) { PropertyInfo loggingProperty = serverSettingsType.GetRuntimeProperty("PunLogging"); loggingProperty.SetValue(serverSettings, PhotonLogLevel.Full); PropertyInfo networkLoggingProperty = serverSettingsType.GetRuntimeProperty("NetworkLogging"); networkLoggingProperty.SetValue(serverSettings, ExitGames.Client.Photon.DebugLevel.ALL); } PropertyInfo appIdProperty = serverSettingsType.GetRuntimeProperty("AppID"); PropertyInfo voiceAppIdProperty = serverSettingsType.GetRuntimeProperty("VoiceAppID"); Util.ConditionalDebug($"New Photon AppID: '{PhotonConfig.AppID.Value}'"); Util.ConditionalDebug($"New Photon AppID: '{PhotonConfig.VoiceAppID.Value}'"); appIdProperty.SetValue(serverSettings, PhotonConfig.AppID.Value); voiceAppIdProperty.SetValue(serverSettings, PhotonConfig.VoiceAppID.Value); if (PhotonConfig.SelfHosted.Value) { MethodInfo useMyServerMethod = serverSettingsType.GetMethod("UseMyServer"); useMyServerMethod.Invoke(serverSettings, [ PhotonConfig.ServerAddress.Value, PhotonConfig.ServerPort.Value, PhotonConfig.AppID.Value, ]); } Type authValuesType = AccessTools.TypeByName("AuthenticationValues"); if (authValuesType != null) { PropertyInfo networkingPeerProperty = photonNetworkType.GetRuntimeProperty("networkingPeer"); if (networkingPeerProperty == null) { UniversalPatchPlugin.Log.LogError("Cannot patch Photon: networkingPeerProperty was null. Is this build supported?"); return; } if (networkingPeerProperty.GetValue(null) == null) { UniversalPatchPlugin.Log.LogError("Cannot patch Photon: networkingPeerInstance was null. Is this build supported?"); return; } string id = Core.Util.LocalInstanceGuid; Util.ConditionalDebug($"Instance GUID is {id}"); PhotonNetwork.AuthValues = new AuthenticationValues { UserId = id }; Util.ConditionalDebug($"Set the authValues userId to {id}"); } UniversalPatchPlugin.Log.LogInfo($"Photon patch ({(PhotonConfig.SelfHosted.Value ? "self-hosted" : "cloud")}) succeeded."); } } }