Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of MissionRandomizer v0.1.25
plugins/MissionRandomizer/MissionRandomizer.dll
Decompiled 17 hours ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Text; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Unity.Collections; using Unity.Netcode; using UnityEngine; using UnityEngine.SceneManagement; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: AssemblyTitle("ScrapVisbility")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("ScrapVisbility")] [assembly: AssemblyCopyright("Copyright © 2026")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("8a6853bd-bdc9-4741-95c7-5aa2c8c6a6f9")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyVersion("1.0.0.0")] namespace LC_MissionRandomizer; [BepInPlugin("yellowcube.lc.mission_randomizer", "Mission Randomizer", "0.1.25")] public class Plugin : BaseUnityPlugin { public const string PluginGuid = "yellowcube.lc.mission_randomizer"; public const string PluginName = "Mission Randomizer"; public const string PluginVersion = "0.1.25"; internal static ManualLogSource Log; internal static Plugin Instance; private Harmony harmony; internal ConfigEntry<bool> ModEnabled; internal ConfigEntry<bool> BlockMoonTerminalCommands; internal ConfigEntry<bool> ForceStarterMoon; internal ConfigEntry<bool> RestrictTerminalMoonCatalogue; internal ConfigEntry<bool> DisableOutsideAndDaytimePower; internal ConfigEntry<bool> ShowMonitorStats; internal ConfigEntry<bool> DebugLogging; internal ConfigEntry<bool> AutoFileDebugLogging; internal ConfigEntry<bool> HostDebugTeleportScrapWithP; internal ConfigEntry<bool> NormalizeGeneratedScrapValue; internal ConfigEntry<bool> EnforceGeneratedScrapCount; internal ConfigEntry<bool> PreClampScrapValuesBeforeGeneration; internal ConfigEntry<bool> CleaningCompanySupport; internal ConfigEntry<int> MinimumTotalScrapValue; internal ConfigEntry<int> MaximumTotalScrapValueCap; internal ConfigEntry<float> QuotaCoverageMultiplier; internal ConfigEntry<int> MinimumScrapCount; internal ConfigEntry<int> MaximumScrapCountCap; internal ConfigEntry<int> MaximumMissionScrapCount; internal ConfigEntry<int> MaximumInsideEnemyPowerCap; internal ConfigEntry<int> MaximumMinEnemiesToSpawn; internal ConfigEntry<float> MaximumFactorySizeMultiplier; internal ConfigEntry<float> MaximumScrapAmountMultiplier; internal ConfigEntry<float> MaximumScrapValueMultiplier; internal ConfigEntry<float> CleaningCompanyConversionSearchRadius; internal ConfigEntry<float> CleaningCompanyConversionWindowSeconds; internal ConfigEntry<int> SeedOffset; private void Awake() { //IL_042a: Unknown result type (might be due to invalid IL or missing references) //IL_0434: Expected O, but got Unknown Instance = this; Log = ((BaseUnityPlugin)this).Logger; try { ((BaseUnityPlugin)this).Config.SaveOnConfigSet = true; } catch { } ModEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Enable or disable the mission randomizer."); BlockMoonTerminalCommands = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "BlockMoonTerminalCommands", true, "If true, the moons and route terminal commands are replaced with mission information / blocked."); ForceStarterMoon = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "ForceStarterMoon", true, "If true, the current level is forced back to the starter moon while in orbit and before loading a level."); RestrictTerminalMoonCatalogue = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "RestrictTerminalMoonCatalogue", false, "If true, the terminal moon catalogue is trimmed to only the starter moon and the Company. Leave false if another mod expects the normal catalogue."); DisableOutsideAndDaytimePower = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "DisableOutsideAndDaytimePower", true, "If true, outside and daytime enemy power caps are forced to zero."); ShowMonitorStats = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "ShowMonitorStats", true, "If true, ship monitor text is replaced with the current randomized mission stats."); DebugLogging = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "DebugEnabled", false, "If true, enable diagnostic console logging and allow debug files to be written."); AutoFileDebugLogging = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "WriteDebugFiles", true, "If true and DebugEnabled is true, write orbit / landed / manual diagnostic snapshots to BepInEx/MissionRandomizerDebugLogs."); HostDebugTeleportScrapWithP = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "HostCanPressPToTeleportScrap", false, "If true, the host can press P to teleport scrap to themselves for testing. This only works on the host/server and does not sync scrap positions to clients."); NormalizeGeneratedScrapValue = ((BaseUnityPlugin)this).Config.Bind<bool>("Gameplay", "NormalizeGeneratedScrapValue", true, "If true, the host keeps generated mission scrap inside the displayed total value range. It no longer forces the total to always equal the max value."); EnforceGeneratedScrapCount = ((BaseUnityPlugin)this).Config.Bind<bool>("Gameplay", "EnforceGeneratedScrapCount", true, "If true, the host removes excess generated mission scrap above the mission profile max count before vanilla scrap values sync."); PreClampScrapValuesBeforeGeneration = ((BaseUnityPlugin)this).Config.Bind<bool>("Gameplay", "PreScaleScrapValuesBeforeGeneration", false, "Legacy option. Keep this off. The mod now edits the real vanilla scrap values before the vanilla scrap sync instead of using temporary fake item ranges."); CleaningCompanySupport = ((BaseUnityPlugin)this).Config.Bind<bool>("Compatibility", "CleaningCompanySupport", true, "If true, preserve scrap value for direct Cleaning Company conversions: Scav Goop / Thumper Drool to Dirty Water, and Bone Pile / Nail Pile Item / BrackenDustItem / Ethereal Essence / Hoarding Bug Eggs / Spore Pile to Full Garbage Bag."); MinimumTotalScrapValue = ((BaseUnityPlugin)this).Config.Bind<int>("Scaling", "MinimumTotalScrapValue", 220, "Lowest maxTotalScrapValue the mod will generate."); MaximumTotalScrapValueCap = ((BaseUnityPlugin)this).Config.Bind<int>("Scaling", "MaximumTotalScrapValueCap", 1250, "Hard cap for generated maxTotalScrapValue."); QuotaCoverageMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Scaling", "QuotaCoverageMultiplier", 1.2f, "Each remaining day tries to offer at least quotaRemaining / daysLeft multiplied by this value."); MinimumScrapCount = ((BaseUnityPlugin)this).Config.Bind<int>("Scaling", "MinimumScrapCount", 12, "Lowest generated minScrap count."); MaximumScrapCountCap = ((BaseUnityPlugin)this).Config.Bind<int>("Scaling", "MaximumScrapCountCap", 48, "Legacy cap for generated maxScrap count. MaximumMissionScrapCount is the main physical scrap cap."); MaximumMissionScrapCount = ((BaseUnityPlugin)this).Config.Bind<int>("Scaling", "MaximumMissionScrapCount", 48, "Hard cap for how many physical mission scrap items can spawn. This does not cap total scrap value."); MaximumInsideEnemyPowerCap = ((BaseUnityPlugin)this).Config.Bind<int>("Scaling", "MaximumInsideEnemyPowerCap", 14, "Hard cap for generated maxEnemyPowerCount."); MaximumMinEnemiesToSpawn = ((BaseUnityPlugin)this).Config.Bind<int>("Scaling", "MaximumMinEnemiesToSpawn", 3, "Hard cap for RoundManager.minEnemiesToSpawn."); MaximumFactorySizeMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Scaling", "MaximumFactorySizeMultiplier", 2.05f, "Hard cap for generated factorySizeMultiplier / RoundManager.mapSizeMultiplier."); MaximumScrapAmountMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Scaling", "MaximumScrapAmountMultiplier", 2.25f, "Hard cap for RoundManager.scrapAmountMultiplier."); MaximumScrapValueMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Scaling", "MaximumScrapValueMultiplier", 2.25f, "Hard cap for RoundManager.scrapValueMultiplier."); CleaningCompanyConversionSearchRadius = ((BaseUnityPlugin)this).Config.Bind<float>("Compatibility", "CleaningCompanyConversionSearchRadius", 6f, "How close a newly appeared scrap item must be to a disappeared Cleaning Company mess or converted scrap item to inherit its value."); CleaningCompanyConversionWindowSeconds = ((BaseUnityPlugin)this).Config.Bind<float>("Compatibility", "CleaningCompanyConversionWindowSeconds", 4f, "How long a disappeared scrap value stays pending while waiting for a nearby newly appeared scrap item."); SeedOffset = ((BaseUnityPlugin)this).Config.Bind<int>("Scaling", "SeedOffset", 7319, "Change this to produce a different deterministic mission sequence."); try { ((BaseUnityPlugin)this).Config.Save(); ((BaseUnityPlugin)this).Logger.LogInfo((object)("Mission Randomizer config saved to: " + ((BaseUnityPlugin)this).Config.ConfigFilePath)); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Mission Randomizer config save failed: " + ex.Message)); } MissionController.Initialize(this); harmony = new Harmony("yellowcube.lc.mission_randomizer"); harmony.PatchAll(typeof(Plugin).Assembly); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Mission Randomizer 0.1.25 loaded."); } private void OnDestroy() { try { MissionController.Shutdown(); Harmony obj = harmony; if (obj != null) { obj.UnpatchSelf(); } } catch { } } private void OnGUI() { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Invalid comparison between Unknown and I4 //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Invalid comparison between Unknown and I4 Event current = Event.current; if (current != null && (int)current.type == 4 && (int)current.keyCode == 112 && HostDebugTeleportScrapWithP != null && HostDebugTeleportScrapWithP.Value) { MissionController.DebugTeleportScrapToPlayer(); } } } internal static class MissionController { [CompilerGenerated] private sealed class <DelayedNormalizeSpawnedScrap>d__65 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public string reason; public float delaySeconds; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <DelayedNormalizeSpawnedScrap>d__65(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; if (delaySeconds > 0f) { <>2__current = (object)new WaitForSeconds(delaySeconds); <>1__state = 1; return true; } break; case 1: <>1__state = -1; break; } NormalizeSpawnedScrapForCurrentRoll(reason, writeLog: true); return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class <DelayedRestoreTemporaryScrapValueRanges>d__67 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public string reason; public float delaySeconds; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <DelayedRestoreTemporaryScrapValueRanges>d__67(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; if (delaySeconds > 0f) { <>2__current = (object)new WaitForSeconds(delaySeconds); <>1__state = 1; return true; } break; case 1: <>1__state = -1; break; } RestoreTemporaryScrapValueRanges(reason, writeLog: true); return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class <DelayedSendRollToClient>d__174 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public ulong clientId; public float delaySeconds; private StartOfRound <start>5__1; private RoundManager <round>5__2; private TimeOfDay <time>5__3; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <DelayedSendRollToClient>d__174(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <start>5__1 = null; <round>5__2 = null; <time>5__3 = null; <>1__state = -2; } private bool MoveNext() { //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; if (delaySeconds > 0f) { <>2__current = (object)new WaitForSeconds(delaySeconds); <>1__state = 1; return true; } break; case 1: <>1__state = -1; break; } if (IsCompanyRouteActive(RoundManager.Instance, TimeOfDay.Instance)) { return false; } if (!HasRoll) { <start>5__1 = StartOfRound.Instance; <round>5__2 = RoundManager.Instance; <time>5__3 = TimeOfDay.Instance; if ((Object)(object)<start>5__1 != (Object)null && (Object)(object)<round>5__2 != (Object)null && (Object)(object)<time>5__3 != (Object)null) { EnsureRollForCurrentOrbit(<start>5__1, <round>5__2, <time>5__3); } <start>5__1 = null; <round>5__2 = null; <time>5__3 = null; } if (HasRoll) { SendRollToClient(CurrentRoll, clientId); } return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class <DelayedSendScrapValuesToClient>d__159 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public ulong clientId; public float delaySeconds; private List<ScrapComponentRecord> <records>5__1; private int <total>5__2; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <DelayedSendScrapValuesToClient>d__159(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <records>5__1 = null; <>1__state = -2; } private bool MoveNext() { //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; if (delaySeconds > 0f) { <>2__current = (object)new WaitForSeconds(delaySeconds); <>1__state = 1; return true; } break; case 1: <>1__state = -1; break; } if (!HasRoll) { return false; } if (IsCompanyRouteActive(RoundManager.Instance, TimeOfDay.Instance)) { return false; } <records>5__1 = CollectMissionScrapRecords(includeHeld: false); <total>5__2 = SumScrapRecordValues(<records>5__1); if (<records>5__1.Count > 0) { SendScrapValueSyncToClient(<records>5__1, <total>5__2, clientId, "late join delayed sync"); } return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class <EarlyLiveScrapNormalizeCoroutine>d__61 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public string reason; public float delaySeconds; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <EarlyLiveScrapNormalizeCoroutine>d__61(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; if (delaySeconds > 0f) { <>2__current = (object)new WaitForSeconds(delaySeconds); <>1__state = 1; return true; } break; case 1: <>1__state = -1; break; } earlyLiveScrapNormalizeScheduled = false; NormalizeSpawnedScrapForCurrentRoll(reason, writeLog: true); return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class <RapidNormalizeSpawnedScrapAtRoundStart>d__66 : IEnumerator<object>, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <RapidNormalizeSpawnedScrapAtRoundStart>d__66(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>2__current = null; <>1__state = 1; return true; case 1: <>1__state = -1; NormalizeSpawnedScrapForCurrentRoll("round start rapid single-frame safety", writeLog: false); <>2__current = (object)new WaitForSeconds(0.5f); <>1__state = 2; return true; case 2: <>1__state = -1; NormalizeSpawnedScrapForCurrentRoll("round start rapid 0.50s safety", writeLog: false); return false; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } private const string NetMessageName = "yellowcube.mission_randomizer.roll.v1"; private const string NetRequestMessageName = "yellowcube.mission_randomizer.roll_request.v1"; private const string NetScrapValuesMessageName = "yellowcube.mission_randomizer.scrap_values.v1"; private const string NetScrapValuesRequestMessageName = "yellowcube.mission_randomizer.scrap_values_request.v1"; private static Plugin plugin; private static bool networkRegistered; private static bool sceneHooked; private static NetworkManager registeredNetworkManager; private static StartOfRound trackedStartOfRound; private static RoundManager trackedRoundManager; private static float nextClientRollRequestTime; private static float nextClientScrapValueRequestTime; private static int clientScrapValueRequestSeed = int.MinValue; private static int clientScrapValueRequestAttempts; private static int clientScrapValueSyncReceivedSeed = int.MinValue; private static float nextPendingScrapApplyTime; private static int pendingScrapValueTotal; private static int runtimeRandomSeedSalt; private static string runtimeRandomSeedReason = string.Empty; private static readonly List<PendingScrapValue> pendingScrapValues = new List<PendingScrapValue>(); private static readonly Dictionary<ulong, float> nextServerScrapValueResponseByClient = new Dictionary<ulong, float>(); private static readonly List<CleaningConversionRecord> pendingCleaningConversions = new List<CleaningConversionRecord>(); private static readonly List<OriginalScrapItemValueRange> temporaryScrapValueRanges = new List<OriginalScrapItemValueRange>(); private static string lastRollKey = string.Empty; private static float nextPeriodicBroadcastTime; private static float nextMonitorRefreshTime; private static float nextMissingMonitorLogTime; private static float nextScrapDebugTime; private static float nextCleaningConversionCleanupTime; private static int orbitDebugSequence; private static int landingSnapshotStage; private static float nextLandingSnapshotTime; private static string currentMissionDebugPrefix = string.Empty; private static TerminalNode missionTerminalNode; private static TerminalNode routeMissionTerminalNode; private static TerminalNode routeCompanyTerminalNode; private static TerminalNode routeMissionPromptTerminalNode; private static TerminalNode routeCompanyPromptTerminalNode; private static int pendingTerminalRoute; private static float pendingTerminalRouteExpiresAt; private static bool earlyLiveScrapNormalizeScheduled; private static float nextEarlyLiveScrapNormalizeAllowedTime; internal static MissionRoll CurrentRoll; internal static bool HasRoll; internal static void Initialize(Plugin owner) { plugin = owner; if (!sceneHooked) { SceneManager.sceneLoaded += OnSceneLoaded; sceneHooked = true; } } internal static void Shutdown() { ResetMissionRuntimeState("Plugin shutdown", keepTrackedInstances: false); ResetNetworkRegistration("Plugin shutdown"); if (sceneHooked) { try { SceneManager.sceneLoaded -= OnSceneLoaded; } catch { } sceneHooked = false; } } private static bool ShouldDebugLog() { return (Object)(object)plugin != (Object)null && plugin.DebugLogging != null && plugin.DebugLogging.Value; } private static bool ShouldWriteDebugFiles() { return (Object)(object)plugin != (Object)null && plugin.DebugLogging != null && plugin.DebugLogging.Value && plugin.AutoFileDebugLogging != null && plugin.AutoFileDebugLogging.Value; } private static int GetConfiguredMaxMissionScrapCount() { if ((Object)(object)plugin == (Object)null || plugin.MaximumMissionScrapCount == null) { return 48; } return Mathf.Clamp(plugin.MaximumMissionScrapCount.Value, 1, 500); } private static void OnSceneLoaded(Scene scene, LoadSceneMode mode) { nextMonitorRefreshTime = 0f; if (((Scene)(ref scene)).name.Equals("MainMenu", StringComparison.OrdinalIgnoreCase)) { ResetMissionRuntimeState("Main menu loaded", keepTrackedInstances: false); ResetNetworkRegistration("Main menu loaded"); } TryRegisterNetworking(); } internal static void UpdateLoop() { if ((Object)(object)plugin == (Object)null || !plugin.ModEnabled.Value) { return; } TryRegisterNetworking(); StartOfRound instance = StartOfRound.Instance; RoundManager instance2 = RoundManager.Instance; TimeOfDay instance3 = TimeOfDay.Instance; if ((Object)(object)instance == (Object)null || (Object)(object)instance2 == (Object)null || (Object)(object)instance3 == (Object)null) { return; } DetectNewGameSystemInstances(instance, instance2); RequestRollFromHostIfNeeded(); CleanupExpiredCleaningCompanyConversions(); bool @bool = GetBool(instance, "inShipPhase", fallback: false); bool bool2 = GetBool(instance, "shipHasLanded", fallback: false); bool bool3 = GetBool(instance, "shipIsLeaving", fallback: false); if (!IsServerOrNoNetwork()) { ApplyPendingScrapValues("client update loop"); RequestScrapValuesFromHostIfNeeded(bool2, bool3); } HandleAutomaticLandingDebugSnapshots(instance, instance2, instance3, @bool, bool2, bool3); bool flag = IsCompanyRouteActive(instance2, instance3); if (@bool && !bool2 && !bool3 && !flag) { EnsureRollForCurrentOrbit(instance, instance2, instance3); if (plugin.ForceStarterMoon.Value) { ForceStarterLevel(instance2, instance3); } if (plugin.RestrictTerminalMoonCatalogue.Value) { RestrictTerminalCatalogueToStarter(); } } if (!flag && IsServerOrNoNetwork() && HasRoll && Time.realtimeSinceStartup >= nextPeriodicBroadcastTime) { nextPeriodicBroadcastTime = Time.realtimeSinceStartup + 5f; BroadcastRoll(CurrentRoll); } if (!flag && HasRoll) { ApplyRollToGameObjects(CurrentRoll, "UpdateLoop"); } if (!flag && plugin.ShowMonitorStats.Value && Time.realtimeSinceStartup >= nextMonitorRefreshTime) { nextMonitorRefreshTime = Time.realtimeSinceStartup + 0.75f; UpdateMonitorText(); } } private static void DetectNewGameSystemInstances(StartOfRound start, RoundManager round) { if ((Object)(object)trackedStartOfRound != (Object)null && trackedStartOfRound != start) { ResetMissionRuntimeState("StartOfRound instance changed", keepTrackedInstances: true); } if ((Object)(object)trackedRoundManager != (Object)null && trackedRoundManager != round) { ResetMissionRuntimeState("RoundManager instance changed", keepTrackedInstances: true); } trackedStartOfRound = start; trackedRoundManager = round; } private static void ResetMissionRuntimeState(string reason, bool keepTrackedInstances) { HasRoll = false; CurrentRoll = default(MissionRoll); lastRollKey = string.Empty; nextPeriodicBroadcastTime = 0f; nextMonitorRefreshTime = 0f; nextMissingMonitorLogTime = 0f; nextClientRollRequestTime = 0f; nextClientScrapValueRequestTime = 0f; clientScrapValueRequestSeed = int.MinValue; clientScrapValueRequestAttempts = 0; clientScrapValueSyncReceivedSeed = int.MinValue; nextPendingScrapApplyTime = 0f; pendingScrapValueTotal = 0; pendingScrapValues.Clear(); nextServerScrapValueResponseByClient.Clear(); pendingCleaningConversions.Clear(); nextCleaningConversionCleanupTime = 0f; nextScrapDebugTime = 0f; orbitDebugSequence = 0; landingSnapshotStage = 0; nextLandingSnapshotTime = 0f; currentMissionDebugPrefix = string.Empty; missionTerminalNode = null; routeMissionTerminalNode = null; routeCompanyTerminalNode = null; routeMissionPromptTerminalNode = null; routeCompanyPromptTerminalNode = null; pendingTerminalRoute = 0; pendingTerminalRouteExpiresAt = 0f; earlyLiveScrapNormalizeScheduled = false; nextEarlyLiveScrapNormalizeAllowedTime = 0f; RestoreTemporaryScrapValueRanges("runtime reset: " + reason, writeLog: false); if (!keepTrackedInstances || reason.IndexOf("Main menu", StringComparison.OrdinalIgnoreCase) >= 0 || reason.IndexOf("Plugin shutdown", StringComparison.OrdinalIgnoreCase) >= 0) { runtimeRandomSeedSalt = 0; runtimeRandomSeedReason = string.Empty; } if (!keepTrackedInstances) { trackedStartOfRound = null; trackedRoundManager = null; } if ((Object)(object)plugin != (Object)null && plugin.DebugLogging.Value) { Plugin.Log.LogInfo((object)("Mission runtime state reset: " + reason)); } } private static void RequestRollFromHostIfNeeded() { //IL_0083: Unknown result type (might be due to invalid IL or missing references) try { NetworkManager singleton = NetworkManager.Singleton; if ((Object)(object)singleton == (Object)null || singleton.CustomMessagingManager == null || !singleton.IsClient || singleton.IsServer || HasRoll || Time.realtimeSinceStartup < nextClientRollRequestTime) { return; } nextClientRollRequestTime = Time.realtimeSinceStartup + 2f; FastBufferWriter val = default(FastBufferWriter); ((FastBufferWriter)(ref val))..ctor(4, (Allocator)2, -1); try { singleton.CustomMessagingManager.SendNamedMessage("yellowcube.mission_randomizer.roll_request.v1", 0uL, val, (NetworkDelivery)3); } finally { ((IDisposable)(FastBufferWriter)(ref val)).Dispose(); } } catch (Exception ex) { if ((Object)(object)plugin != (Object)null && plugin.DebugLogging.Value) { Plugin.Log.LogWarning((object)("Mission roll request failed: " + ex.Message)); } } } internal static void BeforeLoadNewLevel() { if ((Object)(object)plugin == (Object)null || !plugin.ModEnabled.Value) { return; } StartOfRound instance = StartOfRound.Instance; RoundManager instance2 = RoundManager.Instance; TimeOfDay instance3 = TimeOfDay.Instance; if (!((Object)(object)instance == (Object)null) && !((Object)(object)instance2 == (Object)null) && !((Object)(object)instance3 == (Object)null) && !IsCompanyRouteActive(instance2, instance3)) { EnsureRollForCurrentOrbit(instance, instance2, instance3); if (HasRoll) { ApplyMissionRandomSeedToGameObjects(CurrentRoll, instance2, instance, "BeforeLoadNewLevel"); } if (plugin.ForceStarterMoon.Value) { ForceStarterLevel(instance2, instance3); } if (HasRoll) { ApplyRollToGameObjects(CurrentRoll, "BeforeLoadNewLevel"); } } } internal static void AfterGrabbableObjectStart(Component component) { HandleCleaningCompanyGrabbableStart(component); } internal static void BeforeSpawnScrapInLevel(RoundManager round) { if ((Object)(object)plugin == (Object)null || !plugin.ModEnabled.Value || !IsServerOrNoNetwork() || IsCompanyRouteActive(round, TimeOfDay.Instance)) { return; } if (!HasRoll) { StartOfRound instance = StartOfRound.Instance; TimeOfDay instance2 = TimeOfDay.Instance; if ((Object)(object)instance != (Object)null && (Object)(object)round != (Object)null && (Object)(object)instance2 != (Object)null) { EnsureRollForCurrentOrbit(instance, round, instance2); } } if (HasRoll) { ApplyRollToGameObjects(CurrentRoll, "BeforeSpawnScrapInLevel"); RestoreTemporaryScrapValueRanges("BeforeSpawnScrapInLevel cleanup", writeLog: false); } } internal static void AfterSpawnScrapInLevel(RoundManager round) { if ((Object)(object)plugin == (Object)null || !plugin.ModEnabled.Value || !IsServerOrNoNetwork() || IsCompanyRouteActive(round, TimeOfDay.Instance)) { return; } if (!HasRoll) { StartOfRound instance = StartOfRound.Instance; TimeOfDay instance2 = TimeOfDay.Instance; if ((Object)(object)instance != (Object)null && (Object)(object)round != (Object)null && (Object)(object)instance2 != (Object)null) { EnsureRollForCurrentOrbit(instance, round, instance2); } } if (!HasRoll) { return; } ApplyRollToGameObjects(CurrentRoll, "AfterSpawnScrapInLevel"); try { RestoreTemporaryScrapValueRanges("right after SpawnScrapInLevel", writeLog: false); ((MonoBehaviour)plugin).StartCoroutine(DelayedRestoreTemporaryScrapValueRanges("after round start scrap generation safety", 1f)); } catch (Exception ex) { if (plugin.DebugLogging.Value) { Plugin.Log.LogWarning((object)("Mission scrap normalization scheduling failed: " + ex.Message)); } } } internal static void BeforeVanillaScrapValuesSync(RoundManager round, NetworkObjectReference[] spawnedScrap, int[] scrapValues) { //IL_00f0: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)plugin == (Object)null || !plugin.ModEnabled.Value || !IsServerOrNoNetwork() || IsCompanyRouteActive(round, TimeOfDay.Instance)) { return; } if (!HasRoll) { StartOfRound instance = StartOfRound.Instance; TimeOfDay instance2 = TimeOfDay.Instance; if ((Object)(object)instance != (Object)null && (Object)(object)round != (Object)null && (Object)(object)instance2 != (Object)null) { EnsureRollForCurrentOrbit(instance, round, instance2); } } if (!HasRoll || spawnedScrap == null || scrapValues == null || spawnedScrap.Length == 0 || scrapValues.Length == 0) { return; } int num = Mathf.Min(spawnedScrap.Length, scrapValues.Length); List<ScrapComponentRecord> list = new List<ScrapComponentRecord>(); List<int> list2 = new List<int>(); for (int i = 0; i < num; i++) { NetworkObject val = null; try { NetworkObjectReference val2 = spawnedScrap[i]; if (!((NetworkObjectReference)(ref val2)).TryGet(ref val, NetworkManager.Singleton)) { val = null; } } catch { val = null; } if ((Object)(object)val == (Object)null || (Object)(object)((Component)val).gameObject == (Object)null) { continue; } Component val3 = (Component)(object)((Component)val).GetComponent<GrabbableObject>(); if ((Object)(object)val3 == (Object)null) { val3 = (Component)(object)((Component)val).GetComponentInChildren<GrabbableObject>(true); } if ((Object)(object)val3 == (Object)null || !IsScrapGrabbable(val3)) { continue; } object field = GetField<object>(val3, "itemProperties", null); if (field != null && GetBool(field, "isScrap", fallback: false)) { string itemDisplayName = GetItemDisplayName(val3, field); if (!IsApparatusItem(val3, val3.gameObject, itemDisplayName)) { int value = Mathf.Max(1, scrapValues[i]); list.Add(new ScrapComponentRecord { Component = val3, GameObject = val3.gameObject, Value = value, ItemName = itemDisplayName, SyncIndex = i }); list2.Add(i); } } } if (list.Count == 0) { return; } int num2 = Mathf.Min(CurrentRoll.MaxScrap, GetConfiguredMaxMissionScrapCount()); int num3 = 0; int num4 = 0; if (plugin.EnforceGeneratedScrapCount.Value && list.Count > num2) { list.Sort((ScrapComponentRecord a, ScrapComponentRecord b) => b.Value.CompareTo(a.Value)); int num5 = list.Count - num2; for (int j = 0; j < num5; j++) { ScrapComponentRecord scrapComponentRecord = list[j]; num3++; num4 += Mathf.Max(0, scrapComponentRecord.Value); if (scrapComponentRecord.SyncIndex >= 0 && scrapComponentRecord.SyncIndex < scrapValues.Length) { scrapValues[scrapComponentRecord.SyncIndex] = 0; } DespawnOrDestroyScrap(scrapComponentRecord.Component); } list.RemoveRange(0, num5); } int minimumTotalScrapValueForRoll = GetMinimumTotalScrapValueForRoll(CurrentRoll); int num6 = Mathf.Max(minimumTotalScrapValueForRoll, CurrentRoll.MaxTotalScrapValue); int num7 = 0; for (int k = 0; k < list.Count; k++) { num7 += Mathf.Max(1, list[k].Value); } int num8 = num7; bool flag = num3 > 0; if (plugin.NormalizeGeneratedScrapValue.Value && list.Count > 0 && (num7 < minimumTotalScrapValueForRoll || num7 > num6)) { int targetValue = ChooseScrapTotalValueWithinRange(CurrentRoll, num7, list.Count); NormalizeScrapRecordValues(list, targetValue); num8 = SumScrapRecordValues(list); flag = true; } else { for (int l = 0; l < list.Count; l++) { SetScrapValue(list[l].Component, list[l].Value); } } for (int m = 0; m < list.Count; m++) { int syncIndex = list[m].SyncIndex; if (syncIndex >= 0 && syncIndex < scrapValues.Length) { scrapValues[syncIndex] = Mathf.Max(1, list[m].Value); } } if ((Object)(object)round != (Object)null) { SetField(round, "totalScrapValueInLevel", (float)num8); } BroadcastScrapValueSync(list, num8, "before vanilla scrap value sync"); RestoreTemporaryScrapValueRanges("before vanilla scrap value sync", writeLog: false); if (plugin.DebugLogging.Value) { Plugin.Log.LogInfo((object)("Mission scrap values applied before vanilla sync: final " + list.Count + " / $" + num8 + ", removed " + num3 + " / $" + num4 + ", allowed count <= " + num2 + ", allowed range $" + minimumTotalScrapValueForRoll + "-$" + num6 + ", adjusted=" + flag + ".")); } } internal static void BeforeFinishGeneratingNewLevelClientRpc(RoundManager round) { if ((Object)(object)plugin == (Object)null || !plugin.ModEnabled.Value || !IsServerOrNoNetwork()) { return; } if ((Object)(object)round == (Object)null) { round = RoundManager.Instance; } if (IsCompanyRouteActive(round, TimeOfDay.Instance)) { return; } if (!HasRoll) { StartOfRound instance = StartOfRound.Instance; TimeOfDay instance2 = TimeOfDay.Instance; if ((Object)(object)instance != (Object)null && (Object)(object)round != (Object)null && (Object)(object)instance2 != (Object)null) { EnsureRollForCurrentOrbit(instance, round, instance2); } } if (!HasRoll) { return; } ApplyRollToGameObjects(CurrentRoll, "BeforeFinishGeneratingNewLevelClientRpc"); NormalizeSpawnedScrapForCurrentRoll("BeforeFinishGeneratingNewLevelClientRpc live scrap pass", writeLog: true); try { ScheduleEarlyLiveScrapNormalize("post FinishGeneratingNewLevelClientRpc safety", 0.1f); } catch { } } private static void ScheduleEarlyLiveScrapNormalize(string reason, float delaySeconds) { if ((Object)(object)plugin == (Object)null || !plugin.ModEnabled.Value || !IsServerOrNoNetwork() || !HasRoll || IsCompanyRouteActive(RoundManager.Instance, TimeOfDay.Instance)) { return; } float realtimeSinceStartup = Time.realtimeSinceStartup; if (earlyLiveScrapNormalizeScheduled || realtimeSinceStartup < nextEarlyLiveScrapNormalizeAllowedTime) { return; } earlyLiveScrapNormalizeScheduled = true; nextEarlyLiveScrapNormalizeAllowedTime = realtimeSinceStartup + 0.2f; try { ((MonoBehaviour)plugin).StartCoroutine(EarlyLiveScrapNormalizeCoroutine(reason, delaySeconds)); } catch { earlyLiveScrapNormalizeScheduled = false; } } [IteratorStateMachine(typeof(<EarlyLiveScrapNormalizeCoroutine>d__61))] private static IEnumerator EarlyLiveScrapNormalizeCoroutine(string reason, float delaySeconds) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <EarlyLiveScrapNormalizeCoroutine>d__61(0) { reason = reason, delaySeconds = delaySeconds }; } private static int GetMinimumTotalScrapValueForRoll(MissionRoll roll) { int num = Mathf.Max(1, roll.MaxTotalScrapValue); int num2 = Mathf.RoundToInt((float)num * 0.8f); return Mathf.Clamp(num2, 1, num); } private static int ChooseScrapTotalValueWithinRange(MissionRoll roll, int sourceTotal, int scrapCount) { int minimumTotalScrapValueForRoll = GetMinimumTotalScrapValueForRoll(roll); int num = Mathf.Max(minimumTotalScrapValueForRoll, roll.MaxTotalScrapValue); if (num <= minimumTotalScrapValueForRoll) { return num; } int seed = roll.Seed; seed = (seed * 397) ^ Mathf.Max(1, sourceTotal); seed = (seed * 397) ^ Mathf.Max(1, scrapCount); seed = (seed * 397) ^ 0x4D52564C; Random random = new Random(seed); return random.Next(minimumTotalScrapValueForRoll, num + 1); } private static string TotalScrapValueRangeText(MissionRoll roll) { return "$" + GetMinimumTotalScrapValueForRoll(roll) + " - $" + Mathf.Max(GetMinimumTotalScrapValueForRoll(roll), roll.MaxTotalScrapValue); } [IteratorStateMachine(typeof(<DelayedNormalizeSpawnedScrap>d__65))] private static IEnumerator DelayedNormalizeSpawnedScrap(string reason, float delaySeconds) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <DelayedNormalizeSpawnedScrap>d__65(0) { reason = reason, delaySeconds = delaySeconds }; } [IteratorStateMachine(typeof(<RapidNormalizeSpawnedScrapAtRoundStart>d__66))] private static IEnumerator RapidNormalizeSpawnedScrapAtRoundStart() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <RapidNormalizeSpawnedScrapAtRoundStart>d__66(0); } [IteratorStateMachine(typeof(<DelayedRestoreTemporaryScrapValueRanges>d__67))] private static IEnumerator DelayedRestoreTemporaryScrapValueRanges(string reason, float delaySeconds) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <DelayedRestoreTemporaryScrapValueRanges>d__67(0) { reason = reason, delaySeconds = delaySeconds }; } internal static void AfterMapScreenUpdate() { if (!((Object)(object)plugin == (Object)null) && plugin.ModEnabled.Value && plugin.ShowMonitorStats.Value && !IsCompanyRouteActive(RoundManager.Instance, TimeOfDay.Instance)) { UpdateMonitorText(); } } internal static void DebugTeleportScrapToPlayer() { if ((Object)(object)plugin == (Object)null || !plugin.ModEnabled.Value || plugin.HostDebugTeleportScrapWithP == null || !plugin.HostDebugTeleportScrapWithP.Value || Time.realtimeSinceStartup < nextScrapDebugTime) { return; } nextScrapDebugTime = Time.realtimeSinceStartup + 0.75f; if (!IsServerOrNoNetwork()) { SendDebugChatLine("Mission Debug: press P on the host/server. Scrap movement must be server authoritative."); return; } StartOfRound instance = StartOfRound.Instance; RoundManager instance2 = RoundManager.Instance; TimeOfDay instance3 = TimeOfDay.Instance; if ((Object)(object)instance == (Object)null || (Object)(object)instance2 == (Object)null || (Object)(object)instance3 == (Object)null) { SendDebugChatLine("Mission Debug: StartOfRound, RoundManager, or TimeOfDay is missing."); return; } if (IsCompanyRouteActive(instance2, instance3)) { SendDebugChatLine("Mission Debug: Company route active. Mission randomizer scrap controls are disabled at the Company."); return; } if (!HasRoll) { EnsureRollForCurrentOrbit(instance, instance2, instance3); } NormalizeSpawnedScrapForCurrentRoll("Before manual P teleport", writeLog: true); ScrapDebugStats scrapDebugStats = TeleportSpawnedScrapToLocalPlayer(instance); string text = BuildActualVsExpectedDebugReport(instance2, instance3, scrapDebugStats); string[] array = SplitDebugReportForChat(text); foreach (string message in array) { SendDebugChatLine(message); } if (plugin.DebugLogging.Value) { Plugin.Log.LogInfo((object)("Mission Debug P report:\n" + text)); } if (!ShouldWriteDebugFiles()) { return; } try { WriteDebugTextFile("MANUAL_P_TELEPORT", BuildFullMissionDebugFileReport("MANUAL_P_TELEPORT", instance2, instance3, scrapDebugStats)); } catch (Exception ex) { if (plugin.DebugLogging.Value) { Plugin.Log.LogWarning((object)("Could not write manual P debug file: " + ex.Message)); } } } private static void ResetLandingDebugStateForNewMission() { orbitDebugSequence++; landingSnapshotStage = 0; nextLandingSnapshotTime = 0f; currentMissionDebugPrefix = DateTime.Now.ToString("yyyyMMdd_HHmmss") + "_mission" + orbitDebugSequence.ToString("000") + "_seed" + (HasRoll ? CurrentRoll.Seed.ToString() : "none"); } private static void HandleAutomaticLandingDebugSnapshots(StartOfRound start, RoundManager round, TimeOfDay time, bool inShipPhase, bool shipHasLanded, bool shipIsLeaving) { if ((Object)(object)plugin == (Object)null || !plugin.ModEnabled.Value || !ShouldWriteDebugFiles() || !IsServerOrNoNetwork() || !HasRoll) { return; } if (inShipPhase && !shipHasLanded && !shipIsLeaving) { landingSnapshotStage = 0; nextLandingSnapshotTime = 0f; } else if (!inShipPhase || shipHasLanded) { if (landingSnapshotStage == 0) { landingSnapshotStage = 1; nextLandingSnapshotTime = Time.realtimeSinceStartup + 8f; } else if (landingSnapshotStage == 1 && Time.realtimeSinceStartup >= nextLandingSnapshotTime) { WriteLandedScrapDebugFile("AUTO_8_SECONDS_AFTER_LANDING", start, round, time); landingSnapshotStage = 2; nextLandingSnapshotTime = Time.realtimeSinceStartup + 12f; } else if (landingSnapshotStage == 2 && Time.realtimeSinceStartup >= nextLandingSnapshotTime) { WriteLandedScrapDebugFile("AUTO_20_SECONDS_AFTER_LANDING", start, round, time); landingSnapshotStage = 3; } } } private static void WriteOrbitMissionDebugFile(string reason, RoundManager round, TimeOfDay time) { if ((Object)(object)plugin == (Object)null || !ShouldWriteDebugFiles()) { return; } try { string report = BuildFullMissionDebugFileReport(reason, round, time, null); WriteDebugTextFile("ORBIT_" + SanitizeFilePart(reason), report); } catch (Exception ex) { if (plugin.DebugLogging.Value) { Plugin.Log.LogWarning((object)("Could not write orbit mission debug file: " + ex.Message)); } } } private static void WriteLandedScrapDebugFile(string reason, StartOfRound start, RoundManager round, TimeOfDay time) { if ((Object)(object)plugin == (Object)null || !ShouldWriteDebugFiles()) { return; } try { NormalizeSpawnedScrapForCurrentRoll("Before landed debug snapshot " + reason, writeLog: true); ScrapDebugStats value = CollectSpawnedScrapStats(start, teleportToPlayer: false); string report = BuildFullMissionDebugFileReport(reason, round, time, value); WriteDebugTextFile("LANDED_" + SanitizeFilePart(reason), report); if (plugin.DebugLogging.Value) { Plugin.Log.LogInfo((object)("Mission Randomizer wrote landed debug snapshot: " + reason + " actualMissionScrapCount=" + value.SpawnedScrapCount + " actualMissionScrapValue=$" + value.TotalScrapValue)); } } catch (Exception ex) { if (plugin.DebugLogging.Value) { Plugin.Log.LogWarning((object)("Could not write landed scrap debug file: " + ex.Message)); } } } private static void WriteDebugTextFile(string suffix, string report) { string text = Path.Combine(Paths.BepInExRootPath, "MissionRandomizerDebugLogs"); Directory.CreateDirectory(text); if (string.IsNullOrWhiteSpace(currentMissionDebugPrefix)) { currentMissionDebugPrefix = DateTime.Now.ToString("yyyyMMdd_HHmmss") + "_mission_unknown"; } string path = currentMissionDebugPrefix + "_" + suffix + ".txt"; string text2 = Path.Combine(text, path); File.WriteAllText(text2, report ?? string.Empty); if ((Object)(object)plugin != (Object)null && plugin.DebugLogging.Value) { Plugin.Log.LogInfo((object)("Mission Randomizer debug file written: " + text2)); } } private static string SanitizeFilePart(string value) { if (string.IsNullOrWhiteSpace(value)) { return "UNKNOWN"; } StringBuilder stringBuilder = new StringBuilder(value.Length); foreach (char c in value) { if (char.IsLetterOrDigit(c) || c == '_' || c == '-') { stringBuilder.Append(c); } else { stringBuilder.Append('_'); } } return stringBuilder.ToString(); } private static ScrapDebugStats TeleportSpawnedScrapToLocalPlayer(StartOfRound start) { return CollectSpawnedScrapStats(start, teleportToPlayer: true); } private static ScrapDebugStats CollectSpawnedScrapStats(StartOfRound start, bool teleportToPlayer) { //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: 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_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_014f: Unknown result type (might be due to invalid IL or missing references) //IL_0154: Unknown result type (might be due to invalid IL or missing references) //IL_0161: Unknown result type (might be due to invalid IL or missing references) //IL_0166: Unknown result type (might be due to invalid IL or missing references) //IL_026a: Unknown result type (might be due to invalid IL or missing references) //IL_026f: Unknown result type (might be due to invalid IL or missing references) //IL_02ab: Unknown result type (might be due to invalid IL or missing references) //IL_02b0: Unknown result type (might be due to invalid IL or missing references) //IL_02b9: Unknown result type (might be due to invalid IL or missing references) //IL_034e: Unknown result type (might be due to invalid IL or missing references) //IL_0353: Unknown result type (might be due to invalid IL or missing references) //IL_035c: Unknown result type (might be due to invalid IL or missing references) //IL_042a: Unknown result type (might be due to invalid IL or missing references) //IL_042f: Unknown result type (might be due to invalid IL or missing references) //IL_0438: Unknown result type (might be due to invalid IL or missing references) //IL_039d: Unknown result type (might be due to invalid IL or missing references) //IL_03a2: Unknown result type (might be due to invalid IL or missing references) //IL_03a6: Unknown result type (might be due to invalid IL or missing references) //IL_03a8: Unknown result type (might be due to invalid IL or missing references) //IL_03aa: Unknown result type (might be due to invalid IL or missing references) //IL_0505: Unknown result type (might be due to invalid IL or missing references) //IL_050a: Unknown result type (might be due to invalid IL or missing references) //IL_0513: Unknown result type (might be due to invalid IL or missing references) //IL_0479: Unknown result type (might be due to invalid IL or missing references) //IL_047e: Unknown result type (might be due to invalid IL or missing references) //IL_0482: Unknown result type (might be due to invalid IL or missing references) //IL_0484: Unknown result type (might be due to invalid IL or missing references) //IL_0486: Unknown result type (might be due to invalid IL or missing references) ScrapDebugStats result = default(ScrapDebugStats); StringBuilder stringBuilder = new StringBuilder(); StringBuilder stringBuilder2 = new StringBuilder(); StringBuilder stringBuilder3 = new StringBuilder(); StringBuilder stringBuilder4 = new StringBuilder(); Component val = (((Object)(object)start != (Object)null) ? GetField<Component>(start, "localPlayerController", null) : null); Transform val2 = (((Object)(object)val != (Object)null) ? val.transform : null); if ((Object)(object)val2 == (Object)null && (Object)(object)Camera.main != (Object)null) { val2 = ((Component)Camera.main).transform; } if (teleportToPlayer && (Object)(object)val2 == (Object)null) { result.Error = "Could not find local player transform."; return result; } Vector3 val3 = (((Object)(object)val2 != (Object)null) ? (val2.position + val2.forward * 2f + Vector3.up * 0.75f) : Vector3.zero); Component[] array = Resources.FindObjectsOfTypeAll<Component>(); int num = 0; int num2 = 0; int num3 = 0; int num4 = 0; int num5 = int.MaxValue; int num6 = int.MinValue; Component[] array2 = array; foreach (Component val4 in array2) { if ((Object)(object)val4 == (Object)null || (Object)(object)val4.gameObject == (Object)null) { continue; } GameObject gameObject = val4.gameObject; Scene scene = gameObject.scene; if (!((Scene)(ref scene)).IsValid()) { continue; } scene = gameObject.scene; if (!((Scene)(ref scene)).isLoaded || !gameObject.activeInHierarchy || !IsScrapGrabbable(val4)) { continue; } int @int = GetInt(val4, "scrapValue", 0); bool flag = GetBool(val4, "isHeld", fallback: false) || GetBool(val4, "isHeldByEnemy", fallback: false); bool inShip = GetBool(val4, "isInShipRoom", fallback: false) || GetBool(val4, "isInElevator", fallback: false); bool @bool = GetBool(val4, "isInFactory", fallback: false); object field = GetField<object>(val4, "itemProperties", null); bool flag2 = field != null && GetBool(field, "isScrap", fallback: false); string itemDisplayName = GetItemDisplayName(val4, field); bool flag3 = IsApparatusItem(val4, gameObject, itemDisplayName); bool flag4 = flag2 && !flag3; string path = GetPath(gameObject.transform); Vector3 position = val4.transform.position; num4++; result.RawValuedGrabbableCount++; result.RawValuedGrabbableValue += @int; int index = num4; string name = ((Object)gameObject).name; string name2 = ((object)val4).GetType().Name; scene = gameObject.scene; string value = BuildScrapLine(index, @int, itemDisplayName, name, name2, ((Scene)(ref scene)).name, position, flag2, flag3, flag, inShip, @bool, path); stringBuilder4.Append(value); if (flag4) { result.SpawnedScrapCount++; result.TotalScrapValue += @int; result.ItemPropertiesScrapCount++; result.ItemPropertiesScrapValue += @int; num5 = Mathf.Min(num5, @int); num6 = Mathf.Max(num6, @int); num++; int index2 = num; string name3 = ((Object)gameObject).name; string name4 = ((object)val4).GetType().Name; scene = gameObject.scene; stringBuilder.Append(BuildScrapLine(index2, @int, itemDisplayName, name3, name4, ((Scene)(ref scene)).name, position, flag2, flag3, flag, inShip, @bool, path)); if (flag) { result.HeldOrSkippedCount++; } else if (teleportToPlayer) { Vector3 val5 = ScrapDebugOffset(result.TeleportedCount); TeleportScrapComponent(val4, val3 + val5); result.TeleportedCount++; } } else if (flag3 && flag2) { result.ApparatusCount++; result.ApparatusValue += @int; result.TrueScrapIncludingApparatusCount++; result.TrueScrapIncludingApparatusValue += @int; num2++; int index3 = num2; string name5 = ((Object)gameObject).name; string name6 = ((object)val4).GetType().Name; scene = gameObject.scene; stringBuilder2.Append(BuildScrapLine(index3, @int, itemDisplayName, name5, name6, ((Scene)(ref scene)).name, position, flag2, flag3, flag, inShip, @bool, path)); if (flag) { result.HeldOrSkippedCount++; } else if (teleportToPlayer) { Vector3 val6 = ScrapDebugOffset(result.TeleportedCount); TeleportScrapComponent(val4, val3 + val6); result.TeleportedCount++; } } else { if (flag2) { result.TrueScrapIncludingApparatusCount++; result.TrueScrapIncludingApparatusValue += @int; } else { result.ValueOnlyCount++; result.ValueOnlyValue += @int; } num3++; int index4 = num3; string name7 = ((Object)gameObject).name; string name8 = ((object)val4).GetType().Name; scene = gameObject.scene; stringBuilder3.Append(BuildScrapLine(index4, @int, itemDisplayName, name7, name8, ((Scene)(ref scene)).name, position, flag2, flag3, flag, inShip, @bool, path)); } } result.TrueScrapIncludingApparatusCount = result.SpawnedScrapCount + result.ApparatusCount; result.TrueScrapIncludingApparatusValue = result.TotalScrapValue + result.ApparatusValue; result.MinScrapValue = ((result.SpawnedScrapCount > 0) ? num5 : 0); result.MaxScrapValue = ((result.SpawnedScrapCount > 0) ? num6 : 0); result.ItemBreakdown = stringBuilder.ToString(); result.ApparatusBreakdown = stringBuilder2.ToString(); result.NonScrapBreakdown = stringBuilder3.ToString(); result.RawBreakdown = stringBuilder4.ToString(); return result; } private static void PreClampSpawnableScrapValueRanges(RoundManager round, string reason) { if ((Object)(object)plugin == (Object)null || !plugin.PreClampScrapValuesBeforeGeneration.Value || !HasRoll || !IsServerOrNoNetwork() || IsCompanyRouteActive(round, TimeOfDay.Instance)) { return; } SelectableLevel val = null; if ((Object)(object)round != (Object)null) { val = GetField<SelectableLevel>(round, "currentLevel", null); } if ((Object)(object)val == (Object)null && (Object)(object)TimeOfDay.Instance != (Object)null) { val = GetField<SelectableLevel>(TimeOfDay.Instance, "currentLevel", null); } if ((Object)(object)val == (Object)null) { val = GetStarterLevel(); } if ((Object)(object)val == (Object)null) { return; } object field = GetField<object>(val, "spawnableScrap", null); if (!(field is IEnumerable enumerable)) { return; } List<SpawnableItemValueFields> list = new List<SpawnableItemValueFields>(); foreach (object item in enumerable) { if (item == null) { continue; } object obj = GetField<object>(item, "spawnableItem", null); if (obj == null) { obj = item; } if (obj == null) { continue; } FieldInfo fieldInfo = FindField(obj.GetType(), "minValue"); FieldInfo fieldInfo2 = FindField(obj.GetType(), "maxValue"); if (fieldInfo == null || fieldInfo2 == null) { continue; } int num = 0; int num2 = 0; try { num = Convert.ToInt32(fieldInfo.GetValue(obj)); } catch { num = 0; } try { num2 = Convert.ToInt32(fieldInfo2.GetValue(obj)); } catch { num2 = 0; } if (num <= 0 && num2 <= 0) { continue; } bool flag = false; for (int i = 0; i < temporaryScrapValueRanges.Count; i++) { if (temporaryScrapValueRanges[i].Item == obj) { flag = true; break; } } if (!flag) { temporaryScrapValueRanges.Add(new OriginalScrapItemValueRange { Item = obj, MinValue = num, MaxValue = num2 }); } list.Add(new SpawnableItemValueFields { Item = obj, MinField = fieldInfo, MaxField = fieldInfo2, OldMin = num, OldMax = num2, OldMid = Mathf.Max(1f, (float)(num + num2) * 0.5f) }); } if (list.Count == 0) { return; } float num3 = 0f; for (int j = 0; j < list.Count; j++) { num3 += list[j].OldMid; } num3 = Mathf.Max(1f, num3 / (float)list.Count); int num4 = Mathf.Max(1, Mathf.RoundToInt((float)(CurrentRoll.MinScrap + CurrentRoll.MaxScrap) * 0.5f)); float num5 = Mathf.Max(1f, (float)CurrentRoll.MaxTotalScrapValue / (float)num4); float num6 = Mathf.Clamp(num5 / num3, 0.02f, 2f); int num7 = 0; for (int k = 0; k < list.Count; k++) { SpawnableItemValueFields spawnableItemValueFields = list[k]; int num8 = Mathf.Max(1, Mathf.RoundToInt((float)spawnableItemValueFields.OldMin * num6)); int num9 = Mathf.Max(num8, Mathf.RoundToInt((float)spawnableItemValueFields.OldMax * num6)); int num10 = Mathf.Max(num8, Mathf.CeilToInt(num5 * 3f)); num9 = Mathf.Min(num9, num10); num8 = Mathf.Min(num8, num9); try { spawnableItemValueFields.MinField.SetValue(spawnableItemValueFields.Item, num8); } catch { } try { spawnableItemValueFields.MaxField.SetValue(spawnableItemValueFields.Item, num9); } catch { } num7++; } if (num7 > 0 && plugin.DebugLogging.Value) { Plugin.Log.LogInfo((object)("Mission pre-scaled scrap item value ranges before generation (" + reason + "): " + num7 + " spawnable entries. Expected count " + num4 + ", target average $" + Mathf.RoundToInt(num5) + ", scale " + num6.ToString("0.000") + ".")); } } private static void RestoreTemporaryScrapValueRanges(string reason, bool writeLog) { if (temporaryScrapValueRanges.Count == 0) { return; } int num = 0; for (int i = 0; i < temporaryScrapValueRanges.Count; i++) { OriginalScrapItemValueRange originalScrapItemValueRange = temporaryScrapValueRanges[i]; if (originalScrapItemValueRange == null || originalScrapItemValueRange.Item == null) { continue; } try { FieldInfo fieldInfo = FindField(originalScrapItemValueRange.Item.GetType(), "minValue"); FieldInfo fieldInfo2 = FindField(originalScrapItemValueRange.Item.GetType(), "maxValue"); if (fieldInfo != null) { fieldInfo.SetValue(originalScrapItemValueRange.Item, originalScrapItemValueRange.MinValue); } if (fieldInfo2 != null) { fieldInfo2.SetValue(originalScrapItemValueRange.Item, originalScrapItemValueRange.MaxValue); } num++; } catch { } } temporaryScrapValueRanges.Clear(); if (writeLog && (Object)(object)plugin != (Object)null && plugin.DebugLogging.Value) { Plugin.Log.LogInfo((object)("Mission restored temporary scrap item value ranges (" + reason + "): " + num + " items restored.")); } } private static void NormalizeSpawnedScrapForCurrentRoll(string reason, bool writeLog) { if ((Object)(object)plugin == (Object)null || !plugin.ModEnabled.Value || !HasRoll || !IsServerOrNoNetwork() || IsCompanyRouteActive(RoundManager.Instance, TimeOfDay.Instance) || (!plugin.NormalizeGeneratedScrapValue.Value && !plugin.EnforceGeneratedScrapCount.Value)) { return; } RoundManager instance = RoundManager.Instance; List<ScrapComponentRecord> list = CollectMissionScrapRecords(includeHeld: false); int count = list.Count; int num = SumScrapRecordValues(list); int num2 = 0; int num3 = 0; int num4 = Mathf.Min(CurrentRoll.MaxScrap, GetConfiguredMaxMissionScrapCount()); if (plugin.EnforceGeneratedScrapCount.Value && list.Count > num4) { list.Sort((ScrapComponentRecord a, ScrapComponentRecord b) => b.Value.CompareTo(a.Value)); int num5 = list.Count - num4; for (int i = 0; i < num5; i++) { ScrapComponentRecord scrapComponentRecord = list[i]; num2++; num3 += scrapComponentRecord.Value; DespawnOrDestroyScrap(scrapComponentRecord.Component); } list.RemoveRange(0, num5); } int minimumTotalScrapValueForRoll = GetMinimumTotalScrapValueForRoll(CurrentRoll); int num6 = Mathf.Max(minimumTotalScrapValueForRoll, CurrentRoll.MaxTotalScrapValue); int num7 = SumScrapRecordValues(list); bool flag = false; if (plugin.NormalizeGeneratedScrapValue.Value && list.Count > 0 && (num7 < minimumTotalScrapValueForRoll || num7 > num6)) { int targetValue = ChooseScrapTotalValueWithinRange(CurrentRoll, num7, list.Count); NormalizeScrapRecordValues(list, targetValue); num7 = SumScrapRecordValues(list); flag = true; } if ((Object)(object)instance != (Object)null) { SetField(instance, "totalScrapValueInLevel", (float)num7); } BroadcastScrapValueSync(list, num7, reason); if (writeLog && plugin.DebugLogging.Value) { Plugin.Log.LogInfo((object)("Mission scrap value range check (" + reason + "): original " + count + " / $" + num + ", removed " + num2 + " / $" + num3 + ", final " + list.Count + " / $" + num7 + ", allowed count <= " + num4 + ", allowed value range $" + minimumTotalScrapValueForRoll + "-$" + num6 + ", adjustedValue=" + flag + ".")); } } private static void HandleCleaningCompanyGrabbableStart(Component component) { if (!CleaningCompanyEnabled() || (Object)(object)component == (Object)null || (Object)(object)component.gameObject == (Object)null || !IsServerOrNoNetwork() || IsCompanyRouteActive(RoundManager.Instance, TimeOfDay.Instance) || !IsScrapGrabbable(component)) { return; } object field = GetField<object>(component, "itemProperties", null); if (field == null || !GetBool(field, "isScrap", fallback: false)) { return; } string name = ((object)component).GetType().Name; string itemDisplayName = GetItemDisplayName(component, field); string objectName = ((Object)component.gameObject).name ?? string.Empty; if (IsApparatusItem(component, component.gameObject, itemDisplayName)) { return; } TryApplyCleaningCompanyConvertedValue(component, "new scrap appeared"); string messType; string outputType; bool flag = TryGetCleaningCompanyMessConversion(name, itemDisplayName, objectName, out messType, out outputType); bool flag2 = IsCleaningCompanyOutputType(name, itemDisplayName, objectName); if (flag || flag2) { CleaningMessValueTracker cleaningMessValueTracker = component.gameObject.GetComponent<CleaningMessValueTracker>(); if ((Object)(object)cleaningMessValueTracker == (Object)null) { cleaningMessValueTracker = component.gameObject.AddComponent<CleaningMessValueTracker>(); } if (flag) { cleaningMessValueTracker.Initialize(component, messType, outputType, tracksCleaningSource: true); } else { cleaningMessValueTracker.Initialize(component, GetCleaningCompanyOutputType(name, itemDisplayName, objectName), string.Empty, tracksCleaningSource: false); } } } private static bool CleaningCompanyEnabled() { return (Object)(object)plugin != (Object)null && plugin.ModEnabled.Value && plugin.CleaningCompanySupport != null && plugin.CleaningCompanySupport.Value; } internal static void NotifyCleaningCompanyMessGone(CleaningMessValueTracker tracker, string reason) { //IL_00f9: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) if (!CleaningCompanyEnabled() || (Object)(object)tracker == (Object)null || !IsServerOrNoNetwork() || IsCompanyRouteActive(RoundManager.Instance, TimeOfDay.Instance)) { return; } Component scrapComponent = tracker.ScrapComponent; int num = Mathf.Max(1, tracker.LastKnownValue); if ((Object)(object)scrapComponent != (Object)null) { num = Mathf.Max(1, GetInt(scrapComponent, "scrapValue", num)); } Vector3 position = tracker.LastKnownPosition; try { if ((Object)(object)((Component)tracker).transform != (Object)null) { position = ((Component)tracker).transform.position; } } catch { } CleaningConversionRecord cleaningConversionRecord = new CleaningConversionRecord { MessType = (string.IsNullOrEmpty(tracker.MessType) ? "scrap" : tracker.MessType), OutputType = (string.IsNullOrEmpty(tracker.OutputType) ? "*" : tracker.OutputType), Value = num, Position = position, CreatedAt = Time.realtimeSinceStartup, SourceInstanceId = tracker.SourceInstanceId, SourceObjectName = (tracker.SourceObjectName ?? string.Empty) }; pendingCleaningConversions.Add(cleaningConversionRecord); CleanupExpiredCleaningCompanyConversions(); TryApplyCleaningCompanyQueuedValuesToExistingOutputs("scrap disappeared " + reason); if (ShouldDebugLog()) { Plugin.Log.LogInfo((object)("Cleaning Company value queued: " + cleaningConversionRecord.MessType + " -> " + cleaningConversionRecord.OutputType + " value=$" + cleaningConversionRecord.Value + " reason=" + reason + ".")); } } private static void CleanupExpiredCleaningCompanyConversions() { if (pendingCleaningConversions.Count == 0 || Time.realtimeSinceStartup < nextCleaningConversionCleanupTime) { return; } nextCleaningConversionCleanupTime = Time.realtimeSinceStartup + 0.5f; float realtimeSinceStartup = Time.realtimeSinceStartup; float num = (((Object)(object)plugin != (Object)null && plugin.CleaningCompanyConversionWindowSeconds != null) ? Mathf.Max(0.25f, plugin.CleaningCompanyConversionWindowSeconds.Value) : 4f); for (int num2 = pendingCleaningConversions.Count - 1; num2 >= 0; num2--) { if (realtimeSinceStartup - pendingCleaningConversions[num2].CreatedAt > num) { pendingCleaningConversions.RemoveAt(num2); } } } private static void TryApplyCleaningCompanyQueuedValuesToExistingOutputs(string reason) { if (!CleaningCompanyEnabled() || pendingCleaningConversions.Count == 0) { return; } GrabbableObject[] array = Object.FindObjectsOfType<GrabbableObject>(); for (int i = 0; i < array.Length; i++) { if (pendingCleaningConversions.Count == 0) { break; } Component val = (Component)(object)array[i]; if (!((Object)(object)val == (Object)null) && !((Object)(object)val.gameObject == (Object)null) && IsRecentlyStartedCleaningTrackedScrap(val)) { TryApplyCleaningCompanyConvertedValue(val, reason); } } } private static bool TryApplyCleaningCompanyConvertedValue(Component outputComponent, string reason) { //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_0175: Unknown result type (might be due to invalid IL or missing references) //IL_017a: Unknown result type (might be due to invalid IL or missing references) //IL_017c: Unknown result type (might be due to invalid IL or missing references) //IL_0181: Unknown result type (might be due to invalid IL or missing references) if (!CleaningCompanyEnabled() || (Object)(object)outputComponent == (Object)null || (Object)(object)outputComponent.gameObject == (Object)null || pendingCleaningConversions.Count == 0) { return false; } if (!IsScrapGrabbable(outputComponent)) { return false; } object field = GetField<object>(outputComponent, "itemProperties", null); if (field == null || !GetBool(field, "isScrap", fallback: false)) { return false; } string name = ((object)outputComponent).GetType().Name; string itemDisplayName = GetItemDisplayName(outputComponent, field); string objectName = ((Object)outputComponent.gameObject).name ?? string.Empty; if (IsApparatusItem(outputComponent, outputComponent.gameObject, itemDisplayName)) { return false; } Vector3 position = outputComponent.transform.position; float num = (((Object)(object)plugin != (Object)null && plugin.CleaningCompanyConversionSearchRadius != null) ? Mathf.Max(0.25f, plugin.CleaningCompanyConversionSearchRadius.Value) : 6f); float num2 = num * num; int instanceID = ((Object)outputComponent.gameObject).GetInstanceID(); int num3 = -1; float num4 = float.MaxValue; for (int i = 0; i < pendingCleaningConversions.Count; i++) { CleaningConversionRecord cleaningConversionRecord = pendingCleaningConversions[i]; if (cleaningConversionRecord.SourceInstanceId != instanceID && CleaningCompanyOutputMatches(cleaningConversionRecord.OutputType, name, itemDisplayName, objectName)) { Vector3 val = cleaningConversionRecord.Position - position; float sqrMagnitude = ((Vector3)(ref val)).sqrMagnitude; if (sqrMagnitude <= num2 && sqrMagnitude < num4) { num4 = sqrMagnitude; num3 = i; } } } if (num3 < 0) { return false; } CleaningConversionRecord cleaningConversionRecord2 = pendingCleaningConversions[num3]; pendingCleaningConversions.RemoveAt(num3); int num5 = Mathf.Max(1, cleaningConversionRecord2.Value); SetScrapValue(outputComponent, num5); RoundManager instance = RoundManager.Instance; int num6 = (((Object)(object)instance != (Object)null) ? Mathf.RoundToInt(GetField(instance, "totalScrapValueInLevel", 0f)) : 0); if (num6 <= 0) { num6 = num5; } List<ScrapComponentRecord> list = new List<ScrapComponentRecord>(); list.Add(new ScrapComponentRecord { Component = outputComponent, GameObject = outputComponent.gameObject, Value = num5, ItemName = itemDisplayName, SyncIndex = -1 }); BroadcastScrapValueSync(list, num6, "Cleaning Company nearby conversion " + reason); CleaningMessValueTracker component = outputComponent.gameObject.GetComponent<CleaningMessValueTracker>(); if ((Object)(object)component != (Object)null) { component.LastKnownValue = num5; } if (ShouldDebugLog()) { Plugin.Log.LogInfo((object)("Cleaning Company preserved nearby value: " + cleaningConversionRecord2.MessType + " -> " + BuildCleaningCompanyScrapToken(name, itemDisplayName, objectName) + " value=$" + num5 + " reason=" + reason + ".")); } return true; } private static bool IsRecentlyStartedCleaningTrackedScrap(Component component) { if ((Object)(object)component == (Object)null || (Object)(object)component.gameObject == (Object)null) { return false; } CleaningMessValueTracker component2 = component.gameObject.GetComponent<CleaningMessValueTracker>(); if ((Object)(object)component2 == (Object)null) { return false; } float num = (((Object)(object)plugin != (Object)null && plugin.CleaningCompanyConversionWindowSeconds != null) ? Mathf.Max(0.25f, plugin.CleaningCompanyConversionWindowSeconds.Value) : 4f); return Time.realtimeSinceStartup - component2.CreatedAt <= num; } private static bool CleaningCompanyOutputMatches(string expectedOutputType, string typeName, string itemName, string objectName) { if (string.IsNullOrEmpty(expectedOutputType)) { return false; } string cleaningCompanyOutputType = GetCleaningCompanyOutputType(typeName, itemName, objectName); return !string.IsNullOrEmpty(cleaningCompanyOutputType) && string.Equals(cleaningCompanyOutputType, expectedOutputType, StringComparison.OrdinalIgnoreCase); } private static bool TryGetCleaningCompanyMessConversion(string typeName, string itemName, string objectName, out string messType, out string outputType) { string token = BuildCleaningCompanyScrapToken(typeName, itemName, objectName); messType = string.Empty; outputType = string.Empty; if (TokenMatchesAnyCleaningName(token, "Scav Goop")) { messType = "Scav Goop"; outputType = "Dirty Water"; return true; } if (TokenMatchesAnyCleaningName(token, "Thumper Drool")) { messType = "Thumper Drool"; outputType = "Dirty Water"; return true; } if (TokenMatchesAnyCleaningName(token, "Bone Pile")) { messType = "Bone Pile"; outputType = "Full Garbage Bag"; return true; } if (TokenMatchesAnyCleaningName(token, "Nail Pile Item")) { messType = "Nail Pile Item"; outputType = "Full Garbage Bag"; return true; } if (TokenMatchesAnyCleaningName(token, "BrackenDustItem")) { messType = "BrackenDustItem"; outputType = "Full Garbage Bag"; return true; } if (TokenMatchesAnyCleaningName(token, "Ethereal Essence")) { messType = "Ethereal Essence"; outputType = "Full Garbage Bag"; return true; } if (TokenMatchesAnyCleaningName(token, "Hoarding Bug Eggs")) { messType = "Hoarding Bug Eggs"; outputType = "Full Garbage Bag"; return true; } if (TokenMatchesAnyCleaningName(token, "Spore Pile")) { messType = "Spore Pile"; outputType = "Full Garbage Bag"; return true; } return false; } private static bool IsCleaningCompanyOutputType(string typeName, string itemName, string objectName) { string cleaningCompanyOutputType = GetCleaningCompanyOutputType(typeName, itemName, objectName); return !string.IsNullOrEmpty(cleaningCompanyOutputType); } private static string GetCleaningCompanyOutputType(string typeName, string itemName, string objectName) { string token = BuildCleaningCompanyScrapToken(typeName, itemName, objectName); if (TokenMatchesAnyCleaningName(token, "Dirty Water")) { return "Dirty Water"; } if (TokenMatchesAnyCleaningName(token, "Full Garbage Bag")) { return "Full Garbage Bag"; } return string.Empty; } private static string BuildCleaningCompanyScrapToken(string typeName, string itemName, string objectName) { string text = ((typeName ?? string.Empty) + " " + (itemName ?? string.Empty) + " " + (objectName ?? string.Empty)).Trim(); return string.IsNullOrEmpty(text) ? "scrap" : text; } private static bool TokenMatchesAnyCleaningName(string token, params string[] names) { for (int i = 0; i < names.Length; i++) { if (TokenMatchesCleaningName(token, names[i])) { return true; } } return false; } private static bool TokenMatchesCleaningName(string token, string name) { if (string.IsNullOrEmpty(token) || string.IsNullOrEmpty(name)) { return false; } string text = NormalizeCleaningName(token); string value = NormalizeCleaningName(name); return text.IndexOf(value, StringComparison.OrdinalIgnoreCase) >= 0; } private static string NormalizeCleaningName(string value) { if (string.IsNullOrEmpty(value)) { return string.Empty; } StringBuilder stringBuilder = new StringBuilder(value.Length); foreach (char c in value) { if (char.IsLetterOrDigit(c)) { stringBuilder.Append(char.ToLowerInvariant(c)); } } return stringBuilder.ToString(); } private static List<ScrapComponentRecord> CollectMissionScrapRecords(bool includeHeld) { //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) List<ScrapComponentRecord> list = new List<ScrapComponentRecord>(); Component[] array = Resources.FindObjectsOfTypeAll<Component>(); Component[] array2 = array; foreach (Component val in array2) { if ((Object)(object)val == (Object)null || (Object)(object)val.gameObject == (Object)null) { continue; } GameObject gameObject = val.gameObject; Scene scene = gameObject.scene; if (!((Scene)(ref scene)).IsValid()) { continue; } scene = gameObject.scene; if (!((Scene)(ref scene)).isLoaded || !gameObject.activeInHierarchy || !IsScrapGrabbable(val) || ((GetBool(val, "isHeld", fallback: false) || GetBool(val, "isHeldByEnemy", fallback: false)) && !includeHeld)) { continue; } object field = GetField<object>(val, "itemProperties", null); if (field != null && GetBool(field, "isScrap", fallback: false)) { string itemDisplayName = GetItemDisplayName(val, field); if (!IsApparatusItem(val, gameObject, itemDisplayName)) { list.Add(new ScrapComponentRecord { Component = val, GameObject = gameObject, Value = GetInt(val, "scrapValue", 0), ItemName = itemDisplayName }); } } } return list; } private static int SumScrapRecordValues(List<ScrapComponentRecord> records) { int num = 0; if (records == null) { return 0; } for (int i = 0; i < records.Count; i++) { if (records[i] != null && (Object)(object)records[i].Component != (Object)null) { num += Mathf.Max(0, GetInt(records[i].Component, "scrapValue", records[i].Value)); } } return num; } private static void NormalizeScrapRecordValues(List<ScrapComponentRecord> records, int targetValue) { if (records == null || records.Count == 0) { return; } targetValue = Mathf.Max(records.Count, targetValue); int num = 0; for (int i = 0; i < records.Count; i++) { num += Mathf.Max(1, records[i].Value); } if (num <= 0) { num = records.Count; } int[] array = new int[records.Count]; int num2 = 0; for (int j = 0; j < records.Count; j++) { float num3 = (float)Mathf.Max(1, records[j].Value) / (float)num * (float)targetValue; num2 += (array[j] = Mathf.Max(1, Mathf.FloorToInt(num3))); } int num4 = targetValue - num2; int num5 = 0; while (num4 != 0 && num5 < 100000) { int num6 = num5 % array.Length; if (num4 > 0) { array[num6]++; num4--; } else if (array[num6] > 1) { array[num6]--; num4++; } num5++; } for (int k = 0; k < records.Count; k++) { SetScrapValue(records[k].Component, array[k]); records[k].Value = array[k]; } } private static void SetScrapValue(Component component, int value) { if ((Object)(object)component == (Object)null) { return; } value = Mathf.Max(0, value); try { MethodInfo method = ((object)component).GetType().GetMethod("SetScrapValue", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[1] { typeof(int) }, null); if (method != null) { method.Invoke(component, new object[1] { value }); } } catch { } ForceScrapValueFields(component, value); } private static void ForceScrapValueFields(Component component, int value) { if ((Object)(object)component == (Object)null) { return; } value = Mathf.Max(0, value); try { SetField(component, "scrapValue", value); } catch { } try { ScanNodeProperties val = (((Object)(object)component.gameObject != (Object)null) ? component.gameObject.GetComponentInChildren<ScanNodeProperties>(true) : null); if ((Object)(object)val != (Object)null) { val.scrapValue = value; val.subText = "Value: $" + value; } } catch { } } private static void DespawnOrDestroyScrap(Component component) { if ((Object)(object)component == (Object)null || (Object)(object)component.gameObject == (Object)null) { return; } try { NetworkObject component2 = component.GetComponent<NetworkObject>(); if ((Object)(object)component2 != (Object)null && component2.IsSpawned && IsServerOrNoNetwork()) { component2.Despawn(true); return; } } catch { } try { Object.Destroy((Object)(object)component.gameObject); } catch { } } private static string BuildScrapLine(int index, int scrapValue, string itemName, string objectName, string typeName, string sceneName, Vector3 pos, bool itemPropertiesSaysScrap, bool isApparatus, bool held, bool inShip, bool inFactory, string path) { //IL_0099: Unknown result type (might be due to invalid IL or missing references) StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append(" "); stringBuilder.Append(index.ToString("000")); stringBuilder.Append(" | value=$"); stringBuilder.Append(scrapValue); stringBuilder.Append(" | item='"); stringBuilder.Append(itemName); stringBuilder.Append("' | object='"); stringBuilder.Append(objectName); stringBuilder.Append("' | type="); stringBuilder.Append(typeName); stringBuilder.Append(" | scene="); stringBuilder.Append(sceneName); stringBuilder.Append(" | pos="); stringBuilder.Append(FormatVector(pos)); stringBuilder.Append(" | itemProperties.isScrap="); stringBuilder.Append(itemPropertiesSaysScrap); stringBuilder.Append(" | apparatus="); stringBuilder.Append(isApparatus); stringBuilder.Append(" | held="); stringBuilder.Append(held); stringBuilder.Append(" | inShip="); stringBuilder.Append(inShip); stringBuilder.Append(" | inFactory="); stringBuilder.Append(inFactory); stringBuilder.Append(" | path="); stringBuilder.Append(path); stringBuilder.AppendLine(); return stringBuilder.ToString(); } private static bool IsApparatusItem(Component component, GameObject gameObject, string itemName) { string text = (((Object)(object)component != (Object)null) ? ((object)component).GetType().Name : string.Empty); string text2 = (((Object)(object)gameObject != (Object)null) ? ((Object)gameObject).name : string.Empty); if (!string.IsNullOrEmpty(text) && text.IndexOf("Lung", StringComparison.OrdinalIgnoreCase) >= 0) { return true; } if (!string.IsNullOrEmpty(text2) && text2.IndexOf("LungApparatus", StringComparison.OrdinalIgnoreCase) >= 0) { return true; } if (!string.IsNullOrEmpty(itemName) && itemName.IndexOf("Apparatus", StringComparison.OrdinalIgnoreCase) >= 0) { return true; } return false; } private static string GetItemDisplayName(Component component, object itemProperties) { string text = ((itemProperties != null) ? GetField<string>(itemProperties, "itemName", null) : null); if (!string.IsNullOrWhiteSpace(text)) { return text; } text = GetField<string>(component, "itemName", null); if (!string.IsNullOrWhiteSpace(text)) { return text; } return ((Object)(object)component != (Object)null && (Object)(object)component.gameObject != (Object)null) ? ((Object)component.gameObject).name : "unknown"; } private static string FormatVector(Vector3 value) { return "(" + value.x.ToString("0.00") + ", " + value.y.ToString("0.00") + ", " + value.z.ToString("0.00") + ")"; } private static Vector3 ScrapDebugOffset(int index) { //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_003b: 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) int num = index % 7; int num2 = index / 7 % 7; int num3 = index / 49; float num4 = (float)(num - 3) * 0.55f; float num5 = (float)(num2 - 3) * 0.55f; float num6 = (float)num3 * 0.2f; return new Vector3(num4, num6, num5); } private static void TeleportScrapComponent(Component component, Vector3 position) { //IL_0009: 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_0056: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) Transform transform = component.transform; transform.position = position; transform.rotation = Quaternion.identity; Rigidbody component2 = component.GetComponent<Rigidbody>(); if ((Object)(object)component2 != (Object)null) { component2.velocity = Vector3.zero; component2.angularVelocity = Vector3.zero; component2.position = position; } SetField(component, "startFallingPosition", position); SetField(component, "targetFloorPosition", position); SetField(component, "floorYRot", transform.eulerAngles.y); SetField(component, "fallTime", 1f); SetField(component, "hasHitGround", true); SetField(component, "reachedFloorTarget", true); SetField(component, "isInElevator", false); SetField(component, "isInShipRoom", false); SetField(component, "isInFactory", true); } private static bool IsScrapGrabbable(Component component) { if ((Object)(object)component == (Object)null) { return false; } if (!TypeIsOrInherits(((object)component).GetType(), "GrabbableObject")) { return false; } object field = GetField<object>(component, "itemProperties", null); if (field != null && GetBool(field, "isScrap", fallback: false)) { return true; } return GetInt(component, "scrapValue", 0) > 0; } private static bool TypeIsOrInherits(Type type, string typeName) { while (type != null) { if (string.Equals(type.Name, typeName, StringComparison.OrdinalIgnoreCase)) { return true; } type = type.BaseType; } return false; } private static string BuildActualVsExpectedDebugReport(RoundManager round, TimeOfDay time, ScrapDebugStats scrapStats) { StringBuilder stringBuilder = new StringBuilder(); MissionRoll currentRoll = CurrentRoll; SelectableLevel activeLevel = GetActiveLevel(round, time); stringBuilder.AppendLine("Mission Debug: actual mission scrap " + scrapStats.SpawnedScrapCount + " items / $" + scrapStats.TotalScrapValue + " excluding apparatus. Apparatus " + scrapStats.ApparatusCount + " / $" + scrapStats.ApparatusValue + ". Raw valued objects " + scrapStats.RawValuedGrabbableCount + " / $" + scrapStats.RawValuedGrabbableValue + ". Teleported true scrap " + scrapStats.TeleportedCount + "."); if (!string.IsNullOrEmpty(scrapStats.Error)) { stringBuilder.AppendLine("Mission Debug error: " + scrapStats.Error); } if (HasRoll) { float num = (((Object)(object)round != (Object)null) ? GetFloat(round, "scrapAmountMultiplier", currentRoll.ScrapAmountMultiplier) : currentRoll.ScrapAmountMultiplier); int num2 = Mathf.RoundToInt((float)currentRoll.MinScrap * num); int num3 = Mathf.CeilToInt((float)currentRoll.MaxScrap * num); stringBuilder.AppendLine("Expected orbit roll: rank " + currentRoll.Rank + ", displayed scrap " + currentRoll.MinScrap + "-" + currentRoll.MaxScrap + ", effective if multiplier applies " + num2 + "-" + num3 + ", value range " + TotalScrapValueRangeText(currentRoll) + ", power " + currentRoll.MaxInsideEnemyPower + ", size " + currentRoll.FactorySizeMultiplier.ToString("0.00") + ", amount x" + num.ToString("0.00") + ", value x" + currentRoll.ScrapValueMultiplier.ToString("0.00") + "."); } else { stringBuilder.AppendLine("Expected orbit roll: no mission roll exists yet."); } if ((Object)(object)activeLevel != (Object)null) { string field = GetField(activeLevel, "riskLevel", "?"); int @int = GetInt(activeLevel, "minScrap", -1); int int2 = GetInt(activeLevel, "maxScrap", -1); int int3 = GetInt(activeLevel, "maxTotalScrapValue", -1); int int4 = GetInt(activeLevel, "maxEnemyPowerCount", -1); int int5 = GetInt(activeLevel, "maxOutsideEnemyPowerCount", -1); int int6 = GetInt(activeLevel, "maxDaytimeEnemyPowerCount", -1); float @float = GetFloat(activeLevel, "factorySizeMultiplier", -1f); stringBuilder.AppendLine("Actual level values: risk " + field + ", scrap " + @int + "-" + int2 + ", max value $" + int3 + ", inside power " + int4 + ", outside/day " + int5 + "/" + int6 + ", size " + @float.ToString("0.00") + "."); } else { stringBuilder.AppendLine("Actual level values: no active SelectableLevel found."); } if ((Object)(object)round != (Object)null) { float float2 = GetFloat(round, "currentMaxInsidePower", -1f); float float3 = GetFloat(round, "currentMaxOutsidePower", -1f); int int7 = GetInt(round, "currentMaxInsideDiversityLevel", -1); int int8 = GetInt(round, "minEnemiesToSpawn", -1); int int9 = GetInt(round, "hourTimeBetweenEnemySpawnBatches", -1); float float4 = GetFloat(round, "mapSizeMultiplier", -1f); float float5 = GetFloat(round, "scrapAmountMultiplier", -1f); float float6 = GetFloat(round, "scrapValueMultiplier", -1f); stringBuilder.AppendLine("Actual round values: inside/outside power " + float2.ToString("0.##") + "/" + float3.ToString("0.##") + ", diversity " + int7 + ", min enemies " + int8 + ", batch hours " + int9 + ", size " + float4.ToString("0.00") + ", amount x" + float5.ToString("0.00") + ", value x" + float6.ToString("0.00") + "."); } return stringBuilder.ToString().Trim(); } private static string BuildFullMissionDebugFileReport(string reason, RoundManager round, TimeOfDay time, ScrapDebugStats? scrapStatsNullable) { StringBuilder stringBuilder = new StringBuilder(); SelectableLevel activeLevel = GetActiveLevel(round, time); stringBuilder.AppendLine("============================================================"); stringBuilder.AppendLine("LC MISSION RANDOMIZER DEBUG FILE"); stringBuilder.AppendLine("============================================================"); stringBuilder.AppendLine("Reason: " + reason); stringBuilder.AppendLine("Local time: " + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")); stringBuilder.AppendLine("UTC time: " + DateTime.UtcNow.ToString("yyyy-MM-dd HH:mm:ss") + " UTC"); stringBuilder.AppendLine("Plugin version: 0.1.25"); stringBuilder.AppendLine("Server/host authoritative side: " + IsServerOrNoNetwork()); stringBuilder.AppendLine("Has mission roll: " + HasRoll); stringBuilder.AppendLine(); AppendSceneList(stringBuilder); stringBuilder.AppendLine(); stringBuilder.AppendLine("=== EXPECTED ORBIT MISSION ROLL ==="); if (HasRoll) { AppendExpectedRoll(stringBuilder, CurrentRoll); } else { stringBuilder.AppendLine("No mission roll exists yet."); } stringBuilder.AppendLine(); stringBuilder.AppendLine("=== VALUES THIS MOD TRIED TO APPLY ==="); if (HasRoll) { AppendAttemptedChangedValues(stringBuilder, CurrentRoll); } else { stringBuilder.AppendLine("No attempted values. No roll exists yet."); } stringBuilder.AppendLine(); stringBuilder.AppendLine("=== ACTUAL SELECTABLE LEVEL VALUES NOW ==="); AppendSelectableLevelValues(stringBuilder, activeLevel); stringBuilder.AppendLine(); stringBuilder.AppendLine("=== ACTUAL ROUND MANAGER VALUES NOW ==="); AppendRoundManagerValues(stringBuilder, round); stringBuilder.AppendLine(); stringBuilder.AppendLine("=== ACTUAL TIME OF DAY VALUES NOW ==="); AppendTimeOfDayValues(stringBuilder, time); stringBuilder.AppendLine(); stringBuilder.AppendLine("=== TERMINAL / CATALOGUE SNAPSHOT ==="); AppendTerminalSnapshot(stringBuilder); stringBuilder.AppendLine(); if (scrapStatsNullable.HasValue) { ScrapDebugStats value = scrapStatsNullable.Value; stringBuilder.AppendLine("=== SPAWNED SCRAP SNAPSHOT ==="); stringBuilder.AppendLine("Raw valued grabbables found: " + value.RawValuedGrabbableCount + " / $" + value.RawValuedGrabbableValue); stringBuilder.AppendLine("Actual mission scrap only, excluding apparatus and non-scrap valued items: " + value.SpawnedScrapCount + " / $" + value.TotalScrapValue); stringBuilder.AppendLine("True scrap including apparatus: " + value.TrueScrapIncludingApparatusCount + " / $" + value.TrueScrapIncludingApparatusValue); stringBuilder.AppendLine("Apparatus only: " + value.ApparatusCount + " / $" + value.ApparatusValue); stringBuilder.AppendLine("Non-scrap valued grabbables, keys/manual/sticky notes/etc: " + value.ValueOnlyCount + " / $" + value.ValueOnlyValue); stringBuilder.AppendLine("Held/skipped count: " + value.HeldOrSkippedCount); stringBuilder.AppendLine("Teleported true scrap count: " + value.TeleportedCount); stringBuilder.AppendLine("Mission scrap min item value: $" + value.MinScrapValue); stringBuilder.AppendLine("Mission scrap max item value: $" + value.MaxScrapValue); if (!string.IsNullOrEmpty(value.Error)) { stringBuilder.AppendLine("Error: " + value.Error); } stringBuilder.AppendLine(); stringBuilder.AppendLine("--- ACTUAL LOADED MISSION SCRAP ITEMS ONLY ---"); stringBuilder.Append(value.ItemBreakdown); if (string.IsNullOrWhiteSpace(value.ItemBreakdown)) { stringBuilder.AppendLine("No actual mission scrap items were found."); } stringBuilder.AppendLine(); stringBuilder.AppendLine("--- APPARATUS ITEMS, LOGGED SEPARATELY ---"); stringBuilder.Append(value.ApparatusBreakdown); if (string.IsNullOrWhiteSpace(value.ApparatusBreakdown)) { stringBuilder.AppendLine("No apparatus item was found."); } stringBuilder.AppendLine(); stringBuilder.AppendLine("--- NON-SCRAP VALUED GRABBABLES, EXCLUDED FROM MISSION SCRAP TOTAL ---"); stringBuilder.Append(value.NonScrapBreakdown); if (string.IsNullOrWhiteSpace(value.NonScrapBreakdown)) { stringBuilder.AppendLine("No non-scrap valued grabbables were found."); } stringBuilder.AppendLine(); if (HasRoll) { float num = (((Object)(object)round != (Object)null) ? GetFloat(round, "scrapAmountMultiplier", CurrentRoll.ScrapAmountMultiplier) : CurrentRoll.ScrapAmountMultiplier); int num2 = Mathf.RoundToInt((float)CurrentRoll.MinScrap * num); int num3 = Mathf.CeilToInt((float)CurrentRoll.MaxScrap * num); stringBuilder.AppendLine("=== EXPECTED VS ACTUAL QUICK CHECK ==="); stringBuilder.AppendLine("Displayed/base scrap count range: " + CurrentRoll.MinScrap + " - " + CurrentRoll.MaxScrap); stringBuilder.AppendLine("RoundManager.scrapAmountMultiplier at snapshot: " + num.ToString("0.000")); stringBuilder.AppendLine("Effective generated range if the game applies that multiplier: " + num2 + " - " + num3); stringBuilder.AppendLine("Actual loaded mission scrap count, excluding apparatus: " + value.SpawnedScrapCount); stringBuilder.AppendLine("Base displayed count inside expected range: " + (value.SpawnedScrapCount >= CurrentRoll.MinScrap && value.SpawnedScrapCount <= CurrentRoll.MaxScrap)); stringBuilder.AppendLine("Effective multiplied count inside expected range: " + (value.SpawnedScrapCount >= num2 && value.SpawnedScrapCount <= num3)); stringBuilder.AppendLine("Expected total scrap value range target: " + TotalScrapValueRangeText(CurrentRoll)); stringBuilder.AppendLine("Actual loaded mission scrap value, excluding apparatus: $" + value.TotalScrapValue); stringBuilder.AppendLine("Actual loaded mission scrap over max target by: $" + (value.TotalScrapValue - CurrentRoll.MaxTotalScrapValue)); stringBuilder.AppendLine("Actual true scrap including apparatus over max target by: $" + (value.TrueScrapIncludingApparatusValue - CurrentRoll.MaxTotalScrapValue)); stringBuilder.AppendLine(); } } return stringBuilder.ToString(); } private static void AppendSceneList(StringBuilder sb) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) sb.AppendLine("=== LOADED SCENES ==="); for (int i = 0; i < SceneManager.sceneCount; i++) { Scene sceneAt = SceneManager.GetSceneAt(i); sb.AppendLine("Scene[" + i + "] name='" + ((Scene)(ref sceneAt)).name + "' path='" + ((Scene)(ref sceneAt)).path + "' loaded=" + ((Scene)(ref sceneAt)).isLoaded + " rootCount=" + ((Scene)(ref sceneAt)).rootCount); } } private static void AppendExpectedRoll(StringBuilder sb, MissionRoll r) { sb.AppendLine("Seed: " + r.Seed); sb.AppendLine("Quota: $" + r.QuotaFulfilled + " / $" + r.ProfitQuota + " remaining=$" + r.QuotaRemaining + " daysLeft=" + r.DaysLeft + " quotaNumber=" + r.QuotaNumber); sb.AppendLine("Rank: " + r.Rank + " rankIndex=" + r.RankIndex + " difficultyScore=" + r.DifficultyScore.ToString("0.000")); sb.AppendLine("Scrap count target: " + r.MinScrap + " - " + r.MaxScrap); sb.AppendLine("Total scrap value range target: " + TotalScrapValueRangeText(r)); sb.AppendLine("Inside/outside/daytime enemy power: " + r.MaxInsideEnemyPower + " / " + r.MaxOutsideEnemyPower + " / " + r.MaxDaytimeEnemyPower); sb.AppendLine("Min enemies to spawn: " + r.MinEnemiesToSpawn); sb.AppendLine("Spawn batch hours: " + r.SpawnBatchHours); sb.AppendLine("Inside diversity: " + r.MaxInsideDiversity); sb.AppendLine("Factory size multiplier: " + r.FactorySizeMultiplier.ToString("0.000")); sb.AppendLine("RoundManager scrap amount multiplier: " + r.ScrapAmountMultiplier.ToString("0.000")); sb.AppendLine("RoundManager scrap value multiplier: " + r.ScrapValueMultiplier.ToString("0.000")); } private static void AppendAttemptedChangedValues(StringBuilder sb, MissionRoll r) { int minimumTotalScrapValueForRoll = GetMinimumTotalScrapValueForRoll(r); sb.AppendLine("SelectableLevel.PlanetName -> Mission Zone"); sb.AppendLine("SelectableLevel.riskLevel -> " + r.Rank); sb.AppendLine("SelectableLevel.factorySizeMultiplier -> " + r.FactorySizeMultiplier.ToString("0.000")); sb.AppendLine("SelectableLevel.minScrap -> " + r.MinScrap); sb.AppendLine("SelectableLevel.maxScrap -> " + r.MaxScrap); sb.AppendLine("SelectableLevel.minTotalScrapValue -> " + minimumTotalScrapValueForRoll); sb.AppendLine("SelectableLevel.maxTotalScrapValue -> " + r.MaxTotalScrapValue); sb.AppendLine("SelectableLevel.maxEnemyPowerCount -> " + r.MaxInsideEnemyPower); sb.AppendLine("SelectableLevel.maxOutsideEnemyPowerCount -> " + r.MaxOutsideEnemyPower); sb.AppendLine("SelectableLevel.maxDaytimeEnemyPowerCount -> " + r.MaxDaytimeEnemyPower); sb.AppendLine("SelectableLevel.spawnEnemiesAndScrap -> true"); sb.AppendLine("RoundManager.scrapValueMultiplier -> " + r.ScrapValueMultiplier.ToString("0.000")); sb.AppendLine("RoundManager.scrapAmountMultiplier -> " + r.ScrapAmountMultiplier.ToString("0.000")); sb.AppendLine("RoundManager.mapSizeMultiplier -> " + r.FactorySizeMultiplier.ToString("0.000")); sb.AppendLine("RoundManager.currentMaxInsidePower -> " + r.MaxInsideEnemyPower); sb.AppendLine("RoundManager.currentMaxOutsidePower -> " + r.MaxOutsideEnemyPower); sb.AppendLine("RoundManager.currentMaxInsideDiversityLevel -> " + r.MaxInsideDiversity); sb.AppendLine("RoundManager.currentMaxOutsideDiversityLevel -> " + ((!plugin.DisableOutsideAndDaytimePower.Value) ? r.MaxInsideDiversity : 0)); sb.AppendLine("RoundManager.minEnemiesToSpawn -> " + r.MinEnemiesToSpawn); sb.AppendLine("RoundManager.minOutsideEnemiesToSpawn -> 0"); sb.AppendLine("RoundManager.hourTimeBetweenEnemySpawnBatches -> " + r.SpawnBatchHours); } private static void AppendSelectableLevelValues(StringBuilder sb, SelectableLevel level) { if ((Object)(object)level == (Object)null) { sb.AppendLine("No active SelectableLevel found."); return; } sb.AppendLine("Unity name: " + ((Object)level).name); sb.AppendLine("PlanetName: " + GetField(level, "PlanetName", "?")); sb.AppendLine("sceneName: " + GetField(level, "sceneName", "?")); sb.Append