Files
PersistentID/PersistentID/PersistentID.cs
T
2026-04-22 21:59:43 +01:00

330 lines
12 KiB
C#

using HarmonyLib;
using Il2Cpp;
using MelonLoader;
[assembly: MelonInfo(typeof(PersistentID.PersistentID), "Persistent IDs", "1.0.0", "404NyanFound")]
namespace PersistentID;
public class PersistentID : MelonMod
{
private static readonly HashSet<int> PatchedDevices = new();
private const string SwitchPrefix = "404ID:Switch:";
private const string PatchPanelPrefix = "404ID:PatchPanel:";
private const string ServerPrefix = "404ID:Server:";
public override void OnInitializeMelon() => MelonLogger.Msg(System.ConsoleColor.Green, "[Persistent IDs] Hello Administrator!");
private static string CleanId(string prefix, string switchId, int hashCode)
{
if (switchId.StartsWith(prefix) && switchId.Contains('_'))
{
string cleanId = switchId.Split('_')[0];
if (!PatchedDevices.Contains(hashCode))
MelonLogger.Msg($"Unity Id Removal | Cleaned Device Id | {switchId} -> {cleanId}");
return cleanId;
}
return switchId;
}
#region SWITCH ID PERSISTENCE
[HarmonyPatch(typeof(NetworkSwitch), nameof(NetworkSwitch.Start))]
public static class NewSwitchIdPatch
{
public static void Postfix(NetworkSwitch __instance)
{
string currentId = __instance.switchId;
if (string.IsNullOrEmpty(currentId) || !currentId.StartsWith(SwitchPrefix))
{
// Apply new GUID-based ID. Remapping will handle legacy ids.
string uniqueId = $"{SwitchPrefix}{Guid.NewGuid().ToString()[..8]}";
// Set values with unique id
__instance.switchId = uniqueId;
__instance.gameObject.name = uniqueId;
// Persist the unique id in the save
if (SaveSystem.displayToRawMap != null)
{
SaveSystem.displayToRawMap[uniqueId] = uniqueId;
if (!string.IsNullOrEmpty(currentId))
SaveSystem.displayToRawMap.Remove(currentId); // Clean up the old legacy ids
}
// Refresh UI
__instance.UpdateScreenUI();
}
}
}
[HarmonyPatch(typeof(NetworkSwitch), nameof(NetworkSwitch.switchId), MethodType.Getter)]
public static class SwitchIdPropertyPatch
{
// Capture generated ID and clean it! SAY NO TO UNITY "GETINSTANCEID" SUFFIXES!
public static void Postfix(NetworkSwitch __instance, ref string __result)
{
if (string.IsNullOrEmpty(__result)) return;
int instanceKey = __instance.GetHashCode();
__result = CleanId(SwitchPrefix, __result, instanceKey);
if (!PatchedDevices.Contains(instanceKey))
PatchedDevices.Add(instanceKey);
}
}
[HarmonyPatch(typeof(NetworkSwitch), nameof(NetworkSwitch.GenerateUniqueSwitchId))]
public static class UniqueSwitchIdPatch
{
// Capture generated ID and clean it! SAY NO TO UNITY "GETINSTANCEID" SUFFIXES!
public static void Postfix(NetworkSwitch __instance, ref string __result)
{
if (string.IsNullOrEmpty(__result)) return;
int instanceKey = __instance.GetHashCode();
__result = CleanId(SwitchPrefix, __result, instanceKey);
if (!PatchedDevices.Contains(instanceKey))
PatchedDevices.Add(instanceKey);
}
}
#endregion
#region PATCH PANEL ID PERSISTENCE
[HarmonyPatch(typeof(PatchPanel), nameof(PatchPanel.Awake))]
public static class NewPatchPanelIdpatch
{
public static void Postfix(PatchPanel __instance)
{
string currentId = __instance.patchPanelId;
if (string.IsNullOrEmpty(currentId) || !currentId.StartsWith(PatchPanelPrefix))
{
// Apply new GUID-based ID. Remapping will handle legacy ids.
string uniqueId = $"{PatchPanelPrefix}{Guid.NewGuid().ToString()[..8]}";
// Set values with unique id
__instance.patchPanelId = uniqueId;
__instance.gameObject.name = uniqueId;
// Persist the unique id in the save
if (SaveSystem.displayToRawMap != null)
{
SaveSystem.displayToRawMap[uniqueId] = uniqueId;
if (!string.IsNullOrEmpty(currentId))
SaveSystem.displayToRawMap.Remove(currentId); // Clean up the old legacy ids
}
}
}
}
[HarmonyPatch(typeof(PatchPanel), nameof(PatchPanel.patchPanelId), MethodType.Getter)]
public static class PatchPanelIdPropertyPatch
{
// Capture generated ID and clean it! SAY NO TO UNITY "GETINSTANCEID" SUFFIXES!
public static void Postfix(PatchPanel __instance, ref string __result)
{
if (string.IsNullOrEmpty(__result)) return;
int instanceKey = __instance.GetHashCode();
__result = CleanId(PatchPanelPrefix, __result, instanceKey);
if (!PatchedDevices.Contains(instanceKey))
PatchedDevices.Add(instanceKey);
}
}
[HarmonyPatch(typeof(PatchPanel), nameof(PatchPanel.GenerateUniquePatchPanelId))]
public static class UniquePatchPanelIdPatch
{
// Capture generated ID and clean it! SAY NO TO UNITY "GETINSTANCEID" SUFFIXES!
public static void Postfix(Server __instance, ref string __result)
{
if (string.IsNullOrEmpty(__result)) return;
int instanceKey = __instance.GetHashCode();
__result = CleanId(PatchPanelPrefix, __result, instanceKey);
if (!PatchedDevices.Contains(instanceKey))
PatchedDevices.Add(instanceKey);
}
}
#endregion
#region SERVER ID PERSISTENCE
[HarmonyPatch(typeof(Server), nameof(Server.Start))]
public static class NewServerIdPatch
{
public static void Postfix(Server __instance)
{
string currentId = __instance.ServerID;
if (string.IsNullOrEmpty(currentId) || !currentId.StartsWith(ServerPrefix))
{
// Apply new GUID-based ID. Remapping will handle legacy ids.
string uniqueId = $"{ServerPrefix}{Guid.NewGuid().ToString()[..8]}";
// Set values with unique id
__instance.ServerID = uniqueId;
__instance.gameObject.name = uniqueId;
// Persist the unique id in the save
if (SaveSystem.displayToRawMap != null)
{
SaveSystem.displayToRawMap[uniqueId] = uniqueId;
if (!string.IsNullOrEmpty(currentId))
SaveSystem.displayToRawMap.Remove(currentId); // Clean up the old legacy ids
}
// Refresh UI
__instance.UpdateServerScreenUI();
}
}
}
[HarmonyPatch(typeof(Server), nameof(Server.ServerID), MethodType.Getter)]
public static class ServerIdPropertyPatch
{
// Capture generated ID and clean it! SAY NO TO UNITY "GETINSTANCEID" SUFFIXES!
public static void Postfix(Server __instance, ref string __result)
{
if (string.IsNullOrEmpty(__result)) return;
int instanceKey = __instance.GetHashCode();
__result = CleanId(ServerPrefix, __result, instanceKey);
if (!PatchedDevices.Contains(instanceKey))
PatchedDevices.Add(instanceKey);
}
}
[HarmonyPatch(typeof(Server), nameof(Server.GenerateUniqueServerId))]
public static class UniqueServerIdPatch
{
// Capture generated ID and clean it! SAY NO TO UNITY "GETINSTANCEID" SUFFIXES!
public static void Postfix(Server __instance, ref string __result)
{
if (string.IsNullOrEmpty(__result)) return;
int instanceKey = __instance.GetHashCode();
__result = CleanId(ServerPrefix, __result, instanceKey);
if (!PatchedDevices.Contains(instanceKey))
PatchedDevices.Add(instanceKey);
}
}
#endregion
[HarmonyPatch(typeof(WaypointInitializationSystem), nameof(WaypointInitializationSystem.LoadNetworkState))]
public static class MapDataHealing
{
public static void Prefix(object[] __args)
{
if (__args is null || __args.Length < 3) return;
NetworkSaveData data = (NetworkSaveData)__args[0];
MelonLogger.Msg("Checking for legacy Switch IDs in map data...");
foreach (var swData in data.switches)
{
string oldId = swData.switchID;
if (!string.IsNullOrEmpty(oldId) && !oldId.StartsWith(SwitchPrefix))
{
string newGuid = $"{SwitchPrefix}{Guid.NewGuid().ToString()[..8]}";
swData.switchID = newGuid;
int healedCables = 0;
foreach (var cable in data.cables)
{
if (cable.startPoint.switchID == oldId)
{
cable.startPoint.switchID = newGuid;
healedCables++;
}
if (cable.endPoint.switchID == oldId)
{
cable.endPoint.switchID = newGuid;
healedCables++;
}
}
MelonLogger.Msg($"Legacy Mapping | Switch: {oldId} -> {newGuid} | Healed Cables: {healedCables}");
}
}
foreach (var ppData in data.patchPanels)
{
string oldId = ppData.patchPanelID;
if (!string.IsNullOrEmpty(oldId) && !oldId.StartsWith(PatchPanelPrefix))
{
string newGuid = $"{PatchPanelPrefix}{Guid.NewGuid().ToString()[..8]}";
ppData.patchPanelID = newGuid;
int healedCables = 0;
foreach (var cable in data.cables)
{
if (cable.startPoint.switchID.StartsWith(oldId))
{
cable.startPoint.switchID = cable.startPoint.switchID.Replace(oldId, newGuid);
healedCables++;
}
if (cable.endPoint.switchID.StartsWith(oldId))
{
cable.endPoint.switchID = cable.endPoint.switchID.Replace(oldId, newGuid);
healedCables++;
}
}
MelonLogger.Msg($"Legacy Mapping | Patch Panel: {oldId} -> {newGuid} | Healed Cables: {healedCables}");
}
}
foreach (var serverData in data.servers)
{
string oldId = serverData.serverID;
if (!string.IsNullOrEmpty(oldId) && !oldId.StartsWith(ServerPrefix))
{
string newGuid = $"{ServerPrefix}{Guid.NewGuid().ToString()[..8]}";
serverData.serverID = newGuid;
int healedCables = 0;
foreach (var cable in data.cables)
{
if (cable.startPoint.serverID == oldId)
{
cable.startPoint.serverID = newGuid;
healedCables++;
}
if (cable.endPoint.serverID == oldId)
{
cable.endPoint.serverID = newGuid;
healedCables++;
}
}
MelonLogger.Msg($"Legacy Mapping | Server: {oldId} -> {newGuid} | Healed Cables: {healedCables}");
}
}
}
public static void Postfix(WaypointInitializationSystem __instance) => __instance.RequestRouteEvaluation();
}
}