210 lines
5.7 KiB
C#
210 lines
5.7 KiB
C#
// Undead Universal Patch - for patching Rec Room builds
|
|
// Copyright (C) 2026 proxnet.dev (@zombieb)
|
|
//
|
|
// This program is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY
|
|
|
|
using HarmonyLib;
|
|
using System;
|
|
using System.Linq;
|
|
using System.Reflection;
|
|
using UndeadUniversalPatch.Core.Exceptions;
|
|
|
|
namespace UndeadUniversalPatch.Core;
|
|
|
|
internal static class BuildSettings
|
|
{
|
|
public static Assembly GetAssemblyCSharp()
|
|
{
|
|
if (!Init.GetIsRecRoom())
|
|
throw new NotRecRoomException();
|
|
|
|
return AccessTools.TypeByName("BootSequence").Assembly; // always unobfuscated
|
|
}
|
|
|
|
private static Type GetBuildSettings()
|
|
{
|
|
var assembly = GetAssemblyCSharp();
|
|
|
|
try
|
|
{
|
|
Type type = assembly.GetTypes().First(type => Symbols.BuildSettings.Contains(type.Name));
|
|
return type;
|
|
} catch (ReflectionTypeLoadException ex)
|
|
{
|
|
Type type = ex.Types.First(type => Symbols.BuildSettings.Contains(type.Name));
|
|
return type;
|
|
} catch
|
|
{
|
|
return null;
|
|
}
|
|
}
|
|
|
|
public static string GetVersion()
|
|
{
|
|
var unknown = "Unknown Version";
|
|
|
|
var buildSettings = GetBuildSettings();
|
|
if (buildSettings == null)
|
|
#if NET35
|
|
{
|
|
try
|
|
{
|
|
// doesn't exist? -> error will be caught & unknown will be returned
|
|
var field = AccessTools.Field("PUNNetworkManager:BUILD_VERSION");
|
|
|
|
if (field != null) return (string)field.GetValue(null);
|
|
else return "Unknown Legacy Version";
|
|
} catch
|
|
{
|
|
return unknown;
|
|
}
|
|
}
|
|
#else
|
|
return unknown;
|
|
#endif
|
|
|
|
Func<string, bool> check = (string value) =>
|
|
{
|
|
if (value == null) return false;
|
|
return value.StartsWith("20") || value.EndsWith("_EA");
|
|
};
|
|
|
|
try
|
|
{
|
|
#if NET6_0
|
|
return (string)buildSettings.GetRuntimeProperties().Where(prop => prop.PropertyType == typeof(string)).First(prop =>
|
|
{
|
|
var value = (string)prop.GetValue(null);
|
|
return check(value);
|
|
}).GetValue(null);
|
|
#else
|
|
return (string)buildSettings.GetFields().Where(field => field.FieldType == typeof(string)).First(field =>
|
|
{
|
|
var value = (string)field.GetValue(null);
|
|
return check(value);
|
|
}).GetValue(null);
|
|
#endif
|
|
}
|
|
catch
|
|
{
|
|
return unknown;
|
|
}
|
|
}
|
|
|
|
public static string GetBuildTimestamp()
|
|
{
|
|
var unknown = "Unknown Timestamp";
|
|
|
|
var buildSettings = GetBuildSettings();
|
|
if (buildSettings == null) return unknown;
|
|
|
|
// Only one `long` exists on BuildSettings across all supported builds
|
|
try
|
|
{
|
|
#if NET6_0
|
|
var foundProp = buildSettings.GetRuntimeProperties()
|
|
.First(prop => prop.PropertyType == typeof(long));
|
|
|
|
var value = (long)foundProp.GetValue(null);
|
|
return new DateTime(value).ToString();
|
|
#else
|
|
var foundField = buildSettings.GetFields()
|
|
.First(field => field.FieldType == typeof(long));
|
|
|
|
var value = (long)foundField.GetValue(null);
|
|
return new DateTime(value).ToString();
|
|
#endif
|
|
}
|
|
catch
|
|
{
|
|
return unknown;
|
|
}
|
|
}
|
|
|
|
private static class Symbols
|
|
{
|
|
// type list compiled by @zombieb
|
|
public static string[] BuildSettings = [
|
|
"BuildSettings",
|
|
"BBHENFCNLAB",
|
|
"KMJJGELKNAP",
|
|
"FJEEPOKGDNG",
|
|
"LACHJMJGMPK",
|
|
"NNBKABHFGFB",
|
|
"KMGJBIHAAJL",
|
|
"FALNDOJFPMN",
|
|
"IODMKGDNMID",
|
|
"HIPJBMLBLHH",
|
|
"LEADBBLICBL",
|
|
"NPPACKKFLIK",
|
|
"MOFAAFLMFJO",
|
|
"EMIDOAHOJNO",
|
|
"IKJNDDBHIAC",
|
|
"OOCIKEIJMCA",
|
|
"HPFCOJFIIKK",
|
|
"MONBJIBCJFA",
|
|
"GFDKEKGOMCP",
|
|
"MIMHAGFDGND",
|
|
"LFJMHJPHKOK",
|
|
"NOHBMMJBMIP",
|
|
"GJBEJNGDEJM",
|
|
"OGBGLFJGKJL",
|
|
"PEJOGOOEOKE",
|
|
"FDKFNHNNDEE",
|
|
"EDNIOJBEKLL",
|
|
"FEKFIFPGDDP",
|
|
"POOFEABAPOB",
|
|
"JHFKADKFKPD",
|
|
"GGKABOEOKMI",
|
|
"FAPDBIGGJHM",
|
|
"EPKEIOCFFMO",
|
|
"ECLPNEHKLEP",
|
|
"BGMDPOMLCKD",
|
|
"IMJIAGILBOG",
|
|
"OGGKBKOBHLP",
|
|
"DMAKDOEIOFE",
|
|
"HHGCEDNGMDD",
|
|
"OFDPCKGMCFG",
|
|
"FPABNHKCIDD",
|
|
"NEOOKMCECAL",
|
|
"CKEBMNKBEAH",
|
|
"IBPMLICGIOI",
|
|
"LMJOEPJHBLC",
|
|
"HJINOEPLIMF",
|
|
"JMHFJIBKCMG",
|
|
"HJKAEMGCIGB",
|
|
"BNOEINBHPIG",
|
|
"AJJAIFIKCJP",
|
|
"FCPHGJMAGPI",
|
|
"DDCENHLJGNM",
|
|
"AEPEEKCCDJL",
|
|
"IDDIAODMAPP",
|
|
"CHIMGKLHFMK",
|
|
"OGDOAJJPBOC",
|
|
"EMABNNHNJIB",
|
|
"JNEAMPKAHFM",
|
|
"FPGILFHDJNI",
|
|
"MDPMNBEPOKF",
|
|
"FNKGHFILBEE",
|
|
"AEOMDHAKPGC",
|
|
"OGEBJBBMDEO",
|
|
"CJMCNIDOMCP",
|
|
"LCCKMCOLKFI",
|
|
"DEIHAEKLPDJ",
|
|
"LENMMNLPJOL",
|
|
"JKNIDJECBFD",
|
|
"FMEMABGECKK",
|
|
"HAOBGEPJMAN",
|
|
"FDCGGKFBOPN",
|
|
"OKCPMCEGCOK",
|
|
"BNKCNOFCGDK"
|
|
];
|
|
}
|
|
}
|