using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Net; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text; using System.Text.RegularExpressions; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using TMPro; using UnityEngine; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("Asta.EVLog")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+0fca40d549258fa37c4b6428476bc1c91dd42809")] [assembly: AssemblyProduct("Asta.EVLog")] [assembly: AssemblyTitle("Asta.EVLog")] [assembly: AssemblyVersion("1.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace Asta.EVLog { [HarmonyPatch(typeof(HUDManager))] internal static class HudManagerPatches { [HarmonyPatch("Start")] [HarmonyPostfix] private static void PostStart(HUDManager __instance) { //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_014a: Unknown result type (might be due to invalid IL or missing references) if (Plugin.IsSessionValid) { Plugin.SessionHashHudGo = Object.Instantiate(((Component)__instance.debugText).gameObject, __instance.HUDContainer.transform); Plugin.SessionHashHud = Plugin.SessionHashHudGo.GetComponent(); Vector2 val = ((GameNetworkManager.Instance.gameVersionNum >= 81) ? new Vector2(-0.044f, -0.03f) : new Vector2(0.02f, 0.03f)); ((TMP_Text)Plugin.SessionHashHud).transform.localScale = (Vector3)((GameNetworkManager.Instance.gameVersionNum >= 81) ? new Vector3(1.11f, 1.11f, 1.11f) : Vector3.one); ((TMP_Text)Plugin.SessionHashHud).rectTransform.pivot = val; ((TMP_Text)Plugin.SessionHashHud).rectTransform.anchorMin = val; ((TMP_Text)Plugin.SessionHashHud).rectTransform.anchorMax = val; ((TMP_Text)Plugin.SessionHashHud).rectTransform.anchoredPosition = Vector2.zero; ((TMP_Text)Plugin.SessionHashHud).alignment = (TextAlignmentOptions)1025; ((TMP_Text)Plugin.SessionHashHud).font = ((TMP_Text)__instance.newProfitQuotaText).font; ((TMP_Text)Plugin.SessionHashHud).fontSize = 10f; ((TMP_Text)Plugin.SessionHashHud).text = $"{Plugin.SessionHash}#{++Plugin.Counter}"; ((Graphic)Plugin.SessionHashHud).color = RainbowColor(0.75f); ((Behaviour)Plugin.SessionHashHud).enabled = true; } } [HarmonyPatch("Update")] [HarmonyPostfix] private static void PostUpdate() { //IL_0017: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)Plugin.SessionHashHud != (Object)null) { ((Graphic)Plugin.SessionHashHud).color = RainbowColor(0.75f); } } internal static Color RainbowColor(float alpha) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) Color result = Color.HSVToRGB(Mathf.Repeat(Time.unscaledTime * 0.18f, 1f), 0.95f, 1f); result.a = alpha; return result; } } [HarmonyPatch(typeof(MenuManager))] internal static class MenuManagerPatches { private static void DisplayMenuNotificationMixedCall(MenuManager instance, string notificationText, string buttonText) { Type typeFromHandle = typeof(MenuManager); MethodInfo method = typeFromHandle.GetMethod("DisplayMenuNotification", new Type[3] { typeof(string), typeof(string), typeof(bool) }); if (method != null) { method.Invoke(instance, new object[3] { notificationText, buttonText, true }); } else { typeFromHandle.GetMethod("DisplayMenuNotification", new Type[2] { typeof(string), typeof(string) })?.Invoke(instance, new object[2] { notificationText, buttonText }); } } [HarmonyPatch("Start")] [HarmonyPostfix] private static void PostStart(MenuManager __instance) { //IL_0043: Unknown result type (might be due to invalid IL or missing references) if (Plugin.IsSessionValid) { ((TMP_Text)__instance.versionNumberText).autoSizeTextContainer = true; TextMeshProUGUI versionNumberText = __instance.versionNumberText; ((TMP_Text)versionNumberText).text = ((TMP_Text)versionNumberText).text + "(" + Plugin.SessionHash + ")"; ((Graphic)__instance.versionNumberText).color = HudManagerPatches.RainbowColor(1f); } else { string text = ((Plugin.DisallowedModIds.Count > 0) ? string.Join("\n", Plugin.DisallowedModIds) : "Check BepInEx console for details."); DisplayMenuNotificationMixedCall(__instance, "Mods not on the allowed list detected.\n\nDisallowed IDs:\n" + text + "\n\nRuns performed on this session won't be accepted.", "[ Back ]"); } } } [BepInPlugin("asta.evlog", "EVLog", "1.0.0")] public sealed class Plugin : BaseUnityPlugin { public const string PluginGuid = "asta.evlog"; public const string PluginName = "EVLog"; public const string PluginVersion = "1.0.0"; private const string EventsUrl = "https://f.asta.rs/hq-launcher/events.json"; private readonly HashSet allowedVanillaMods = new HashSet { "chboo1.lethalcompany.hqfixes", "com.adibtw.loadstone", "com.fumiko.CullFactory", "com.github.tinyhoot.ShipLoot", "com.rune580.LethalCompanyInputUtils", "LCBetterSaves", "LightsOut", "mrov.LightsOut", "MrovLib", "mattymatty.TooManyItems", "MoreItems", "OreoM.HQoL.73", "OreoM.HQoL.72", "OreoM.VLog", "OreoM.ShipLootCruiser", "LethalRebinding", "ArlenFreii.40Arachnophobia", "quackandcheese.togglemute", "viviko.NoSellLimit", "Zaggy1024.PathfindingLib", "Zaggy1024.PathfindingLagFix", "SlushyRH.LethalCompany.FreeMoons", "com.github.zehsteam.StreamOverlays", "com.github.zehsteam.SellMyScrap", "com.github.zehsteam.SellMyScrap.v40-v72", "lekakid.lcfontpatcher", ".LCMaxSoundsFix", "MysticDEV.BetterCruiserSync", "LethalSpongeLegacy", "hlb.V73dcfix", "dev.timmywastor.overworkedUI", "OreoM.StatsTracker", "asta.evlog" }; private readonly HashSet allowedModdedMods = new HashSet { "atomic.terminalapi", "Drinkable.BrutalCompanyMinus", "LethalNetworkAPI", "AudioKnight.StarlancerAIFix", "bauyrsaq.SynthesisAssembly", "evaisa.lethallib", "MaxWasUnavailable.LethalModDataLib", "imabatby.lethallevelloader", "CompanyCruiserFix", "DerelictMoonPlugin", "imabatby.lethaltoolbox", "JacobG5.JLL", "JacobG5.JLLItemModule", "JacobG5.WesleyMoonScripts", "ShowMoonPriceLLL", "Tomatobird.BluranceTerrainFix", "ViewExtension", "Yorimor.CustomStoryLogs", "Chaos.LCCutscene", "com.github.WhiteSpike.MoonDaySpeedMultiplierPatcher", "dev.ladyalice.dungenplus", "dev.ladyalice.dungenplus.loadstonepatch", "JacobG5.ReverbTriggerFix", "JacobG5.WesleyMoons", "LethalPerformance", "MW.MagicWesleyInteriors", "voxx.TerraMesh", "ScienceBird.UniversalRadar", "Tomatobird.BCMHQModule", "Tomatobird.ClassicMoonsHQModule", "Tomatobird.WesleysMoonsHQModule", "Tomatobird.DerelictFix", "Tomatobird.LertzFix", "Tomatobird.TandrausFix", "mrov.WeatherRegistry", "Sniper1_1.WaterAssetRestorer", "stormytuna.EclipseOnly", "JacobG5.DestroyItemInSlotFix", "Sniper1_1.MaterialAssetRestorerCore" }; private ConfigEntry eventId; private CustomLogger? vlogger; private bool isModded; internal static Plugin? Instance { get; private set; } internal static ManualLogSource Log { get; private set; } = null; internal static Harmony? Harmony { get; private set; } internal static bool IsSessionValid { get; private set; } internal static string SessionHash { get; private set; } = ""; internal static string EventId { get; private set; } = ""; internal static GameObject? SessionHashHudGo { get; set; } internal static TextMeshProUGUI? SessionHashHud { get; set; } internal static int Counter { get; set; } internal static List DisallowedModIds { get; } = new List(); private void Awake() { Instance = this; Log = ((BaseUnityPlugin)this).Logger; eventId = ((BaseUnityPlugin)this).Config.Bind("HQ Launcher", "EventId", "", "hq-launcher events.json에서 mods[].id를 허용 목록에 추가할 이벤트 id입니다."); EventId = eventId.Value.Trim(); LoadEventAllowedModsBlocking(); Patch(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"EVLog v1.0.0 has loaded."); } private void LoadEventAllowedModsBlocking() { string text = EventId; if (string.IsNullOrWhiteSpace(text)) { Log.LogWarning((object)"EventId is empty. Remote event mods will not be added."); return; } try { ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls12; HttpWebRequest obj = (HttpWebRequest)WebRequest.Create("https://f.asta.rs/hq-launcher/events.json"); obj.Method = "GET"; obj.Timeout = 10000; obj.ReadWriteTimeout = 10000; obj.UserAgent = "EVLog/1.0.0"; using WebResponse webResponse = obj.GetResponse(); using Stream stream = webResponse.GetResponseStream(); using StreamReader streamReader = new StreamReader(stream); AddEventModsFromJson(text, streamReader.ReadToEnd()); } catch (Exception ex) { Log.LogWarning((object)("Could not load https://f.asta.rs/hq-launcher/events.json: " + ex.Message)); } } private void AddEventModsFromJson(string configuredId, string json) { try { List list = ExtractEventModIds(json, configuredId); if (list.Count == 0) { Log.LogWarning((object)("No hq-launcher event found for EventId '" + configuredId + "'.")); return; } int num = 0; foreach (string item in list) { if (allowedModdedMods.Add(item)) { num++; } } Log.LogInfo((object)$"Added {num} remote allowed mods for event '{configuredId}'."); } catch (Exception arg) { Log.LogError((object)$"Failed to parse hq-launcher events JSON: {arg}"); } } private static List ExtractEventModIds(string json, string configuredId) { List list = new List(); Match match = Regex.Match(json, "\"id\"\\s*:\\s*\"" + Regex.Escape(configuredId) + "\"", RegexOptions.IgnoreCase | RegexOptions.CultureInvariant); if (!match.Success) { return list; } int num = json.LastIndexOf('{', match.Index); int num2 = FindMatchingBracket(json, num, '{', '}'); if (num < 0 || num2 < 0) { return list; } string text = json.Substring(num, num2 - num + 1); Match match2 = Regex.Match(text, "\"mods\"\\s*:\\s*\\[", RegexOptions.IgnoreCase | RegexOptions.CultureInvariant); if (!match2.Success) { return list; } int num3 = text.IndexOf('[', match2.Index); int num4 = FindMatchingBracket(text, num3, '[', ']'); if (num3 < 0 || num4 < 0) { return list; } foreach (Match item in Regex.Matches(text.Substring(num3, num4 - num3 + 1), "\"id\"\\s*:\\s*\"([^\"]+)\"", RegexOptions.CultureInvariant)) { string text2 = item.Groups[1].Value.Trim(); if (!string.IsNullOrWhiteSpace(text2)) { list.Add(text2); } } return list; } private static int FindMatchingBracket(string text, int startIndex, char open, char close) { if (startIndex < 0 || startIndex >= text.Length || text[startIndex] != open) { return -1; } bool flag = false; bool flag2 = false; int num = 0; for (int i = startIndex; i < text.Length; i++) { char c = text[i]; if (flag) { if (flag2) { flag2 = false; continue; } switch (c) { case '\\': flag2 = true; break; case '"': flag = false; break; } } else if (c == '"') { flag = true; } else if (c == open) { num++; } else if (c == close && --num == 0) { return i; } } return -1; } private void OnDestroy() { //IL_023f: Unknown result type (might be due to invalid IL or missing references) //IL_0249: Expected O, but got Unknown //IL_0255: Unknown result type (might be due to invalid IL or missing references) //IL_025f: Expected O, but got Unknown HashSet merged = new HashSet(allowedVanillaMods); isModded = false; bool num = Chainloader.PluginInfos.Keys.All((string pluginGuid) => allowedVanillaMods.Contains(pluginGuid)); if (!num) { merged.UnionWith(allowedModdedMods); isModded = Chainloader.PluginInfos.Keys.All((string pluginGuid) => merged.Contains(pluginGuid)); } if (!num && !isModded) { DisallowedModIds.Clear(); DisallowedModIds.AddRange(from pluginGuid in Chainloader.PluginInfos.Keys where !merged.Contains(pluginGuid) orderby pluginGuid select pluginGuid); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Please make sure you're only using allowed mods.\nDisallowed mod IDs:"); { foreach (string disallowedModId in DisallowedModIds) { PluginInfo val = Chainloader.PluginInfos[disallowedModId]; ((BaseUnityPlugin)this).Logger.LogInfo((object)$"{val.Metadata.GUID} - {val.Metadata.Name} {val.Metadata.Version}"); } return; } } try { ((BaseUnityPlugin)this).Logger.LogInfo((object)$"Mods verified!\nModded: {isModded}"); SessionHash = XxHash.Hash64(Chainloader.PluginInfos.Keys.Aggregate((string a, string n) => a + n)).ToString("x") + "#" + XxHash.Hash64(DateTime.Now.ToLongDateString() + DateTime.Now.ToLongTimeString()).ToString("x") + "#" + EventId; IsSessionValid = true; vlogger = new CustomLogger(SessionHash); Application.logMessageReceived += new LogCallback(vlogger.LogUnity); Application.logMessageReceivedThreaded += new LogCallback(vlogger.LogUnity); Debug.unityLogger.logHandler = (ILogHandler)(object)vlogger; Logger.Listeners.Clear(); Logger.Listeners.Add((ILogListener)(object)vlogger); } catch (Exception ex) { Debug.LogException(ex); } } private static void Patch() { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Expected O, but got Unknown if (Harmony == null) { Harmony = new Harmony("asta.evlog"); } Log.LogDebug((object)"Patching..."); Harmony.PatchAll(); Log.LogDebug((object)"Finished patching."); } } internal sealed class CustomLogger : ILogListener, IDisposable, ILogHandler { private readonly StreamWriter logWriter; private readonly DateTime time = DateTime.Now; public CustomLogger(string sessionHash) { string text = Path.Combine(Application.persistentDataPath, "VLogs"); Directory.CreateDirectory(text); string path = $"Player_{time:yyyy-MM-dd_HH-mm-ss}_{sessionHash}.log"; string text2 = Path.Combine(text, path); string text3 = Path.Combine(Application.persistentDataPath, "Player.log"); if (File.Exists(text3)) { File.Copy(text3, text2, overwrite: true); } logWriter = new StreamWriter(text2, append: true) { AutoFlush = true }; } public void LogEvent(object sender, LogEventArgs args) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) logWriter.WriteLine($"[{args.Level}] {args.Source.SourceName}: {args.Data}"); } public void LogUnity(string log, string stackTrace, LogType type) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) logWriter.WriteLine($"{type}: {log}\n{stackTrace}"); } public void LogFormat(LogType logType, Object context, string format, params object[] args) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) logWriter.WriteLine($"{logType}: {string.Format(format, args)}"); } public void LogException(Exception exception, Object context) { logWriter.WriteLine($"Exception: {exception}"); } public void Dispose() { logWriter.Dispose(); } } internal static class XxHash { public static ulong Hash64(string text) { byte[] bytes = Encoding.UTF8.GetBytes(text); int i = 0; int num = bytes.Length; ulong num2 = (ulong)(2870177450012600261L + num); for (; i + 8 <= num; i += 8) { ulong num3 = BitConverter.ToUInt64(bytes, i); num2 ^= (ulong)((long)RotateLeft(num3 * 14029467366897019727uL, 31) * -7046029288634856825L); num2 = (ulong)((long)RotateLeft(num2, 27) * -7046029288634856825L + -8796714831421723037L); } for (; i + 4 <= num; i += 4) { num2 ^= (ulong)(BitConverter.ToUInt32(bytes, i) * -7046029288634856825L); num2 = (ulong)((long)RotateLeft(num2, 23) * -4417276706812531889L + 1609587929392839161L); } for (; i < num; i++) { num2 ^= (ulong)(bytes[i] * 2870177450012600261L); num2 = RotateLeft(num2, 11) * 11400714785074694791uL; } num2 ^= num2 >> 33; num2 *= 14029467366897019727uL; num2 ^= num2 >> 29; num2 *= 1609587929392839161L; return num2 ^ (num2 >> 32); } private static ulong RotateLeft(ulong value, int count) { return (value << count) | (value >> 64 - count); } } }