using System; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using Unity.Collections; using Unity.Netcode; using UnityEngine; [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("WeatherReroll")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("WeatherReroll")] [assembly: AssemblyTitle("WeatherReroll")] [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.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace WeatherReroll { [HarmonyPatch] internal static class GamePatches { [HarmonyPatch(typeof(StartOfRound), "Start")] [HarmonyPostfix] private static void StartOfRound_Start_Postfix() { RerollService.ResetDailyUses(); RerollService.RegisterMessageHandlers(); } [HarmonyPatch(typeof(TimeOfDay), "OnDayChanged")] [HarmonyPostfix] private static void TimeOfDay_OnDayChanged_Postfix() { RerollService.ResetDailyUses(); } } [BepInPlugin("BLUJAY.WeatherReroll", "Weather Reroll", "1.0.0")] public class WeatherRerollPlugin : BaseUnityPlugin { public const string Guid = "BLUJAY.WeatherReroll"; public const string Name = "Weather Reroll"; public const string Version = "1.0.0"; internal static ManualLogSource Log; internal static ConfigEntry StartingCost; internal static ConfigEntry CostIncrease; private void Awake() { //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) Log = ((BaseUnityPlugin)this).Logger; StartingCost = ((BaseUnityPlugin)this).Config.Bind("Pricing", "StartingCost", 1000, "Cost of the first weather reroll of the day. The host's settings are authoritative in multiplayer."); CostIncrease = ((BaseUnityPlugin)this).Config.Bind("Pricing", "CostIncrease", 2000, "How much the price goes up with each reroll purchased that day (1000 -> 3000 -> 5000 -> ...). Resets when the day ends."); Harmony val = new Harmony("BLUJAY.WeatherReroll"); val.PatchAll(typeof(TerminalPatches)); val.PatchAll(typeof(GamePatches)); Log.LogInfo((object)"Weather Reroll v1.0.0 loaded. Type REROLL in the terminal while in orbit."); } } internal static class RerollService { [CompilerGenerated] private static class <>O { public static HandleNamedMessageDelegate <0>__OnRequestReceived; public static HandleNamedMessageDelegate <1>__OnSyncReceived; public static HandleNamedMessageDelegate <2>__OnDeniedReceived; } private const string MsgRequest = "WeatherReroll.Request"; private const string MsgSync = "WeatherReroll.Sync"; private const string MsgDenied = "WeatherReroll.Denied"; internal static int RerollsUsedToday; internal static int CurrentCost => CostFor(RerollsUsedToday); internal static bool InOrbit { get { if ((Object)(object)StartOfRound.Instance != (Object)null && StartOfRound.Instance.inShipPhase) { return !StartOfRound.Instance.travellingToNewLevel; } return false; } } internal static int CostFor(int usedCount) { return Mathf.Max(1, WeatherRerollPlugin.StartingCost.Value + usedCount * WeatherRerollPlugin.CostIncrease.Value); } internal static string FormatMoney(int amount) { return "$" + amount.ToString("N0"); } internal static void ResetDailyUses() { RerollsUsedToday = 0; } internal static void RegisterMessageHandlers() { //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Expected O, but got Unknown //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Expected O, but got Unknown //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Expected O, but got Unknown NetworkManager singleton = NetworkManager.Singleton; if (!((Object)(object)singleton == (Object)null) && singleton.CustomMessagingManager != null) { CustomMessagingManager customMessagingManager = singleton.CustomMessagingManager; object obj = <>O.<0>__OnRequestReceived; if (obj == null) { HandleNamedMessageDelegate val = OnRequestReceived; <>O.<0>__OnRequestReceived = val; obj = (object)val; } customMessagingManager.RegisterNamedMessageHandler("WeatherReroll.Request", (HandleNamedMessageDelegate)obj); CustomMessagingManager customMessagingManager2 = singleton.CustomMessagingManager; object obj2 = <>O.<1>__OnSyncReceived; if (obj2 == null) { HandleNamedMessageDelegate val2 = OnSyncReceived; <>O.<1>__OnSyncReceived = val2; obj2 = (object)val2; } customMessagingManager2.RegisterNamedMessageHandler("WeatherReroll.Sync", (HandleNamedMessageDelegate)obj2); CustomMessagingManager customMessagingManager3 = singleton.CustomMessagingManager; object obj3 = <>O.<2>__OnDeniedReceived; if (obj3 == null) { HandleNamedMessageDelegate val3 = OnDeniedReceived; <>O.<2>__OnDeniedReceived = val3; obj3 = (object)val3; } customMessagingManager3.RegisterNamedMessageHandler("WeatherReroll.Denied", (HandleNamedMessageDelegate)obj3); } } internal unsafe static void PurchaseReroll(Terminal terminal) { //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) NetworkManager singleton = NetworkManager.Singleton; if ((Object)(object)singleton == (Object)null) { return; } if (singleton.IsServer) { ServerPerformReroll(terminal, singleton.LocalClientId); return; } FastBufferWriter val = default(FastBufferWriter); ((FastBufferWriter)(ref val))..ctor(4, (Allocator)2, -1); try { ((FastBufferWriter)(ref val)).WriteValueSafe(ref RerollsUsedToday, default(ForPrimitives)); singleton.CustomMessagingManager.SendNamedMessage("WeatherReroll.Request", 0uL, val, (NetworkDelivery)3); } finally { ((IDisposable)(*(FastBufferWriter*)(&val))/*cast due to .constrained prefix*/).Dispose(); } } private unsafe static void OnRequestReceived(ulong senderClientId, FastBufferReader reader) { //IL_001e: 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_0069: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) NetworkManager singleton = NetworkManager.Singleton; if ((Object)(object)singleton == (Object)null || !singleton.IsServer) { return; } int num = default(int); ((FastBufferReader)(ref reader)).ReadValueSafe(ref num, default(ForPrimitives)); Terminal val = Object.FindObjectOfType(); if ((Object)(object)val == (Object)null) { return; } if (num != RerollsUsedToday || !InOrbit || val.groupCredits < CurrentCost) { FastBufferWriter val2 = default(FastBufferWriter); ((FastBufferWriter)(ref val2))..ctor(1, (Allocator)2, -1); try { byte b = 0; ((FastBufferWriter)(ref val2)).WriteValueSafe(ref b, default(ForPrimitives)); singleton.CustomMessagingManager.SendNamedMessage("WeatherReroll.Denied", senderClientId, val2, (NetworkDelivery)3); return; } finally { ((IDisposable)(*(FastBufferWriter*)(&val2))/*cast due to .constrained prefix*/).Dispose(); } } ServerPerformReroll(val, senderClientId); } private unsafe static void ServerPerformReroll(Terminal terminal, ulong purchaserClientId) { //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_011e: Unknown result type (might be due to invalid IL or missing references) NetworkManager singleton = NetworkManager.Singleton; if (!InOrbit || terminal.groupCredits < CurrentCost) { return; } int currentCost = CurrentCost; int num = new Random().Next(2, 100000000); int num2 = RerollsUsedToday + 1; int newCredits = Mathf.Clamp(terminal.groupCredits - currentCost, 0, 10000000); WeatherRerollPlugin.Log.LogInfo((object)$"Weather reroll #{num2} purchased for {FormatMoney(currentCost)} by client {purchaserClientId}; new seed {num}."); Apply(terminal, num, num2, newCredits, purchaserClientId); FastBufferWriter val = default(FastBufferWriter); ((FastBufferWriter)(ref val))..ctor(20, (Allocator)2, -1); try { ((FastBufferWriter)(ref val)).WriteValueSafe(ref num, default(ForPrimitives)); ((FastBufferWriter)(ref val)).WriteValueSafe(ref num2, default(ForPrimitives)); ((FastBufferWriter)(ref val)).WriteValueSafe(ref newCredits, default(ForPrimitives)); ((FastBufferWriter)(ref val)).WriteValueSafe(ref purchaserClientId, default(ForPrimitives)); foreach (ulong connectedClientsId in singleton.ConnectedClientsIds) { if (connectedClientsId != singleton.LocalClientId) { singleton.CustomMessagingManager.SendNamedMessage("WeatherReroll.Sync", connectedClientsId, val, (NetworkDelivery)3); } } } finally { ((IDisposable)(*(FastBufferWriter*)(&val))/*cast due to .constrained prefix*/).Dispose(); } } private static void OnSyncReceived(ulong senderClientId, FastBufferReader reader) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) int newSeed = default(int); ((FastBufferReader)(ref reader)).ReadValueSafe(ref newSeed, default(ForPrimitives)); int newCount = default(int); ((FastBufferReader)(ref reader)).ReadValueSafe(ref newCount, default(ForPrimitives)); int newCredits = default(int); ((FastBufferReader)(ref reader)).ReadValueSafe(ref newCredits, default(ForPrimitives)); ulong purchaserClientId = default(ulong); ((FastBufferReader)(ref reader)).ReadValueSafe(ref purchaserClientId, default(ForPrimitives)); Terminal val = Object.FindObjectOfType(); if (!((Object)(object)val == (Object)null)) { Apply(val, newSeed, newCount, newCredits, purchaserClientId); } } private static void OnDeniedReceived(ulong senderClientId, FastBufferReader reader) { if ((Object)(object)HUDManager.Instance != (Object)null) { HUDManager.Instance.DisplayTip("Weather reroll failed", "The transaction was rejected by the server. Check the moons catalogue and try again.", true, false, "LC_Tip1"); } } private static void Apply(Terminal terminal, int newSeed, int newCount, int newCredits, ulong purchaserClientId) { StartOfRound instance = StartOfRound.Instance; if (!((Object)(object)instance == (Object)null)) { RerollsUsedToday = newCount; terminal.groupCredits = newCredits; instance.randomMapSeed = newSeed; instance.SetPlanetsWeather(0); instance.SetMapScreenInfoToCurrentLevel(); NetworkManager singleton = NetworkManager.Singleton; if ((!((Object)(object)singleton != (Object)null) || singleton.LocalClientId != purchaserClientId) && (Object)(object)HUDManager.Instance != (Object)null) { HUDManager.Instance.DisplayTip("Weather rerolled", "A crewmate purchased a weather reroll for " + FormatMoney(CostFor(newCount - 1)) + ". All forecasts have been updated.", false, false, "LC_Tip1"); } } } } [HarmonyPatch] internal static class TerminalPatches { private static TerminalKeyword rerollKeyword; private static TerminalNode promptNode; private static TerminalNode successNode; private static TerminalNode cancelNode; private static TerminalNode errorNode; [HarmonyPatch(typeof(Terminal), "Awake")] [HarmonyPostfix] private static void Terminal_Awake_Postfix(Terminal __instance) { TerminalNodesList terminalNodes = __instance.terminalNodes; if ((Object)(object)terminalNodes == (Object)null || terminalNodes.allKeywords == null) { return; } TerminalKeyword val = FindKeyword(terminalNodes.allKeywords, "confirm"); TerminalKeyword val2 = FindKeyword(terminalNodes.allKeywords, "deny"); if ((Object)(object)val == (Object)null || (Object)(object)val2 == (Object)null) { WeatherRerollPlugin.Log.LogError((object)"Could not find the vanilla CONFIRM/DENY keywords; REROLL command not registered."); return; } EnsureNodesExist(val, val2); if ((Object)(object)FindKeyword(terminalNodes.allKeywords, "reroll") == (Object)null) { terminalNodes.allKeywords = CollectionExtensions.AddToArray(terminalNodes.allKeywords, rerollKeyword); WeatherRerollPlugin.Log.LogInfo((object)"REROLL terminal command registered."); } } private static void EnsureNodesExist(TerminalKeyword confirmKeyword, TerminalKeyword denyKeyword) { //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Expected O, but got Unknown //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Expected O, but got Unknown if (!((Object)(object)promptNode != (Object)null)) { successNode = CreateNode("WeatherRerollSuccess"); successNode.playSyncedClip = 0; cancelNode = CreateNode("WeatherRerollCancel"); cancelNode.displayText = "Cancelled weather reroll.\n\n"; errorNode = CreateNode("WeatherRerollError"); promptNode = CreateNode("WeatherRerollPrompt"); promptNode.overrideOptions = true; promptNode.terminalOptions = (CompatibleNoun[])(object)new CompatibleNoun[2] { new CompatibleNoun(confirmKeyword, successNode), new CompatibleNoun(denyKeyword, cancelNode) }; rerollKeyword = ScriptableObject.CreateInstance(); ((Object)rerollKeyword).hideFlags = (HideFlags)61; ((Object)rerollKeyword).name = "WeatherRerollKeyword"; rerollKeyword.word = "reroll"; rerollKeyword.isVerb = false; rerollKeyword.specialKeywordResult = promptNode; } } private static TerminalNode CreateNode(string nodeName) { TerminalNode obj = ScriptableObject.CreateInstance(); ((Object)obj).hideFlags = (HideFlags)61; ((Object)obj).name = nodeName; obj.clearPreviousText = true; obj.maxCharactersToType = 50; obj.buyItemIndex = -1; obj.buyVehicleIndex = -1; obj.buyRerouteToMoon = -1; obj.displayPlanetInfo = -1; obj.shipUnlockableID = -1; obj.creatureFileID = -1; obj.storyLogFileID = -1; obj.playSyncedClip = -1; return obj; } private static TerminalKeyword FindKeyword(TerminalKeyword[] keywords, string word) { foreach (TerminalKeyword val in keywords) { if ((Object)(object)val != (Object)null && val.word == word) { return val; } } return null; } [HarmonyPatch(typeof(Terminal), "LoadNewNode")] [HarmonyPrefix] private static void Terminal_LoadNewNode_Prefix(Terminal __instance, ref TerminalNode node) { if ((Object)(object)promptNode == (Object)null || (Object)(object)node == (Object)null) { return; } if ((Object)(object)node == (Object)(object)promptNode) { if (IsBlocked(__instance, out var reason)) { errorNode.displayText = reason; node = errorNode; } else { promptNode.displayText = "You have requested to reroll the weather conditions of all moons.\nTotal cost of this service: " + RerollService.FormatMoney(RerollService.CurrentCost) + ".\n\nPlease CONFIRM or DENY.\n\n"; } } else if ((Object)(object)node == (Object)(object)successNode) { if (IsBlocked(__instance, out var reason2)) { errorNode.displayText = reason2; node = errorNode; return; } int currentCost = RerollService.CurrentCost; int amount = Mathf.Max(0, __instance.groupCredits - currentCost); int amount2 = RerollService.CostFor(RerollService.RerollsUsedToday + 1); successNode.displayText = "Weather systems rerolled. Your new balance is " + RerollService.FormatMoney(amount) + ".\n\nUpdated forecasts are available in the moons catalogue.\nThe next reroll today will cost " + RerollService.FormatMoney(amount2) + ".\n\n"; RerollService.PurchaseReroll(__instance); } } private static bool IsBlocked(Terminal terminal, out string reason) { if (!RerollService.InOrbit) { reason = "Weather can only be rerolled while the ship is in orbit.\n\n"; return true; } if (terminal.groupCredits < RerollService.CurrentCost) { reason = "You do not have enough credits to reroll the weather.\nCost: " + RerollService.FormatMoney(RerollService.CurrentCost) + " // Your balance: " + RerollService.FormatMoney(terminal.groupCredits) + ".\n\n"; return true; } reason = null; return false; } [HarmonyPatch(typeof(Terminal), "TextPostProcess")] [HarmonyPostfix] private static void Terminal_TextPostProcess_Postfix(Terminal __instance, TerminalNode node, ref string __result) { if (!((Object)(object)node == (Object)null) && !((Object)(object)__instance.terminalNodes == (Object)null)) { TerminalKeyword val = FindKeyword(__instance.terminalNodes.allKeywords, "moons"); if (!((Object)(object)val == (Object)null) && !((Object)(object)node != (Object)(object)val.specialKeywordResult)) { int rerollsUsedToday = RerollService.RerollsUsedToday; string text = rerollsUsedToday switch { 0 => "The price rises with each use and resets daily.", 1 => "Rerolled 1 time today. Prices reset at the end of the day.", _ => $"Rerolled {rerollsUsedToday} times today. Prices reset at the end of the day.", }; __result = __result + "\n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _\n\n* Weather reroll // Price: " + RerollService.FormatMoney(RerollService.CurrentCost) + "\nType REROLL to randomize the weather of all moons.\n" + text + "\n"; } } } } }